1 /** 2 * Copyright (c) 2010-2012 Broadcom. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions, and the following disclaimer, 9 * without modification. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The names of the above-listed copyright holders may not be used 14 * to endorse or promote products derived from this software without 15 * specific prior written permission. 16 * 17 * ALTERNATIVELY, this software may be distributed under the terms of the 18 * GNU General Public License ("GPL") version 2, as published by the Free 19 * Software Foundation. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <interface/compat/vchi_bsd.h> 35 36 #include "interface/vchi/vchi.h" 37 #include "vchiq.h" 38 #include "vchiq_core.h" 39 40 #include "vchiq_util.h" 41 42 #define vchiq_status_to_vchi(status) ((int32_t)status) 43 44 typedef struct { 45 VCHIQ_SERVICE_HANDLE_T handle; 46 47 VCHIU_QUEUE_T queue; 48 49 VCHI_CALLBACK_T callback; 50 void *callback_param; 51 } SHIM_SERVICE_T; 52 53 /* ---------------------------------------------------------------------- 54 * return pointer to the mphi message driver function table 55 * -------------------------------------------------------------------- */ 56 const VCHI_MESSAGE_DRIVER_T * 57 vchi_mphi_message_driver_func_table(void) 58 { 59 return NULL; 60 } 61 62 /* ---------------------------------------------------------------------- 63 * return a pointer to the 'single' connection driver fops 64 * -------------------------------------------------------------------- */ 65 const VCHI_CONNECTION_API_T * 66 single_get_func_table(void) 67 { 68 return NULL; 69 } 70 71 VCHI_CONNECTION_T *vchi_create_connection( 72 const VCHI_CONNECTION_API_T *function_table, 73 const VCHI_MESSAGE_DRIVER_T *low_level) 74 { 75 (void)function_table; 76 (void)low_level; 77 return NULL; 78 } 79 80 /*********************************************************** 81 * Name: vchi_msg_peek 82 * 83 * Arguments: const VCHI_SERVICE_HANDLE_T handle, 84 * void **data, 85 * uint32_t *msg_size, 86 87 88 * VCHI_FLAGS_T flags 89 * 90 * Description: Routine to return a pointer to the current message (to allow in 91 * place processing). The message can be removed using 92 * vchi_msg_remove when you're finished 93 * 94 * Returns: int32_t - success == 0 95 * 96 ***********************************************************/ 97 int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle, 98 void **data, 99 uint32_t *msg_size, 100 VCHI_FLAGS_T flags) 101 { 102 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 103 VCHIQ_HEADER_T *header; 104 105 WARN_ON((flags != VCHI_FLAGS_NONE) && 106 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); 107 108 if (flags == VCHI_FLAGS_NONE) 109 if (vchiu_queue_is_empty(&service->queue)) 110 return -1; 111 112 header = vchiu_queue_peek(&service->queue); 113 114 *data = header->data; 115 *msg_size = header->size; 116 117 return 0; 118 } 119 EXPORT_SYMBOL(vchi_msg_peek); 120 121 /*********************************************************** 122 * Name: vchi_msg_remove 123 * 124 * Arguments: const VCHI_SERVICE_HANDLE_T handle, 125 * 126 * Description: Routine to remove a message (after it has been read with 127 * vchi_msg_peek) 128 * 129 * Returns: int32_t - success == 0 130 * 131 ***********************************************************/ 132 int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle) 133 { 134 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 135 VCHIQ_HEADER_T *header; 136 137 header = vchiu_queue_pop(&service->queue); 138 139 vchiq_release_message(service->handle, header); 140 141 return 0; 142 } 143 EXPORT_SYMBOL(vchi_msg_remove); 144 145 /*********************************************************** 146 * Name: vchi_msg_queue 147 * 148 * Arguments: VCHI_SERVICE_HANDLE_T handle, 149 * const void *data, 150 * uint32_t data_size, 151 * VCHI_FLAGS_T flags, 152 * void *msg_handle, 153 * 154 * Description: Thin wrapper to queue a message onto a connection 155 * 156 * Returns: int32_t - success == 0 157 * 158 ***********************************************************/ 159 int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, 160 const void *data, 161 uint32_t data_size, 162 VCHI_FLAGS_T flags, 163 void *msg_handle) 164 { 165 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 166 VCHIQ_ELEMENT_T element = {data, data_size}; 167 VCHIQ_STATUS_T status; 168 169 (void)msg_handle; 170 171 WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); 172 173 status = vchiq_queue_message(service->handle, &element, 1); 174 175 /* vchiq_queue_message() may return VCHIQ_RETRY, so we need to 176 ** implement a retry mechanism since this function is supposed 177 ** to block until queued 178 */ 179 while (status == VCHIQ_RETRY) { 180 msleep(1); 181 status = vchiq_queue_message(service->handle, &element, 1); 182 } 183 184 return vchiq_status_to_vchi(status); 185 } 186 EXPORT_SYMBOL(vchi_msg_queue); 187 188 /*********************************************************** 189 * Name: vchi_bulk_queue_receive 190 * 191 * Arguments: VCHI_BULK_HANDLE_T handle, 192 * void *data_dst, 193 * const uint32_t data_size, 194 * VCHI_FLAGS_T flags 195 * void *bulk_handle 196 * 197 * Description: Routine to setup a rcv buffer 198 * 199 * Returns: int32_t - success == 0 200 * 201 ***********************************************************/ 202 int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle, 203 void *data_dst, 204 uint32_t data_size, 205 VCHI_FLAGS_T flags, 206 void *bulk_handle) 207 { 208 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 209 VCHIQ_BULK_MODE_T mode; 210 VCHIQ_STATUS_T status; 211 212 switch ((int)flags) { 213 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE 214 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 215 WARN_ON(!service->callback); 216 mode = VCHIQ_BULK_MODE_CALLBACK; 217 break; 218 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: 219 mode = VCHIQ_BULK_MODE_BLOCKING; 220 break; 221 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 222 case VCHI_FLAGS_NONE: 223 mode = VCHIQ_BULK_MODE_NOCALLBACK; 224 break; 225 default: 226 WARN(1, "unsupported message\n"); 227 return vchiq_status_to_vchi(VCHIQ_ERROR); 228 } 229 230 status = vchiq_bulk_receive(service->handle, data_dst, data_size, 231 bulk_handle, mode); 232 233 /* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to 234 ** implement a retry mechanism since this function is supposed 235 ** to block until queued 236 */ 237 while (status == VCHIQ_RETRY) { 238 msleep(1); 239 status = vchiq_bulk_receive(service->handle, data_dst, 240 data_size, bulk_handle, mode); 241 } 242 243 return vchiq_status_to_vchi(status); 244 } 245 EXPORT_SYMBOL(vchi_bulk_queue_receive); 246 247 /*********************************************************** 248 * Name: vchi_bulk_queue_transmit 249 * 250 * Arguments: VCHI_BULK_HANDLE_T handle, 251 * void *data_src, 252 * uint32_t data_size, 253 * VCHI_FLAGS_T flags, 254 * void *bulk_handle 255 * 256 * Description: Routine to transmit some data 257 * 258 * Returns: int32_t - success == 0 259 * 260 ***********************************************************/ 261 int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle, 262 void *data_src, 263 uint32_t data_size, 264 VCHI_FLAGS_T flags, 265 void *bulk_handle) 266 { 267 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 268 VCHIQ_BULK_MODE_T mode; 269 VCHIQ_STATUS_T status; 270 271 switch ((int)flags) { 272 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE 273 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 274 WARN_ON(!service->callback); 275 mode = VCHIQ_BULK_MODE_CALLBACK; 276 break; 277 case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ: 278 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: 279 mode = VCHIQ_BULK_MODE_BLOCKING; 280 break; 281 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 282 case VCHI_FLAGS_NONE: 283 mode = VCHIQ_BULK_MODE_NOCALLBACK; 284 break; 285 default: 286 WARN(1, "unsupported message\n"); 287 return vchiq_status_to_vchi(VCHIQ_ERROR); 288 } 289 290 status = vchiq_bulk_transmit(service->handle, data_src, data_size, 291 bulk_handle, mode); 292 293 /* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to 294 ** implement a retry mechanism since this function is supposed 295 ** to block until queued 296 */ 297 while (status == VCHIQ_RETRY) { 298 msleep(1); 299 status = vchiq_bulk_transmit(service->handle, data_src, 300 data_size, bulk_handle, mode); 301 } 302 303 return vchiq_status_to_vchi(status); 304 } 305 EXPORT_SYMBOL(vchi_bulk_queue_transmit); 306 307 /*********************************************************** 308 * Name: vchi_msg_dequeue 309 * 310 * Arguments: VCHI_SERVICE_HANDLE_T handle, 311 * void *data, 312 * uint32_t max_data_size_to_read, 313 * uint32_t *actual_msg_size 314 * VCHI_FLAGS_T flags 315 * 316 * Description: Routine to dequeue a message into the supplied buffer 317 * 318 * Returns: int32_t - success == 0 319 * 320 ***********************************************************/ 321 int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle, 322 void *data, 323 uint32_t max_data_size_to_read, 324 uint32_t *actual_msg_size, 325 VCHI_FLAGS_T flags) 326 { 327 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 328 VCHIQ_HEADER_T *header; 329 330 WARN_ON((flags != VCHI_FLAGS_NONE) && 331 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); 332 333 if (flags == VCHI_FLAGS_NONE) 334 if (vchiu_queue_is_empty(&service->queue)) 335 return -1; 336 337 header = vchiu_queue_pop(&service->queue); 338 339 memcpy(data, header->data, header->size < max_data_size_to_read ? 340 header->size : max_data_size_to_read); 341 342 *actual_msg_size = header->size; 343 344 vchiq_release_message(service->handle, header); 345 346 return 0; 347 } 348 EXPORT_SYMBOL(vchi_msg_dequeue); 349 350 /*********************************************************** 351 * Name: vchi_msg_queuev 352 * 353 * Arguments: VCHI_SERVICE_HANDLE_T handle, 354 * VCHI_MSG_VECTOR_T *vector, 355 * uint32_t count, 356 * VCHI_FLAGS_T flags, 357 * void *msg_handle 358 * 359 * Description: Thin wrapper to queue a message onto a connection 360 * 361 * Returns: int32_t - success == 0 362 * 363 ***********************************************************/ 364 365 vchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T)); 366 vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == 367 offsetof(VCHIQ_ELEMENT_T, data)); 368 vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == 369 offsetof(VCHIQ_ELEMENT_T, size)); 370 371 int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle, 372 VCHI_MSG_VECTOR_T *vector, 373 uint32_t count, 374 VCHI_FLAGS_T flags, 375 void *msg_handle) 376 { 377 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 378 379 (void)msg_handle; 380 381 WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); 382 383 return vchiq_status_to_vchi(vchiq_queue_message(service->handle, 384 (const VCHIQ_ELEMENT_T *)vector, count)); 385 } 386 EXPORT_SYMBOL(vchi_msg_queuev); 387 388 /*********************************************************** 389 * Name: vchi_held_msg_release 390 * 391 * Arguments: VCHI_HELD_MSG_T *message_handle 392 * 393 * Description: Routine to release a held message (after it has been read with 394 * vchi_msg_hold) 395 * 396 * Returns: int32_t - success == 0 397 * 398 ***********************************************************/ 399 int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message_handle) 400 { 401 SHIM_SERVICE_T *service; 402 VCHIQ_HEADER_T *header; 403 404 service = (SHIM_SERVICE_T *)message_handle->service; 405 header = (VCHIQ_HEADER_T *)message_handle->message; 406 407 vchiq_release_message(service->handle, header); 408 409 return 0; 410 } 411 EXPORT_SYMBOL(vchi_held_msg_release); 412 413 /*********************************************************** 414 * Name: vchi_msg_hold 415 * 416 * Arguments: VCHI_SERVICE_HANDLE_T handle, 417 * void **data, 418 * uint32_t *msg_size, 419 * VCHI_FLAGS_T flags, 420 * VCHI_HELD_MSG_T *message_handle 421 * 422 * Description: Routine to return a pointer to the current message (to allow 423 * in place processing). The message is dequeued - don't forget 424 * to release the message using vchi_held_msg_release when you're 425 * finished. 426 * 427 * Returns: int32_t - success == 0 428 * 429 ***********************************************************/ 430 int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle, 431 void **data, 432 uint32_t *msg_size, 433 VCHI_FLAGS_T flags, 434 VCHI_HELD_MSG_T *message_handle) 435 { 436 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 437 VCHIQ_HEADER_T *header; 438 439 WARN_ON((flags != VCHI_FLAGS_NONE) && 440 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); 441 442 if (flags == VCHI_FLAGS_NONE) 443 if (vchiu_queue_is_empty(&service->queue)) 444 return -1; 445 446 header = vchiu_queue_pop(&service->queue); 447 448 *data = header->data; 449 *msg_size = header->size; 450 451 message_handle->service = 452 (struct opaque_vchi_service_t *)(uintptr_t)service->handle; 453 message_handle->message = header; 454 455 return 0; 456 } 457 EXPORT_SYMBOL(vchi_msg_hold); 458 459 /*********************************************************** 460 * Name: vchi_initialise 461 * 462 * Arguments: VCHI_INSTANCE_T *instance_handle 463 * 464 * Description: Initialises the hardware but does not transmit anything 465 * When run as a Host App this will be called twice hence the need 466 * to malloc the state information 467 * 468 * Returns: 0 if successful, failure otherwise 469 * 470 ***********************************************************/ 471 472 int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle) 473 { 474 VCHIQ_INSTANCE_T instance; 475 VCHIQ_STATUS_T status; 476 477 status = vchiq_initialise(&instance); 478 479 *instance_handle = (VCHI_INSTANCE_T)instance; 480 481 return vchiq_status_to_vchi(status); 482 } 483 EXPORT_SYMBOL(vchi_initialise); 484 485 /*********************************************************** 486 * Name: vchi_connect 487 * 488 * Arguments: VCHI_CONNECTION_T **connections 489 * const uint32_t num_connections 490 * VCHI_INSTANCE_T instance_handle) 491 * 492 * Description: Starts the command service on each connection, 493 * causing INIT messages to be pinged back and forth 494 * 495 * Returns: 0 if successful, failure otherwise 496 * 497 ***********************************************************/ 498 int32_t vchi_connect(VCHI_CONNECTION_T **connections, 499 const uint32_t num_connections, 500 VCHI_INSTANCE_T instance_handle) 501 { 502 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 503 504 (void)connections; 505 (void)num_connections; 506 507 return vchiq_connect(instance); 508 } 509 EXPORT_SYMBOL(vchi_connect); 510 511 512 /*********************************************************** 513 * Name: vchi_disconnect 514 * 515 * Arguments: VCHI_INSTANCE_T instance_handle 516 * 517 * Description: Stops the command service on each connection, 518 * causing DE-INIT messages to be pinged back and forth 519 * 520 * Returns: 0 if successful, failure otherwise 521 * 522 ***********************************************************/ 523 int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle) 524 { 525 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 526 return vchiq_status_to_vchi(vchiq_shutdown(instance)); 527 } 528 EXPORT_SYMBOL(vchi_disconnect); 529 530 531 /*********************************************************** 532 * Name: vchi_service_open 533 * Name: vchi_service_create 534 * 535 * Arguments: VCHI_INSTANCE_T *instance_handle 536 * SERVICE_CREATION_T *setup, 537 * VCHI_SERVICE_HANDLE_T *handle 538 * 539 * Description: Routine to open a service 540 * 541 * Returns: int32_t - success == 0 542 * 543 ***********************************************************/ 544 545 static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, 546 VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user) 547 { 548 SHIM_SERVICE_T *service = 549 (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle); 550 551 if (!service->callback) 552 goto release; 553 554 switch (reason) { 555 case VCHIQ_MESSAGE_AVAILABLE: 556 vchiu_queue_push(&service->queue, header); 557 558 service->callback(service->callback_param, 559 VCHI_CALLBACK_MSG_AVAILABLE, NULL); 560 561 goto done; 562 break; 563 564 case VCHIQ_BULK_TRANSMIT_DONE: 565 service->callback(service->callback_param, 566 VCHI_CALLBACK_BULK_SENT, bulk_user); 567 break; 568 569 case VCHIQ_BULK_RECEIVE_DONE: 570 service->callback(service->callback_param, 571 VCHI_CALLBACK_BULK_RECEIVED, bulk_user); 572 break; 573 574 case VCHIQ_SERVICE_CLOSED: 575 service->callback(service->callback_param, 576 VCHI_CALLBACK_SERVICE_CLOSED, NULL); 577 break; 578 579 case VCHIQ_SERVICE_OPENED: 580 /* No equivalent VCHI reason */ 581 break; 582 583 case VCHIQ_BULK_TRANSMIT_ABORTED: 584 service->callback(service->callback_param, 585 VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, 586 bulk_user); 587 break; 588 589 case VCHIQ_BULK_RECEIVE_ABORTED: 590 service->callback(service->callback_param, 591 VCHI_CALLBACK_BULK_RECEIVE_ABORTED, 592 bulk_user); 593 break; 594 595 default: 596 WARN(1, "not supported\n"); 597 break; 598 } 599 600 release: 601 vchiq_release_message(service->handle, header); 602 done: 603 return VCHIQ_SUCCESS; 604 } 605 606 static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance, 607 SERVICE_CREATION_T *setup) 608 { 609 SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL); 610 611 (void)instance; 612 613 if (service) { 614 if (vchiu_queue_init(&service->queue, 64)) { 615 service->callback = setup->callback; 616 service->callback_param = setup->callback_param; 617 } else { 618 kfree(service); 619 service = NULL; 620 } 621 } 622 623 return service; 624 } 625 626 static void service_free(SHIM_SERVICE_T *service) 627 { 628 if (service) { 629 vchiu_queue_delete(&service->queue); 630 kfree(service); 631 } 632 } 633 634 int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, 635 SERVICE_CREATION_T *setup, 636 VCHI_SERVICE_HANDLE_T *handle) 637 { 638 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 639 SHIM_SERVICE_T *service = service_alloc(instance, setup); 640 641 *handle = (VCHI_SERVICE_HANDLE_T)service; 642 643 if (service) { 644 VCHIQ_SERVICE_PARAMS_T params; 645 VCHIQ_STATUS_T status; 646 647 memset(¶ms, 0, sizeof(params)); 648 params.fourcc = setup->service_id; 649 params.callback = shim_callback; 650 params.userdata = service; 651 params.version = setup->version.version; 652 params.version_min = setup->version.version_min; 653 654 status = vchiq_open_service(instance, ¶ms, 655 &service->handle); 656 if (status != VCHIQ_SUCCESS) { 657 service_free(service); 658 service = NULL; 659 *handle = NULL; 660 } 661 } 662 663 return (service != NULL) ? 0 : -1; 664 } 665 EXPORT_SYMBOL(vchi_service_open); 666 667 int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle, 668 SERVICE_CREATION_T *setup, 669 VCHI_SERVICE_HANDLE_T *handle) 670 { 671 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 672 SHIM_SERVICE_T *service = service_alloc(instance, setup); 673 674 *handle = (VCHI_SERVICE_HANDLE_T)service; 675 676 if (service) { 677 VCHIQ_SERVICE_PARAMS_T params; 678 VCHIQ_STATUS_T status; 679 680 memset(¶ms, 0, sizeof(params)); 681 params.fourcc = setup->service_id; 682 params.callback = shim_callback; 683 params.userdata = service; 684 params.version = setup->version.version; 685 params.version_min = setup->version.version_min; 686 status = vchiq_add_service(instance, ¶ms, &service->handle); 687 688 if (status != VCHIQ_SUCCESS) { 689 service_free(service); 690 service = NULL; 691 *handle = NULL; 692 } 693 } 694 695 return (service != NULL) ? 0 : -1; 696 } 697 EXPORT_SYMBOL(vchi_service_create); 698 699 int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle) 700 { 701 int32_t ret = -1; 702 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 703 if (service) { 704 VCHIQ_STATUS_T status = vchiq_close_service(service->handle); 705 if (status == VCHIQ_SUCCESS) { 706 service_free(service); 707 service = NULL; 708 } 709 710 ret = vchiq_status_to_vchi(status); 711 } 712 return ret; 713 } 714 EXPORT_SYMBOL(vchi_service_close); 715 716 int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle) 717 { 718 int32_t ret = -1; 719 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 720 if (service) { 721 VCHIQ_STATUS_T status = vchiq_remove_service(service->handle); 722 if (status == VCHIQ_SUCCESS) { 723 service_free(service); 724 service = NULL; 725 } 726 727 ret = vchiq_status_to_vchi(status); 728 } 729 return ret; 730 } 731 EXPORT_SYMBOL(vchi_service_destroy); 732 733 int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, 734 VCHI_SERVICE_OPTION_T option, 735 int value) 736 { 737 int32_t ret = -1; 738 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 739 VCHIQ_SERVICE_OPTION_T vchiq_option; 740 switch (option) { 741 case VCHI_SERVICE_OPTION_TRACE: 742 vchiq_option = VCHIQ_SERVICE_OPTION_TRACE; 743 break; 744 case VCHI_SERVICE_OPTION_SYNCHRONOUS: 745 vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS; 746 break; 747 default: 748 service = NULL; 749 break; 750 } 751 if (service) { 752 VCHIQ_STATUS_T status = 753 vchiq_set_service_option(service->handle, 754 vchiq_option, 755 value); 756 757 ret = vchiq_status_to_vchi(status); 758 } 759 return ret; 760 } 761 EXPORT_SYMBOL(vchi_service_set_option); 762 763 int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version ) 764 { 765 int32_t ret = -1; 766 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 767 if(service) 768 { 769 VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version); 770 ret = vchiq_status_to_vchi( status ); 771 } 772 return ret; 773 } 774 EXPORT_SYMBOL(vchi_get_peer_version); 775 776 #if notyet 777 /* ---------------------------------------------------------------------- 778 * read a uint32_t from buffer. 779 * network format is defined to be little endian 780 * -------------------------------------------------------------------- */ 781 uint32_t 782 vchi_readbuf_uint32(const void *_ptr) 783 { 784 const unsigned char *ptr = _ptr; 785 return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); 786 } 787 788 /* ---------------------------------------------------------------------- 789 * write a uint32_t to buffer. 790 * network format is defined to be little endian 791 * -------------------------------------------------------------------- */ 792 void 793 vchi_writebuf_uint32(void *_ptr, uint32_t value) 794 { 795 unsigned char *ptr = _ptr; 796 ptr[0] = (unsigned char)((value >> 0) & 0xFF); 797 ptr[1] = (unsigned char)((value >> 8) & 0xFF); 798 ptr[2] = (unsigned char)((value >> 16) & 0xFF); 799 ptr[3] = (unsigned char)((value >> 24) & 0xFF); 800 } 801 802 /* ---------------------------------------------------------------------- 803 * read a uint16_t from buffer. 804 * network format is defined to be little endian 805 * -------------------------------------------------------------------- */ 806 uint16_t 807 vchi_readbuf_uint16(const void *_ptr) 808 { 809 const unsigned char *ptr = _ptr; 810 return ptr[0] | (ptr[1] << 8); 811 } 812 813 /* ---------------------------------------------------------------------- 814 * write a uint16_t into the buffer. 815 * network format is defined to be little endian 816 * -------------------------------------------------------------------- */ 817 void 818 vchi_writebuf_uint16(void *_ptr, uint16_t value) 819 { 820 unsigned char *ptr = _ptr; 821 ptr[0] = (value >> 0) & 0xFF; 822 ptr[1] = (value >> 8) & 0xFF; 823 } 824 #endif 825 826 /*********************************************************** 827 * Name: vchi_service_use 828 * 829 * Arguments: const VCHI_SERVICE_HANDLE_T handle 830 * 831 * Description: Routine to increment refcount on a service 832 * 833 * Returns: void 834 * 835 ***********************************************************/ 836 int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle) 837 { 838 int32_t ret = -1; 839 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 840 if (service) 841 ret = vchiq_status_to_vchi(vchiq_use_service(service->handle)); 842 return ret; 843 } 844 EXPORT_SYMBOL(vchi_service_use); 845 846 /*********************************************************** 847 * Name: vchi_service_release 848 * 849 * Arguments: const VCHI_SERVICE_HANDLE_T handle 850 * 851 * Description: Routine to decrement refcount on a service 852 * 853 * Returns: void 854 * 855 ***********************************************************/ 856 int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle) 857 { 858 int32_t ret = -1; 859 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 860 if (service) 861 ret = vchiq_status_to_vchi( 862 vchiq_release_service(service->handle)); 863 return ret; 864 } 865 EXPORT_SYMBOL(vchi_service_release); 866