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;
47 struct vchiu_queue queue;
49 VCHI_CALLBACK_T callback;
53 /***********************************************************
56 * Arguments: const VCHI_SERVICE_HANDLE_T handle,
62 * Description: Routine to return a pointer to the current message (to allow in
63 * place processing). The message can be removed using
64 * vchi_msg_remove when you're finished
66 * Returns: int32_t - success == 0
68 ***********************************************************/
69 int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
74 struct shim_service *service = (struct shim_service *)handle;
75 struct vchiq_header *header;
77 WARN_ON((flags != VCHI_FLAGS_NONE) &&
78 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
80 if (flags == VCHI_FLAGS_NONE)
81 if (vchiu_queue_is_empty(&service->queue))
84 header = vchiu_queue_peek(&service->queue);
87 *msg_size = header->size;
91 EXPORT_SYMBOL(vchi_msg_peek);
93 /***********************************************************
94 * Name: vchi_msg_remove
96 * Arguments: const VCHI_SERVICE_HANDLE_T handle,
98 * Description: Routine to remove a message (after it has been read with
101 * Returns: int32_t - success == 0
103 ***********************************************************/
104 int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
106 struct shim_service *service = (struct shim_service *)handle;
107 struct vchiq_header *header;
109 header = vchiu_queue_pop(&service->queue);
111 vchiq_release_message(service->handle, header);
115 EXPORT_SYMBOL(vchi_msg_remove);
117 /***********************************************************
118 * Name: vchi_msg_queue
120 * Arguments: VCHI_SERVICE_HANDLE_T handle,
121 * ssize_t (*copy_callback)(void *context, void *dest,
122 * size_t offset, size_t maxsize),
126 * Description: Thin wrapper to queue a message onto a connection
128 * Returns: int32_t - success == 0
130 ***********************************************************/
132 int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
133 ssize_t (*copy_callback)(void *context, void *dest,
134 size_t offset, size_t maxsize),
138 struct shim_service *service = (struct shim_service *)handle;
139 VCHIQ_STATUS_T status;
142 status = vchiq_queue_message(service->handle,
148 * vchiq_queue_message() may return VCHIQ_RETRY, so we need to
149 * implement a retry mechanism since this function is supposed
150 * to block until queued
152 if (status != VCHIQ_RETRY)
158 return vchiq_status_to_vchi(status);
162 vchi_queue_kernel_message_callback(void *context,
167 memcpy(dest, context + offset, maxsize);
172 vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,
176 return vchi_msg_queue(handle,
177 vchi_queue_kernel_message_callback,
181 EXPORT_SYMBOL(vchi_queue_kernel_message);
183 struct vchi_queue_user_message_context {
188 vchi_queue_user_message_callback(void *context,
193 struct vchi_queue_user_message_context *copycontext = context;
195 if (copy_from_user(dest, copycontext->data + offset, maxsize))
202 vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,
206 struct vchi_queue_user_message_context copycontext = {
210 return vchi_msg_queue(handle,
211 vchi_queue_user_message_callback,
215 EXPORT_SYMBOL(vchi_queue_user_message);
217 /***********************************************************
218 * Name: vchi_bulk_queue_receive
220 * Arguments: VCHI_BULK_HANDLE_T handle,
222 * const uint32_t data_size,
226 * Description: Routine to setup a rcv buffer
228 * Returns: int32_t - success == 0
230 ***********************************************************/
231 int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
237 struct shim_service *service = (struct shim_service *)handle;
238 VCHIQ_BULK_MODE_T mode;
239 VCHIQ_STATUS_T status;
241 switch ((int)flags) {
242 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
243 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
244 WARN_ON(!service->callback);
245 mode = VCHIQ_BULK_MODE_CALLBACK;
247 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
248 mode = VCHIQ_BULK_MODE_BLOCKING;
250 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
251 case VCHI_FLAGS_NONE:
252 mode = VCHIQ_BULK_MODE_NOCALLBACK;
255 WARN(1, "unsupported message\n");
256 return vchiq_status_to_vchi(VCHIQ_ERROR);
260 status = vchiq_bulk_receive(service->handle, data_dst,
261 data_size, bulk_handle, mode);
263 * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
264 * implement a retry mechanism since this function is supposed
265 * to block until queued
267 if (status != VCHIQ_RETRY)
273 return vchiq_status_to_vchi(status);
275 EXPORT_SYMBOL(vchi_bulk_queue_receive);
277 /***********************************************************
278 * Name: vchi_bulk_queue_transmit
280 * Arguments: VCHI_BULK_HANDLE_T handle,
281 * const void *data_src,
282 * uint32_t data_size,
283 * VCHI_FLAGS_T flags,
286 * Description: Routine to transmit some data
288 * Returns: int32_t - success == 0
290 ***********************************************************/
291 int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
292 const void *data_src,
297 struct shim_service *service = (struct shim_service *)handle;
298 VCHIQ_BULK_MODE_T mode;
299 VCHIQ_STATUS_T status;
301 switch ((int)flags) {
302 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
303 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
304 WARN_ON(!service->callback);
305 mode = VCHIQ_BULK_MODE_CALLBACK;
307 case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
308 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
309 mode = VCHIQ_BULK_MODE_BLOCKING;
311 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
312 case VCHI_FLAGS_NONE:
313 mode = VCHIQ_BULK_MODE_NOCALLBACK;
316 WARN(1, "unsupported message\n");
317 return vchiq_status_to_vchi(VCHIQ_ERROR);
321 status = vchiq_bulk_transmit(service->handle, data_src,
322 data_size, bulk_handle, mode);
325 * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
326 * implement a retry mechanism since this function is supposed
327 * to block until queued
329 if (status != VCHIQ_RETRY)
335 return vchiq_status_to_vchi(status);
337 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
339 /***********************************************************
340 * Name: vchi_msg_dequeue
342 * Arguments: VCHI_SERVICE_HANDLE_T handle,
344 * uint32_t max_data_size_to_read,
345 * uint32_t *actual_msg_size
348 * Description: Routine to dequeue a message into the supplied buffer
350 * Returns: int32_t - success == 0
352 ***********************************************************/
353 int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
355 uint32_t max_data_size_to_read,
356 uint32_t *actual_msg_size,
359 struct shim_service *service = (struct shim_service *)handle;
360 struct vchiq_header *header;
362 WARN_ON((flags != VCHI_FLAGS_NONE) &&
363 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
365 if (flags == VCHI_FLAGS_NONE)
366 if (vchiu_queue_is_empty(&service->queue))
369 header = vchiu_queue_pop(&service->queue);
371 memcpy(data, header->data, header->size < max_data_size_to_read ?
372 header->size : max_data_size_to_read);
374 *actual_msg_size = header->size;
376 vchiq_release_message(service->handle, header);
380 EXPORT_SYMBOL(vchi_msg_dequeue);
382 /***********************************************************
383 * Name: vchi_held_msg_release
385 * Arguments: struct vchi_held_msg *message
387 * Description: Routine to release a held message (after it has been read with
390 * Returns: int32_t - success == 0
392 ***********************************************************/
393 int32_t vchi_held_msg_release(struct vchi_held_msg *message)
396 * Convert the service field pointer back to an
397 * VCHIQ_SERVICE_HANDLE_T which is an int.
398 * This pointer is opaque to everything except
399 * vchi_msg_hold which simply upcasted the int
403 vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)(long)message->service,
404 (struct vchiq_header *)message->message);
408 EXPORT_SYMBOL(vchi_held_msg_release);
410 /***********************************************************
411 * Name: vchi_msg_hold
413 * Arguments: VCHI_SERVICE_HANDLE_T handle,
415 * uint32_t *msg_size,
416 * VCHI_FLAGS_T flags,
417 * struct vchi_held_msg *message_handle
419 * Description: Routine to return a pointer to the current message (to allow
420 * in place processing). The message is dequeued - don't forget
421 * to release the message using vchi_held_msg_release when you're
424 * Returns: int32_t - success == 0
426 ***********************************************************/
427 int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
431 struct vchi_held_msg *message_handle)
433 struct shim_service *service = (struct shim_service *)handle;
434 struct vchiq_header *header;
436 WARN_ON((flags != VCHI_FLAGS_NONE) &&
437 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
439 if (flags == VCHI_FLAGS_NONE)
440 if (vchiu_queue_is_empty(&service->queue))
443 header = vchiu_queue_pop(&service->queue);
445 *data = header->data;
446 *msg_size = header->size;
449 * upcast the VCHIQ_SERVICE_HANDLE_T which is an int
450 * to a pointer and stuff it in the held message.
451 * This pointer is opaque to everything except
452 * vchi_held_msg_release which simply downcasts it back
456 message_handle->service =
457 (struct opaque_vchi_service_t *)(long)service->handle;
458 message_handle->message = header;
462 EXPORT_SYMBOL(vchi_msg_hold);
464 /***********************************************************
465 * Name: vchi_initialise
467 * Arguments: VCHI_INSTANCE_T *instance_handle
469 * Description: Initialises the hardware but does not transmit anything
470 * When run as a Host App this will be called twice hence the need
471 * to malloc the state information
473 * Returns: 0 if successful, failure otherwise
475 ***********************************************************/
477 int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
479 VCHIQ_INSTANCE_T instance;
480 VCHIQ_STATUS_T status;
482 status = vchiq_initialise(&instance);
484 *instance_handle = (VCHI_INSTANCE_T)instance;
486 return vchiq_status_to_vchi(status);
488 EXPORT_SYMBOL(vchi_initialise);
490 /***********************************************************
493 * Arguments: VCHI_INSTANCE_T instance_handle
495 * Description: Starts the command service on each connection,
496 * causing INIT messages to be pinged back and forth
498 * Returns: 0 if successful, failure otherwise
500 ***********************************************************/
501 int32_t vchi_connect(VCHI_INSTANCE_T instance_handle)
503 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
505 return vchiq_connect(instance);
507 EXPORT_SYMBOL(vchi_connect);
509 /***********************************************************
510 * Name: vchi_disconnect
512 * Arguments: VCHI_INSTANCE_T instance_handle
514 * Description: Stops the command service on each connection,
515 * causing DE-INIT messages to be pinged back and forth
517 * Returns: 0 if successful, failure otherwise
519 ***********************************************************/
520 int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
522 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
524 return vchiq_status_to_vchi(vchiq_shutdown(instance));
526 EXPORT_SYMBOL(vchi_disconnect);
528 /***********************************************************
529 * Name: vchi_service_open
530 * Name: vchi_service_create
532 * Arguments: VCHI_INSTANCE_T *instance_handle
533 * struct service_creation *setup,
534 * VCHI_SERVICE_HANDLE_T *handle
536 * Description: Routine to open a service
538 * Returns: int32_t - success == 0
540 ***********************************************************/
542 static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
543 struct vchiq_header *header,
544 VCHIQ_SERVICE_HANDLE_T handle,
547 struct shim_service *service =
548 (struct shim_service *)VCHIQ_GET_SERVICE_USERDATA(handle);
550 if (!service->callback)
554 case VCHIQ_MESSAGE_AVAILABLE:
555 vchiu_queue_push(&service->queue, header);
557 service->callback(service->callback_param,
558 VCHI_CALLBACK_MSG_AVAILABLE, NULL);
562 case VCHIQ_BULK_TRANSMIT_DONE:
563 service->callback(service->callback_param,
564 VCHI_CALLBACK_BULK_SENT, bulk_user);
567 case VCHIQ_BULK_RECEIVE_DONE:
568 service->callback(service->callback_param,
569 VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
572 case VCHIQ_SERVICE_CLOSED:
573 service->callback(service->callback_param,
574 VCHI_CALLBACK_SERVICE_CLOSED, NULL);
577 case VCHIQ_SERVICE_OPENED:
578 /* No equivalent VCHI reason */
581 case VCHIQ_BULK_TRANSMIT_ABORTED:
582 service->callback(service->callback_param,
583 VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
587 case VCHIQ_BULK_RECEIVE_ABORTED:
588 service->callback(service->callback_param,
589 VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
594 WARN(1, "not supported\n");
599 vchiq_release_message(service->handle, header);
601 return VCHIQ_SUCCESS;
604 static struct shim_service *service_alloc(VCHIQ_INSTANCE_T instance,
605 struct service_creation *setup)
607 struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL);
612 if (vchiu_queue_init(&service->queue, 64)) {
613 service->callback = setup->callback;
614 service->callback_param = setup->callback_param;
624 static void service_free(struct shim_service *service)
627 vchiu_queue_delete(&service->queue);
632 int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
633 struct service_creation *setup,
634 VCHI_SERVICE_HANDLE_T *handle)
636 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
637 struct shim_service *service = service_alloc(instance, setup);
639 *handle = (VCHI_SERVICE_HANDLE_T)service;
642 struct vchiq_service_params params;
643 VCHIQ_STATUS_T status;
645 memset(¶ms, 0, sizeof(params));
646 params.fourcc = setup->service_id;
647 params.callback = shim_callback;
648 params.userdata = service;
649 params.version = setup->version.version;
650 params.version_min = setup->version.version_min;
652 status = vchiq_open_service(instance, ¶ms,
654 if (status != VCHIQ_SUCCESS) {
655 service_free(service);
661 return (service != NULL) ? 0 : -1;
663 EXPORT_SYMBOL(vchi_service_open);
665 int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
668 struct shim_service *service = (struct shim_service *)handle;
671 VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
672 if (status == VCHIQ_SUCCESS) {
673 service_free(service);
677 ret = vchiq_status_to_vchi(status);
681 EXPORT_SYMBOL(vchi_service_close);
683 int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
686 struct shim_service *service = (struct shim_service *)handle;
689 VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
691 if (status == VCHIQ_SUCCESS) {
692 service_free(service);
696 ret = vchiq_status_to_vchi(status);
700 EXPORT_SYMBOL(vchi_service_destroy);
702 int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
703 VCHI_SERVICE_OPTION_T option,
707 struct shim_service *service = (struct shim_service *)handle;
708 VCHIQ_SERVICE_OPTION_T vchiq_option;
711 case VCHI_SERVICE_OPTION_TRACE:
712 vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
714 case VCHI_SERVICE_OPTION_SYNCHRONOUS:
715 vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
722 VCHIQ_STATUS_T status =
723 vchiq_set_service_option(service->handle,
727 ret = vchiq_status_to_vchi(status);
731 EXPORT_SYMBOL(vchi_service_set_option);
733 int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, short *peer_version)
736 struct shim_service *service = (struct shim_service *)handle;
739 VCHIQ_STATUS_T status;
741 status = vchiq_get_peer_version(service->handle, peer_version);
742 ret = vchiq_status_to_vchi(status);
746 EXPORT_SYMBOL(vchi_get_peer_version);
748 /***********************************************************
749 * Name: vchi_service_use
751 * Arguments: const VCHI_SERVICE_HANDLE_T handle
753 * Description: Routine to increment refcount on a service
757 ***********************************************************/
758 int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
762 struct shim_service *service = (struct shim_service *)handle;
764 ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
767 EXPORT_SYMBOL(vchi_service_use);
769 /***********************************************************
770 * Name: vchi_service_release
772 * Arguments: const VCHI_SERVICE_HANDLE_T handle
774 * Description: Routine to decrement refcount on a service
778 ***********************************************************/
779 int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
783 struct shim_service *service = (struct shim_service *)handle;
785 ret = vchiq_status_to_vchi(
786 vchiq_release_service(service->handle));
789 EXPORT_SYMBOL(vchi_service_release);