vchiq_shim.c revision 290245
1345153Sdim/** 2345153Sdim * Copyright (c) 2010-2012 Broadcom. All rights reserved. 3345153Sdim * 4345153Sdim * Redistribution and use in source and binary forms, with or without 5345153Sdim * modification, are permitted provided that the following conditions 6345153Sdim * are met: 7353358Sdim * 1. Redistributions of source code must retain the above copyright 8353358Sdim * notice, this list of conditions, and the following disclaimer, 9353358Sdim * without modification. 10345153Sdim * 2. Redistributions in binary form must reproduce the above copyright 11345153Sdim * notice, this list of conditions and the following disclaimer in the 12345153Sdim * documentation and/or other materials provided with the distribution. 13345153Sdim * 3. The names of the above-listed copyright holders may not be used 14345153Sdim * to endorse or promote products derived from this software without 15345153Sdim * specific prior written permission. 16345153Sdim * 17345153Sdim * ALTERNATIVELY, this software may be distributed under the terms of the 18345153Sdim * GNU General Public License ("GPL") version 2, as published by the Free 19345153Sdim * Software Foundation. 20345153Sdim * 21345153Sdim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22345153Sdim * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23345153Sdim * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24345153Sdim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 25345153Sdim * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26345153Sdim * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27345153Sdim * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28345153Sdim * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29345153Sdim * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30345153Sdim * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31353358Sdim * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32345153Sdim */ 33345153Sdim 34345153Sdim#include <interface/compat/vchi_bsd.h> 35345153Sdim 36345153Sdim#include "interface/vchi/vchi.h" 37345153Sdim#include "vchiq.h" 38345153Sdim#include "vchiq_core.h" 39345153Sdim 40345153Sdim#include "vchiq_util.h" 41345153Sdim 42345153Sdim#define vchiq_status_to_vchi(status) ((int32_t)status) 43345153Sdim 44345153Sdimtypedef struct { 45345153Sdim VCHIQ_SERVICE_HANDLE_T handle; 46345153Sdim 47345153Sdim VCHIU_QUEUE_T queue; 48345153Sdim 49345153Sdim VCHI_CALLBACK_T callback; 50345153Sdim void *callback_param; 51345153Sdim} SHIM_SERVICE_T; 52345153Sdim 53345153Sdim/* ---------------------------------------------------------------------- 54345153Sdim * return pointer to the mphi message driver function table 55345153Sdim * -------------------------------------------------------------------- */ 56345153Sdimconst VCHI_MESSAGE_DRIVER_T * 57345153Sdimvchi_mphi_message_driver_func_table(void) 58345153Sdim{ 59345153Sdim return NULL; 60345153Sdim} 61345153Sdim 62345153Sdim/* ---------------------------------------------------------------------- 63345153Sdim * return a pointer to the 'single' connection driver fops 64345153Sdim * -------------------------------------------------------------------- */ 65345153Sdimconst VCHI_CONNECTION_API_T * 66345153Sdimsingle_get_func_table(void) 67345153Sdim{ 68345153Sdim return NULL; 69345153Sdim} 70345153Sdim 71345153SdimVCHI_CONNECTION_T *vchi_create_connection( 72345153Sdim const VCHI_CONNECTION_API_T *function_table, 73345153Sdim const VCHI_MESSAGE_DRIVER_T *low_level) 74345153Sdim{ 75345153Sdim (void)function_table; 76345153Sdim (void)low_level; 77345153Sdim return NULL; 78345153Sdim} 79345153Sdim 80345153Sdim/*********************************************************** 81345153Sdim * Name: vchi_msg_peek 82345153Sdim * 83345153Sdim * Arguments: const VCHI_SERVICE_HANDLE_T handle, 84345153Sdim * void **data, 85345153Sdim * uint32_t *msg_size, 86345153Sdim 87345153Sdim 88345153Sdim * VCHI_FLAGS_T flags 89345153Sdim * 90345153Sdim * Description: Routine to return a pointer to the current message (to allow in 91345153Sdim * place processing). The message can be removed using 92345153Sdim * vchi_msg_remove when you're finished 93345153Sdim * 94345153Sdim * Returns: int32_t - success == 0 95345153Sdim * 96345153Sdim ***********************************************************/ 97345153Sdimint32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle, 98345153Sdim void **data, 99345153Sdim uint32_t *msg_size, 100345153Sdim VCHI_FLAGS_T flags) 101345153Sdim{ 102345153Sdim SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 103345153Sdim VCHIQ_HEADER_T *header; 104345153Sdim 105345153Sdim WARN_ON((flags != VCHI_FLAGS_NONE) && 106345153Sdim (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); 107345153Sdim 108345153Sdim if (flags == VCHI_FLAGS_NONE) 109345153Sdim if (vchiu_queue_is_empty(&service->queue)) 110345153Sdim return -1; 111345153Sdim 112345153Sdim header = vchiu_queue_peek(&service->queue); 113345153Sdim 114345153Sdim *data = header->data; 115345153Sdim *msg_size = header->size; 116345153Sdim 117345153Sdim return 0; 118345153Sdim} 119345153SdimEXPORT_SYMBOL(vchi_msg_peek); 120345153Sdim 121345153Sdim/*********************************************************** 122345153Sdim * Name: vchi_msg_remove 123345153Sdim * 124345153Sdim * Arguments: const VCHI_SERVICE_HANDLE_T handle, 125345153Sdim * 126345153Sdim * Description: Routine to remove a message (after it has been read with 127345153Sdim * vchi_msg_peek) 128345153Sdim * 129345153Sdim * Returns: int32_t - success == 0 130345153Sdim * 131345153Sdim ***********************************************************/ 132345153Sdimint32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle) 133345153Sdim{ 134345153Sdim SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 135345153Sdim VCHIQ_HEADER_T *header; 136345153Sdim 137345153Sdim header = vchiu_queue_pop(&service->queue); 138345153Sdim 139345153Sdim vchiq_release_message(service->handle, header); 140345153Sdim 141345153Sdim return 0; 142345153Sdim} 143345153SdimEXPORT_SYMBOL(vchi_msg_remove); 144345153Sdim 145345153Sdim/*********************************************************** 146345153Sdim * Name: vchi_msg_queue 147345153Sdim * 148345153Sdim * Arguments: VCHI_SERVICE_HANDLE_T handle, 149345153Sdim * const void *data, 150345153Sdim * uint32_t data_size, 151345153Sdim * VCHI_FLAGS_T flags, 152345153Sdim * void *msg_handle, 153345153Sdim * 154345153Sdim * Description: Thin wrapper to queue a message onto a connection 155345153Sdim * 156345153Sdim * Returns: int32_t - success == 0 157345153Sdim * 158345153Sdim ***********************************************************/ 159345153Sdimint32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, 160345153Sdim const void *data, 161345153Sdim uint32_t data_size, 162345153Sdim VCHI_FLAGS_T flags, 163345153Sdim void *msg_handle) 164345153Sdim{ 165345153Sdim SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 166345153Sdim VCHIQ_ELEMENT_T element = {data, data_size}; 167345153Sdim VCHIQ_STATUS_T status; 168345153Sdim 169345153Sdim (void)msg_handle; 170345153Sdim 171345153Sdim WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); 172345153Sdim 173345153Sdim status = vchiq_queue_message(service->handle, &element, 1); 174345153Sdim 175345153Sdim /* vchiq_queue_message() may return VCHIQ_RETRY, so we need to 176345153Sdim ** implement a retry mechanism since this function is supposed 177345153Sdim ** to block until queued 178345153Sdim */ 179345153Sdim while (status == VCHIQ_RETRY) { 180345153Sdim msleep(1); 181345153Sdim status = vchiq_queue_message(service->handle, &element, 1); 182345153Sdim } 183345153Sdim 184345153Sdim return vchiq_status_to_vchi(status); 185345153Sdim} 186345153SdimEXPORT_SYMBOL(vchi_msg_queue); 187345153Sdim 188345153Sdim/*********************************************************** 189345153Sdim * Name: vchi_bulk_queue_receive 190345153Sdim * 191345153Sdim * Arguments: VCHI_BULK_HANDLE_T handle, 192345153Sdim * void *data_dst, 193345153Sdim * const uint32_t data_size, 194345153Sdim * VCHI_FLAGS_T flags 195345153Sdim * void *bulk_handle 196345153Sdim * 197345153Sdim * Description: Routine to setup a rcv buffer 198345153Sdim * 199345153Sdim * Returns: int32_t - success == 0 200345153Sdim * 201345153Sdim ***********************************************************/ 202345153Sdimint32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle, 203345153Sdim void *data_dst, 204345153Sdim uint32_t data_size, 205345153Sdim VCHI_FLAGS_T flags, 206345153Sdim void *bulk_handle) 207345153Sdim{ 208345153Sdim SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 209345153Sdim VCHIQ_BULK_MODE_T mode; 210345153Sdim VCHIQ_STATUS_T status; 211345153Sdim 212345153Sdim switch ((int)flags) { 213345153Sdim case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE 214345153Sdim | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 215353358Sdim WARN_ON(!service->callback); 216345153Sdim mode = VCHIQ_BULK_MODE_CALLBACK; 217345153Sdim break; 218345153Sdim case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: 219345153Sdim mode = VCHIQ_BULK_MODE_BLOCKING; 220345153Sdim break; 221345153Sdim case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 222345153Sdim case VCHI_FLAGS_NONE: 223345153Sdim mode = VCHIQ_BULK_MODE_NOCALLBACK; 224345153Sdim break; 225345153Sdim default: 226345153Sdim WARN(1, "unsupported message\n"); 227345153Sdim return vchiq_status_to_vchi(VCHIQ_ERROR); 228345153Sdim } 229345153Sdim 230345153Sdim status = vchiq_bulk_receive(service->handle, data_dst, data_size, 231345153Sdim bulk_handle, mode); 232345153Sdim 233345153Sdim /* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to 234345153Sdim ** implement a retry mechanism since this function is supposed 235345153Sdim ** to block until queued 236345153Sdim */ 237345153Sdim while (status == VCHIQ_RETRY) { 238345153Sdim msleep(1); 239345153Sdim status = vchiq_bulk_receive(service->handle, data_dst, 240345153Sdim data_size, bulk_handle, mode); 241345153Sdim } 242345153Sdim 243345153Sdim return vchiq_status_to_vchi(status); 244345153Sdim} 245345153SdimEXPORT_SYMBOL(vchi_bulk_queue_receive); 246345153Sdim 247345153Sdim/*********************************************************** 248345153Sdim * Name: vchi_bulk_queue_transmit 249345153Sdim * 250345153Sdim * Arguments: VCHI_BULK_HANDLE_T handle, 251345153Sdim * void *data_src, 252345153Sdim * uint32_t data_size, 253345153Sdim * VCHI_FLAGS_T flags, 254345153Sdim * void *bulk_handle 255345153Sdim * 256353358Sdim * Description: Routine to transmit some data 257345153Sdim * 258345153Sdim * Returns: int32_t - success == 0 259345153Sdim * 260345153Sdim ***********************************************************/ 261345153Sdimint32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle, 262345153Sdim void *data_src, 263345153Sdim uint32_t data_size, 264345153Sdim VCHI_FLAGS_T flags, 265345153Sdim void *bulk_handle) 266345153Sdim{ 267345153Sdim SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 268353358Sdim VCHIQ_BULK_MODE_T mode; 269353358Sdim VCHIQ_STATUS_T status; 270345153Sdim 271345153Sdim switch ((int)flags) { 272345153Sdim case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE 273345153Sdim | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 274345153Sdim WARN_ON(!service->callback); 275345153Sdim mode = VCHIQ_BULK_MODE_CALLBACK; 276345153Sdim break; 277345153Sdim case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ: 278345153Sdim case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: 279345153Sdim mode = VCHIQ_BULK_MODE_BLOCKING; 280345153Sdim break; 281353358Sdim case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 282353358Sdim case VCHI_FLAGS_NONE: 283345153Sdim mode = VCHIQ_BULK_MODE_NOCALLBACK; 284345153Sdim break; 285345153Sdim default: 286345153Sdim WARN(1, "unsupported message\n"); 287345153Sdim return vchiq_status_to_vchi(VCHIQ_ERROR); 288345153Sdim } 289345153Sdim 290345153Sdim status = vchiq_bulk_transmit(service->handle, data_src, data_size, 291345153Sdim bulk_handle, mode); 292345153Sdim 293345153Sdim /* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to 294345153Sdim ** implement a retry mechanism since this function is supposed 295345153Sdim ** to block until queued 296345153Sdim */ 297345153Sdim while (status == VCHIQ_RETRY) { 298345153Sdim msleep(1); 299345153Sdim status = vchiq_bulk_transmit(service->handle, data_src, 300345153Sdim data_size, bulk_handle, mode); 301345153Sdim } 302345153Sdim 303345153Sdim return vchiq_status_to_vchi(status); 304345153Sdim} 305345153SdimEXPORT_SYMBOL(vchi_bulk_queue_transmit); 306345153Sdim 307345153Sdim/*********************************************************** 308345153Sdim * Name: vchi_msg_dequeue 309345153Sdim * 310345153Sdim * Arguments: VCHI_SERVICE_HANDLE_T handle, 311345153Sdim * void *data, 312345153Sdim * uint32_t max_data_size_to_read, 313345153Sdim * uint32_t *actual_msg_size 314345153Sdim * VCHI_FLAGS_T flags 315345153Sdim * 316345153Sdim * Description: Routine to dequeue a message into the supplied buffer 317345153Sdim * 318345153Sdim * Returns: int32_t - success == 0 319345153Sdim * 320345153Sdim ***********************************************************/ 321345153Sdimint32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle, 322345153Sdim void *data, 323345153Sdim uint32_t max_data_size_to_read, 324345153Sdim uint32_t *actual_msg_size, 325345153Sdim VCHI_FLAGS_T flags) 326345153Sdim{ 327345153Sdim SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 328345153Sdim VCHIQ_HEADER_T *header; 329345153Sdim 330345153Sdim WARN_ON((flags != VCHI_FLAGS_NONE) && 331345153Sdim (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); 332345153Sdim 333345153Sdim if (flags == VCHI_FLAGS_NONE) 334345153Sdim if (vchiu_queue_is_empty(&service->queue)) 335345153Sdim return -1; 336345153Sdim 337345153Sdim header = vchiu_queue_pop(&service->queue); 338345153Sdim 339345153Sdim memcpy(data, header->data, header->size < max_data_size_to_read ? 340345153Sdim header->size : max_data_size_to_read); 341345153Sdim 342345153Sdim *actual_msg_size = header->size; 343345153Sdim 344345153Sdim vchiq_release_message(service->handle, header); 345345153Sdim 346345153Sdim return 0; 347345153Sdim} 348345153SdimEXPORT_SYMBOL(vchi_msg_dequeue); 349345153Sdim 350345153Sdim/*********************************************************** 351345153Sdim * Name: vchi_msg_queuev 352345153Sdim * 353345153Sdim * Arguments: VCHI_SERVICE_HANDLE_T handle, 354345153Sdim * VCHI_MSG_VECTOR_T *vector, 355345153Sdim * uint32_t count, 356345153Sdim * VCHI_FLAGS_T flags, 357345153Sdim * void *msg_handle 358345153Sdim * 359345153Sdim * Description: Thin wrapper to queue a message onto a connection 360345153Sdim * 361345153Sdim * Returns: int32_t - success == 0 362345153Sdim * 363345153Sdim ***********************************************************/ 364345153Sdim 365345153Sdimvchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T)); 366345153Sdimvchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == 367345153Sdim offsetof(VCHIQ_ELEMENT_T, data)); 368345153Sdimvchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == 369345153Sdim offsetof(VCHIQ_ELEMENT_T, size)); 370345153Sdim 371345153Sdimint32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle, 372345153Sdim VCHI_MSG_VECTOR_T *vector, 373345153Sdim uint32_t count, 374345153Sdim VCHI_FLAGS_T flags, 375345153Sdim void *msg_handle) 376345153Sdim{ 377345153Sdim SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 378345153Sdim 379345153Sdim (void)msg_handle; 380345153Sdim 381345153Sdim WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); 382345153Sdim 383345153Sdim return vchiq_status_to_vchi(vchiq_queue_message(service->handle, 384345153Sdim (const VCHIQ_ELEMENT_T *)vector, count)); 385345153Sdim} 386345153SdimEXPORT_SYMBOL(vchi_msg_queuev); 387345153Sdim 388345153Sdim/*********************************************************** 389345153Sdim * Name: vchi_held_msg_release 390353358Sdim * 391353358Sdim * Arguments: VCHI_HELD_MSG_T *message 392345153Sdim * 393345153Sdim * Description: Routine to release a held message (after it has been read with 394345153Sdim * vchi_msg_hold) 395345153Sdim * 396345153Sdim * Returns: int32_t - success == 0 397345153Sdim * 398345153Sdim ***********************************************************/ 399345153Sdimint32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message) 400345153Sdim{ 401345153Sdim vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service, 402345153Sdim (VCHIQ_HEADER_T *)message->message); 403345153Sdim 404345153Sdim return 0; 405345153Sdim} 406345153SdimEXPORT_SYMBOL(vchi_held_msg_release); 407345153Sdim 408345153Sdim/*********************************************************** 409345153Sdim * Name: vchi_msg_hold 410345153Sdim * 411345153Sdim * Arguments: VCHI_SERVICE_HANDLE_T handle, 412345153Sdim * void **data, 413345153Sdim * uint32_t *msg_size, 414345153Sdim * VCHI_FLAGS_T flags, 415345153Sdim * VCHI_HELD_MSG_T *message_handle 416345153Sdim * 417345153Sdim * Description: Routine to return a pointer to the current message (to allow 418345153Sdim * in place processing). The message is dequeued - don't forget 419345153Sdim * to release the message using vchi_held_msg_release when you're 420345153Sdim * finished. 421345153Sdim * 422345153Sdim * Returns: int32_t - success == 0 423345153Sdim * 424345153Sdim ***********************************************************/ 425345153Sdimint32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle, 426345153Sdim void **data, 427345153Sdim uint32_t *msg_size, 428345153Sdim VCHI_FLAGS_T flags, 429345153Sdim VCHI_HELD_MSG_T *message_handle) 430345153Sdim{ 431345153Sdim SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 432345153Sdim VCHIQ_HEADER_T *header; 433345153Sdim 434345153Sdim WARN_ON((flags != VCHI_FLAGS_NONE) && 435345153Sdim (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); 436345153Sdim 437345153Sdim if (flags == VCHI_FLAGS_NONE) 438345153Sdim if (vchiu_queue_is_empty(&service->queue)) 439345153Sdim return -1; 440345153Sdim 441345153Sdim header = vchiu_queue_pop(&service->queue); 442345153Sdim 443345153Sdim *data = header->data; 444345153Sdim *msg_size = header->size; 445345153Sdim 446345153Sdim message_handle->service = 447345153Sdim (struct opaque_vchi_service_t *)service->handle; 448345153Sdim message_handle->message = header; 449 450 return 0; 451} 452EXPORT_SYMBOL(vchi_msg_hold); 453 454/*********************************************************** 455 * Name: vchi_initialise 456 * 457 * Arguments: VCHI_INSTANCE_T *instance_handle 458 * 459 * Description: Initialises the hardware but does not transmit anything 460 * When run as a Host App this will be called twice hence the need 461 * to malloc the state information 462 * 463 * Returns: 0 if successful, failure otherwise 464 * 465 ***********************************************************/ 466 467int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle) 468{ 469 VCHIQ_INSTANCE_T instance; 470 VCHIQ_STATUS_T status; 471 472 status = vchiq_initialise(&instance); 473 474 *instance_handle = (VCHI_INSTANCE_T)instance; 475 476 return vchiq_status_to_vchi(status); 477} 478EXPORT_SYMBOL(vchi_initialise); 479 480/*********************************************************** 481 * Name: vchi_connect 482 * 483 * Arguments: VCHI_CONNECTION_T **connections 484 * const uint32_t num_connections 485 * VCHI_INSTANCE_T instance_handle) 486 * 487 * Description: Starts the command service on each connection, 488 * causing INIT messages to be pinged back and forth 489 * 490 * Returns: 0 if successful, failure otherwise 491 * 492 ***********************************************************/ 493int32_t vchi_connect(VCHI_CONNECTION_T **connections, 494 const uint32_t num_connections, 495 VCHI_INSTANCE_T instance_handle) 496{ 497 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 498 499 (void)connections; 500 (void)num_connections; 501 502 return vchiq_connect(instance); 503} 504EXPORT_SYMBOL(vchi_connect); 505 506 507/*********************************************************** 508 * Name: vchi_disconnect 509 * 510 * Arguments: VCHI_INSTANCE_T instance_handle 511 * 512 * Description: Stops the command service on each connection, 513 * causing DE-INIT messages to be pinged back and forth 514 * 515 * Returns: 0 if successful, failure otherwise 516 * 517 ***********************************************************/ 518int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle) 519{ 520 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 521 return vchiq_status_to_vchi(vchiq_shutdown(instance)); 522} 523EXPORT_SYMBOL(vchi_disconnect); 524 525 526/*********************************************************** 527 * Name: vchi_service_open 528 * Name: vchi_service_create 529 * 530 * Arguments: VCHI_INSTANCE_T *instance_handle 531 * SERVICE_CREATION_T *setup, 532 * VCHI_SERVICE_HANDLE_T *handle 533 * 534 * Description: Routine to open a service 535 * 536 * Returns: int32_t - success == 0 537 * 538 ***********************************************************/ 539 540static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, 541 VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user) 542{ 543 SHIM_SERVICE_T *service = 544 (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle); 545 546 if (!service->callback) 547 goto release; 548 549 switch (reason) { 550 case VCHIQ_MESSAGE_AVAILABLE: 551 vchiu_queue_push(&service->queue, header); 552 553 service->callback(service->callback_param, 554 VCHI_CALLBACK_MSG_AVAILABLE, NULL); 555 556 goto done; 557 break; 558 559 case VCHIQ_BULK_TRANSMIT_DONE: 560 service->callback(service->callback_param, 561 VCHI_CALLBACK_BULK_SENT, bulk_user); 562 break; 563 564 case VCHIQ_BULK_RECEIVE_DONE: 565 service->callback(service->callback_param, 566 VCHI_CALLBACK_BULK_RECEIVED, bulk_user); 567 break; 568 569 case VCHIQ_SERVICE_CLOSED: 570 service->callback(service->callback_param, 571 VCHI_CALLBACK_SERVICE_CLOSED, NULL); 572 break; 573 574 case VCHIQ_SERVICE_OPENED: 575 /* No equivalent VCHI reason */ 576 break; 577 578 case VCHIQ_BULK_TRANSMIT_ABORTED: 579 service->callback(service->callback_param, 580 VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, 581 bulk_user); 582 break; 583 584 case VCHIQ_BULK_RECEIVE_ABORTED: 585 service->callback(service->callback_param, 586 VCHI_CALLBACK_BULK_RECEIVE_ABORTED, 587 bulk_user); 588 break; 589 590 default: 591 WARN(1, "not supported\n"); 592 break; 593 } 594 595release: 596 vchiq_release_message(service->handle, header); 597done: 598 return VCHIQ_SUCCESS; 599} 600 601static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance, 602 SERVICE_CREATION_T *setup) 603{ 604 SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL); 605 606 (void)instance; 607 608 if (service) { 609 if (vchiu_queue_init(&service->queue, 64)) { 610 service->callback = setup->callback; 611 service->callback_param = setup->callback_param; 612 } else { 613 kfree(service); 614 service = NULL; 615 } 616 } 617 618 return service; 619} 620 621static void service_free(SHIM_SERVICE_T *service) 622{ 623 if (service) { 624 vchiu_queue_delete(&service->queue); 625 kfree(service); 626 } 627} 628 629int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, 630 SERVICE_CREATION_T *setup, 631 VCHI_SERVICE_HANDLE_T *handle) 632{ 633 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 634 SHIM_SERVICE_T *service = service_alloc(instance, setup); 635 636 *handle = (VCHI_SERVICE_HANDLE_T)service; 637 638 if (service) { 639 VCHIQ_SERVICE_PARAMS_T params; 640 VCHIQ_STATUS_T status; 641 642 memset(¶ms, 0, sizeof(params)); 643 params.fourcc = setup->service_id; 644 params.callback = shim_callback; 645 params.userdata = service; 646 params.version = setup->version.version; 647 params.version_min = setup->version.version_min; 648 649 status = vchiq_open_service(instance, ¶ms, 650 &service->handle); 651 if (status != VCHIQ_SUCCESS) { 652 service_free(service); 653 service = NULL; 654 *handle = NULL; 655 } 656 } 657 658 return (service != NULL) ? 0 : -1; 659} 660EXPORT_SYMBOL(vchi_service_open); 661 662int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle, 663 SERVICE_CREATION_T *setup, 664 VCHI_SERVICE_HANDLE_T *handle) 665{ 666 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 667 SHIM_SERVICE_T *service = service_alloc(instance, setup); 668 669 *handle = (VCHI_SERVICE_HANDLE_T)service; 670 671 if (service) { 672 VCHIQ_SERVICE_PARAMS_T params; 673 VCHIQ_STATUS_T status; 674 675 memset(¶ms, 0, sizeof(params)); 676 params.fourcc = setup->service_id; 677 params.callback = shim_callback; 678 params.userdata = service; 679 params.version = setup->version.version; 680 params.version_min = setup->version.version_min; 681 status = vchiq_add_service(instance, ¶ms, &service->handle); 682 683 if (status != VCHIQ_SUCCESS) { 684 service_free(service); 685 service = NULL; 686 *handle = NULL; 687 } 688 } 689 690 return (service != NULL) ? 0 : -1; 691} 692EXPORT_SYMBOL(vchi_service_create); 693 694int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle) 695{ 696 int32_t ret = -1; 697 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 698 if (service) { 699 VCHIQ_STATUS_T status = vchiq_close_service(service->handle); 700 if (status == VCHIQ_SUCCESS) { 701 service_free(service); 702 service = NULL; 703 } 704 705 ret = vchiq_status_to_vchi(status); 706 } 707 return ret; 708} 709EXPORT_SYMBOL(vchi_service_close); 710 711int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle) 712{ 713 int32_t ret = -1; 714 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 715 if (service) { 716 VCHIQ_STATUS_T status = vchiq_remove_service(service->handle); 717 if (status == VCHIQ_SUCCESS) { 718 service_free(service); 719 service = NULL; 720 } 721 722 ret = vchiq_status_to_vchi(status); 723 } 724 return ret; 725} 726EXPORT_SYMBOL(vchi_service_destroy); 727 728int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, 729 VCHI_SERVICE_OPTION_T option, 730 int value) 731{ 732 int32_t ret = -1; 733 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 734 VCHIQ_SERVICE_OPTION_T vchiq_option; 735 switch (option) { 736 case VCHI_SERVICE_OPTION_TRACE: 737 vchiq_option = VCHIQ_SERVICE_OPTION_TRACE; 738 break; 739 case VCHI_SERVICE_OPTION_SYNCHRONOUS: 740 vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS; 741 break; 742 default: 743 service = NULL; 744 break; 745 } 746 if (service) { 747 VCHIQ_STATUS_T status = 748 vchiq_set_service_option(service->handle, 749 vchiq_option, 750 value); 751 752 ret = vchiq_status_to_vchi(status); 753 } 754 return ret; 755} 756EXPORT_SYMBOL(vchi_service_set_option); 757 758int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version ) 759{ 760 int32_t ret = -1; 761 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 762 if(service) 763 { 764 VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version); 765 ret = vchiq_status_to_vchi( status ); 766 } 767 return ret; 768} 769EXPORT_SYMBOL(vchi_get_peer_version); 770 771#ifdef notyet 772/* ---------------------------------------------------------------------- 773 * read a uint32_t from buffer. 774 * network format is defined to be little endian 775 * -------------------------------------------------------------------- */ 776uint32_t 777vchi_readbuf_uint32(const void *_ptr) 778{ 779 const unsigned char *ptr = _ptr; 780 return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); 781} 782 783/* ---------------------------------------------------------------------- 784 * write a uint32_t to buffer. 785 * network format is defined to be little endian 786 * -------------------------------------------------------------------- */ 787void 788vchi_writebuf_uint32(void *_ptr, uint32_t value) 789{ 790 unsigned char *ptr = _ptr; 791 ptr[0] = (unsigned char)((value >> 0) & 0xFF); 792 ptr[1] = (unsigned char)((value >> 8) & 0xFF); 793 ptr[2] = (unsigned char)((value >> 16) & 0xFF); 794 ptr[3] = (unsigned char)((value >> 24) & 0xFF); 795} 796 797/* ---------------------------------------------------------------------- 798 * read a uint16_t from buffer. 799 * network format is defined to be little endian 800 * -------------------------------------------------------------------- */ 801uint16_t 802vchi_readbuf_uint16(const void *_ptr) 803{ 804 const unsigned char *ptr = _ptr; 805 return ptr[0] | (ptr[1] << 8); 806} 807 808/* ---------------------------------------------------------------------- 809 * write a uint16_t into the buffer. 810 * network format is defined to be little endian 811 * -------------------------------------------------------------------- */ 812void 813vchi_writebuf_uint16(void *_ptr, uint16_t value) 814{ 815 unsigned char *ptr = _ptr; 816 ptr[0] = (value >> 0) & 0xFF; 817 ptr[1] = (value >> 8) & 0xFF; 818} 819#endif 820 821/*********************************************************** 822 * Name: vchi_service_use 823 * 824 * Arguments: const VCHI_SERVICE_HANDLE_T handle 825 * 826 * Description: Routine to increment refcount on a service 827 * 828 * Returns: void 829 * 830 ***********************************************************/ 831int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle) 832{ 833 int32_t ret = -1; 834 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 835 if (service) 836 ret = vchiq_status_to_vchi(vchiq_use_service(service->handle)); 837 return ret; 838} 839EXPORT_SYMBOL(vchi_service_use); 840 841/*********************************************************** 842 * Name: vchi_service_release 843 * 844 * Arguments: const VCHI_SERVICE_HANDLE_T handle 845 * 846 * Description: Routine to decrement refcount on a service 847 * 848 * Returns: void 849 * 850 ***********************************************************/ 851int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle) 852{ 853 int32_t ret = -1; 854 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 855 if (service) 856 ret = vchiq_status_to_vchi( 857 vchiq_release_service(service->handle)); 858 return ret; 859} 860EXPORT_SYMBOL(vchi_service_release); 861