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.
33 #include <linux/module.h>
34 #include <linux/types.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,
149 * ssize_t (*copy_callback)(void *context, void *dest,
150 * size_t offset, size_t maxsize),
154 * Description: Thin wrapper to queue a message onto a connection
156 * Returns: int32_t - success == 0
158 ***********************************************************/
160 int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
161 ssize_t (*copy_callback)(void *context, void *dest,
162 size_t offset, size_t maxsize),
166 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
167 VCHIQ_STATUS_T status;
170 status = vchiq_queue_message(service->handle,
176 * vchiq_queue_message() may return VCHIQ_RETRY, so we need to
177 * implement a retry mechanism since this function is supposed
178 * to block until queued
180 if (status != VCHIQ_RETRY)
186 return vchiq_status_to_vchi(status);
190 vchi_queue_kernel_message_callback(void *context,
195 memcpy(dest, context + offset, maxsize);
200 vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,
204 return vchi_msg_queue(handle,
205 vchi_queue_kernel_message_callback,
209 EXPORT_SYMBOL(vchi_queue_kernel_message);
211 struct vchi_queue_user_message_context {
216 vchi_queue_user_message_callback(void *context,
221 struct vchi_queue_user_message_context *copycontext = context;
223 if (copy_from_user(dest, copycontext->data + offset, maxsize))
230 vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,
234 struct vchi_queue_user_message_context copycontext = {
238 return vchi_msg_queue(handle,
239 vchi_queue_user_message_callback,
243 EXPORT_SYMBOL(vchi_queue_user_message);
245 /***********************************************************
246 * Name: vchi_bulk_queue_receive
248 * Arguments: VCHI_BULK_HANDLE_T handle,
250 * const uint32_t data_size,
254 * Description: Routine to setup a rcv buffer
256 * Returns: int32_t - success == 0
258 ***********************************************************/
259 int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
265 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
266 VCHIQ_BULK_MODE_T mode;
267 VCHIQ_STATUS_T status;
269 switch ((int)flags) {
270 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
271 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
272 WARN_ON(!service->callback);
273 mode = VCHIQ_BULK_MODE_CALLBACK;
275 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
276 mode = VCHIQ_BULK_MODE_BLOCKING;
278 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
279 case VCHI_FLAGS_NONE:
280 mode = VCHIQ_BULK_MODE_NOCALLBACK;
283 WARN(1, "unsupported message\n");
284 return vchiq_status_to_vchi(VCHIQ_ERROR);
288 status = vchiq_bulk_receive(service->handle, data_dst,
289 data_size, bulk_handle, mode);
291 * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
292 * implement a retry mechanism since this function is supposed
293 * to block until queued
295 if (status != VCHIQ_RETRY)
301 return vchiq_status_to_vchi(status);
303 EXPORT_SYMBOL(vchi_bulk_queue_receive);
305 /***********************************************************
306 * Name: vchi_bulk_queue_transmit
308 * Arguments: VCHI_BULK_HANDLE_T handle,
309 * const void *data_src,
310 * uint32_t data_size,
311 * VCHI_FLAGS_T flags,
314 * Description: Routine to transmit some data
316 * Returns: int32_t - success == 0
318 ***********************************************************/
319 int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
320 const void *data_src,
325 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
326 VCHIQ_BULK_MODE_T mode;
327 VCHIQ_STATUS_T status;
329 switch ((int)flags) {
330 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
331 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
332 WARN_ON(!service->callback);
333 mode = VCHIQ_BULK_MODE_CALLBACK;
335 case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
336 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
337 mode = VCHIQ_BULK_MODE_BLOCKING;
339 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
340 case VCHI_FLAGS_NONE:
341 mode = VCHIQ_BULK_MODE_NOCALLBACK;
344 WARN(1, "unsupported message\n");
345 return vchiq_status_to_vchi(VCHIQ_ERROR);
349 status = vchiq_bulk_transmit(service->handle, data_src,
350 data_size, bulk_handle, mode);
353 * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
354 * implement a retry mechanism since this function is supposed
355 * to block until queued
357 if (status != VCHIQ_RETRY)
363 return vchiq_status_to_vchi(status);
365 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
367 /***********************************************************
368 * Name: vchi_msg_dequeue
370 * Arguments: VCHI_SERVICE_HANDLE_T handle,
372 * uint32_t max_data_size_to_read,
373 * uint32_t *actual_msg_size
376 * Description: Routine to dequeue a message into the supplied buffer
378 * Returns: int32_t - success == 0
380 ***********************************************************/
381 int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
383 uint32_t max_data_size_to_read,
384 uint32_t *actual_msg_size,
387 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
388 VCHIQ_HEADER_T *header;
390 WARN_ON((flags != VCHI_FLAGS_NONE) &&
391 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
393 if (flags == VCHI_FLAGS_NONE)
394 if (vchiu_queue_is_empty(&service->queue))
397 header = vchiu_queue_pop(&service->queue);
399 memcpy(data, header->data, header->size < max_data_size_to_read ?
400 header->size : max_data_size_to_read);
402 *actual_msg_size = header->size;
404 vchiq_release_message(service->handle, header);
408 EXPORT_SYMBOL(vchi_msg_dequeue);
410 /***********************************************************
411 * Name: vchi_held_msg_release
413 * Arguments: VCHI_HELD_MSG_T *message
415 * Description: Routine to release a held message (after it has been read with
418 * Returns: int32_t - success == 0
420 ***********************************************************/
421 int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
424 * Convert the service field pointer back to an
425 * VCHIQ_SERVICE_HANDLE_T which is an int.
426 * This pointer is opaque to everything except
427 * vchi_msg_hold which simply upcasted the int
431 vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)(long)message->service,
432 (VCHIQ_HEADER_T *)message->message);
436 EXPORT_SYMBOL(vchi_held_msg_release);
438 /***********************************************************
439 * Name: vchi_msg_hold
441 * Arguments: VCHI_SERVICE_HANDLE_T handle,
443 * uint32_t *msg_size,
444 * VCHI_FLAGS_T flags,
445 * VCHI_HELD_MSG_T *message_handle
447 * Description: Routine to return a pointer to the current message (to allow
448 * in place processing). The message is dequeued - don't forget
449 * to release the message using vchi_held_msg_release when you're
452 * Returns: int32_t - success == 0
454 ***********************************************************/
455 int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
459 VCHI_HELD_MSG_T *message_handle)
461 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
462 VCHIQ_HEADER_T *header;
464 WARN_ON((flags != VCHI_FLAGS_NONE) &&
465 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
467 if (flags == VCHI_FLAGS_NONE)
468 if (vchiu_queue_is_empty(&service->queue))
471 header = vchiu_queue_pop(&service->queue);
473 *data = header->data;
474 *msg_size = header->size;
477 * upcast the VCHIQ_SERVICE_HANDLE_T which is an int
478 * to a pointer and stuff it in the held message.
479 * This pointer is opaque to everything except
480 * vchi_held_msg_release which simply downcasts it back
484 message_handle->service =
485 (struct opaque_vchi_service_t *)(long)service->handle;
486 message_handle->message = header;
490 EXPORT_SYMBOL(vchi_msg_hold);
492 /***********************************************************
493 * Name: vchi_initialise
495 * Arguments: VCHI_INSTANCE_T *instance_handle
497 * Description: Initialises the hardware but does not transmit anything
498 * When run as a Host App this will be called twice hence the need
499 * to malloc the state information
501 * Returns: 0 if successful, failure otherwise
503 ***********************************************************/
505 int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
507 VCHIQ_INSTANCE_T instance;
508 VCHIQ_STATUS_T status;
510 status = vchiq_initialise(&instance);
512 *instance_handle = (VCHI_INSTANCE_T)instance;
514 return vchiq_status_to_vchi(status);
516 EXPORT_SYMBOL(vchi_initialise);
518 /***********************************************************
521 * Arguments: VCHI_CONNECTION_T **connections
522 * const uint32_t num_connections
523 * VCHI_INSTANCE_T instance_handle)
525 * Description: Starts the command service on each connection,
526 * causing INIT messages to be pinged back and forth
528 * Returns: 0 if successful, failure otherwise
530 ***********************************************************/
531 int32_t vchi_connect(VCHI_CONNECTION_T **connections,
532 const uint32_t num_connections,
533 VCHI_INSTANCE_T instance_handle)
535 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
538 (void)num_connections;
540 return vchiq_connect(instance);
542 EXPORT_SYMBOL(vchi_connect);
545 /***********************************************************
546 * Name: vchi_disconnect
548 * Arguments: VCHI_INSTANCE_T instance_handle
550 * Description: Stops the command service on each connection,
551 * causing DE-INIT messages to be pinged back and forth
553 * Returns: 0 if successful, failure otherwise
555 ***********************************************************/
556 int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
558 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
560 return vchiq_status_to_vchi(vchiq_shutdown(instance));
562 EXPORT_SYMBOL(vchi_disconnect);
565 /***********************************************************
566 * Name: vchi_service_open
567 * Name: vchi_service_create
569 * Arguments: VCHI_INSTANCE_T *instance_handle
570 * SERVICE_CREATION_T *setup,
571 * VCHI_SERVICE_HANDLE_T *handle
573 * Description: Routine to open a service
575 * Returns: int32_t - success == 0
577 ***********************************************************/
579 static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
580 VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
582 SHIM_SERVICE_T *service =
583 (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
585 if (!service->callback)
589 case VCHIQ_MESSAGE_AVAILABLE:
590 vchiu_queue_push(&service->queue, header);
592 service->callback(service->callback_param,
593 VCHI_CALLBACK_MSG_AVAILABLE, NULL);
598 case VCHIQ_BULK_TRANSMIT_DONE:
599 service->callback(service->callback_param,
600 VCHI_CALLBACK_BULK_SENT, bulk_user);
603 case VCHIQ_BULK_RECEIVE_DONE:
604 service->callback(service->callback_param,
605 VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
608 case VCHIQ_SERVICE_CLOSED:
609 service->callback(service->callback_param,
610 VCHI_CALLBACK_SERVICE_CLOSED, NULL);
613 case VCHIQ_SERVICE_OPENED:
614 /* No equivalent VCHI reason */
617 case VCHIQ_BULK_TRANSMIT_ABORTED:
618 service->callback(service->callback_param,
619 VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
623 case VCHIQ_BULK_RECEIVE_ABORTED:
624 service->callback(service->callback_param,
625 VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
630 WARN(1, "not supported\n");
635 vchiq_release_message(service->handle, header);
637 return VCHIQ_SUCCESS;
640 static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
641 SERVICE_CREATION_T *setup)
643 SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL);
648 if (vchiu_queue_init(&service->queue, 64)) {
649 service->callback = setup->callback;
650 service->callback_param = setup->callback_param;
660 static void service_free(SHIM_SERVICE_T *service)
663 vchiu_queue_delete(&service->queue);
668 int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
669 SERVICE_CREATION_T *setup,
670 VCHI_SERVICE_HANDLE_T *handle)
672 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
673 SHIM_SERVICE_T *service = service_alloc(instance, setup);
675 *handle = (VCHI_SERVICE_HANDLE_T)service;
678 VCHIQ_SERVICE_PARAMS_T params;
679 VCHIQ_STATUS_T status;
681 memset(¶ms, 0, sizeof(params));
682 params.fourcc = setup->service_id;
683 params.callback = shim_callback;
684 params.userdata = service;
685 params.version = setup->version.version;
686 params.version_min = setup->version.version_min;
688 status = vchiq_open_service(instance, ¶ms,
690 if (status != VCHIQ_SUCCESS) {
691 service_free(service);
697 return (service != NULL) ? 0 : -1;
699 EXPORT_SYMBOL(vchi_service_open);
701 int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
702 SERVICE_CREATION_T *setup,
703 VCHI_SERVICE_HANDLE_T *handle)
705 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
706 SHIM_SERVICE_T *service = service_alloc(instance, setup);
708 *handle = (VCHI_SERVICE_HANDLE_T)service;
711 VCHIQ_SERVICE_PARAMS_T params;
712 VCHIQ_STATUS_T status;
714 memset(¶ms, 0, sizeof(params));
715 params.fourcc = setup->service_id;
716 params.callback = shim_callback;
717 params.userdata = service;
718 params.version = setup->version.version;
719 params.version_min = setup->version.version_min;
720 status = vchiq_add_service(instance, ¶ms, &service->handle);
722 if (status != VCHIQ_SUCCESS) {
723 service_free(service);
729 return (service != NULL) ? 0 : -1;
731 EXPORT_SYMBOL(vchi_service_create);
733 int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
736 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
739 VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
740 if (status == VCHIQ_SUCCESS) {
741 service_free(service);
745 ret = vchiq_status_to_vchi(status);
749 EXPORT_SYMBOL(vchi_service_close);
751 int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
754 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
757 VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
759 if (status == VCHIQ_SUCCESS) {
760 service_free(service);
764 ret = vchiq_status_to_vchi(status);
768 EXPORT_SYMBOL(vchi_service_destroy);
770 int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
771 VCHI_SERVICE_OPTION_T option,
775 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
776 VCHIQ_SERVICE_OPTION_T vchiq_option;
779 case VCHI_SERVICE_OPTION_TRACE:
780 vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
782 case VCHI_SERVICE_OPTION_SYNCHRONOUS:
783 vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
790 VCHIQ_STATUS_T status =
791 vchiq_set_service_option(service->handle,
795 ret = vchiq_status_to_vchi(status);
799 EXPORT_SYMBOL(vchi_service_set_option);
801 int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, short *peer_version)
804 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
808 VCHIQ_STATUS_T status;
810 status = vchiq_get_peer_version(service->handle, peer_version);
811 ret = vchiq_status_to_vchi(status);
815 EXPORT_SYMBOL(vchi_get_peer_version);
817 /***********************************************************
818 * Name: vchi_service_use
820 * Arguments: const VCHI_SERVICE_HANDLE_T handle
822 * Description: Routine to increment refcount on a service
826 ***********************************************************/
827 int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
831 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
833 ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
836 EXPORT_SYMBOL(vchi_service_use);
838 /***********************************************************
839 * Name: vchi_service_release
841 * Arguments: const VCHI_SERVICE_HANDLE_T handle
843 * Description: Routine to decrement refcount on a service
847 ***********************************************************/
848 int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
852 SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
854 ret = vchiq_status_to_vchi(
855 vchiq_release_service(service->handle));
858 EXPORT_SYMBOL(vchi_service_release);