Home | History | Annotate | Line # | Download | only in vchiq_arm
      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(&params, 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, &params,
    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(&params, 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, &params, &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