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,
89 * Description: Routine to return a pointer to the current message (to allow in
90 * place processing). The message can be removed using
91 * vchi_msg_remove when you're finished
93 * Returns: int32_t - success == 0
95 ***********************************************************/
96 int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
101 struct shim_service *service = (struct shim_service *)handle;
102 VCHIQ_HEADER_T *header;
104 WARN_ON((flags != VCHI_FLAGS_NONE) &&
105 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
107 if (flags == VCHI_FLAGS_NONE)
108 if (vchiu_queue_is_empty(&service->queue))
111 header = vchiu_queue_peek(&service->queue);
113 *data = header->data;
114 *msg_size = header->size;
118 EXPORT_SYMBOL(vchi_msg_peek);
120 /***********************************************************
121 * Name: vchi_msg_remove
123 * Arguments: const VCHI_SERVICE_HANDLE_T handle,
125 * Description: Routine to remove a message (after it has been read with
128 * Returns: int32_t - success == 0
130 ***********************************************************/
131 int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
133 struct shim_service *service = (struct shim_service *)handle;
134 VCHIQ_HEADER_T *header;
136 header = vchiu_queue_pop(&service->queue);
138 vchiq_release_message(service->handle, header);
142 EXPORT_SYMBOL(vchi_msg_remove);
144 /***********************************************************
145 * Name: vchi_msg_queue
147 * Arguments: VCHI_SERVICE_HANDLE_T handle,
148 * ssize_t (*copy_callback)(void *context, void *dest,
149 * size_t offset, size_t maxsize),
153 * Description: Thin wrapper to queue a message onto a connection
155 * Returns: int32_t - success == 0
157 ***********************************************************/
159 int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
160 ssize_t (*copy_callback)(void *context, void *dest,
161 size_t offset, size_t maxsize),
165 struct shim_service *service = (struct shim_service *)handle;
166 VCHIQ_STATUS_T status;
169 status = vchiq_queue_message(service->handle,
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 if (status != VCHIQ_RETRY)
185 return vchiq_status_to_vchi(status);
189 vchi_queue_kernel_message_callback(void *context,
194 memcpy(dest, context + offset, maxsize);
199 vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,
203 return vchi_msg_queue(handle,
204 vchi_queue_kernel_message_callback,
208 EXPORT_SYMBOL(vchi_queue_kernel_message);
210 struct vchi_queue_user_message_context {
215 vchi_queue_user_message_callback(void *context,
220 struct vchi_queue_user_message_context *copycontext = context;
222 if (copy_from_user(dest, copycontext->data + offset, maxsize))
229 vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,
233 struct vchi_queue_user_message_context copycontext = {
237 return vchi_msg_queue(handle,
238 vchi_queue_user_message_callback,
242 EXPORT_SYMBOL(vchi_queue_user_message);
244 /***********************************************************
245 * Name: vchi_bulk_queue_receive
247 * Arguments: VCHI_BULK_HANDLE_T handle,
249 * const uint32_t data_size,
253 * Description: Routine to setup a rcv buffer
255 * Returns: int32_t - success == 0
257 ***********************************************************/
258 int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
264 struct shim_service *service = (struct shim_service *)handle;
265 VCHIQ_BULK_MODE_T mode;
266 VCHIQ_STATUS_T status;
268 switch ((int)flags) {
269 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
270 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
271 WARN_ON(!service->callback);
272 mode = VCHIQ_BULK_MODE_CALLBACK;
274 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
275 mode = VCHIQ_BULK_MODE_BLOCKING;
277 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
278 case VCHI_FLAGS_NONE:
279 mode = VCHIQ_BULK_MODE_NOCALLBACK;
282 WARN(1, "unsupported message\n");
283 return vchiq_status_to_vchi(VCHIQ_ERROR);
287 status = vchiq_bulk_receive(service->handle, data_dst,
288 data_size, bulk_handle, mode);
290 * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
291 * implement a retry mechanism since this function is supposed
292 * to block until queued
294 if (status != VCHIQ_RETRY)
300 return vchiq_status_to_vchi(status);
302 EXPORT_SYMBOL(vchi_bulk_queue_receive);
304 /***********************************************************
305 * Name: vchi_bulk_queue_transmit
307 * Arguments: VCHI_BULK_HANDLE_T handle,
308 * const void *data_src,
309 * uint32_t data_size,
310 * VCHI_FLAGS_T flags,
313 * Description: Routine to transmit some data
315 * Returns: int32_t - success == 0
317 ***********************************************************/
318 int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
319 const void *data_src,
324 struct shim_service *service = (struct shim_service *)handle;
325 VCHIQ_BULK_MODE_T mode;
326 VCHIQ_STATUS_T status;
328 switch ((int)flags) {
329 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
330 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
331 WARN_ON(!service->callback);
332 mode = VCHIQ_BULK_MODE_CALLBACK;
334 case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
335 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
336 mode = VCHIQ_BULK_MODE_BLOCKING;
338 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
339 case VCHI_FLAGS_NONE:
340 mode = VCHIQ_BULK_MODE_NOCALLBACK;
343 WARN(1, "unsupported message\n");
344 return vchiq_status_to_vchi(VCHIQ_ERROR);
348 status = vchiq_bulk_transmit(service->handle, data_src,
349 data_size, bulk_handle, mode);
352 * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
353 * implement a retry mechanism since this function is supposed
354 * to block until queued
356 if (status != VCHIQ_RETRY)
362 return vchiq_status_to_vchi(status);
364 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
366 /***********************************************************
367 * Name: vchi_msg_dequeue
369 * Arguments: VCHI_SERVICE_HANDLE_T handle,
371 * uint32_t max_data_size_to_read,
372 * uint32_t *actual_msg_size
375 * Description: Routine to dequeue a message into the supplied buffer
377 * Returns: int32_t - success == 0
379 ***********************************************************/
380 int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
382 uint32_t max_data_size_to_read,
383 uint32_t *actual_msg_size,
386 struct shim_service *service = (struct shim_service *)handle;
387 VCHIQ_HEADER_T *header;
389 WARN_ON((flags != VCHI_FLAGS_NONE) &&
390 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
392 if (flags == VCHI_FLAGS_NONE)
393 if (vchiu_queue_is_empty(&service->queue))
396 header = vchiu_queue_pop(&service->queue);
398 memcpy(data, header->data, header->size < max_data_size_to_read ?
399 header->size : max_data_size_to_read);
401 *actual_msg_size = header->size;
403 vchiq_release_message(service->handle, header);
407 EXPORT_SYMBOL(vchi_msg_dequeue);
409 /***********************************************************
410 * Name: vchi_held_msg_release
412 * Arguments: VCHI_HELD_MSG_T *message
414 * Description: Routine to release a held message (after it has been read with
417 * Returns: int32_t - success == 0
419 ***********************************************************/
420 int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
423 * Convert the service field pointer back to an
424 * VCHIQ_SERVICE_HANDLE_T which is an int.
425 * This pointer is opaque to everything except
426 * vchi_msg_hold which simply upcasted the int
430 vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)(long)message->service,
431 (VCHIQ_HEADER_T *)message->message);
435 EXPORT_SYMBOL(vchi_held_msg_release);
437 /***********************************************************
438 * Name: vchi_msg_hold
440 * Arguments: VCHI_SERVICE_HANDLE_T handle,
442 * uint32_t *msg_size,
443 * VCHI_FLAGS_T flags,
444 * VCHI_HELD_MSG_T *message_handle
446 * Description: Routine to return a pointer to the current message (to allow
447 * in place processing). The message is dequeued - don't forget
448 * to release the message using vchi_held_msg_release when you're
451 * Returns: int32_t - success == 0
453 ***********************************************************/
454 int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
458 VCHI_HELD_MSG_T *message_handle)
460 struct shim_service *service = (struct shim_service *)handle;
461 VCHIQ_HEADER_T *header;
463 WARN_ON((flags != VCHI_FLAGS_NONE) &&
464 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
466 if (flags == VCHI_FLAGS_NONE)
467 if (vchiu_queue_is_empty(&service->queue))
470 header = vchiu_queue_pop(&service->queue);
472 *data = header->data;
473 *msg_size = header->size;
476 * upcast the VCHIQ_SERVICE_HANDLE_T which is an int
477 * to a pointer and stuff it in the held message.
478 * This pointer is opaque to everything except
479 * vchi_held_msg_release which simply downcasts it back
483 message_handle->service =
484 (struct opaque_vchi_service_t *)(long)service->handle;
485 message_handle->message = header;
489 EXPORT_SYMBOL(vchi_msg_hold);
491 /***********************************************************
492 * Name: vchi_initialise
494 * Arguments: VCHI_INSTANCE_T *instance_handle
496 * Description: Initialises the hardware but does not transmit anything
497 * When run as a Host App this will be called twice hence the need
498 * to malloc the state information
500 * Returns: 0 if successful, failure otherwise
502 ***********************************************************/
504 int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
506 VCHIQ_INSTANCE_T instance;
507 VCHIQ_STATUS_T status;
509 status = vchiq_initialise(&instance);
511 *instance_handle = (VCHI_INSTANCE_T)instance;
513 return vchiq_status_to_vchi(status);
515 EXPORT_SYMBOL(vchi_initialise);
517 /***********************************************************
520 * Arguments: VCHI_CONNECTION_T **connections
521 * const uint32_t num_connections
522 * VCHI_INSTANCE_T instance_handle)
524 * Description: Starts the command service on each connection,
525 * causing INIT messages to be pinged back and forth
527 * Returns: 0 if successful, failure otherwise
529 ***********************************************************/
530 int32_t vchi_connect(VCHI_CONNECTION_T **connections,
531 const uint32_t num_connections,
532 VCHI_INSTANCE_T instance_handle)
534 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
537 (void)num_connections;
539 return vchiq_connect(instance);
541 EXPORT_SYMBOL(vchi_connect);
543 /***********************************************************
544 * Name: vchi_disconnect
546 * Arguments: VCHI_INSTANCE_T instance_handle
548 * Description: Stops the command service on each connection,
549 * causing DE-INIT messages to be pinged back and forth
551 * Returns: 0 if successful, failure otherwise
553 ***********************************************************/
554 int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
556 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
558 return vchiq_status_to_vchi(vchiq_shutdown(instance));
560 EXPORT_SYMBOL(vchi_disconnect);
562 /***********************************************************
563 * Name: vchi_service_open
564 * Name: vchi_service_create
566 * Arguments: VCHI_INSTANCE_T *instance_handle
567 * SERVICE_CREATION_T *setup,
568 * VCHI_SERVICE_HANDLE_T *handle
570 * Description: Routine to open a service
572 * Returns: int32_t - success == 0
574 ***********************************************************/
576 static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
577 VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
579 struct shim_service *service =
580 (struct shim_service *)VCHIQ_GET_SERVICE_USERDATA(handle);
582 if (!service->callback)
586 case VCHIQ_MESSAGE_AVAILABLE:
587 vchiu_queue_push(&service->queue, header);
589 service->callback(service->callback_param,
590 VCHI_CALLBACK_MSG_AVAILABLE, NULL);
594 case VCHIQ_BULK_TRANSMIT_DONE:
595 service->callback(service->callback_param,
596 VCHI_CALLBACK_BULK_SENT, bulk_user);
599 case VCHIQ_BULK_RECEIVE_DONE:
600 service->callback(service->callback_param,
601 VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
604 case VCHIQ_SERVICE_CLOSED:
605 service->callback(service->callback_param,
606 VCHI_CALLBACK_SERVICE_CLOSED, NULL);
609 case VCHIQ_SERVICE_OPENED:
610 /* No equivalent VCHI reason */
613 case VCHIQ_BULK_TRANSMIT_ABORTED:
614 service->callback(service->callback_param,
615 VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
619 case VCHIQ_BULK_RECEIVE_ABORTED:
620 service->callback(service->callback_param,
621 VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
626 WARN(1, "not supported\n");
631 vchiq_release_message(service->handle, header);
633 return VCHIQ_SUCCESS;
636 static struct shim_service *service_alloc(VCHIQ_INSTANCE_T instance,
637 SERVICE_CREATION_T *setup)
639 struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL);
644 if (vchiu_queue_init(&service->queue, 64)) {
645 service->callback = setup->callback;
646 service->callback_param = setup->callback_param;
656 static void service_free(struct shim_service *service)
659 vchiu_queue_delete(&service->queue);
664 int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
665 SERVICE_CREATION_T *setup,
666 VCHI_SERVICE_HANDLE_T *handle)
668 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
669 struct shim_service *service = service_alloc(instance, setup);
671 *handle = (VCHI_SERVICE_HANDLE_T)service;
674 VCHIQ_SERVICE_PARAMS_T params;
675 VCHIQ_STATUS_T status;
677 memset(¶ms, 0, sizeof(params));
678 params.fourcc = setup->service_id;
679 params.callback = shim_callback;
680 params.userdata = service;
681 params.version = setup->version.version;
682 params.version_min = setup->version.version_min;
684 status = vchiq_open_service(instance, ¶ms,
686 if (status != VCHIQ_SUCCESS) {
687 service_free(service);
693 return (service != NULL) ? 0 : -1;
695 EXPORT_SYMBOL(vchi_service_open);
697 int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
698 SERVICE_CREATION_T *setup,
699 VCHI_SERVICE_HANDLE_T *handle)
701 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
702 struct shim_service *service = service_alloc(instance, setup);
704 *handle = (VCHI_SERVICE_HANDLE_T)service;
707 VCHIQ_SERVICE_PARAMS_T params;
708 VCHIQ_STATUS_T status;
710 memset(¶ms, 0, sizeof(params));
711 params.fourcc = setup->service_id;
712 params.callback = shim_callback;
713 params.userdata = service;
714 params.version = setup->version.version;
715 params.version_min = setup->version.version_min;
716 status = vchiq_add_service(instance, ¶ms, &service->handle);
718 if (status != VCHIQ_SUCCESS) {
719 service_free(service);
725 return (service != NULL) ? 0 : -1;
727 EXPORT_SYMBOL(vchi_service_create);
729 int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
732 struct shim_service *service = (struct shim_service *)handle;
735 VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
736 if (status == VCHIQ_SUCCESS) {
737 service_free(service);
741 ret = vchiq_status_to_vchi(status);
745 EXPORT_SYMBOL(vchi_service_close);
747 int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
750 struct shim_service *service = (struct shim_service *)handle;
753 VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
755 if (status == VCHIQ_SUCCESS) {
756 service_free(service);
760 ret = vchiq_status_to_vchi(status);
764 EXPORT_SYMBOL(vchi_service_destroy);
766 int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
767 VCHI_SERVICE_OPTION_T option,
771 struct shim_service *service = (struct shim_service *)handle;
772 VCHIQ_SERVICE_OPTION_T vchiq_option;
775 case VCHI_SERVICE_OPTION_TRACE:
776 vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
778 case VCHI_SERVICE_OPTION_SYNCHRONOUS:
779 vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
786 VCHIQ_STATUS_T status =
787 vchiq_set_service_option(service->handle,
791 ret = vchiq_status_to_vchi(status);
795 EXPORT_SYMBOL(vchi_service_set_option);
797 int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, short *peer_version)
800 struct shim_service *service = (struct shim_service *)handle;
803 VCHIQ_STATUS_T status;
805 status = vchiq_get_peer_version(service->handle, peer_version);
806 ret = vchiq_status_to_vchi(status);
810 EXPORT_SYMBOL(vchi_get_peer_version);
812 /***********************************************************
813 * Name: vchi_service_use
815 * Arguments: const VCHI_SERVICE_HANDLE_T handle
817 * Description: Routine to increment refcount on a service
821 ***********************************************************/
822 int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
826 struct shim_service *service = (struct shim_service *)handle;
828 ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
831 EXPORT_SYMBOL(vchi_service_use);
833 /***********************************************************
834 * Name: vchi_service_release
836 * Arguments: const VCHI_SERVICE_HANDLE_T handle
838 * Description: Routine to decrement refcount on a service
842 ***********************************************************/
843 int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
847 struct shim_service *service = (struct shim_service *)handle;
849 ret = vchiq_status_to_vchi(
850 vchiq_release_service(service->handle));
853 EXPORT_SYMBOL(vchi_service_release);