| /** |
| * Copyright (c) 2010-2012 Broadcom. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions, and the following disclaimer, |
| * without modification. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The names of the above-listed copyright holders may not be used |
| * to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * ALTERNATIVELY, this software may be distributed under the terms of the |
| * GNU General Public License ("GPL") version 2, as published by the Free |
| * Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| #include <linux/module.h> |
| #include <linux/types.h> |
| |
| #include "interface/vchi/vchi.h" |
| #include "vchiq.h" |
| #include "vchiq_core.h" |
| |
| #include "vchiq_util.h" |
| |
| #include <stddef.h> |
| |
| #define vchiq_status_to_vchi(status) ((int32_t)status) |
| |
| typedef struct { |
| VCHIQ_SERVICE_HANDLE_T handle; |
| |
| VCHIU_QUEUE_T queue; |
| |
| VCHI_CALLBACK_T callback; |
| void *callback_param; |
| } SHIM_SERVICE_T; |
| |
| /* ---------------------------------------------------------------------- |
| * return pointer to the mphi message driver function table |
| * -------------------------------------------------------------------- */ |
| const VCHI_MESSAGE_DRIVER_T * |
| vchi_mphi_message_driver_func_table(void) |
| { |
| return NULL; |
| } |
| |
| /* ---------------------------------------------------------------------- |
| * return a pointer to the 'single' connection driver fops |
| * -------------------------------------------------------------------- */ |
| const VCHI_CONNECTION_API_T * |
| single_get_func_table(void) |
| { |
| return NULL; |
| } |
| |
| VCHI_CONNECTION_T *vchi_create_connection( |
| const VCHI_CONNECTION_API_T *function_table, |
| const VCHI_MESSAGE_DRIVER_T *low_level) |
| { |
| (void)function_table; |
| (void)low_level; |
| return NULL; |
| } |
| |
| /*********************************************************** |
| * Name: vchi_msg_peek |
| * |
| * Arguments: const VCHI_SERVICE_HANDLE_T handle, |
| * void **data, |
| * uint32_t *msg_size, |
| |
| |
| * VCHI_FLAGS_T flags |
| * |
| * Description: Routine to return a pointer to the current message (to allow in |
| * place processing). The message can be removed using |
| * vchi_msg_remove when you're finished |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle, |
| void **data, |
| uint32_t *msg_size, |
| VCHI_FLAGS_T flags) |
| { |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| VCHIQ_HEADER_T *header; |
| |
| WARN_ON((flags != VCHI_FLAGS_NONE) && |
| (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); |
| |
| if (flags == VCHI_FLAGS_NONE) |
| if (vchiu_queue_is_empty(&service->queue)) |
| return -1; |
| |
| header = vchiu_queue_peek(&service->queue); |
| |
| *data = header->data; |
| *msg_size = header->size; |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(vchi_msg_peek); |
| |
| /*********************************************************** |
| * Name: vchi_msg_remove |
| * |
| * Arguments: const VCHI_SERVICE_HANDLE_T handle, |
| * |
| * Description: Routine to remove a message (after it has been read with |
| * vchi_msg_peek) |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle) |
| { |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| VCHIQ_HEADER_T *header; |
| |
| header = vchiu_queue_pop(&service->queue); |
| |
| vchiq_release_message(service->handle, header); |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(vchi_msg_remove); |
| |
| /*********************************************************** |
| * Name: vchi_msg_queue |
| * |
| * Arguments: VCHI_SERVICE_HANDLE_T handle, |
| * const void *data, |
| * uint32_t data_size, |
| * VCHI_FLAGS_T flags, |
| * void *msg_handle, |
| * |
| * Description: Thin wrapper to queue a message onto a connection |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, |
| const void *data, |
| uint32_t data_size, |
| VCHI_FLAGS_T flags, |
| void *msg_handle) |
| { |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| VCHIQ_ELEMENT_T element = {data, data_size}; |
| VCHIQ_STATUS_T status; |
| |
| (void)msg_handle; |
| |
| WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); |
| |
| status = vchiq_queue_message(service->handle, &element, 1); |
| |
| /* vchiq_queue_message() may return VCHIQ_RETRY, so we need to |
| ** implement a retry mechanism since this function is supposed |
| ** to block until queued |
| */ |
| while (status == VCHIQ_RETRY) { |
| msleep(1); |
| status = vchiq_queue_message(service->handle, &element, 1); |
| } |
| |
| return vchiq_status_to_vchi(status); |
| } |
| EXPORT_SYMBOL(vchi_msg_queue); |
| |
| /*********************************************************** |
| * Name: vchi_bulk_queue_receive |
| * |
| * Arguments: VCHI_BULK_HANDLE_T handle, |
| * void *data_dst, |
| * const uint32_t data_size, |
| * VCHI_FLAGS_T flags |
| * void *bulk_handle |
| * |
| * Description: Routine to setup a rcv buffer |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle, |
| void *data_dst, |
| uint32_t data_size, |
| VCHI_FLAGS_T flags, |
| void *bulk_handle) |
| { |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| VCHIQ_BULK_MODE_T mode; |
| VCHIQ_STATUS_T status; |
| |
| switch ((int)flags) { |
| case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
| | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: |
| WARN_ON(!service->callback); |
| mode = VCHIQ_BULK_MODE_CALLBACK; |
| break; |
| case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: |
| mode = VCHIQ_BULK_MODE_BLOCKING; |
| break; |
| case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: |
| case VCHI_FLAGS_NONE: |
| mode = VCHIQ_BULK_MODE_NOCALLBACK; |
| break; |
| default: |
| WARN(1, "unsupported message\n"); |
| return vchiq_status_to_vchi(VCHIQ_ERROR); |
| } |
| |
| status = vchiq_bulk_receive(service->handle, data_dst, data_size, |
| bulk_handle, mode); |
| |
| /* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to |
| ** implement a retry mechanism since this function is supposed |
| ** to block until queued |
| */ |
| while (status == VCHIQ_RETRY) { |
| msleep(1); |
| status = vchiq_bulk_receive(service->handle, data_dst, |
| data_size, bulk_handle, mode); |
| } |
| |
| return vchiq_status_to_vchi(status); |
| } |
| EXPORT_SYMBOL(vchi_bulk_queue_receive); |
| |
| /*********************************************************** |
| * Name: vchi_bulk_queue_transmit |
| * |
| * Arguments: VCHI_BULK_HANDLE_T handle, |
| * const void *data_src, |
| * uint32_t data_size, |
| * VCHI_FLAGS_T flags, |
| * void *bulk_handle |
| * |
| * Description: Routine to transmit some data |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle, |
| const void *data_src, |
| uint32_t data_size, |
| VCHI_FLAGS_T flags, |
| void *bulk_handle) |
| { |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| VCHIQ_BULK_MODE_T mode; |
| VCHIQ_STATUS_T status; |
| |
| switch ((int)flags) { |
| case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
| | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: |
| WARN_ON(!service->callback); |
| mode = VCHIQ_BULK_MODE_CALLBACK; |
| break; |
| case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ: |
| case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: |
| mode = VCHIQ_BULK_MODE_BLOCKING; |
| break; |
| case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: |
| case VCHI_FLAGS_NONE: |
| mode = VCHIQ_BULK_MODE_NOCALLBACK; |
| break; |
| default: |
| WARN(1, "unsupported message\n"); |
| return vchiq_status_to_vchi(VCHIQ_ERROR); |
| } |
| |
| status = vchiq_bulk_transmit(service->handle, data_src, data_size, |
| bulk_handle, mode); |
| |
| /* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to |
| ** implement a retry mechanism since this function is supposed |
| ** to block until queued |
| */ |
| while (status == VCHIQ_RETRY) { |
| msleep(1); |
| status = vchiq_bulk_transmit(service->handle, data_src, |
| data_size, bulk_handle, mode); |
| } |
| |
| return vchiq_status_to_vchi(status); |
| } |
| EXPORT_SYMBOL(vchi_bulk_queue_transmit); |
| |
| /*********************************************************** |
| * Name: vchi_msg_dequeue |
| * |
| * Arguments: VCHI_SERVICE_HANDLE_T handle, |
| * void *data, |
| * uint32_t max_data_size_to_read, |
| * uint32_t *actual_msg_size |
| * VCHI_FLAGS_T flags |
| * |
| * Description: Routine to dequeue a message into the supplied buffer |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle, |
| void *data, |
| uint32_t max_data_size_to_read, |
| uint32_t *actual_msg_size, |
| VCHI_FLAGS_T flags) |
| { |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| VCHIQ_HEADER_T *header; |
| |
| WARN_ON((flags != VCHI_FLAGS_NONE) && |
| (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); |
| |
| if (flags == VCHI_FLAGS_NONE) |
| if (vchiu_queue_is_empty(&service->queue)) |
| return -1; |
| |
| header = vchiu_queue_pop(&service->queue); |
| |
| memcpy(data, header->data, header->size < max_data_size_to_read ? |
| header->size : max_data_size_to_read); |
| |
| *actual_msg_size = header->size; |
| |
| vchiq_release_message(service->handle, header); |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(vchi_msg_dequeue); |
| |
| /*********************************************************** |
| * Name: vchi_msg_queuev |
| * |
| * Arguments: VCHI_SERVICE_HANDLE_T handle, |
| * VCHI_MSG_VECTOR_T *vector, |
| * uint32_t count, |
| * VCHI_FLAGS_T flags, |
| * void *msg_handle |
| * |
| * Description: Thin wrapper to queue a message onto a connection |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| |
| vchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T)); |
| vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == |
| offsetof(VCHIQ_ELEMENT_T, data)); |
| vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == |
| offsetof(VCHIQ_ELEMENT_T, size)); |
| |
| int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle, |
| VCHI_MSG_VECTOR_T *vector, |
| uint32_t count, |
| VCHI_FLAGS_T flags, |
| void *msg_handle) |
| { |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| |
| (void)msg_handle; |
| |
| WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); |
| |
| return vchiq_status_to_vchi(vchiq_queue_message(service->handle, |
| (const VCHIQ_ELEMENT_T *)vector, count)); |
| } |
| EXPORT_SYMBOL(vchi_msg_queuev); |
| |
| /*********************************************************** |
| * Name: vchi_held_msg_release |
| * |
| * Arguments: VCHI_HELD_MSG_T *message |
| * |
| * Description: Routine to release a held message (after it has been read with |
| * vchi_msg_hold) |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message) |
| { |
| vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service, |
| (VCHIQ_HEADER_T *)message->message); |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(vchi_held_msg_release); |
| |
| /*********************************************************** |
| * Name: vchi_msg_hold |
| * |
| * Arguments: VCHI_SERVICE_HANDLE_T handle, |
| * void **data, |
| * uint32_t *msg_size, |
| * VCHI_FLAGS_T flags, |
| * VCHI_HELD_MSG_T *message_handle |
| * |
| * Description: Routine to return a pointer to the current message (to allow |
| * in place processing). The message is dequeued - don't forget |
| * to release the message using vchi_held_msg_release when you're |
| * finished. |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle, |
| void **data, |
| uint32_t *msg_size, |
| VCHI_FLAGS_T flags, |
| VCHI_HELD_MSG_T *message_handle) |
| { |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| VCHIQ_HEADER_T *header; |
| |
| WARN_ON((flags != VCHI_FLAGS_NONE) && |
| (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); |
| |
| if (flags == VCHI_FLAGS_NONE) |
| if (vchiu_queue_is_empty(&service->queue)) |
| return -1; |
| |
| header = vchiu_queue_pop(&service->queue); |
| |
| *data = header->data; |
| *msg_size = header->size; |
| |
| message_handle->service = |
| (struct opaque_vchi_service_t *)service->handle; |
| message_handle->message = header; |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(vchi_msg_hold); |
| |
| /*********************************************************** |
| * Name: vchi_initialise |
| * |
| * Arguments: VCHI_INSTANCE_T *instance_handle |
| * |
| * Description: Initialises the hardware but does not transmit anything |
| * When run as a Host App this will be called twice hence the need |
| * to malloc the state information |
| * |
| * Returns: 0 if successful, failure otherwise |
| * |
| ***********************************************************/ |
| |
| int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle) |
| { |
| VCHIQ_INSTANCE_T instance; |
| VCHIQ_STATUS_T status; |
| |
| status = vchiq_initialise(&instance); |
| |
| *instance_handle = (VCHI_INSTANCE_T)instance; |
| |
| return vchiq_status_to_vchi(status); |
| } |
| EXPORT_SYMBOL(vchi_initialise); |
| |
| /*********************************************************** |
| * Name: vchi_connect |
| * |
| * Arguments: VCHI_CONNECTION_T **connections |
| * const uint32_t num_connections |
| * VCHI_INSTANCE_T instance_handle) |
| * |
| * Description: Starts the command service on each connection, |
| * causing INIT messages to be pinged back and forth |
| * |
| * Returns: 0 if successful, failure otherwise |
| * |
| ***********************************************************/ |
| int32_t vchi_connect(VCHI_CONNECTION_T **connections, |
| const uint32_t num_connections, |
| VCHI_INSTANCE_T instance_handle) |
| { |
| VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; |
| |
| (void)connections; |
| (void)num_connections; |
| |
| return vchiq_connect(instance); |
| } |
| EXPORT_SYMBOL(vchi_connect); |
| |
| |
| /*********************************************************** |
| * Name: vchi_disconnect |
| * |
| * Arguments: VCHI_INSTANCE_T instance_handle |
| * |
| * Description: Stops the command service on each connection, |
| * causing DE-INIT messages to be pinged back and forth |
| * |
| * Returns: 0 if successful, failure otherwise |
| * |
| ***********************************************************/ |
| int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle) |
| { |
| VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; |
| return vchiq_status_to_vchi(vchiq_shutdown(instance)); |
| } |
| EXPORT_SYMBOL(vchi_disconnect); |
| |
| |
| /*********************************************************** |
| * Name: vchi_service_open |
| * Name: vchi_service_create |
| * |
| * Arguments: VCHI_INSTANCE_T *instance_handle |
| * SERVICE_CREATION_T *setup, |
| * VCHI_SERVICE_HANDLE_T *handle |
| * |
| * Description: Routine to open a service |
| * |
| * Returns: int32_t - success == 0 |
| * |
| ***********************************************************/ |
| |
| static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, |
| VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user) |
| { |
| SHIM_SERVICE_T *service = |
| (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle); |
| |
| if (!service->callback) |
| goto release; |
| |
| switch (reason) { |
| case VCHIQ_MESSAGE_AVAILABLE: |
| vchiu_queue_push(&service->queue, header); |
| |
| service->callback(service->callback_param, |
| VCHI_CALLBACK_MSG_AVAILABLE, NULL); |
| |
| goto done; |
| break; |
| |
| case VCHIQ_BULK_TRANSMIT_DONE: |
| service->callback(service->callback_param, |
| VCHI_CALLBACK_BULK_SENT, bulk_user); |
| break; |
| |
| case VCHIQ_BULK_RECEIVE_DONE: |
| service->callback(service->callback_param, |
| VCHI_CALLBACK_BULK_RECEIVED, bulk_user); |
| break; |
| |
| case VCHIQ_SERVICE_CLOSED: |
| service->callback(service->callback_param, |
| VCHI_CALLBACK_SERVICE_CLOSED, NULL); |
| break; |
| |
| case VCHIQ_SERVICE_OPENED: |
| /* No equivalent VCHI reason */ |
| break; |
| |
| case VCHIQ_BULK_TRANSMIT_ABORTED: |
| service->callback(service->callback_param, |
| VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, |
| bulk_user); |
| break; |
| |
| case VCHIQ_BULK_RECEIVE_ABORTED: |
| service->callback(service->callback_param, |
| VCHI_CALLBACK_BULK_RECEIVE_ABORTED, |
| bulk_user); |
| break; |
| |
| default: |
| WARN(1, "not supported\n"); |
| break; |
| } |
| |
| release: |
| vchiq_release_message(service->handle, header); |
| done: |
| return VCHIQ_SUCCESS; |
| } |
| |
| static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance, |
| SERVICE_CREATION_T *setup) |
| { |
| SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL); |
| |
| (void)instance; |
| |
| if (service) { |
| if (vchiu_queue_init(&service->queue, 64)) { |
| service->callback = setup->callback; |
| service->callback_param = setup->callback_param; |
| } else { |
| kfree(service); |
| service = NULL; |
| } |
| } |
| |
| return service; |
| } |
| |
| static void service_free(SHIM_SERVICE_T *service) |
| { |
| if (service) { |
| vchiu_queue_delete(&service->queue); |
| kfree(service); |
| } |
| } |
| |
| int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, |
| SERVICE_CREATION_T *setup, |
| VCHI_SERVICE_HANDLE_T *handle) |
| { |
| VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; |
| SHIM_SERVICE_T *service = service_alloc(instance, setup); |
| |
| *handle = (VCHI_SERVICE_HANDLE_T)service; |
| |
| if (service) { |
| VCHIQ_SERVICE_PARAMS_T params; |
| VCHIQ_STATUS_T status; |
| |
| memset(¶ms, 0, sizeof(params)); |
| params.fourcc = setup->service_id; |
| params.callback = shim_callback; |
| params.userdata = service; |
| params.version = setup->version.version; |
| params.version_min = setup->version.version_min; |
| |
| status = vchiq_open_service(instance, ¶ms, |
| &service->handle); |
| if (status != VCHIQ_SUCCESS) { |
| service_free(service); |
| service = NULL; |
| *handle = NULL; |
| } |
| } |
| |
| return (service != NULL) ? 0 : -1; |
| } |
| EXPORT_SYMBOL(vchi_service_open); |
| |
| int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle, |
| SERVICE_CREATION_T *setup, |
| VCHI_SERVICE_HANDLE_T *handle) |
| { |
| VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; |
| SHIM_SERVICE_T *service = service_alloc(instance, setup); |
| |
| *handle = (VCHI_SERVICE_HANDLE_T)service; |
| |
| if (service) { |
| VCHIQ_SERVICE_PARAMS_T params; |
| VCHIQ_STATUS_T status; |
| |
| memset(¶ms, 0, sizeof(params)); |
| params.fourcc = setup->service_id; |
| params.callback = shim_callback; |
| params.userdata = service; |
| params.version = setup->version.version; |
| params.version_min = setup->version.version_min; |
| status = vchiq_add_service(instance, ¶ms, &service->handle); |
| |
| if (status != VCHIQ_SUCCESS) { |
| service_free(service); |
| service = NULL; |
| *handle = NULL; |
| } |
| } |
| |
| return (service != NULL) ? 0 : -1; |
| } |
| EXPORT_SYMBOL(vchi_service_create); |
| |
| int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle) |
| { |
| int32_t ret = -1; |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| if (service) { |
| VCHIQ_STATUS_T status = vchiq_close_service(service->handle); |
| if (status == VCHIQ_SUCCESS) { |
| service_free(service); |
| service = NULL; |
| } |
| |
| ret = vchiq_status_to_vchi(status); |
| } |
| return ret; |
| } |
| EXPORT_SYMBOL(vchi_service_close); |
| |
| int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle) |
| { |
| int32_t ret = -1; |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| if (service) { |
| VCHIQ_STATUS_T status = vchiq_remove_service(service->handle); |
| if (status == VCHIQ_SUCCESS) { |
| service_free(service); |
| service = NULL; |
| } |
| |
| ret = vchiq_status_to_vchi(status); |
| } |
| return ret; |
| } |
| EXPORT_SYMBOL(vchi_service_destroy); |
| |
| int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, |
| VCHI_SERVICE_OPTION_T option, |
| int value) |
| { |
| int32_t ret = -1; |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| VCHIQ_SERVICE_OPTION_T vchiq_option; |
| switch (option) { |
| case VCHI_SERVICE_OPTION_TRACE: |
| vchiq_option = VCHIQ_SERVICE_OPTION_TRACE; |
| break; |
| case VCHI_SERVICE_OPTION_SYNCHRONOUS: |
| vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS; |
| break; |
| default: |
| service = NULL; |
| break; |
| } |
| if (service) { |
| VCHIQ_STATUS_T status = |
| vchiq_set_service_option(service->handle, |
| vchiq_option, |
| value); |
| |
| ret = vchiq_status_to_vchi(status); |
| } |
| return ret; |
| } |
| EXPORT_SYMBOL(vchi_service_set_option); |
| |
| int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version ) |
| { |
| int32_t ret = -1; |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| if(service) |
| { |
| VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version); |
| ret = vchiq_status_to_vchi( status ); |
| } |
| return ret; |
| } |
| EXPORT_SYMBOL(vchi_get_peer_version); |
| |
| /* ---------------------------------------------------------------------- |
| * read a uint32_t from buffer. |
| * network format is defined to be little endian |
| * -------------------------------------------------------------------- */ |
| uint32_t |
| vchi_readbuf_uint32(const void *_ptr) |
| { |
| const unsigned char *ptr = _ptr; |
| return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); |
| } |
| |
| /* ---------------------------------------------------------------------- |
| * write a uint32_t to buffer. |
| * network format is defined to be little endian |
| * -------------------------------------------------------------------- */ |
| void |
| vchi_writebuf_uint32(void *_ptr, uint32_t value) |
| { |
| unsigned char *ptr = _ptr; |
| ptr[0] = (unsigned char)((value >> 0) & 0xFF); |
| ptr[1] = (unsigned char)((value >> 8) & 0xFF); |
| ptr[2] = (unsigned char)((value >> 16) & 0xFF); |
| ptr[3] = (unsigned char)((value >> 24) & 0xFF); |
| } |
| |
| /* ---------------------------------------------------------------------- |
| * read a uint16_t from buffer. |
| * network format is defined to be little endian |
| * -------------------------------------------------------------------- */ |
| uint16_t |
| vchi_readbuf_uint16(const void *_ptr) |
| { |
| const unsigned char *ptr = _ptr; |
| return ptr[0] | (ptr[1] << 8); |
| } |
| |
| /* ---------------------------------------------------------------------- |
| * write a uint16_t into the buffer. |
| * network format is defined to be little endian |
| * -------------------------------------------------------------------- */ |
| void |
| vchi_writebuf_uint16(void *_ptr, uint16_t value) |
| { |
| unsigned char *ptr = _ptr; |
| ptr[0] = (value >> 0) & 0xFF; |
| ptr[1] = (value >> 8) & 0xFF; |
| } |
| |
| /*********************************************************** |
| * Name: vchi_service_use |
| * |
| * Arguments: const VCHI_SERVICE_HANDLE_T handle |
| * |
| * Description: Routine to increment refcount on a service |
| * |
| * Returns: void |
| * |
| ***********************************************************/ |
| int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle) |
| { |
| int32_t ret = -1; |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| if (service) |
| ret = vchiq_status_to_vchi(vchiq_use_service(service->handle)); |
| return ret; |
| } |
| EXPORT_SYMBOL(vchi_service_use); |
| |
| /*********************************************************** |
| * Name: vchi_service_release |
| * |
| * Arguments: const VCHI_SERVICE_HANDLE_T handle |
| * |
| * Description: Routine to decrement refcount on a service |
| * |
| * Returns: void |
| * |
| ***********************************************************/ |
| int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle) |
| { |
| int32_t ret = -1; |
| SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; |
| if (service) |
| ret = vchiq_status_to_vchi( |
| vchiq_release_service(service->handle)); |
| return ret; |
| } |
| EXPORT_SYMBOL(vchi_service_release); |