1278277Sgonzo/** 2278277Sgonzo * Copyright (c) 2010-2012 Broadcom. All rights reserved. 3278277Sgonzo * 4278277Sgonzo * Redistribution and use in source and binary forms, with or without 5278277Sgonzo * modification, are permitted provided that the following conditions 6278277Sgonzo * are met: 7278277Sgonzo * 1. Redistributions of source code must retain the above copyright 8278277Sgonzo * notice, this list of conditions, and the following disclaimer, 9278277Sgonzo * without modification. 10278277Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11278277Sgonzo * notice, this list of conditions and the following disclaimer in the 12278277Sgonzo * documentation and/or other materials provided with the distribution. 13278277Sgonzo * 3. The names of the above-listed copyright holders may not be used 14278277Sgonzo * to endorse or promote products derived from this software without 15278277Sgonzo * specific prior written permission. 16278277Sgonzo * 17278277Sgonzo * ALTERNATIVELY, this software may be distributed under the terms of the 18278277Sgonzo * GNU General Public License ("GPL") version 2, as published by the Free 19278277Sgonzo * Software Foundation. 20278277Sgonzo * 21278277Sgonzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22278277Sgonzo * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23278277Sgonzo * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24278277Sgonzo * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 25278277Sgonzo * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26278277Sgonzo * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27278277Sgonzo * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28278277Sgonzo * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29278277Sgonzo * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30278277Sgonzo * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31278277Sgonzo * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32278277Sgonzo */ 33278277Sgonzo 34278277Sgonzo#include <interface/compat/vchi_bsd.h> 35278277Sgonzo 36278277Sgonzo#include "interface/vchi/vchi.h" 37278277Sgonzo#include "vchiq.h" 38278277Sgonzo#include "vchiq_core.h" 39278277Sgonzo 40278277Sgonzo#include "vchiq_util.h" 41278277Sgonzo 42278277Sgonzo#define vchiq_status_to_vchi(status) ((int32_t)status) 43278277Sgonzo 44278277Sgonzotypedef struct { 45278277Sgonzo VCHIQ_SERVICE_HANDLE_T handle; 46278277Sgonzo 47278277Sgonzo VCHIU_QUEUE_T queue; 48278277Sgonzo 49278277Sgonzo VCHI_CALLBACK_T callback; 50278277Sgonzo void *callback_param; 51278277Sgonzo} SHIM_SERVICE_T; 52278277Sgonzo 53278277Sgonzo/* ---------------------------------------------------------------------- 54278277Sgonzo * return pointer to the mphi message driver function table 55278277Sgonzo * -------------------------------------------------------------------- */ 56278277Sgonzoconst VCHI_MESSAGE_DRIVER_T * 57278277Sgonzovchi_mphi_message_driver_func_table(void) 58278277Sgonzo{ 59278277Sgonzo return NULL; 60278277Sgonzo} 61278277Sgonzo 62278277Sgonzo/* ---------------------------------------------------------------------- 63278277Sgonzo * return a pointer to the 'single' connection driver fops 64278277Sgonzo * -------------------------------------------------------------------- */ 65278277Sgonzoconst VCHI_CONNECTION_API_T * 66278277Sgonzosingle_get_func_table(void) 67278277Sgonzo{ 68278277Sgonzo return NULL; 69278277Sgonzo} 70278277Sgonzo 71278277SgonzoVCHI_CONNECTION_T *vchi_create_connection( 72278277Sgonzo const VCHI_CONNECTION_API_T *function_table, 73278277Sgonzo const VCHI_MESSAGE_DRIVER_T *low_level) 74278277Sgonzo{ 75278277Sgonzo (void)function_table; 76278277Sgonzo (void)low_level; 77278277Sgonzo return NULL; 78278277Sgonzo} 79278277Sgonzo 80278277Sgonzo/*********************************************************** 81278277Sgonzo * Name: vchi_msg_peek 82278277Sgonzo * 83278277Sgonzo * Arguments: const VCHI_SERVICE_HANDLE_T handle, 84278277Sgonzo * void **data, 85278277Sgonzo * uint32_t *msg_size, 86278277Sgonzo 87278277Sgonzo 88278277Sgonzo * VCHI_FLAGS_T flags 89278277Sgonzo * 90278277Sgonzo * Description: Routine to return a pointer to the current message (to allow in 91278277Sgonzo * place processing). The message can be removed using 92278277Sgonzo * vchi_msg_remove when you're finished 93278277Sgonzo * 94278277Sgonzo * Returns: int32_t - success == 0 95278277Sgonzo * 96278277Sgonzo ***********************************************************/ 97278277Sgonzoint32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle, 98278277Sgonzo void **data, 99278277Sgonzo uint32_t *msg_size, 100278277Sgonzo VCHI_FLAGS_T flags) 101278277Sgonzo{ 102278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 103278277Sgonzo VCHIQ_HEADER_T *header; 104278277Sgonzo 105278277Sgonzo WARN_ON((flags != VCHI_FLAGS_NONE) && 106278277Sgonzo (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); 107278277Sgonzo 108278277Sgonzo if (flags == VCHI_FLAGS_NONE) 109278277Sgonzo if (vchiu_queue_is_empty(&service->queue)) 110278277Sgonzo return -1; 111278277Sgonzo 112278277Sgonzo header = vchiu_queue_peek(&service->queue); 113278277Sgonzo 114278277Sgonzo *data = header->data; 115278277Sgonzo *msg_size = header->size; 116278277Sgonzo 117278277Sgonzo return 0; 118278277Sgonzo} 119278277SgonzoEXPORT_SYMBOL(vchi_msg_peek); 120278277Sgonzo 121278277Sgonzo/*********************************************************** 122278277Sgonzo * Name: vchi_msg_remove 123278277Sgonzo * 124278277Sgonzo * Arguments: const VCHI_SERVICE_HANDLE_T handle, 125278277Sgonzo * 126278277Sgonzo * Description: Routine to remove a message (after it has been read with 127278277Sgonzo * vchi_msg_peek) 128278277Sgonzo * 129278277Sgonzo * Returns: int32_t - success == 0 130278277Sgonzo * 131278277Sgonzo ***********************************************************/ 132278277Sgonzoint32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle) 133278277Sgonzo{ 134278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 135278277Sgonzo VCHIQ_HEADER_T *header; 136278277Sgonzo 137278277Sgonzo header = vchiu_queue_pop(&service->queue); 138278277Sgonzo 139278277Sgonzo vchiq_release_message(service->handle, header); 140278277Sgonzo 141278277Sgonzo return 0; 142278277Sgonzo} 143278277SgonzoEXPORT_SYMBOL(vchi_msg_remove); 144278277Sgonzo 145278277Sgonzo/*********************************************************** 146278277Sgonzo * Name: vchi_msg_queue 147278277Sgonzo * 148278277Sgonzo * Arguments: VCHI_SERVICE_HANDLE_T handle, 149278277Sgonzo * const void *data, 150278277Sgonzo * uint32_t data_size, 151278277Sgonzo * VCHI_FLAGS_T flags, 152278277Sgonzo * void *msg_handle, 153278277Sgonzo * 154278277Sgonzo * Description: Thin wrapper to queue a message onto a connection 155278277Sgonzo * 156278277Sgonzo * Returns: int32_t - success == 0 157278277Sgonzo * 158278277Sgonzo ***********************************************************/ 159278277Sgonzoint32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, 160278277Sgonzo const void *data, 161278277Sgonzo uint32_t data_size, 162278277Sgonzo VCHI_FLAGS_T flags, 163278277Sgonzo void *msg_handle) 164278277Sgonzo{ 165278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 166278277Sgonzo VCHIQ_ELEMENT_T element = {data, data_size}; 167278277Sgonzo VCHIQ_STATUS_T status; 168278277Sgonzo 169278277Sgonzo (void)msg_handle; 170278277Sgonzo 171278277Sgonzo WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); 172278277Sgonzo 173278277Sgonzo status = vchiq_queue_message(service->handle, &element, 1); 174278277Sgonzo 175278277Sgonzo /* vchiq_queue_message() may return VCHIQ_RETRY, so we need to 176278277Sgonzo ** implement a retry mechanism since this function is supposed 177278277Sgonzo ** to block until queued 178278277Sgonzo */ 179278277Sgonzo while (status == VCHIQ_RETRY) { 180278277Sgonzo msleep(1); 181278277Sgonzo status = vchiq_queue_message(service->handle, &element, 1); 182278277Sgonzo } 183278277Sgonzo 184278277Sgonzo return vchiq_status_to_vchi(status); 185278277Sgonzo} 186278277SgonzoEXPORT_SYMBOL(vchi_msg_queue); 187278277Sgonzo 188278277Sgonzo/*********************************************************** 189278277Sgonzo * Name: vchi_bulk_queue_receive 190278277Sgonzo * 191278277Sgonzo * Arguments: VCHI_BULK_HANDLE_T handle, 192278277Sgonzo * void *data_dst, 193278277Sgonzo * const uint32_t data_size, 194278277Sgonzo * VCHI_FLAGS_T flags 195278277Sgonzo * void *bulk_handle 196278277Sgonzo * 197278277Sgonzo * Description: Routine to setup a rcv buffer 198278277Sgonzo * 199278277Sgonzo * Returns: int32_t - success == 0 200278277Sgonzo * 201278277Sgonzo ***********************************************************/ 202278277Sgonzoint32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle, 203278277Sgonzo void *data_dst, 204278277Sgonzo uint32_t data_size, 205278277Sgonzo VCHI_FLAGS_T flags, 206278277Sgonzo void *bulk_handle) 207278277Sgonzo{ 208278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 209278277Sgonzo VCHIQ_BULK_MODE_T mode; 210278277Sgonzo VCHIQ_STATUS_T status; 211278277Sgonzo 212278277Sgonzo switch ((int)flags) { 213278277Sgonzo case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE 214278277Sgonzo | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 215278277Sgonzo WARN_ON(!service->callback); 216278277Sgonzo mode = VCHIQ_BULK_MODE_CALLBACK; 217278277Sgonzo break; 218278277Sgonzo case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: 219278277Sgonzo mode = VCHIQ_BULK_MODE_BLOCKING; 220278277Sgonzo break; 221278277Sgonzo case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 222278277Sgonzo case VCHI_FLAGS_NONE: 223278277Sgonzo mode = VCHIQ_BULK_MODE_NOCALLBACK; 224278277Sgonzo break; 225278277Sgonzo default: 226278277Sgonzo WARN(1, "unsupported message\n"); 227278277Sgonzo return vchiq_status_to_vchi(VCHIQ_ERROR); 228278277Sgonzo } 229278277Sgonzo 230278277Sgonzo status = vchiq_bulk_receive(service->handle, data_dst, data_size, 231278277Sgonzo bulk_handle, mode); 232278277Sgonzo 233278277Sgonzo /* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to 234278277Sgonzo ** implement a retry mechanism since this function is supposed 235278277Sgonzo ** to block until queued 236278277Sgonzo */ 237278277Sgonzo while (status == VCHIQ_RETRY) { 238278277Sgonzo msleep(1); 239278277Sgonzo status = vchiq_bulk_receive(service->handle, data_dst, 240278277Sgonzo data_size, bulk_handle, mode); 241278277Sgonzo } 242278277Sgonzo 243278277Sgonzo return vchiq_status_to_vchi(status); 244278277Sgonzo} 245278277SgonzoEXPORT_SYMBOL(vchi_bulk_queue_receive); 246278277Sgonzo 247278277Sgonzo/*********************************************************** 248278277Sgonzo * Name: vchi_bulk_queue_transmit 249278277Sgonzo * 250278277Sgonzo * Arguments: VCHI_BULK_HANDLE_T handle, 251278277Sgonzo * void *data_src, 252278277Sgonzo * uint32_t data_size, 253278277Sgonzo * VCHI_FLAGS_T flags, 254278277Sgonzo * void *bulk_handle 255278277Sgonzo * 256278277Sgonzo * Description: Routine to transmit some data 257278277Sgonzo * 258278277Sgonzo * Returns: int32_t - success == 0 259278277Sgonzo * 260278277Sgonzo ***********************************************************/ 261278277Sgonzoint32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle, 262278277Sgonzo void *data_src, 263278277Sgonzo uint32_t data_size, 264278277Sgonzo VCHI_FLAGS_T flags, 265278277Sgonzo void *bulk_handle) 266278277Sgonzo{ 267278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 268278277Sgonzo VCHIQ_BULK_MODE_T mode; 269278277Sgonzo VCHIQ_STATUS_T status; 270278277Sgonzo 271278277Sgonzo switch ((int)flags) { 272278277Sgonzo case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE 273278277Sgonzo | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 274278277Sgonzo WARN_ON(!service->callback); 275278277Sgonzo mode = VCHIQ_BULK_MODE_CALLBACK; 276278277Sgonzo break; 277278277Sgonzo case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ: 278278277Sgonzo case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: 279278277Sgonzo mode = VCHIQ_BULK_MODE_BLOCKING; 280278277Sgonzo break; 281278277Sgonzo case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: 282278277Sgonzo case VCHI_FLAGS_NONE: 283278277Sgonzo mode = VCHIQ_BULK_MODE_NOCALLBACK; 284278277Sgonzo break; 285278277Sgonzo default: 286278277Sgonzo WARN(1, "unsupported message\n"); 287278277Sgonzo return vchiq_status_to_vchi(VCHIQ_ERROR); 288278277Sgonzo } 289278277Sgonzo 290278277Sgonzo status = vchiq_bulk_transmit(service->handle, data_src, data_size, 291278277Sgonzo bulk_handle, mode); 292278277Sgonzo 293278277Sgonzo /* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to 294278277Sgonzo ** implement a retry mechanism since this function is supposed 295278277Sgonzo ** to block until queued 296278277Sgonzo */ 297278277Sgonzo while (status == VCHIQ_RETRY) { 298278277Sgonzo msleep(1); 299278277Sgonzo status = vchiq_bulk_transmit(service->handle, data_src, 300278277Sgonzo data_size, bulk_handle, mode); 301278277Sgonzo } 302278277Sgonzo 303278277Sgonzo return vchiq_status_to_vchi(status); 304278277Sgonzo} 305278277SgonzoEXPORT_SYMBOL(vchi_bulk_queue_transmit); 306278277Sgonzo 307278277Sgonzo/*********************************************************** 308278277Sgonzo * Name: vchi_msg_dequeue 309278277Sgonzo * 310278277Sgonzo * Arguments: VCHI_SERVICE_HANDLE_T handle, 311278277Sgonzo * void *data, 312278277Sgonzo * uint32_t max_data_size_to_read, 313278277Sgonzo * uint32_t *actual_msg_size 314278277Sgonzo * VCHI_FLAGS_T flags 315278277Sgonzo * 316278277Sgonzo * Description: Routine to dequeue a message into the supplied buffer 317278277Sgonzo * 318278277Sgonzo * Returns: int32_t - success == 0 319278277Sgonzo * 320278277Sgonzo ***********************************************************/ 321278277Sgonzoint32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle, 322278277Sgonzo void *data, 323278277Sgonzo uint32_t max_data_size_to_read, 324278277Sgonzo uint32_t *actual_msg_size, 325278277Sgonzo VCHI_FLAGS_T flags) 326278277Sgonzo{ 327278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 328278277Sgonzo VCHIQ_HEADER_T *header; 329278277Sgonzo 330278277Sgonzo WARN_ON((flags != VCHI_FLAGS_NONE) && 331278277Sgonzo (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); 332278277Sgonzo 333278277Sgonzo if (flags == VCHI_FLAGS_NONE) 334278277Sgonzo if (vchiu_queue_is_empty(&service->queue)) 335278277Sgonzo return -1; 336278277Sgonzo 337278277Sgonzo header = vchiu_queue_pop(&service->queue); 338278277Sgonzo 339278277Sgonzo memcpy(data, header->data, header->size < max_data_size_to_read ? 340278277Sgonzo header->size : max_data_size_to_read); 341278277Sgonzo 342278277Sgonzo *actual_msg_size = header->size; 343278277Sgonzo 344278277Sgonzo vchiq_release_message(service->handle, header); 345278277Sgonzo 346278277Sgonzo return 0; 347278277Sgonzo} 348278277SgonzoEXPORT_SYMBOL(vchi_msg_dequeue); 349278277Sgonzo 350278277Sgonzo/*********************************************************** 351278277Sgonzo * Name: vchi_msg_queuev 352278277Sgonzo * 353278277Sgonzo * Arguments: VCHI_SERVICE_HANDLE_T handle, 354278277Sgonzo * VCHI_MSG_VECTOR_T *vector, 355278277Sgonzo * uint32_t count, 356278277Sgonzo * VCHI_FLAGS_T flags, 357278277Sgonzo * void *msg_handle 358278277Sgonzo * 359278277Sgonzo * Description: Thin wrapper to queue a message onto a connection 360278277Sgonzo * 361278277Sgonzo * Returns: int32_t - success == 0 362278277Sgonzo * 363278277Sgonzo ***********************************************************/ 364278277Sgonzo 365278277Sgonzovchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T)); 366278277Sgonzovchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == 367278277Sgonzo offsetof(VCHIQ_ELEMENT_T, data)); 368278277Sgonzovchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == 369278277Sgonzo offsetof(VCHIQ_ELEMENT_T, size)); 370278277Sgonzo 371278277Sgonzoint32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle, 372278277Sgonzo VCHI_MSG_VECTOR_T *vector, 373278277Sgonzo uint32_t count, 374278277Sgonzo VCHI_FLAGS_T flags, 375278277Sgonzo void *msg_handle) 376278277Sgonzo{ 377278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 378278277Sgonzo 379278277Sgonzo (void)msg_handle; 380278277Sgonzo 381278277Sgonzo WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); 382278277Sgonzo 383278277Sgonzo return vchiq_status_to_vchi(vchiq_queue_message(service->handle, 384278277Sgonzo (const VCHIQ_ELEMENT_T *)vector, count)); 385278277Sgonzo} 386278277SgonzoEXPORT_SYMBOL(vchi_msg_queuev); 387278277Sgonzo 388278277Sgonzo/*********************************************************** 389278277Sgonzo * Name: vchi_held_msg_release 390278277Sgonzo * 391278277Sgonzo * Arguments: VCHI_HELD_MSG_T *message 392278277Sgonzo * 393278277Sgonzo * Description: Routine to release a held message (after it has been read with 394278277Sgonzo * vchi_msg_hold) 395278277Sgonzo * 396278277Sgonzo * Returns: int32_t - success == 0 397278277Sgonzo * 398278277Sgonzo ***********************************************************/ 399278277Sgonzoint32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message) 400278277Sgonzo{ 401278277Sgonzo vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service, 402278277Sgonzo (VCHIQ_HEADER_T *)message->message); 403278277Sgonzo 404278277Sgonzo return 0; 405278277Sgonzo} 406290245SgonzoEXPORT_SYMBOL(vchi_held_msg_release); 407278277Sgonzo 408278277Sgonzo/*********************************************************** 409278277Sgonzo * Name: vchi_msg_hold 410278277Sgonzo * 411278277Sgonzo * Arguments: VCHI_SERVICE_HANDLE_T handle, 412278277Sgonzo * void **data, 413278277Sgonzo * uint32_t *msg_size, 414278277Sgonzo * VCHI_FLAGS_T flags, 415278277Sgonzo * VCHI_HELD_MSG_T *message_handle 416278277Sgonzo * 417278277Sgonzo * Description: Routine to return a pointer to the current message (to allow 418278277Sgonzo * in place processing). The message is dequeued - don't forget 419278277Sgonzo * to release the message using vchi_held_msg_release when you're 420278277Sgonzo * finished. 421278277Sgonzo * 422278277Sgonzo * Returns: int32_t - success == 0 423278277Sgonzo * 424278277Sgonzo ***********************************************************/ 425278277Sgonzoint32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle, 426278277Sgonzo void **data, 427278277Sgonzo uint32_t *msg_size, 428278277Sgonzo VCHI_FLAGS_T flags, 429278277Sgonzo VCHI_HELD_MSG_T *message_handle) 430278277Sgonzo{ 431278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 432278277Sgonzo VCHIQ_HEADER_T *header; 433278277Sgonzo 434278277Sgonzo WARN_ON((flags != VCHI_FLAGS_NONE) && 435278277Sgonzo (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); 436278277Sgonzo 437278277Sgonzo if (flags == VCHI_FLAGS_NONE) 438278277Sgonzo if (vchiu_queue_is_empty(&service->queue)) 439278277Sgonzo return -1; 440278277Sgonzo 441278277Sgonzo header = vchiu_queue_pop(&service->queue); 442278277Sgonzo 443278277Sgonzo *data = header->data; 444278277Sgonzo *msg_size = header->size; 445278277Sgonzo 446278277Sgonzo message_handle->service = 447278277Sgonzo (struct opaque_vchi_service_t *)service->handle; 448278277Sgonzo message_handle->message = header; 449278277Sgonzo 450278277Sgonzo return 0; 451278277Sgonzo} 452290245SgonzoEXPORT_SYMBOL(vchi_msg_hold); 453278277Sgonzo 454278277Sgonzo/*********************************************************** 455278277Sgonzo * Name: vchi_initialise 456278277Sgonzo * 457278277Sgonzo * Arguments: VCHI_INSTANCE_T *instance_handle 458278277Sgonzo * 459278277Sgonzo * Description: Initialises the hardware but does not transmit anything 460278277Sgonzo * When run as a Host App this will be called twice hence the need 461278277Sgonzo * to malloc the state information 462278277Sgonzo * 463278277Sgonzo * Returns: 0 if successful, failure otherwise 464278277Sgonzo * 465278277Sgonzo ***********************************************************/ 466278277Sgonzo 467278277Sgonzoint32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle) 468278277Sgonzo{ 469278277Sgonzo VCHIQ_INSTANCE_T instance; 470278277Sgonzo VCHIQ_STATUS_T status; 471278277Sgonzo 472278277Sgonzo status = vchiq_initialise(&instance); 473278277Sgonzo 474278277Sgonzo *instance_handle = (VCHI_INSTANCE_T)instance; 475278277Sgonzo 476278277Sgonzo return vchiq_status_to_vchi(status); 477278277Sgonzo} 478278277SgonzoEXPORT_SYMBOL(vchi_initialise); 479278277Sgonzo 480278277Sgonzo/*********************************************************** 481278277Sgonzo * Name: vchi_connect 482278277Sgonzo * 483278277Sgonzo * Arguments: VCHI_CONNECTION_T **connections 484278277Sgonzo * const uint32_t num_connections 485278277Sgonzo * VCHI_INSTANCE_T instance_handle) 486278277Sgonzo * 487278277Sgonzo * Description: Starts the command service on each connection, 488278277Sgonzo * causing INIT messages to be pinged back and forth 489278277Sgonzo * 490278277Sgonzo * Returns: 0 if successful, failure otherwise 491278277Sgonzo * 492278277Sgonzo ***********************************************************/ 493278277Sgonzoint32_t vchi_connect(VCHI_CONNECTION_T **connections, 494278277Sgonzo const uint32_t num_connections, 495278277Sgonzo VCHI_INSTANCE_T instance_handle) 496278277Sgonzo{ 497278277Sgonzo VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 498278277Sgonzo 499278277Sgonzo (void)connections; 500278277Sgonzo (void)num_connections; 501278277Sgonzo 502278277Sgonzo return vchiq_connect(instance); 503278277Sgonzo} 504278277SgonzoEXPORT_SYMBOL(vchi_connect); 505278277Sgonzo 506278277Sgonzo 507278277Sgonzo/*********************************************************** 508278277Sgonzo * Name: vchi_disconnect 509278277Sgonzo * 510278277Sgonzo * Arguments: VCHI_INSTANCE_T instance_handle 511278277Sgonzo * 512278277Sgonzo * Description: Stops the command service on each connection, 513278277Sgonzo * causing DE-INIT messages to be pinged back and forth 514278277Sgonzo * 515278277Sgonzo * Returns: 0 if successful, failure otherwise 516278277Sgonzo * 517278277Sgonzo ***********************************************************/ 518278277Sgonzoint32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle) 519278277Sgonzo{ 520278277Sgonzo VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 521278277Sgonzo return vchiq_status_to_vchi(vchiq_shutdown(instance)); 522278277Sgonzo} 523278277SgonzoEXPORT_SYMBOL(vchi_disconnect); 524278277Sgonzo 525278277Sgonzo 526278277Sgonzo/*********************************************************** 527278277Sgonzo * Name: vchi_service_open 528278277Sgonzo * Name: vchi_service_create 529278277Sgonzo * 530278277Sgonzo * Arguments: VCHI_INSTANCE_T *instance_handle 531278277Sgonzo * SERVICE_CREATION_T *setup, 532278277Sgonzo * VCHI_SERVICE_HANDLE_T *handle 533278277Sgonzo * 534278277Sgonzo * Description: Routine to open a service 535278277Sgonzo * 536278277Sgonzo * Returns: int32_t - success == 0 537278277Sgonzo * 538278277Sgonzo ***********************************************************/ 539278277Sgonzo 540278277Sgonzostatic VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, 541278277Sgonzo VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user) 542278277Sgonzo{ 543278277Sgonzo SHIM_SERVICE_T *service = 544278277Sgonzo (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle); 545278277Sgonzo 546278277Sgonzo if (!service->callback) 547278277Sgonzo goto release; 548278277Sgonzo 549278277Sgonzo switch (reason) { 550278277Sgonzo case VCHIQ_MESSAGE_AVAILABLE: 551278277Sgonzo vchiu_queue_push(&service->queue, header); 552278277Sgonzo 553278277Sgonzo service->callback(service->callback_param, 554278277Sgonzo VCHI_CALLBACK_MSG_AVAILABLE, NULL); 555278277Sgonzo 556278277Sgonzo goto done; 557278277Sgonzo break; 558278277Sgonzo 559278277Sgonzo case VCHIQ_BULK_TRANSMIT_DONE: 560278277Sgonzo service->callback(service->callback_param, 561278277Sgonzo VCHI_CALLBACK_BULK_SENT, bulk_user); 562278277Sgonzo break; 563278277Sgonzo 564278277Sgonzo case VCHIQ_BULK_RECEIVE_DONE: 565278277Sgonzo service->callback(service->callback_param, 566278277Sgonzo VCHI_CALLBACK_BULK_RECEIVED, bulk_user); 567278277Sgonzo break; 568278277Sgonzo 569278277Sgonzo case VCHIQ_SERVICE_CLOSED: 570278277Sgonzo service->callback(service->callback_param, 571278277Sgonzo VCHI_CALLBACK_SERVICE_CLOSED, NULL); 572278277Sgonzo break; 573278277Sgonzo 574278277Sgonzo case VCHIQ_SERVICE_OPENED: 575278277Sgonzo /* No equivalent VCHI reason */ 576278277Sgonzo break; 577278277Sgonzo 578278277Sgonzo case VCHIQ_BULK_TRANSMIT_ABORTED: 579278277Sgonzo service->callback(service->callback_param, 580278277Sgonzo VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, 581278277Sgonzo bulk_user); 582278277Sgonzo break; 583278277Sgonzo 584278277Sgonzo case VCHIQ_BULK_RECEIVE_ABORTED: 585278277Sgonzo service->callback(service->callback_param, 586278277Sgonzo VCHI_CALLBACK_BULK_RECEIVE_ABORTED, 587278277Sgonzo bulk_user); 588278277Sgonzo break; 589278277Sgonzo 590278277Sgonzo default: 591278277Sgonzo WARN(1, "not supported\n"); 592278277Sgonzo break; 593278277Sgonzo } 594278277Sgonzo 595278277Sgonzorelease: 596278277Sgonzo vchiq_release_message(service->handle, header); 597278277Sgonzodone: 598278277Sgonzo return VCHIQ_SUCCESS; 599278277Sgonzo} 600278277Sgonzo 601278277Sgonzostatic SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance, 602278277Sgonzo SERVICE_CREATION_T *setup) 603278277Sgonzo{ 604278277Sgonzo SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL); 605278277Sgonzo 606278277Sgonzo (void)instance; 607278277Sgonzo 608278277Sgonzo if (service) { 609278277Sgonzo if (vchiu_queue_init(&service->queue, 64)) { 610278277Sgonzo service->callback = setup->callback; 611278277Sgonzo service->callback_param = setup->callback_param; 612278277Sgonzo } else { 613278277Sgonzo kfree(service); 614278277Sgonzo service = NULL; 615278277Sgonzo } 616278277Sgonzo } 617278277Sgonzo 618278277Sgonzo return service; 619278277Sgonzo} 620278277Sgonzo 621278277Sgonzostatic void service_free(SHIM_SERVICE_T *service) 622278277Sgonzo{ 623278277Sgonzo if (service) { 624278277Sgonzo vchiu_queue_delete(&service->queue); 625278277Sgonzo kfree(service); 626278277Sgonzo } 627278277Sgonzo} 628278277Sgonzo 629278277Sgonzoint32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, 630278277Sgonzo SERVICE_CREATION_T *setup, 631278277Sgonzo VCHI_SERVICE_HANDLE_T *handle) 632278277Sgonzo{ 633278277Sgonzo VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 634278277Sgonzo SHIM_SERVICE_T *service = service_alloc(instance, setup); 635278277Sgonzo 636278277Sgonzo *handle = (VCHI_SERVICE_HANDLE_T)service; 637278277Sgonzo 638278277Sgonzo if (service) { 639278277Sgonzo VCHIQ_SERVICE_PARAMS_T params; 640278277Sgonzo VCHIQ_STATUS_T status; 641278277Sgonzo 642278277Sgonzo memset(¶ms, 0, sizeof(params)); 643278277Sgonzo params.fourcc = setup->service_id; 644278277Sgonzo params.callback = shim_callback; 645278277Sgonzo params.userdata = service; 646278277Sgonzo params.version = setup->version.version; 647278277Sgonzo params.version_min = setup->version.version_min; 648278277Sgonzo 649278277Sgonzo status = vchiq_open_service(instance, ¶ms, 650278277Sgonzo &service->handle); 651278277Sgonzo if (status != VCHIQ_SUCCESS) { 652278277Sgonzo service_free(service); 653278277Sgonzo service = NULL; 654278277Sgonzo *handle = NULL; 655278277Sgonzo } 656278277Sgonzo } 657278277Sgonzo 658278277Sgonzo return (service != NULL) ? 0 : -1; 659278277Sgonzo} 660278277SgonzoEXPORT_SYMBOL(vchi_service_open); 661278277Sgonzo 662278277Sgonzoint32_t vchi_service_create(VCHI_INSTANCE_T instance_handle, 663278277Sgonzo SERVICE_CREATION_T *setup, 664278277Sgonzo VCHI_SERVICE_HANDLE_T *handle) 665278277Sgonzo{ 666278277Sgonzo VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; 667278277Sgonzo SHIM_SERVICE_T *service = service_alloc(instance, setup); 668278277Sgonzo 669278277Sgonzo *handle = (VCHI_SERVICE_HANDLE_T)service; 670278277Sgonzo 671278277Sgonzo if (service) { 672278277Sgonzo VCHIQ_SERVICE_PARAMS_T params; 673278277Sgonzo VCHIQ_STATUS_T status; 674278277Sgonzo 675278277Sgonzo memset(¶ms, 0, sizeof(params)); 676278277Sgonzo params.fourcc = setup->service_id; 677278277Sgonzo params.callback = shim_callback; 678278277Sgonzo params.userdata = service; 679278277Sgonzo params.version = setup->version.version; 680278277Sgonzo params.version_min = setup->version.version_min; 681278277Sgonzo status = vchiq_add_service(instance, ¶ms, &service->handle); 682278277Sgonzo 683278277Sgonzo if (status != VCHIQ_SUCCESS) { 684278277Sgonzo service_free(service); 685278277Sgonzo service = NULL; 686278277Sgonzo *handle = NULL; 687278277Sgonzo } 688278277Sgonzo } 689278277Sgonzo 690278277Sgonzo return (service != NULL) ? 0 : -1; 691278277Sgonzo} 692278277SgonzoEXPORT_SYMBOL(vchi_service_create); 693278277Sgonzo 694278277Sgonzoint32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle) 695278277Sgonzo{ 696278277Sgonzo int32_t ret = -1; 697278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 698278277Sgonzo if (service) { 699278277Sgonzo VCHIQ_STATUS_T status = vchiq_close_service(service->handle); 700278277Sgonzo if (status == VCHIQ_SUCCESS) { 701278277Sgonzo service_free(service); 702278277Sgonzo service = NULL; 703278277Sgonzo } 704278277Sgonzo 705278277Sgonzo ret = vchiq_status_to_vchi(status); 706278277Sgonzo } 707278277Sgonzo return ret; 708278277Sgonzo} 709278277SgonzoEXPORT_SYMBOL(vchi_service_close); 710278277Sgonzo 711278277Sgonzoint32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle) 712278277Sgonzo{ 713278277Sgonzo int32_t ret = -1; 714278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 715278277Sgonzo if (service) { 716278277Sgonzo VCHIQ_STATUS_T status = vchiq_remove_service(service->handle); 717278277Sgonzo if (status == VCHIQ_SUCCESS) { 718278277Sgonzo service_free(service); 719278277Sgonzo service = NULL; 720278277Sgonzo } 721278277Sgonzo 722278277Sgonzo ret = vchiq_status_to_vchi(status); 723278277Sgonzo } 724278277Sgonzo return ret; 725278277Sgonzo} 726278277SgonzoEXPORT_SYMBOL(vchi_service_destroy); 727278277Sgonzo 728290245Sgonzoint32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, 729290245Sgonzo VCHI_SERVICE_OPTION_T option, 730290245Sgonzo int value) 731290245Sgonzo{ 732290245Sgonzo int32_t ret = -1; 733290245Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 734290245Sgonzo VCHIQ_SERVICE_OPTION_T vchiq_option; 735290245Sgonzo switch (option) { 736290245Sgonzo case VCHI_SERVICE_OPTION_TRACE: 737290245Sgonzo vchiq_option = VCHIQ_SERVICE_OPTION_TRACE; 738290245Sgonzo break; 739290245Sgonzo case VCHI_SERVICE_OPTION_SYNCHRONOUS: 740290245Sgonzo vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS; 741290245Sgonzo break; 742290245Sgonzo default: 743290245Sgonzo service = NULL; 744290245Sgonzo break; 745290245Sgonzo } 746290245Sgonzo if (service) { 747290245Sgonzo VCHIQ_STATUS_T status = 748290245Sgonzo vchiq_set_service_option(service->handle, 749290245Sgonzo vchiq_option, 750290245Sgonzo value); 751290245Sgonzo 752290245Sgonzo ret = vchiq_status_to_vchi(status); 753290245Sgonzo } 754290245Sgonzo return ret; 755290245Sgonzo} 756290245SgonzoEXPORT_SYMBOL(vchi_service_set_option); 757290245Sgonzo 758278277Sgonzoint32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version ) 759278277Sgonzo{ 760278277Sgonzo int32_t ret = -1; 761278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 762278277Sgonzo if(service) 763278277Sgonzo { 764278277Sgonzo VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version); 765278277Sgonzo ret = vchiq_status_to_vchi( status ); 766278277Sgonzo } 767278277Sgonzo return ret; 768278277Sgonzo} 769278277SgonzoEXPORT_SYMBOL(vchi_get_peer_version); 770278277Sgonzo 771278277Sgonzo#ifdef notyet 772278277Sgonzo/* ---------------------------------------------------------------------- 773278277Sgonzo * read a uint32_t from buffer. 774278277Sgonzo * network format is defined to be little endian 775278277Sgonzo * -------------------------------------------------------------------- */ 776278277Sgonzouint32_t 777278277Sgonzovchi_readbuf_uint32(const void *_ptr) 778278277Sgonzo{ 779278277Sgonzo const unsigned char *ptr = _ptr; 780278277Sgonzo return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); 781278277Sgonzo} 782278277Sgonzo 783278277Sgonzo/* ---------------------------------------------------------------------- 784278277Sgonzo * write a uint32_t to buffer. 785278277Sgonzo * network format is defined to be little endian 786278277Sgonzo * -------------------------------------------------------------------- */ 787278277Sgonzovoid 788278277Sgonzovchi_writebuf_uint32(void *_ptr, uint32_t value) 789278277Sgonzo{ 790278277Sgonzo unsigned char *ptr = _ptr; 791278277Sgonzo ptr[0] = (unsigned char)((value >> 0) & 0xFF); 792278277Sgonzo ptr[1] = (unsigned char)((value >> 8) & 0xFF); 793278277Sgonzo ptr[2] = (unsigned char)((value >> 16) & 0xFF); 794278277Sgonzo ptr[3] = (unsigned char)((value >> 24) & 0xFF); 795278277Sgonzo} 796278277Sgonzo 797278277Sgonzo/* ---------------------------------------------------------------------- 798278277Sgonzo * read a uint16_t from buffer. 799278277Sgonzo * network format is defined to be little endian 800278277Sgonzo * -------------------------------------------------------------------- */ 801278277Sgonzouint16_t 802278277Sgonzovchi_readbuf_uint16(const void *_ptr) 803278277Sgonzo{ 804278277Sgonzo const unsigned char *ptr = _ptr; 805278277Sgonzo return ptr[0] | (ptr[1] << 8); 806278277Sgonzo} 807278277Sgonzo 808278277Sgonzo/* ---------------------------------------------------------------------- 809278277Sgonzo * write a uint16_t into the buffer. 810278277Sgonzo * network format is defined to be little endian 811278277Sgonzo * -------------------------------------------------------------------- */ 812278277Sgonzovoid 813278277Sgonzovchi_writebuf_uint16(void *_ptr, uint16_t value) 814278277Sgonzo{ 815278277Sgonzo unsigned char *ptr = _ptr; 816278277Sgonzo ptr[0] = (value >> 0) & 0xFF; 817278277Sgonzo ptr[1] = (value >> 8) & 0xFF; 818278277Sgonzo} 819278277Sgonzo#endif 820278277Sgonzo 821278277Sgonzo/*********************************************************** 822278277Sgonzo * Name: vchi_service_use 823278277Sgonzo * 824278277Sgonzo * Arguments: const VCHI_SERVICE_HANDLE_T handle 825278277Sgonzo * 826278277Sgonzo * Description: Routine to increment refcount on a service 827278277Sgonzo * 828278277Sgonzo * Returns: void 829278277Sgonzo * 830278277Sgonzo ***********************************************************/ 831278277Sgonzoint32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle) 832278277Sgonzo{ 833278277Sgonzo int32_t ret = -1; 834278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 835278277Sgonzo if (service) 836278277Sgonzo ret = vchiq_status_to_vchi(vchiq_use_service(service->handle)); 837278277Sgonzo return ret; 838278277Sgonzo} 839278277SgonzoEXPORT_SYMBOL(vchi_service_use); 840278277Sgonzo 841278277Sgonzo/*********************************************************** 842278277Sgonzo * Name: vchi_service_release 843278277Sgonzo * 844278277Sgonzo * Arguments: const VCHI_SERVICE_HANDLE_T handle 845278277Sgonzo * 846278277Sgonzo * Description: Routine to decrement refcount on a service 847278277Sgonzo * 848278277Sgonzo * Returns: void 849278277Sgonzo * 850278277Sgonzo ***********************************************************/ 851278277Sgonzoint32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle) 852278277Sgonzo{ 853278277Sgonzo int32_t ret = -1; 854278277Sgonzo SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; 855278277Sgonzo if (service) 856278277Sgonzo ret = vchiq_status_to_vchi( 857278277Sgonzo vchiq_release_service(service->handle)); 858278277Sgonzo return ret; 859278277Sgonzo} 860278277SgonzoEXPORT_SYMBOL(vchi_service_release); 861