]> Pileus Git - ~andy/linux/blob - drivers/staging/tidspbridge/rmgr/disp.c
staging: ti dspbridge: Rename words with camel case
[~andy/linux] / drivers / staging / tidspbridge / rmgr / disp.c
1 /*
2  * disp.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * Node Dispatcher interface. Communicates with Resource Manager Server
7  * (RMS) on DSP. Access to RMS is synchronized in NODE.
8  *
9  * Copyright (C) 2005-2006 Texas Instruments, Inc.
10  *
11  * This package is free software;  you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  *
15  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19
20 /*  ----------------------------------- Host OS */
21 #include <dspbridge/host_os.h>
22
23 /*  ----------------------------------- DSP/BIOS Bridge */
24 #include <dspbridge/std.h>
25 #include <dspbridge/dbdefs.h>
26
27 /*  ----------------------------------- Trace & Debug */
28 #include <dspbridge/dbc.h>
29
30 /*  ----------------------------------- OS Adaptation Layer */
31 #include <dspbridge/sync.h>
32
33 /*  ----------------------------------- Link Driver */
34 #include <dspbridge/dspdefs.h>
35
36 /*  ----------------------------------- Platform Manager */
37 #include <dspbridge/dev.h>
38 #include <dspbridge/chnldefs.h>
39
40 /*  ----------------------------------- Resource Manager */
41 #include <dspbridge/nodedefs.h>
42 #include <dspbridge/nodepriv.h>
43 #include <dspbridge/rms_sh.h>
44
45 /*  ----------------------------------- This */
46 #include <dspbridge/disp.h>
47
48 /* Size of a reply from RMS */
49 #define REPLYSIZE (3 * sizeof(rms_word))
50
51 /* Reserved channel offsets for communication with RMS */
52 #define CHNLTORMSOFFSET       0
53 #define CHNLFROMRMSOFFSET     1
54
55 #define CHNLIOREQS      1
56
57 #define SWAP_WORD(x)     (((u32)(x) >> 16) | ((u32)(x) << 16))
58
59 /*
60  *  ======== disp_object ========
61  */
62 struct disp_object {
63         struct dev_object *hdev_obj;    /* Device for this processor */
64         /* Function interface to Bridge driver */
65         struct bridge_drv_interface *intf_fxns;
66         struct chnl_mgr *hchnl_mgr;     /* Channel manager */
67         struct chnl_object *chnl_to_dsp;        /* Chnl for commands to RMS */
68         struct chnl_object *chnl_from_dsp;      /* Chnl for replies from RMS */
69         u8 *pbuf;               /* Buffer for commands, replies */
70         u32 ul_bufsize;         /* pbuf size in bytes */
71         u32 ul_bufsize_rms;     /* pbuf size in RMS words */
72         u32 char_size;          /* Size of DSP character */
73         u32 word_size;          /* Size of DSP word */
74         u32 data_mau_size;      /* Size of DSP Data MAU */
75 };
76
77 static u32 refs;
78
79 static void delete_disp(struct disp_object *disp_obj);
80 static int fill_stream_def(rms_word *pdw_buf, u32 *ptotal, u32 offset,
81                                   struct node_strmdef strm_def, u32 max,
82                                   u32 chars_in_rms_word);
83 static int send_message(struct disp_object *disp_obj, u32 timeout,
84                                u32 ul_bytes, OUT u32 *pdw_arg);
85
86 /*
87  *  ======== disp_create ========
88  *  Create a NODE Dispatcher object.
89  */
90 int disp_create(OUT struct disp_object **dispatch_obj,
91                        struct dev_object *hdev_obj,
92                        IN CONST struct disp_attr *disp_attrs)
93 {
94         struct disp_object *disp_obj;
95         struct bridge_drv_interface *intf_fxns;
96         u32 ul_chnl_id;
97         struct chnl_attr chnl_attr_obj;
98         int status = 0;
99         u8 dev_type;
100
101         DBC_REQUIRE(refs > 0);
102         DBC_REQUIRE(dispatch_obj != NULL);
103         DBC_REQUIRE(disp_attrs != NULL);
104         DBC_REQUIRE(hdev_obj != NULL);
105
106         *dispatch_obj = NULL;
107
108         /* Allocate Node Dispatcher object */
109         disp_obj = kzalloc(sizeof(struct disp_object), GFP_KERNEL);
110         if (disp_obj == NULL)
111                 status = -ENOMEM;
112         else
113                 disp_obj->hdev_obj = hdev_obj;
114
115         /* Get Channel manager and Bridge function interface */
116         if (DSP_SUCCEEDED(status)) {
117                 status = dev_get_chnl_mgr(hdev_obj, &(disp_obj->hchnl_mgr));
118                 if (DSP_SUCCEEDED(status)) {
119                         (void)dev_get_intf_fxns(hdev_obj, &intf_fxns);
120                         disp_obj->intf_fxns = intf_fxns;
121                 }
122         }
123
124         /* check device type and decide if streams or messag'ing is used for
125          * RMS/EDS */
126         if (DSP_FAILED(status))
127                 goto func_cont;
128
129         status = dev_get_dev_type(hdev_obj, &dev_type);
130
131         if (DSP_FAILED(status))
132                 goto func_cont;
133
134         if (dev_type != DSP_UNIT) {
135                 status = -EPERM;
136                 goto func_cont;
137         }
138
139         disp_obj->char_size = DSPWORDSIZE;
140         disp_obj->word_size = DSPWORDSIZE;
141         disp_obj->data_mau_size = DSPWORDSIZE;
142         /* Open channels for communicating with the RMS */
143         chnl_attr_obj.uio_reqs = CHNLIOREQS;
144         chnl_attr_obj.event_obj = NULL;
145         ul_chnl_id = disp_attrs->ul_chnl_offset + CHNLTORMSOFFSET;
146         status = (*intf_fxns->pfn_chnl_open) (&(disp_obj->chnl_to_dsp),
147                                               disp_obj->hchnl_mgr,
148                                               CHNL_MODETODSP, ul_chnl_id,
149                                               &chnl_attr_obj);
150
151         if (DSP_SUCCEEDED(status)) {
152                 ul_chnl_id = disp_attrs->ul_chnl_offset + CHNLFROMRMSOFFSET;
153                 status =
154                     (*intf_fxns->pfn_chnl_open) (&(disp_obj->chnl_from_dsp),
155                                                  disp_obj->hchnl_mgr,
156                                                  CHNL_MODEFROMDSP, ul_chnl_id,
157                                                  &chnl_attr_obj);
158         }
159         if (DSP_SUCCEEDED(status)) {
160                 /* Allocate buffer for commands, replies */
161                 disp_obj->ul_bufsize = disp_attrs->ul_chnl_buf_size;
162                 disp_obj->ul_bufsize_rms = RMS_COMMANDBUFSIZE;
163                 disp_obj->pbuf = kzalloc(disp_obj->ul_bufsize, GFP_KERNEL);
164                 if (disp_obj->pbuf == NULL)
165                         status = -ENOMEM;
166         }
167 func_cont:
168         if (DSP_SUCCEEDED(status))
169                 *dispatch_obj = disp_obj;
170         else
171                 delete_disp(disp_obj);
172
173         DBC_ENSURE(((DSP_FAILED(status)) && ((*dispatch_obj == NULL))) ||
174                                 ((DSP_SUCCEEDED(status)) && *dispatch_obj));
175         return status;
176 }
177
178 /*
179  *  ======== disp_delete ========
180  *  Delete the NODE Dispatcher.
181  */
182 void disp_delete(struct disp_object *disp_obj)
183 {
184         DBC_REQUIRE(refs > 0);
185         DBC_REQUIRE(disp_obj);
186
187         delete_disp(disp_obj);
188 }
189
190 /*
191  *  ======== disp_exit ========
192  *  Discontinue usage of DISP module.
193  */
194 void disp_exit(void)
195 {
196         DBC_REQUIRE(refs > 0);
197
198         refs--;
199
200         DBC_ENSURE(refs >= 0);
201 }
202
203 /*
204  *  ======== disp_init ========
205  *  Initialize the DISP module.
206  */
207 bool disp_init(void)
208 {
209         bool ret = true;
210
211         DBC_REQUIRE(refs >= 0);
212
213         if (ret)
214                 refs++;
215
216         DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
217         return ret;
218 }
219
220 /*
221  *  ======== disp_node_change_priority ========
222  *  Change the priority of a node currently running on the target.
223  */
224 int disp_node_change_priority(struct disp_object *disp_obj,
225                                      struct node_object *hnode,
226                                      u32 ulRMSFxn, nodeenv node_env, s32 prio)
227 {
228         u32 dw_arg;
229         struct rms_command *rms_cmd;
230         int status = 0;
231
232         DBC_REQUIRE(refs > 0);
233         DBC_REQUIRE(disp_obj);
234         DBC_REQUIRE(hnode != NULL);
235
236         /* Send message to RMS to change priority */
237         rms_cmd = (struct rms_command *)(disp_obj->pbuf);
238         rms_cmd->fxn = (rms_word) (ulRMSFxn);
239         rms_cmd->arg1 = (rms_word) node_env;
240         rms_cmd->arg2 = prio;
241         status = send_message(disp_obj, node_get_timeout(hnode),
242                               sizeof(struct rms_command), &dw_arg);
243
244         return status;
245 }
246
247 /*
248  *  ======== disp_node_create ========
249  *  Create a node on the DSP by remotely calling the node's create function.
250  */
251 int disp_node_create(struct disp_object *disp_obj,
252                             struct node_object *hnode, u32 ulRMSFxn,
253                             u32 ul_create_fxn,
254                             IN CONST struct node_createargs *pargs,
255                             OUT nodeenv *node_env)
256 {
257         struct node_msgargs node_msg_args;
258         struct node_taskargs task_arg_obj;
259         struct rms_command *rms_cmd;
260         struct rms_msg_args *pmsg_args;
261         struct rms_more_task_args *more_task_args;
262         enum node_type node_type;
263         u32 dw_length;
264         rms_word *pdw_buf = NULL;
265         u32 ul_bytes;
266         u32 i;
267         u32 total;
268         u32 chars_in_rms_word;
269         s32 task_args_offset;
270         s32 sio_in_def_offset;
271         s32 sio_out_def_offset;
272         s32 sio_defs_offset;
273         s32 args_offset = -1;
274         s32 offset;
275         struct node_strmdef strm_def;
276         u32 max;
277         int status = 0;
278         struct dsp_nodeinfo node_info;
279         u8 dev_type;
280
281         DBC_REQUIRE(refs > 0);
282         DBC_REQUIRE(disp_obj);
283         DBC_REQUIRE(hnode != NULL);
284         DBC_REQUIRE(node_get_type(hnode) != NODE_DEVICE);
285         DBC_REQUIRE(node_env != NULL);
286
287         status = dev_get_dev_type(disp_obj->hdev_obj, &dev_type);
288
289         if (DSP_FAILED(status))
290                 goto func_end;
291
292         if (dev_type != DSP_UNIT) {
293                 dev_dbg(bridge, "%s: unknown device type = 0x%x\n",
294                         __func__, dev_type);
295                 goto func_end;
296         }
297         DBC_REQUIRE(pargs != NULL);
298         node_type = node_get_type(hnode);
299         node_msg_args = pargs->asa.node_msg_args;
300         max = disp_obj->ul_bufsize_rms; /*Max # of RMS words that can be sent */
301         DBC_ASSERT(max == RMS_COMMANDBUFSIZE);
302         chars_in_rms_word = sizeof(rms_word) / disp_obj->char_size;
303         /* Number of RMS words needed to hold arg data */
304         dw_length =
305             (node_msg_args.arg_length + chars_in_rms_word -
306              1) / chars_in_rms_word;
307         /* Make sure msg args and command fit in buffer */
308         total = sizeof(struct rms_command) / sizeof(rms_word) +
309             sizeof(struct rms_msg_args)
310             / sizeof(rms_word) - 1 + dw_length;
311         if (total >= max) {
312                 status = -EPERM;
313                 dev_dbg(bridge, "%s: Message args too large for buffer! size "
314                         "= %d, max = %d\n", __func__, total, max);
315         }
316         /*
317          *  Fill in buffer to send to RMS.
318          *  The buffer will have the following  format:
319          *
320          *  RMS command:
321          *      Address of RMS_CreateNode()
322          *      Address of node's create function
323          *      dummy argument
324          *      node type
325          *
326          *  Message Args:
327          *      max number of messages
328          *      segid for message buffer allocation
329          *      notification type to use when message is received
330          *      length of message arg data
331          *      message args data
332          *
333          *  Task Args (if task or socket node):
334          *      priority
335          *      stack size
336          *      system stack size
337          *      stack segment
338          *      misc
339          *      number of input streams
340          *      pSTRMInDef[] - offsets of STRM definitions for input streams
341          *      number of output streams
342          *      pSTRMOutDef[] - offsets of STRM definitions for output
343          *      streams
344          *      STRMInDef[] - array of STRM definitions for input streams
345          *      STRMOutDef[] - array of STRM definitions for output streams
346          *
347          *  Socket Args (if DAIS socket node):
348          *
349          */
350         if (DSP_SUCCEEDED(status)) {
351                 total = 0;      /* Total number of words in buffer so far */
352                 pdw_buf = (rms_word *) disp_obj->pbuf;
353                 rms_cmd = (struct rms_command *)pdw_buf;
354                 rms_cmd->fxn = (rms_word) (ulRMSFxn);
355                 rms_cmd->arg1 = (rms_word) (ul_create_fxn);
356                 if (node_get_load_type(hnode) == NLDR_DYNAMICLOAD) {
357                         /* Flush ICACHE on Load */
358                         rms_cmd->arg2 = 1;      /* dummy argument */
359                 } else {
360                         /* Do not flush ICACHE */
361                         rms_cmd->arg2 = 0;      /* dummy argument */
362                 }
363                 rms_cmd->data = node_get_type(hnode);
364                 /*
365                  *  args_offset is the offset of the data field in struct
366                  *  rms_command structure. We need this to calculate stream
367                  *  definition offsets.
368                  */
369                 args_offset = 3;
370                 total += sizeof(struct rms_command) / sizeof(rms_word);
371                 /* Message args */
372                 pmsg_args = (struct rms_msg_args *)(pdw_buf + total);
373                 pmsg_args->max_msgs = node_msg_args.max_msgs;
374                 pmsg_args->segid = node_msg_args.seg_id;
375                 pmsg_args->notify_type = node_msg_args.notify_type;
376                 pmsg_args->arg_length = node_msg_args.arg_length;
377                 total += sizeof(struct rms_msg_args) / sizeof(rms_word) - 1;
378                 memcpy(pdw_buf + total, node_msg_args.pdata,
379                        node_msg_args.arg_length);
380                 total += dw_length;
381         }
382         if (DSP_FAILED(status))
383                 goto func_end;
384
385         /* If node is a task node, copy task create arguments into  buffer */
386         if (node_type == NODE_TASK || node_type == NODE_DAISSOCKET) {
387                 task_arg_obj = pargs->asa.task_arg_obj;
388                 task_args_offset = total;
389                 total += sizeof(struct rms_more_task_args) / sizeof(rms_word) +
390                     1 + task_arg_obj.num_inputs + task_arg_obj.num_outputs;
391                 /* Copy task arguments */
392                 if (total < max) {
393                         total = task_args_offset;
394                         more_task_args = (struct rms_more_task_args *)(pdw_buf +
395                                                                        total);
396                         /*
397                          * Get some important info about the node. Note that we
398                          * don't just reach into the hnode struct because
399                          * that would break the node object's abstraction.
400                          */
401                         get_node_info(hnode, &node_info);
402                         more_task_args->priority = node_info.execution_priority;
403                         more_task_args->stack_size = task_arg_obj.stack_size;
404                         more_task_args->sysstack_size =
405                             task_arg_obj.sys_stack_size;
406                         more_task_args->stack_seg = task_arg_obj.stack_seg;
407                         more_task_args->heap_addr = task_arg_obj.udsp_heap_addr;
408                         more_task_args->heap_size = task_arg_obj.heap_size;
409                         more_task_args->misc = task_arg_obj.ul_dais_arg;
410                         more_task_args->num_input_streams =
411                             task_arg_obj.num_inputs;
412                         total +=
413                             sizeof(struct rms_more_task_args) /
414                             sizeof(rms_word);
415                         dev_dbg(bridge, "%s: udsp_heap_addr %x, heap_size %x\n",
416                                 __func__, task_arg_obj.udsp_heap_addr,
417                                 task_arg_obj.heap_size);
418                         /* Keep track of pSIOInDef[] and pSIOOutDef[]
419                          * positions in the buffer, since this needs to be
420                          * filled in later. */
421                         sio_in_def_offset = total;
422                         total += task_arg_obj.num_inputs;
423                         pdw_buf[total++] = task_arg_obj.num_outputs;
424                         sio_out_def_offset = total;
425                         total += task_arg_obj.num_outputs;
426                         sio_defs_offset = total;
427                         /* Fill SIO defs and offsets */
428                         offset = sio_defs_offset;
429                         for (i = 0; i < task_arg_obj.num_inputs; i++) {
430                                 if (DSP_FAILED(status))
431                                         break;
432
433                                 pdw_buf[sio_in_def_offset + i] =
434                                     (offset - args_offset)
435                                     * (sizeof(rms_word) / DSPWORDSIZE);
436                                 strm_def = task_arg_obj.strm_in_def[i];
437                                 status =
438                                     fill_stream_def(pdw_buf, &total, offset,
439                                                     strm_def, max,
440                                                     chars_in_rms_word);
441                                 offset = total;
442                         }
443                         for (i = 0; (i < task_arg_obj.num_outputs) &&
444                              (DSP_SUCCEEDED(status)); i++) {
445                                 pdw_buf[sio_out_def_offset + i] =
446                                     (offset - args_offset)
447                                     * (sizeof(rms_word) / DSPWORDSIZE);
448                                 strm_def = task_arg_obj.strm_out_def[i];
449                                 status =
450                                     fill_stream_def(pdw_buf, &total, offset,
451                                                     strm_def, max,
452                                                     chars_in_rms_word);
453                                 offset = total;
454                         }
455                 } else {
456                         /* Args won't fit */
457                         status = -EPERM;
458                 }
459         }
460         if (DSP_SUCCEEDED(status)) {
461                 ul_bytes = total * sizeof(rms_word);
462                 DBC_ASSERT(ul_bytes < (RMS_COMMANDBUFSIZE * sizeof(rms_word)));
463                 status = send_message(disp_obj, node_get_timeout(hnode),
464                                       ul_bytes, node_env);
465                 if (DSP_SUCCEEDED(status)) {
466                         /*
467                          * Message successfully received from RMS.
468                          * Return the status of the Node's create function
469                          * on the DSP-side
470                          */
471                         status = (((rms_word *) (disp_obj->pbuf))[0]);
472                         if (DSP_FAILED(status))
473                                 dev_dbg(bridge, "%s: DSP-side failed: 0x%x\n",
474                                         __func__, status);
475                 }
476         }
477 func_end:
478         return status;
479 }
480
481 /*
482  *  ======== disp_node_delete ========
483  *  purpose:
484  *      Delete a node on the DSP by remotely calling the node's delete function.
485  *
486  */
487 int disp_node_delete(struct disp_object *disp_obj,
488                             struct node_object *hnode, u32 ulRMSFxn,
489                             u32 ul_delete_fxn, nodeenv node_env)
490 {
491         u32 dw_arg;
492         struct rms_command *rms_cmd;
493         int status = 0;
494         u8 dev_type;
495
496         DBC_REQUIRE(refs > 0);
497         DBC_REQUIRE(disp_obj);
498         DBC_REQUIRE(hnode != NULL);
499
500         status = dev_get_dev_type(disp_obj->hdev_obj, &dev_type);
501
502         if (DSP_SUCCEEDED(status)) {
503
504                 if (dev_type == DSP_UNIT) {
505
506                         /*
507                          *  Fill in buffer to send to RMS
508                          */
509                         rms_cmd = (struct rms_command *)disp_obj->pbuf;
510                         rms_cmd->fxn = (rms_word) (ulRMSFxn);
511                         rms_cmd->arg1 = (rms_word) node_env;
512                         rms_cmd->arg2 = (rms_word) (ul_delete_fxn);
513                         rms_cmd->data = node_get_type(hnode);
514
515                         status = send_message(disp_obj, node_get_timeout(hnode),
516                                               sizeof(struct rms_command),
517                                               &dw_arg);
518                         if (DSP_SUCCEEDED(status)) {
519                                 /*
520                                  * Message successfully received from RMS.
521                                  * Return the status of the Node's delete
522                                  * function on the DSP-side
523                                  */
524                                 status = (((rms_word *) (disp_obj->pbuf))[0]);
525                                 if (DSP_FAILED(status))
526                                         dev_dbg(bridge, "%s: DSP-side failed: "
527                                                 "0x%x\n", __func__, status);
528                         }
529
530                 }
531         }
532         return status;
533 }
534
535 /*
536  *  ======== disp_node_run ========
537  *  purpose:
538  *      Start execution of a node's execute phase, or resume execution of a node
539  *      that has been suspended (via DISP_NodePause()) on the DSP.
540  */
541 int disp_node_run(struct disp_object *disp_obj,
542                          struct node_object *hnode, u32 ulRMSFxn,
543                          u32 ul_execute_fxn, nodeenv node_env)
544 {
545         u32 dw_arg;
546         struct rms_command *rms_cmd;
547         int status = 0;
548         u8 dev_type;
549         DBC_REQUIRE(refs > 0);
550         DBC_REQUIRE(disp_obj);
551         DBC_REQUIRE(hnode != NULL);
552
553         status = dev_get_dev_type(disp_obj->hdev_obj, &dev_type);
554
555         if (DSP_SUCCEEDED(status)) {
556
557                 if (dev_type == DSP_UNIT) {
558
559                         /*
560                          *  Fill in buffer to send to RMS.
561                          */
562                         rms_cmd = (struct rms_command *)disp_obj->pbuf;
563                         rms_cmd->fxn = (rms_word) (ulRMSFxn);
564                         rms_cmd->arg1 = (rms_word) node_env;
565                         rms_cmd->arg2 = (rms_word) (ul_execute_fxn);
566                         rms_cmd->data = node_get_type(hnode);
567
568                         status = send_message(disp_obj, node_get_timeout(hnode),
569                                               sizeof(struct rms_command),
570                                               &dw_arg);
571                         if (DSP_SUCCEEDED(status)) {
572                                 /*
573                                  * Message successfully received from RMS.
574                                  * Return the status of the Node's execute
575                                  * function on the DSP-side
576                                  */
577                                 status = (((rms_word *) (disp_obj->pbuf))[0]);
578                                 if (DSP_FAILED(status))
579                                         dev_dbg(bridge, "%s: DSP-side failed: "
580                                                 "0x%x\n", __func__, status);
581                         }
582
583                 }
584         }
585
586         return status;
587 }
588
589 /*
590  *  ======== delete_disp ========
591  *  purpose:
592  *      Frees the resources allocated for the dispatcher.
593  */
594 static void delete_disp(struct disp_object *disp_obj)
595 {
596         int status = 0;
597         struct bridge_drv_interface *intf_fxns;
598
599         if (disp_obj) {
600                 intf_fxns = disp_obj->intf_fxns;
601
602                 /* Free Node Dispatcher resources */
603                 if (disp_obj->chnl_from_dsp) {
604                         /* Channel close can fail only if the channel handle
605                          * is invalid. */
606                         status = (*intf_fxns->pfn_chnl_close)
607                             (disp_obj->chnl_from_dsp);
608                         if (DSP_FAILED(status)) {
609                                 dev_dbg(bridge, "%s: Failed to close channel "
610                                         "from RMS: 0x%x\n", __func__, status);
611                         }
612                 }
613                 if (disp_obj->chnl_to_dsp) {
614                         status =
615                             (*intf_fxns->pfn_chnl_close) (disp_obj->
616                                                           chnl_to_dsp);
617                         if (DSP_FAILED(status)) {
618                                 dev_dbg(bridge, "%s: Failed to close channel to"
619                                         " RMS: 0x%x\n", __func__, status);
620                         }
621                 }
622                 kfree(disp_obj->pbuf);
623
624                 kfree(disp_obj);
625         }
626 }
627
628 /*
629  *  ======== fill_stream_def ========
630  *  purpose:
631  *      Fills stream definitions.
632  */
633 static int fill_stream_def(rms_word *pdw_buf, u32 *ptotal, u32 offset,
634                                   struct node_strmdef strm_def, u32 max,
635                                   u32 chars_in_rms_word)
636 {
637         struct rms_strm_def *strm_def_obj;
638         u32 total = *ptotal;
639         u32 name_len;
640         u32 dw_length;
641         int status = 0;
642
643         if (total + sizeof(struct rms_strm_def) / sizeof(rms_word) >= max) {
644                 status = -EPERM;
645         } else {
646                 strm_def_obj = (struct rms_strm_def *)(pdw_buf + total);
647                 strm_def_obj->bufsize = strm_def.buf_size;
648                 strm_def_obj->nbufs = strm_def.num_bufs;
649                 strm_def_obj->segid = strm_def.seg_id;
650                 strm_def_obj->align = strm_def.buf_alignment;
651                 strm_def_obj->timeout = strm_def.utimeout;
652         }
653
654         if (DSP_SUCCEEDED(status)) {
655                 /*
656                  *  Since we haven't added the device name yet, subtract
657                  *  1 from total.
658                  */
659                 total += sizeof(struct rms_strm_def) / sizeof(rms_word) - 1;
660                 DBC_REQUIRE(strm_def.sz_device);
661                 dw_length = strlen(strm_def.sz_device) + 1;
662
663                 /* Number of RMS_WORDS needed to hold device name */
664                 name_len =
665                     (dw_length + chars_in_rms_word - 1) / chars_in_rms_word;
666
667                 if (total + name_len >= max) {
668                         status = -EPERM;
669                 } else {
670                         /*
671                          *  Zero out last word, since the device name may not
672                          *  extend to completely fill this word.
673                          */
674                         pdw_buf[total + name_len - 1] = 0;
675                         /** TODO USE SERVICES * */
676                         memcpy(pdw_buf + total, strm_def.sz_device, dw_length);
677                         total += name_len;
678                         *ptotal = total;
679                 }
680         }
681
682         return status;
683 }
684
685 /*
686  *  ======== send_message ======
687  *  Send command message to RMS, get reply from RMS.
688  */
689 static int send_message(struct disp_object *disp_obj, u32 timeout,
690                                u32 ul_bytes, u32 *pdw_arg)
691 {
692         struct bridge_drv_interface *intf_fxns;
693         struct chnl_object *chnl_obj;
694         u32 dw_arg = 0;
695         u8 *pbuf;
696         struct chnl_ioc chnl_ioc_obj;
697         int status = 0;
698
699         DBC_REQUIRE(pdw_arg != NULL);
700
701         *pdw_arg = (u32) NULL;
702         intf_fxns = disp_obj->intf_fxns;
703         chnl_obj = disp_obj->chnl_to_dsp;
704         pbuf = disp_obj->pbuf;
705
706         /* Send the command */
707         status = (*intf_fxns->pfn_chnl_add_io_req) (chnl_obj, pbuf, ul_bytes, 0,
708                                                     0L, dw_arg);
709         if (DSP_FAILED(status))
710                 goto func_end;
711
712         status =
713             (*intf_fxns->pfn_chnl_get_ioc) (chnl_obj, timeout, &chnl_ioc_obj);
714         if (DSP_SUCCEEDED(status)) {
715                 if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
716                         if (CHNL_IS_TIMED_OUT(chnl_ioc_obj))
717                                 status = -ETIME;
718                         else
719                                 status = -EPERM;
720                 }
721         }
722         /* Get the reply */
723         if (DSP_FAILED(status))
724                 goto func_end;
725
726         chnl_obj = disp_obj->chnl_from_dsp;
727         ul_bytes = REPLYSIZE;
728         status = (*intf_fxns->pfn_chnl_add_io_req) (chnl_obj, pbuf, ul_bytes,
729                                                     0, 0L, dw_arg);
730         if (DSP_FAILED(status))
731                 goto func_end;
732
733         status =
734             (*intf_fxns->pfn_chnl_get_ioc) (chnl_obj, timeout, &chnl_ioc_obj);
735         if (DSP_SUCCEEDED(status)) {
736                 if (CHNL_IS_TIMED_OUT(chnl_ioc_obj)) {
737                         status = -ETIME;
738                 } else if (chnl_ioc_obj.byte_size < ul_bytes) {
739                         /* Did not get all of the reply from the RMS */
740                         status = -EPERM;
741                 } else {
742                         if (CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
743                                 DBC_ASSERT(chnl_ioc_obj.pbuf == pbuf);
744                                 status = (*((rms_word *) chnl_ioc_obj.pbuf));
745                                 *pdw_arg =
746                                     (((rms_word *) (chnl_ioc_obj.pbuf))[1]);
747                         } else {
748                                 status = -EPERM;
749                         }
750                 }
751         }
752 func_end:
753         return status;
754 }