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