2 * Copyright (c) 2010-2012 Broadcom. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
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.
34 #include <interface/compat/vchi_bsd.h>
36 #include "interface/vchi/vchi.h"
38 #include "vchiq_core.h"
40 #include "vchiq_util.h"
42 #define vchiq_status_to_vchi(status) ((int32_t)status)
45 VCHIQ_SERVICE_HANDLE_T handle;
49 VCHI_CALLBACK_T callback;
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)
62 /* ----------------------------------------------------------------------
63 * return a pointer to the 'single' connection driver fops
64 * -------------------------------------------------------------------- */
65 const VCHI_CONNECTION_API_T *
66 single_get_func_table(void)
71 VCHI_CONNECTION_T *vchi_create_connection(
72 const VCHI_CONNECTION_API_T *function_table,
73 const VCHI_MESSAGE_DRIVER_T *low_level)
80 /***********************************************************
83 * Arguments: const VCHI_SERVICE_HANDLE_T handle,
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
94 * Returns: int32_t - success == 0
96 ***********************************************************/
97 int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
102 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
103 VCHIQ_HEADER_T *header;
105 WARN_ON((flags != VCHI_FLAGS_NONE) &&
106 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
108 if (flags == VCHI_FLAGS_NONE)
109 if (vchiu_queue_is_empty(&service->queue))
112 header = vchiu_queue_peek(&service->queue);
114 *data = header->data;
115 *msg_size = header->size;
119 EXPORT_SYMBOL(vchi_msg_peek);
121 /***********************************************************
122 * Name: vchi_msg_remove
124 * Arguments: const VCHI_SERVICE_HANDLE_T handle,
126 * Description: Routine to remove a message (after it has been read with
129 * Returns: int32_t - success == 0
131 ***********************************************************/
132 int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
134 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
135 VCHIQ_HEADER_T *header;
137 header = vchiu_queue_pop(&service->queue);
139 vchiq_release_message(service->handle, header);
143 EXPORT_SYMBOL(vchi_msg_remove);
145 /***********************************************************
146 * Name: vchi_msg_queue
148 * Arguments: VCHI_SERVICE_HANDLE_T handle,
150 * uint32_t data_size,
151 * VCHI_FLAGS_T flags,
154 * Description: Thin wrapper to queue a message onto a connection
156 * Returns: int32_t - success == 0
158 ***********************************************************/
159 int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
165 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
166 VCHIQ_ELEMENT_T element = {data, data_size};
167 VCHIQ_STATUS_T status;
171 WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
173 status = vchiq_queue_message(service->handle, &element, 1);
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
179 while (status == VCHIQ_RETRY) {
181 status = vchiq_queue_message(service->handle, &element, 1);
184 return vchiq_status_to_vchi(status);
186 EXPORT_SYMBOL(vchi_msg_queue);
188 /***********************************************************
189 * Name: vchi_bulk_queue_receive
191 * Arguments: VCHI_BULK_HANDLE_T handle,
193 * const uint32_t data_size,
197 * Description: Routine to setup a rcv buffer
199 * Returns: int32_t - success == 0
201 ***********************************************************/
202 int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
208 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
209 VCHIQ_BULK_MODE_T mode;
210 VCHIQ_STATUS_T status;
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;
218 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
219 mode = VCHIQ_BULK_MODE_BLOCKING;
221 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
222 case VCHI_FLAGS_NONE:
223 mode = VCHIQ_BULK_MODE_NOCALLBACK;
226 WARN(1, "unsupported message\n");
227 return vchiq_status_to_vchi(VCHIQ_ERROR);
230 status = vchiq_bulk_receive(service->handle, data_dst, data_size,
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
237 while (status == VCHIQ_RETRY) {
239 status = vchiq_bulk_receive(service->handle, data_dst,
240 data_size, bulk_handle, mode);
243 return vchiq_status_to_vchi(status);
245 EXPORT_SYMBOL(vchi_bulk_queue_receive);
247 /***********************************************************
248 * Name: vchi_bulk_queue_transmit
250 * Arguments: VCHI_BULK_HANDLE_T handle,
252 * uint32_t data_size,
253 * VCHI_FLAGS_T flags,
256 * Description: Routine to transmit some data
258 * Returns: int32_t - success == 0
260 ***********************************************************/
261 int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
267 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
268 VCHIQ_BULK_MODE_T mode;
269 VCHIQ_STATUS_T status;
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;
277 case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
278 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
279 mode = VCHIQ_BULK_MODE_BLOCKING;
281 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
282 case VCHI_FLAGS_NONE:
283 mode = VCHIQ_BULK_MODE_NOCALLBACK;
286 WARN(1, "unsupported message\n");
287 return vchiq_status_to_vchi(VCHIQ_ERROR);
290 status = vchiq_bulk_transmit(service->handle, data_src, data_size,
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
297 while (status == VCHIQ_RETRY) {
299 status = vchiq_bulk_transmit(service->handle, data_src,
300 data_size, bulk_handle, mode);
303 return vchiq_status_to_vchi(status);
305 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
307 /***********************************************************
308 * Name: vchi_msg_dequeue
310 * Arguments: VCHI_SERVICE_HANDLE_T handle,
312 * uint32_t max_data_size_to_read,
313 * uint32_t *actual_msg_size
316 * Description: Routine to dequeue a message into the supplied buffer
318 * Returns: int32_t - success == 0
320 ***********************************************************/
321 int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
323 uint32_t max_data_size_to_read,
324 uint32_t *actual_msg_size,
327 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
328 VCHIQ_HEADER_T *header;
330 WARN_ON((flags != VCHI_FLAGS_NONE) &&
331 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
333 if (flags == VCHI_FLAGS_NONE)
334 if (vchiu_queue_is_empty(&service->queue))
337 header = vchiu_queue_pop(&service->queue);
339 memcpy(data, header->data, header->size < max_data_size_to_read ?
340 header->size : max_data_size_to_read);
342 *actual_msg_size = header->size;
344 vchiq_release_message(service->handle, header);
348 EXPORT_SYMBOL(vchi_msg_dequeue);
350 /***********************************************************
351 * Name: vchi_msg_queuev
353 * Arguments: VCHI_SERVICE_HANDLE_T handle,
354 * VCHI_MSG_VECTOR_T *vector,
356 * VCHI_FLAGS_T flags,
359 * Description: Thin wrapper to queue a message onto a connection
361 * Returns: int32_t - success == 0
363 ***********************************************************/
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));
371 int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,
372 VCHI_MSG_VECTOR_T *vector,
377 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
381 WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
383 return vchiq_status_to_vchi(vchiq_queue_message(service->handle,
384 (const VCHIQ_ELEMENT_T *)vector, count));
386 EXPORT_SYMBOL(vchi_msg_queuev);
388 /***********************************************************
389 * Name: vchi_held_msg_release
391 * Arguments: VCHI_HELD_MSG_T *message
393 * Description: Routine to release a held message (after it has been read with
396 * Returns: int32_t - success == 0
398 ***********************************************************/
399 int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
401 vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service,
402 (VCHIQ_HEADER_T *)message->message);
407 /***********************************************************
408 * Name: vchi_msg_hold
410 * Arguments: VCHI_SERVICE_HANDLE_T handle,
412 * uint32_t *msg_size,
413 * VCHI_FLAGS_T flags,
414 * VCHI_HELD_MSG_T *message_handle
416 * Description: Routine to return a pointer to the current message (to allow
417 * in place processing). The message is dequeued - don't forget
418 * to release the message using vchi_held_msg_release when you're
421 * Returns: int32_t - success == 0
423 ***********************************************************/
424 int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
428 VCHI_HELD_MSG_T *message_handle)
430 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
431 VCHIQ_HEADER_T *header;
433 WARN_ON((flags != VCHI_FLAGS_NONE) &&
434 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
436 if (flags == VCHI_FLAGS_NONE)
437 if (vchiu_queue_is_empty(&service->queue))
440 header = vchiu_queue_pop(&service->queue);
442 *data = header->data;
443 *msg_size = header->size;
445 message_handle->service =
446 (struct opaque_vchi_service_t *)service->handle;
447 message_handle->message = header;
452 /***********************************************************
453 * Name: vchi_initialise
455 * Arguments: VCHI_INSTANCE_T *instance_handle
456 * VCHI_CONNECTION_T **connections
457 * const uint32_t num_connections
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
463 * Returns: 0 if successful, failure otherwise
465 ***********************************************************/
467 int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
469 VCHIQ_INSTANCE_T instance;
470 VCHIQ_STATUS_T status;
472 status = vchiq_initialise(&instance);
474 *instance_handle = (VCHI_INSTANCE_T)instance;
476 return vchiq_status_to_vchi(status);
478 EXPORT_SYMBOL(vchi_initialise);
480 /***********************************************************
483 * Arguments: VCHI_CONNECTION_T **connections
484 * const uint32_t num_connections
485 * VCHI_INSTANCE_T instance_handle)
487 * Description: Starts the command service on each connection,
488 * causing INIT messages to be pinged back and forth
490 * Returns: 0 if successful, failure otherwise
492 ***********************************************************/
493 int32_t vchi_connect(VCHI_CONNECTION_T **connections,
494 const uint32_t num_connections,
495 VCHI_INSTANCE_T instance_handle)
497 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
500 (void)num_connections;
502 return vchiq_connect(instance);
504 EXPORT_SYMBOL(vchi_connect);
507 /***********************************************************
508 * Name: vchi_disconnect
510 * Arguments: VCHI_INSTANCE_T instance_handle
512 * Description: Stops the command service on each connection,
513 * causing DE-INIT messages to be pinged back and forth
515 * Returns: 0 if successful, failure otherwise
517 ***********************************************************/
518 int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
520 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
521 return vchiq_status_to_vchi(vchiq_shutdown(instance));
523 EXPORT_SYMBOL(vchi_disconnect);
526 /***********************************************************
527 * Name: vchi_service_open
528 * Name: vchi_service_create
530 * Arguments: VCHI_INSTANCE_T *instance_handle
531 * SERVICE_CREATION_T *setup,
532 * VCHI_SERVICE_HANDLE_T *handle
534 * Description: Routine to open a service
536 * Returns: int32_t - success == 0
538 ***********************************************************/
540 static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
541 VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
543 SHIM_SERVICE_T *service =
544 (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
546 if (!service->callback)
550 case VCHIQ_MESSAGE_AVAILABLE:
551 vchiu_queue_push(&service->queue, header);
553 service->callback(service->callback_param,
554 VCHI_CALLBACK_MSG_AVAILABLE, NULL);
559 case VCHIQ_BULK_TRANSMIT_DONE:
560 service->callback(service->callback_param,
561 VCHI_CALLBACK_BULK_SENT, bulk_user);
564 case VCHIQ_BULK_RECEIVE_DONE:
565 service->callback(service->callback_param,
566 VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
569 case VCHIQ_SERVICE_CLOSED:
570 service->callback(service->callback_param,
571 VCHI_CALLBACK_SERVICE_CLOSED, NULL);
574 case VCHIQ_SERVICE_OPENED:
575 /* No equivalent VCHI reason */
578 case VCHIQ_BULK_TRANSMIT_ABORTED:
579 service->callback(service->callback_param,
580 VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
584 case VCHIQ_BULK_RECEIVE_ABORTED:
585 service->callback(service->callback_param,
586 VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
591 WARN(1, "not supported\n");
596 vchiq_release_message(service->handle, header);
598 return VCHIQ_SUCCESS;
601 static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
602 SERVICE_CREATION_T *setup)
604 SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL);
609 if (vchiu_queue_init(&service->queue, 64)) {
610 service->callback = setup->callback;
611 service->callback_param = setup->callback_param;
621 static void service_free(SHIM_SERVICE_T *service)
624 vchiu_queue_delete(&service->queue);
629 int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
630 SERVICE_CREATION_T *setup,
631 VCHI_SERVICE_HANDLE_T *handle)
633 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
634 SHIM_SERVICE_T *service = service_alloc(instance, setup);
636 *handle = (VCHI_SERVICE_HANDLE_T)service;
639 VCHIQ_SERVICE_PARAMS_T params;
640 VCHIQ_STATUS_T status;
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;
649 status = vchiq_open_service(instance, ¶ms,
651 if (status != VCHIQ_SUCCESS) {
652 service_free(service);
658 return (service != NULL) ? 0 : -1;
660 EXPORT_SYMBOL(vchi_service_open);
662 int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
663 SERVICE_CREATION_T *setup,
664 VCHI_SERVICE_HANDLE_T *handle)
666 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
667 SHIM_SERVICE_T *service = service_alloc(instance, setup);
669 *handle = (VCHI_SERVICE_HANDLE_T)service;
672 VCHIQ_SERVICE_PARAMS_T params;
673 VCHIQ_STATUS_T status;
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);
683 if (status != VCHIQ_SUCCESS) {
684 service_free(service);
690 return (service != NULL) ? 0 : -1;
692 EXPORT_SYMBOL(vchi_service_create);
694 int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
697 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
699 VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
700 if (status == VCHIQ_SUCCESS) {
701 service_free(service);
705 ret = vchiq_status_to_vchi(status);
709 EXPORT_SYMBOL(vchi_service_close);
711 int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
714 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
716 VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
717 if (status == VCHIQ_SUCCESS) {
718 service_free(service);
722 ret = vchiq_status_to_vchi(status);
726 EXPORT_SYMBOL(vchi_service_destroy);
728 int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version )
731 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
734 VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version);
735 ret = vchiq_status_to_vchi( status );
739 EXPORT_SYMBOL(vchi_get_peer_version);
742 /* ----------------------------------------------------------------------
743 * read a uint32_t from buffer.
744 * network format is defined to be little endian
745 * -------------------------------------------------------------------- */
747 vchi_readbuf_uint32(const void *_ptr)
749 const unsigned char *ptr = _ptr;
750 return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
753 /* ----------------------------------------------------------------------
754 * write a uint32_t to buffer.
755 * network format is defined to be little endian
756 * -------------------------------------------------------------------- */
758 vchi_writebuf_uint32(void *_ptr, uint32_t value)
760 unsigned char *ptr = _ptr;
761 ptr[0] = (unsigned char)((value >> 0) & 0xFF);
762 ptr[1] = (unsigned char)((value >> 8) & 0xFF);
763 ptr[2] = (unsigned char)((value >> 16) & 0xFF);
764 ptr[3] = (unsigned char)((value >> 24) & 0xFF);
767 /* ----------------------------------------------------------------------
768 * read a uint16_t from buffer.
769 * network format is defined to be little endian
770 * -------------------------------------------------------------------- */
772 vchi_readbuf_uint16(const void *_ptr)
774 const unsigned char *ptr = _ptr;
775 return ptr[0] | (ptr[1] << 8);
778 /* ----------------------------------------------------------------------
779 * write a uint16_t into the buffer.
780 * network format is defined to be little endian
781 * -------------------------------------------------------------------- */
783 vchi_writebuf_uint16(void *_ptr, uint16_t value)
785 unsigned char *ptr = _ptr;
786 ptr[0] = (value >> 0) & 0xFF;
787 ptr[1] = (value >> 8) & 0xFF;
791 /***********************************************************
792 * Name: vchi_service_use
794 * Arguments: const VCHI_SERVICE_HANDLE_T handle
796 * Description: Routine to increment refcount on a service
800 ***********************************************************/
801 int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
804 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
806 ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
809 EXPORT_SYMBOL(vchi_service_use);
811 /***********************************************************
812 * Name: vchi_service_release
814 * Arguments: const VCHI_SERVICE_HANDLE_T handle
816 * Description: Routine to decrement refcount on a service
820 ***********************************************************/
821 int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
824 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
826 ret = vchiq_status_to_vchi(
827 vchiq_release_service(service->handle));
830 EXPORT_SYMBOL(vchi_service_release);