1262f27b2SOleksandr Tymoshenko /**
2262f27b2SOleksandr Tymoshenko  * Copyright (c) 2010-2012 Broadcom. All rights reserved.
3262f27b2SOleksandr Tymoshenko  *
4262f27b2SOleksandr Tymoshenko  * Redistribution and use in source and binary forms, with or without
5262f27b2SOleksandr Tymoshenko  * modification, are permitted provided that the following conditions
6262f27b2SOleksandr Tymoshenko  * are met:
7262f27b2SOleksandr Tymoshenko  * 1. Redistributions of source code must retain the above copyright
8262f27b2SOleksandr Tymoshenko  *    notice, this list of conditions, and the following disclaimer,
9262f27b2SOleksandr Tymoshenko  *    without modification.
10262f27b2SOleksandr Tymoshenko  * 2. Redistributions in binary form must reproduce the above copyright
11262f27b2SOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer in the
12262f27b2SOleksandr Tymoshenko  *    documentation and/or other materials provided with the distribution.
13262f27b2SOleksandr Tymoshenko  * 3. The names of the above-listed copyright holders may not be used
14262f27b2SOleksandr Tymoshenko  *    to endorse or promote products derived from this software without
15262f27b2SOleksandr Tymoshenko  *    specific prior written permission.
16262f27b2SOleksandr Tymoshenko  *
17262f27b2SOleksandr Tymoshenko  * ALTERNATIVELY, this software may be distributed under the terms of the
18262f27b2SOleksandr Tymoshenko  * GNU General Public License ("GPL") version 2, as published by the Free
19262f27b2SOleksandr Tymoshenko  * Software Foundation.
20262f27b2SOleksandr Tymoshenko  *
21262f27b2SOleksandr Tymoshenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22262f27b2SOleksandr Tymoshenko  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23262f27b2SOleksandr Tymoshenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24262f27b2SOleksandr Tymoshenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25262f27b2SOleksandr Tymoshenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26262f27b2SOleksandr Tymoshenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27262f27b2SOleksandr Tymoshenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28262f27b2SOleksandr Tymoshenko  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29262f27b2SOleksandr Tymoshenko  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30262f27b2SOleksandr Tymoshenko  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31262f27b2SOleksandr Tymoshenko  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32262f27b2SOleksandr Tymoshenko  */
33262f27b2SOleksandr Tymoshenko 
34262f27b2SOleksandr Tymoshenko #include <interface/compat/vchi_bsd.h>
35262f27b2SOleksandr Tymoshenko 
36262f27b2SOleksandr Tymoshenko #include "interface/vchi/vchi.h"
37262f27b2SOleksandr Tymoshenko #include "vchiq.h"
38262f27b2SOleksandr Tymoshenko #include "vchiq_core.h"
39262f27b2SOleksandr Tymoshenko 
40262f27b2SOleksandr Tymoshenko #include "vchiq_util.h"
41262f27b2SOleksandr Tymoshenko 
42262f27b2SOleksandr Tymoshenko #define vchiq_status_to_vchi(status) ((int32_t)status)
43262f27b2SOleksandr Tymoshenko 
44262f27b2SOleksandr Tymoshenko typedef struct {
45262f27b2SOleksandr Tymoshenko 	VCHIQ_SERVICE_HANDLE_T handle;
46262f27b2SOleksandr Tymoshenko 
47262f27b2SOleksandr Tymoshenko 	VCHIU_QUEUE_T queue;
48262f27b2SOleksandr Tymoshenko 
49262f27b2SOleksandr Tymoshenko 	VCHI_CALLBACK_T callback;
50262f27b2SOleksandr Tymoshenko 	void *callback_param;
51262f27b2SOleksandr Tymoshenko } SHIM_SERVICE_T;
52262f27b2SOleksandr Tymoshenko 
53262f27b2SOleksandr Tymoshenko /* ----------------------------------------------------------------------
54262f27b2SOleksandr Tymoshenko  * return pointer to the mphi message driver function table
55262f27b2SOleksandr Tymoshenko  * -------------------------------------------------------------------- */
56262f27b2SOleksandr Tymoshenko const VCHI_MESSAGE_DRIVER_T *
vchi_mphi_message_driver_func_table(void)57262f27b2SOleksandr Tymoshenko vchi_mphi_message_driver_func_table(void)
58262f27b2SOleksandr Tymoshenko {
59262f27b2SOleksandr Tymoshenko 	return NULL;
60262f27b2SOleksandr Tymoshenko }
61262f27b2SOleksandr Tymoshenko 
62262f27b2SOleksandr Tymoshenko /* ----------------------------------------------------------------------
63262f27b2SOleksandr Tymoshenko  * return a pointer to the 'single' connection driver fops
64262f27b2SOleksandr Tymoshenko  * -------------------------------------------------------------------- */
65262f27b2SOleksandr Tymoshenko const VCHI_CONNECTION_API_T *
single_get_func_table(void)66262f27b2SOleksandr Tymoshenko single_get_func_table(void)
67262f27b2SOleksandr Tymoshenko {
68262f27b2SOleksandr Tymoshenko 	return NULL;
69262f27b2SOleksandr Tymoshenko }
70262f27b2SOleksandr Tymoshenko 
vchi_create_connection(const VCHI_CONNECTION_API_T * function_table,const VCHI_MESSAGE_DRIVER_T * low_level)71262f27b2SOleksandr Tymoshenko VCHI_CONNECTION_T *vchi_create_connection(
72262f27b2SOleksandr Tymoshenko 	const VCHI_CONNECTION_API_T *function_table,
73262f27b2SOleksandr Tymoshenko 	const VCHI_MESSAGE_DRIVER_T *low_level)
74262f27b2SOleksandr Tymoshenko {
75262f27b2SOleksandr Tymoshenko 	(void)function_table;
76262f27b2SOleksandr Tymoshenko 	(void)low_level;
77262f27b2SOleksandr Tymoshenko 	return NULL;
78262f27b2SOleksandr Tymoshenko }
79262f27b2SOleksandr Tymoshenko 
80262f27b2SOleksandr Tymoshenko /***********************************************************
81262f27b2SOleksandr Tymoshenko  * Name: vchi_msg_peek
82262f27b2SOleksandr Tymoshenko  *
83262f27b2SOleksandr Tymoshenko  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
84262f27b2SOleksandr Tymoshenko  *             void **data,
85262f27b2SOleksandr Tymoshenko  *             uint32_t *msg_size,
86262f27b2SOleksandr Tymoshenko 
87262f27b2SOleksandr Tymoshenko 
88262f27b2SOleksandr Tymoshenko  *             VCHI_FLAGS_T flags
89262f27b2SOleksandr Tymoshenko  *
90262f27b2SOleksandr Tymoshenko  * Description: Routine to return a pointer to the current message (to allow in
91262f27b2SOleksandr Tymoshenko  *              place processing). The message can be removed using
92262f27b2SOleksandr Tymoshenko  *              vchi_msg_remove when you're finished
93262f27b2SOleksandr Tymoshenko  *
94262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
95262f27b2SOleksandr Tymoshenko  *
96262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags)97262f27b2SOleksandr Tymoshenko int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
98262f27b2SOleksandr Tymoshenko 	void **data,
99262f27b2SOleksandr Tymoshenko 	uint32_t *msg_size,
100262f27b2SOleksandr Tymoshenko 	VCHI_FLAGS_T flags)
101262f27b2SOleksandr Tymoshenko {
102262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
103262f27b2SOleksandr Tymoshenko 	VCHIQ_HEADER_T *header;
104262f27b2SOleksandr Tymoshenko 
105262f27b2SOleksandr Tymoshenko 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
106262f27b2SOleksandr Tymoshenko 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
107262f27b2SOleksandr Tymoshenko 
108262f27b2SOleksandr Tymoshenko 	if (flags == VCHI_FLAGS_NONE)
109262f27b2SOleksandr Tymoshenko 		if (vchiu_queue_is_empty(&service->queue))
110262f27b2SOleksandr Tymoshenko 			return -1;
111262f27b2SOleksandr Tymoshenko 
112262f27b2SOleksandr Tymoshenko 	header = vchiu_queue_peek(&service->queue);
113262f27b2SOleksandr Tymoshenko 
114262f27b2SOleksandr Tymoshenko 	*data = header->data;
115262f27b2SOleksandr Tymoshenko 	*msg_size = header->size;
116262f27b2SOleksandr Tymoshenko 
117262f27b2SOleksandr Tymoshenko 	return 0;
118262f27b2SOleksandr Tymoshenko }
119262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_msg_peek);
120262f27b2SOleksandr Tymoshenko 
121262f27b2SOleksandr Tymoshenko /***********************************************************
122262f27b2SOleksandr Tymoshenko  * Name: vchi_msg_remove
123262f27b2SOleksandr Tymoshenko  *
124262f27b2SOleksandr Tymoshenko  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
125262f27b2SOleksandr Tymoshenko  *
126262f27b2SOleksandr Tymoshenko  * Description: Routine to remove a message (after it has been read with
127262f27b2SOleksandr Tymoshenko  *              vchi_msg_peek)
128262f27b2SOleksandr Tymoshenko  *
129262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
130262f27b2SOleksandr Tymoshenko  *
131262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)132262f27b2SOleksandr Tymoshenko int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
133262f27b2SOleksandr Tymoshenko {
134262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
135262f27b2SOleksandr Tymoshenko 	VCHIQ_HEADER_T *header;
136262f27b2SOleksandr Tymoshenko 
137262f27b2SOleksandr Tymoshenko 	header = vchiu_queue_pop(&service->queue);
138262f27b2SOleksandr Tymoshenko 
139262f27b2SOleksandr Tymoshenko 	vchiq_release_message(service->handle, header);
140262f27b2SOleksandr Tymoshenko 
141262f27b2SOleksandr Tymoshenko 	return 0;
142262f27b2SOleksandr Tymoshenko }
143262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_msg_remove);
144262f27b2SOleksandr Tymoshenko 
145262f27b2SOleksandr Tymoshenko /***********************************************************
146262f27b2SOleksandr Tymoshenko  * Name: vchi_msg_queue
147262f27b2SOleksandr Tymoshenko  *
148262f27b2SOleksandr Tymoshenko  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
149262f27b2SOleksandr Tymoshenko  *             const void *data,
150262f27b2SOleksandr Tymoshenko  *             uint32_t data_size,
151262f27b2SOleksandr Tymoshenko  *             VCHI_FLAGS_T flags,
152262f27b2SOleksandr Tymoshenko  *             void *msg_handle,
153262f27b2SOleksandr Tymoshenko  *
154262f27b2SOleksandr Tymoshenko  * Description: Thin wrapper to queue a message onto a connection
155262f27b2SOleksandr Tymoshenko  *
156262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
157262f27b2SOleksandr Tymoshenko  *
158262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,const void * data,uint32_t data_size,VCHI_FLAGS_T flags,void * msg_handle)159262f27b2SOleksandr Tymoshenko int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
160262f27b2SOleksandr Tymoshenko 	const void *data,
161262f27b2SOleksandr Tymoshenko 	uint32_t data_size,
162262f27b2SOleksandr Tymoshenko 	VCHI_FLAGS_T flags,
163262f27b2SOleksandr Tymoshenko 	void *msg_handle)
164262f27b2SOleksandr Tymoshenko {
165262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
166262f27b2SOleksandr Tymoshenko 	VCHIQ_ELEMENT_T element = {data, data_size};
167262f27b2SOleksandr Tymoshenko 	VCHIQ_STATUS_T status;
168262f27b2SOleksandr Tymoshenko 
169262f27b2SOleksandr Tymoshenko 	(void)msg_handle;
170262f27b2SOleksandr Tymoshenko 
171262f27b2SOleksandr Tymoshenko 	WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
172262f27b2SOleksandr Tymoshenko 
173262f27b2SOleksandr Tymoshenko 	status = vchiq_queue_message(service->handle, &element, 1);
174262f27b2SOleksandr Tymoshenko 
175262f27b2SOleksandr Tymoshenko 	/* vchiq_queue_message() may return VCHIQ_RETRY, so we need to
176262f27b2SOleksandr Tymoshenko 	** implement a retry mechanism since this function is supposed
177262f27b2SOleksandr Tymoshenko 	** to block until queued
178262f27b2SOleksandr Tymoshenko 	*/
179262f27b2SOleksandr Tymoshenko 	while (status == VCHIQ_RETRY) {
180262f27b2SOleksandr Tymoshenko 		msleep(1);
181262f27b2SOleksandr Tymoshenko 		status = vchiq_queue_message(service->handle, &element, 1);
182262f27b2SOleksandr Tymoshenko 	}
183262f27b2SOleksandr Tymoshenko 
184262f27b2SOleksandr Tymoshenko 	return vchiq_status_to_vchi(status);
185262f27b2SOleksandr Tymoshenko }
186262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_msg_queue);
187262f27b2SOleksandr Tymoshenko 
188262f27b2SOleksandr Tymoshenko /***********************************************************
189262f27b2SOleksandr Tymoshenko  * Name: vchi_bulk_queue_receive
190262f27b2SOleksandr Tymoshenko  *
191262f27b2SOleksandr Tymoshenko  * Arguments:  VCHI_BULK_HANDLE_T handle,
192262f27b2SOleksandr Tymoshenko  *             void *data_dst,
193262f27b2SOleksandr Tymoshenko  *             const uint32_t data_size,
194262f27b2SOleksandr Tymoshenko  *             VCHI_FLAGS_T flags
195262f27b2SOleksandr Tymoshenko  *             void *bulk_handle
196262f27b2SOleksandr Tymoshenko  *
197262f27b2SOleksandr Tymoshenko  * Description: Routine to setup a rcv buffer
198262f27b2SOleksandr Tymoshenko  *
199262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
200262f27b2SOleksandr Tymoshenko  *
201262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,void * data_dst,uint32_t data_size,VCHI_FLAGS_T flags,void * bulk_handle)202262f27b2SOleksandr Tymoshenko int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
203262f27b2SOleksandr Tymoshenko 	void *data_dst,
204262f27b2SOleksandr Tymoshenko 	uint32_t data_size,
205262f27b2SOleksandr Tymoshenko 	VCHI_FLAGS_T flags,
206262f27b2SOleksandr Tymoshenko 	void *bulk_handle)
207262f27b2SOleksandr Tymoshenko {
208262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
209262f27b2SOleksandr Tymoshenko 	VCHIQ_BULK_MODE_T mode;
210262f27b2SOleksandr Tymoshenko 	VCHIQ_STATUS_T status;
211262f27b2SOleksandr Tymoshenko 
212262f27b2SOleksandr Tymoshenko 	switch ((int)flags) {
213262f27b2SOleksandr Tymoshenko 	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
214262f27b2SOleksandr Tymoshenko 		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
215262f27b2SOleksandr Tymoshenko 		WARN_ON(!service->callback);
216262f27b2SOleksandr Tymoshenko 		mode = VCHIQ_BULK_MODE_CALLBACK;
217262f27b2SOleksandr Tymoshenko 		break;
218262f27b2SOleksandr Tymoshenko 	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
219262f27b2SOleksandr Tymoshenko 		mode = VCHIQ_BULK_MODE_BLOCKING;
220262f27b2SOleksandr Tymoshenko 		break;
221262f27b2SOleksandr Tymoshenko 	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
222262f27b2SOleksandr Tymoshenko 	case VCHI_FLAGS_NONE:
223262f27b2SOleksandr Tymoshenko 		mode = VCHIQ_BULK_MODE_NOCALLBACK;
224262f27b2SOleksandr Tymoshenko 		break;
225262f27b2SOleksandr Tymoshenko 	default:
226262f27b2SOleksandr Tymoshenko 		WARN(1, "unsupported message\n");
227262f27b2SOleksandr Tymoshenko 		return vchiq_status_to_vchi(VCHIQ_ERROR);
228262f27b2SOleksandr Tymoshenko 	}
229262f27b2SOleksandr Tymoshenko 
230262f27b2SOleksandr Tymoshenko 	status = vchiq_bulk_receive(service->handle, data_dst, data_size,
231262f27b2SOleksandr Tymoshenko 		bulk_handle, mode);
232262f27b2SOleksandr Tymoshenko 
233262f27b2SOleksandr Tymoshenko 	/* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
234262f27b2SOleksandr Tymoshenko 	** implement a retry mechanism since this function is supposed
235262f27b2SOleksandr Tymoshenko 	** to block until queued
236262f27b2SOleksandr Tymoshenko 	*/
237262f27b2SOleksandr Tymoshenko 	while (status == VCHIQ_RETRY) {
238262f27b2SOleksandr Tymoshenko 		msleep(1);
239262f27b2SOleksandr Tymoshenko 		status = vchiq_bulk_receive(service->handle, data_dst,
240262f27b2SOleksandr Tymoshenko 			data_size, bulk_handle, mode);
241262f27b2SOleksandr Tymoshenko 	}
242262f27b2SOleksandr Tymoshenko 
243262f27b2SOleksandr Tymoshenko 	return vchiq_status_to_vchi(status);
244262f27b2SOleksandr Tymoshenko }
245262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_bulk_queue_receive);
246262f27b2SOleksandr Tymoshenko 
247262f27b2SOleksandr Tymoshenko /***********************************************************
248262f27b2SOleksandr Tymoshenko  * Name: vchi_bulk_queue_transmit
249262f27b2SOleksandr Tymoshenko  *
250262f27b2SOleksandr Tymoshenko  * Arguments:  VCHI_BULK_HANDLE_T handle,
251262f27b2SOleksandr Tymoshenko  *             void *data_src,
252262f27b2SOleksandr Tymoshenko  *             uint32_t data_size,
253262f27b2SOleksandr Tymoshenko  *             VCHI_FLAGS_T flags,
254262f27b2SOleksandr Tymoshenko  *             void *bulk_handle
255262f27b2SOleksandr Tymoshenko  *
256262f27b2SOleksandr Tymoshenko  * Description: Routine to transmit some data
257262f27b2SOleksandr Tymoshenko  *
258262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
259262f27b2SOleksandr Tymoshenko  *
260262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,void * data_src,uint32_t data_size,VCHI_FLAGS_T flags,void * bulk_handle)261262f27b2SOleksandr Tymoshenko int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
262262f27b2SOleksandr Tymoshenko 	void *data_src,
263262f27b2SOleksandr Tymoshenko 	uint32_t data_size,
264262f27b2SOleksandr Tymoshenko 	VCHI_FLAGS_T flags,
265262f27b2SOleksandr Tymoshenko 	void *bulk_handle)
266262f27b2SOleksandr Tymoshenko {
267262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
268262f27b2SOleksandr Tymoshenko 	VCHIQ_BULK_MODE_T mode;
269262f27b2SOleksandr Tymoshenko 	VCHIQ_STATUS_T status;
270262f27b2SOleksandr Tymoshenko 
271262f27b2SOleksandr Tymoshenko 	switch ((int)flags) {
272262f27b2SOleksandr Tymoshenko 	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
273262f27b2SOleksandr Tymoshenko 		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
274262f27b2SOleksandr Tymoshenko 		WARN_ON(!service->callback);
275262f27b2SOleksandr Tymoshenko 		mode = VCHIQ_BULK_MODE_CALLBACK;
276262f27b2SOleksandr Tymoshenko 		break;
277262f27b2SOleksandr Tymoshenko 	case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
278262f27b2SOleksandr Tymoshenko 	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
279262f27b2SOleksandr Tymoshenko 		mode = VCHIQ_BULK_MODE_BLOCKING;
280262f27b2SOleksandr Tymoshenko 		break;
281262f27b2SOleksandr Tymoshenko 	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
282262f27b2SOleksandr Tymoshenko 	case VCHI_FLAGS_NONE:
283262f27b2SOleksandr Tymoshenko 		mode = VCHIQ_BULK_MODE_NOCALLBACK;
284262f27b2SOleksandr Tymoshenko 		break;
285262f27b2SOleksandr Tymoshenko 	default:
286262f27b2SOleksandr Tymoshenko 		WARN(1, "unsupported message\n");
287262f27b2SOleksandr Tymoshenko 		return vchiq_status_to_vchi(VCHIQ_ERROR);
288262f27b2SOleksandr Tymoshenko 	}
289262f27b2SOleksandr Tymoshenko 
290262f27b2SOleksandr Tymoshenko 	status = vchiq_bulk_transmit(service->handle, data_src, data_size,
291262f27b2SOleksandr Tymoshenko 		bulk_handle, mode);
292262f27b2SOleksandr Tymoshenko 
293262f27b2SOleksandr Tymoshenko 	/* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
294262f27b2SOleksandr Tymoshenko 	** implement a retry mechanism since this function is supposed
295262f27b2SOleksandr Tymoshenko 	** to block until queued
296262f27b2SOleksandr Tymoshenko 	*/
297262f27b2SOleksandr Tymoshenko 	while (status == VCHIQ_RETRY) {
298262f27b2SOleksandr Tymoshenko 		msleep(1);
299262f27b2SOleksandr Tymoshenko 		status = vchiq_bulk_transmit(service->handle, data_src,
300262f27b2SOleksandr Tymoshenko 			data_size, bulk_handle, mode);
301262f27b2SOleksandr Tymoshenko 	}
302262f27b2SOleksandr Tymoshenko 
303262f27b2SOleksandr Tymoshenko 	return vchiq_status_to_vchi(status);
304262f27b2SOleksandr Tymoshenko }
305262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_bulk_queue_transmit);
306262f27b2SOleksandr Tymoshenko 
307262f27b2SOleksandr Tymoshenko /***********************************************************
308262f27b2SOleksandr Tymoshenko  * Name: vchi_msg_dequeue
309262f27b2SOleksandr Tymoshenko  *
310262f27b2SOleksandr Tymoshenko  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
311262f27b2SOleksandr Tymoshenko  *             void *data,
312262f27b2SOleksandr Tymoshenko  *             uint32_t max_data_size_to_read,
313262f27b2SOleksandr Tymoshenko  *             uint32_t *actual_msg_size
314262f27b2SOleksandr Tymoshenko  *             VCHI_FLAGS_T flags
315262f27b2SOleksandr Tymoshenko  *
316262f27b2SOleksandr Tymoshenko  * Description: Routine to dequeue a message into the supplied buffer
317262f27b2SOleksandr Tymoshenko  *
318262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
319262f27b2SOleksandr Tymoshenko  *
320262f27b2SOleksandr Tymoshenko  ***********************************************************/
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)321262f27b2SOleksandr Tymoshenko int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
322262f27b2SOleksandr Tymoshenko 	void *data,
323262f27b2SOleksandr Tymoshenko 	uint32_t max_data_size_to_read,
324262f27b2SOleksandr Tymoshenko 	uint32_t *actual_msg_size,
325262f27b2SOleksandr Tymoshenko 	VCHI_FLAGS_T flags)
326262f27b2SOleksandr Tymoshenko {
327262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
328262f27b2SOleksandr Tymoshenko 	VCHIQ_HEADER_T *header;
329262f27b2SOleksandr Tymoshenko 
330262f27b2SOleksandr Tymoshenko 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
331262f27b2SOleksandr Tymoshenko 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
332262f27b2SOleksandr Tymoshenko 
333262f27b2SOleksandr Tymoshenko 	if (flags == VCHI_FLAGS_NONE)
334262f27b2SOleksandr Tymoshenko 		if (vchiu_queue_is_empty(&service->queue))
335262f27b2SOleksandr Tymoshenko 			return -1;
336262f27b2SOleksandr Tymoshenko 
337262f27b2SOleksandr Tymoshenko 	header = vchiu_queue_pop(&service->queue);
338262f27b2SOleksandr Tymoshenko 
339262f27b2SOleksandr Tymoshenko 	memcpy(data, header->data, header->size < max_data_size_to_read ?
340262f27b2SOleksandr Tymoshenko 		header->size : max_data_size_to_read);
341262f27b2SOleksandr Tymoshenko 
342262f27b2SOleksandr Tymoshenko 	*actual_msg_size = header->size;
343262f27b2SOleksandr Tymoshenko 
344262f27b2SOleksandr Tymoshenko 	vchiq_release_message(service->handle, header);
345262f27b2SOleksandr Tymoshenko 
346262f27b2SOleksandr Tymoshenko 	return 0;
347262f27b2SOleksandr Tymoshenko }
348262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_msg_dequeue);
349262f27b2SOleksandr Tymoshenko 
350262f27b2SOleksandr Tymoshenko /***********************************************************
351262f27b2SOleksandr Tymoshenko  * Name: vchi_msg_queuev
352262f27b2SOleksandr Tymoshenko  *
353262f27b2SOleksandr Tymoshenko  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
354262f27b2SOleksandr Tymoshenko  *             VCHI_MSG_VECTOR_T *vector,
355262f27b2SOleksandr Tymoshenko  *             uint32_t count,
356262f27b2SOleksandr Tymoshenko  *             VCHI_FLAGS_T flags,
357262f27b2SOleksandr Tymoshenko  *             void *msg_handle
358262f27b2SOleksandr Tymoshenko  *
359262f27b2SOleksandr Tymoshenko  * Description: Thin wrapper to queue a message onto a connection
360262f27b2SOleksandr Tymoshenko  *
361262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
362262f27b2SOleksandr Tymoshenko  *
363262f27b2SOleksandr Tymoshenko  ***********************************************************/
364262f27b2SOleksandr Tymoshenko 
365262f27b2SOleksandr Tymoshenko vchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
366262f27b2SOleksandr Tymoshenko vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) ==
367262f27b2SOleksandr Tymoshenko 	offsetof(VCHIQ_ELEMENT_T, data));
368262f27b2SOleksandr Tymoshenko vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) ==
369262f27b2SOleksandr Tymoshenko 	offsetof(VCHIQ_ELEMENT_T, size));
370262f27b2SOleksandr Tymoshenko 
vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,VCHI_MSG_VECTOR_T * vector,uint32_t count,VCHI_FLAGS_T flags,void * msg_handle)371262f27b2SOleksandr Tymoshenko int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,
372262f27b2SOleksandr Tymoshenko 	VCHI_MSG_VECTOR_T *vector,
373262f27b2SOleksandr Tymoshenko 	uint32_t count,
374262f27b2SOleksandr Tymoshenko 	VCHI_FLAGS_T flags,
375262f27b2SOleksandr Tymoshenko 	void *msg_handle)
376262f27b2SOleksandr Tymoshenko {
377262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
378262f27b2SOleksandr Tymoshenko 
379262f27b2SOleksandr Tymoshenko 	(void)msg_handle;
380262f27b2SOleksandr Tymoshenko 
381262f27b2SOleksandr Tymoshenko 	WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
382262f27b2SOleksandr Tymoshenko 
383262f27b2SOleksandr Tymoshenko 	return vchiq_status_to_vchi(vchiq_queue_message(service->handle,
384262f27b2SOleksandr Tymoshenko 		(const VCHIQ_ELEMENT_T *)vector, count));
385262f27b2SOleksandr Tymoshenko }
386262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_msg_queuev);
387262f27b2SOleksandr Tymoshenko 
388262f27b2SOleksandr Tymoshenko /***********************************************************
389262f27b2SOleksandr Tymoshenko  * Name: vchi_held_msg_release
390262f27b2SOleksandr Tymoshenko  *
391262f27b2SOleksandr Tymoshenko  * Arguments:  VCHI_HELD_MSG_T *message
392262f27b2SOleksandr Tymoshenko  *
393262f27b2SOleksandr Tymoshenko  * Description: Routine to release a held message (after it has been read with
394262f27b2SOleksandr Tymoshenko  *              vchi_msg_hold)
395262f27b2SOleksandr Tymoshenko  *
396262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
397262f27b2SOleksandr Tymoshenko  *
398262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_held_msg_release(VCHI_HELD_MSG_T * message)399262f27b2SOleksandr Tymoshenko int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
400262f27b2SOleksandr Tymoshenko {
401262f27b2SOleksandr Tymoshenko 	vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service,
402262f27b2SOleksandr Tymoshenko 		(VCHIQ_HEADER_T *)message->message);
403262f27b2SOleksandr Tymoshenko 
404262f27b2SOleksandr Tymoshenko 	return 0;
405262f27b2SOleksandr Tymoshenko }
406a0b87461SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_held_msg_release);
407262f27b2SOleksandr Tymoshenko 
408262f27b2SOleksandr Tymoshenko /***********************************************************
409262f27b2SOleksandr Tymoshenko  * Name: vchi_msg_hold
410262f27b2SOleksandr Tymoshenko  *
411262f27b2SOleksandr Tymoshenko  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
412262f27b2SOleksandr Tymoshenko  *             void **data,
413262f27b2SOleksandr Tymoshenko  *             uint32_t *msg_size,
414262f27b2SOleksandr Tymoshenko  *             VCHI_FLAGS_T flags,
415262f27b2SOleksandr Tymoshenko  *             VCHI_HELD_MSG_T *message_handle
416262f27b2SOleksandr Tymoshenko  *
417262f27b2SOleksandr Tymoshenko  * Description: Routine to return a pointer to the current message (to allow
418262f27b2SOleksandr Tymoshenko  *              in place processing). The message is dequeued - don't forget
419262f27b2SOleksandr Tymoshenko  *              to release the message using vchi_held_msg_release when you're
420262f27b2SOleksandr Tymoshenko  *              finished.
421262f27b2SOleksandr Tymoshenko  *
422262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
423262f27b2SOleksandr Tymoshenko  *
424262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags,VCHI_HELD_MSG_T * message_handle)425262f27b2SOleksandr Tymoshenko int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
426262f27b2SOleksandr Tymoshenko 	void **data,
427262f27b2SOleksandr Tymoshenko 	uint32_t *msg_size,
428262f27b2SOleksandr Tymoshenko 	VCHI_FLAGS_T flags,
429262f27b2SOleksandr Tymoshenko 	VCHI_HELD_MSG_T *message_handle)
430262f27b2SOleksandr Tymoshenko {
431262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
432262f27b2SOleksandr Tymoshenko 	VCHIQ_HEADER_T *header;
433262f27b2SOleksandr Tymoshenko 
434262f27b2SOleksandr Tymoshenko 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
435262f27b2SOleksandr Tymoshenko 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
436262f27b2SOleksandr Tymoshenko 
437262f27b2SOleksandr Tymoshenko 	if (flags == VCHI_FLAGS_NONE)
438262f27b2SOleksandr Tymoshenko 		if (vchiu_queue_is_empty(&service->queue))
439262f27b2SOleksandr Tymoshenko 			return -1;
440262f27b2SOleksandr Tymoshenko 
441262f27b2SOleksandr Tymoshenko 	header = vchiu_queue_pop(&service->queue);
442262f27b2SOleksandr Tymoshenko 
443262f27b2SOleksandr Tymoshenko 	*data = header->data;
444262f27b2SOleksandr Tymoshenko 	*msg_size = header->size;
445262f27b2SOleksandr Tymoshenko 
446262f27b2SOleksandr Tymoshenko 	message_handle->service =
447262f27b2SOleksandr Tymoshenko 		(struct opaque_vchi_service_t *)service->handle;
448262f27b2SOleksandr Tymoshenko 	message_handle->message = header;
449262f27b2SOleksandr Tymoshenko 
450262f27b2SOleksandr Tymoshenko 	return 0;
451262f27b2SOleksandr Tymoshenko }
452a0b87461SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_msg_hold);
453262f27b2SOleksandr Tymoshenko 
454262f27b2SOleksandr Tymoshenko /***********************************************************
455262f27b2SOleksandr Tymoshenko  * Name: vchi_initialise
456262f27b2SOleksandr Tymoshenko  *
457262f27b2SOleksandr Tymoshenko  * Arguments: VCHI_INSTANCE_T *instance_handle
458262f27b2SOleksandr Tymoshenko  *
459262f27b2SOleksandr Tymoshenko  * Description: Initialises the hardware but does not transmit anything
460262f27b2SOleksandr Tymoshenko  *              When run as a Host App this will be called twice hence the need
461262f27b2SOleksandr Tymoshenko  *              to malloc the state information
462262f27b2SOleksandr Tymoshenko  *
463262f27b2SOleksandr Tymoshenko  * Returns: 0 if successful, failure otherwise
464262f27b2SOleksandr Tymoshenko  *
465262f27b2SOleksandr Tymoshenko  ***********************************************************/
466262f27b2SOleksandr Tymoshenko 
vchi_initialise(VCHI_INSTANCE_T * instance_handle)467262f27b2SOleksandr Tymoshenko int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
468262f27b2SOleksandr Tymoshenko {
469262f27b2SOleksandr Tymoshenko 	VCHIQ_INSTANCE_T instance;
470262f27b2SOleksandr Tymoshenko 	VCHIQ_STATUS_T status;
471262f27b2SOleksandr Tymoshenko 
472262f27b2SOleksandr Tymoshenko 	status = vchiq_initialise(&instance);
473262f27b2SOleksandr Tymoshenko 
474262f27b2SOleksandr Tymoshenko 	*instance_handle = (VCHI_INSTANCE_T)instance;
475262f27b2SOleksandr Tymoshenko 
476262f27b2SOleksandr Tymoshenko 	return vchiq_status_to_vchi(status);
477262f27b2SOleksandr Tymoshenko }
478262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_initialise);
479262f27b2SOleksandr Tymoshenko 
480262f27b2SOleksandr Tymoshenko /***********************************************************
481262f27b2SOleksandr Tymoshenko  * Name: vchi_connect
482262f27b2SOleksandr Tymoshenko  *
483262f27b2SOleksandr Tymoshenko  * Arguments: VCHI_CONNECTION_T **connections
484262f27b2SOleksandr Tymoshenko  *            const uint32_t num_connections
485262f27b2SOleksandr Tymoshenko  *            VCHI_INSTANCE_T instance_handle)
486262f27b2SOleksandr Tymoshenko  *
487262f27b2SOleksandr Tymoshenko  * Description: Starts the command service on each connection,
488262f27b2SOleksandr Tymoshenko  *              causing INIT messages to be pinged back and forth
489262f27b2SOleksandr Tymoshenko  *
490262f27b2SOleksandr Tymoshenko  * Returns: 0 if successful, failure otherwise
491262f27b2SOleksandr Tymoshenko  *
492262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_connect(VCHI_CONNECTION_T ** connections,const uint32_t num_connections,VCHI_INSTANCE_T instance_handle)493262f27b2SOleksandr Tymoshenko int32_t vchi_connect(VCHI_CONNECTION_T **connections,
494262f27b2SOleksandr Tymoshenko 	const uint32_t num_connections,
495262f27b2SOleksandr Tymoshenko 	VCHI_INSTANCE_T instance_handle)
496262f27b2SOleksandr Tymoshenko {
497262f27b2SOleksandr Tymoshenko 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
498262f27b2SOleksandr Tymoshenko 
499262f27b2SOleksandr Tymoshenko 	(void)connections;
500262f27b2SOleksandr Tymoshenko 	(void)num_connections;
501262f27b2SOleksandr Tymoshenko 
502262f27b2SOleksandr Tymoshenko 	return vchiq_connect(instance);
503262f27b2SOleksandr Tymoshenko }
504262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_connect);
505262f27b2SOleksandr Tymoshenko 
506262f27b2SOleksandr Tymoshenko 
507262f27b2SOleksandr Tymoshenko /***********************************************************
508262f27b2SOleksandr Tymoshenko  * Name: vchi_disconnect
509262f27b2SOleksandr Tymoshenko  *
510262f27b2SOleksandr Tymoshenko  * Arguments: VCHI_INSTANCE_T instance_handle
511262f27b2SOleksandr Tymoshenko  *
512262f27b2SOleksandr Tymoshenko  * Description: Stops the command service on each connection,
513262f27b2SOleksandr Tymoshenko  *              causing DE-INIT messages to be pinged back and forth
514262f27b2SOleksandr Tymoshenko  *
515262f27b2SOleksandr Tymoshenko  * Returns: 0 if successful, failure otherwise
516262f27b2SOleksandr Tymoshenko  *
517262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_disconnect(VCHI_INSTANCE_T instance_handle)518262f27b2SOleksandr Tymoshenko int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
519262f27b2SOleksandr Tymoshenko {
520262f27b2SOleksandr Tymoshenko 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
521262f27b2SOleksandr Tymoshenko 	return vchiq_status_to_vchi(vchiq_shutdown(instance));
522262f27b2SOleksandr Tymoshenko }
523262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_disconnect);
524262f27b2SOleksandr Tymoshenko 
525262f27b2SOleksandr Tymoshenko 
526262f27b2SOleksandr Tymoshenko /***********************************************************
527262f27b2SOleksandr Tymoshenko  * Name: vchi_service_open
528262f27b2SOleksandr Tymoshenko  * Name: vchi_service_create
529262f27b2SOleksandr Tymoshenko  *
530262f27b2SOleksandr Tymoshenko  * Arguments: VCHI_INSTANCE_T *instance_handle
531262f27b2SOleksandr Tymoshenko  *            SERVICE_CREATION_T *setup,
532262f27b2SOleksandr Tymoshenko  *            VCHI_SERVICE_HANDLE_T *handle
533262f27b2SOleksandr Tymoshenko  *
534262f27b2SOleksandr Tymoshenko  * Description: Routine to open a service
535262f27b2SOleksandr Tymoshenko  *
536262f27b2SOleksandr Tymoshenko  * Returns: int32_t - success == 0
537262f27b2SOleksandr Tymoshenko  *
538262f27b2SOleksandr Tymoshenko  ***********************************************************/
539262f27b2SOleksandr Tymoshenko 
shim_callback(VCHIQ_REASON_T reason,VCHIQ_HEADER_T * header,VCHIQ_SERVICE_HANDLE_T handle,void * bulk_user)540262f27b2SOleksandr Tymoshenko static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
541262f27b2SOleksandr Tymoshenko 	VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
542262f27b2SOleksandr Tymoshenko {
543262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service =
544262f27b2SOleksandr Tymoshenko 		(SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
545262f27b2SOleksandr Tymoshenko 
546262f27b2SOleksandr Tymoshenko         if (!service->callback)
547262f27b2SOleksandr Tymoshenko 		goto release;
548262f27b2SOleksandr Tymoshenko 
549262f27b2SOleksandr Tymoshenko 	switch (reason) {
550262f27b2SOleksandr Tymoshenko 	case VCHIQ_MESSAGE_AVAILABLE:
551262f27b2SOleksandr Tymoshenko 		vchiu_queue_push(&service->queue, header);
552262f27b2SOleksandr Tymoshenko 
553262f27b2SOleksandr Tymoshenko 		service->callback(service->callback_param,
554262f27b2SOleksandr Tymoshenko 				  VCHI_CALLBACK_MSG_AVAILABLE, NULL);
555262f27b2SOleksandr Tymoshenko 
556262f27b2SOleksandr Tymoshenko 		goto done;
557262f27b2SOleksandr Tymoshenko 		break;
558262f27b2SOleksandr Tymoshenko 
559262f27b2SOleksandr Tymoshenko 	case VCHIQ_BULK_TRANSMIT_DONE:
560262f27b2SOleksandr Tymoshenko 		service->callback(service->callback_param,
561262f27b2SOleksandr Tymoshenko 				  VCHI_CALLBACK_BULK_SENT, bulk_user);
562262f27b2SOleksandr Tymoshenko 		break;
563262f27b2SOleksandr Tymoshenko 
564262f27b2SOleksandr Tymoshenko 	case VCHIQ_BULK_RECEIVE_DONE:
565262f27b2SOleksandr Tymoshenko 		service->callback(service->callback_param,
566262f27b2SOleksandr Tymoshenko 				  VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
567262f27b2SOleksandr Tymoshenko 		break;
568262f27b2SOleksandr Tymoshenko 
569262f27b2SOleksandr Tymoshenko 	case VCHIQ_SERVICE_CLOSED:
570262f27b2SOleksandr Tymoshenko 		service->callback(service->callback_param,
571262f27b2SOleksandr Tymoshenko 				  VCHI_CALLBACK_SERVICE_CLOSED, NULL);
572262f27b2SOleksandr Tymoshenko 		break;
573262f27b2SOleksandr Tymoshenko 
574262f27b2SOleksandr Tymoshenko 	case VCHIQ_SERVICE_OPENED:
575262f27b2SOleksandr Tymoshenko 		/* No equivalent VCHI reason */
576262f27b2SOleksandr Tymoshenko 		break;
577262f27b2SOleksandr Tymoshenko 
578262f27b2SOleksandr Tymoshenko 	case VCHIQ_BULK_TRANSMIT_ABORTED:
579262f27b2SOleksandr Tymoshenko 		service->callback(service->callback_param,
580262f27b2SOleksandr Tymoshenko 				  VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
581262f27b2SOleksandr Tymoshenko 				  bulk_user);
582262f27b2SOleksandr Tymoshenko 		break;
583262f27b2SOleksandr Tymoshenko 
584262f27b2SOleksandr Tymoshenko 	case VCHIQ_BULK_RECEIVE_ABORTED:
585262f27b2SOleksandr Tymoshenko 		service->callback(service->callback_param,
586262f27b2SOleksandr Tymoshenko 				  VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
587262f27b2SOleksandr Tymoshenko 				  bulk_user);
588262f27b2SOleksandr Tymoshenko 		break;
589262f27b2SOleksandr Tymoshenko 
590262f27b2SOleksandr Tymoshenko 	default:
591262f27b2SOleksandr Tymoshenko 		WARN(1, "not supported\n");
592262f27b2SOleksandr Tymoshenko 		break;
593262f27b2SOleksandr Tymoshenko 	}
594262f27b2SOleksandr Tymoshenko 
595262f27b2SOleksandr Tymoshenko release:
596262f27b2SOleksandr Tymoshenko         vchiq_release_message(service->handle, header);
597262f27b2SOleksandr Tymoshenko done:
598262f27b2SOleksandr Tymoshenko 	return VCHIQ_SUCCESS;
599262f27b2SOleksandr Tymoshenko }
600262f27b2SOleksandr Tymoshenko 
service_alloc(VCHIQ_INSTANCE_T instance,SERVICE_CREATION_T * setup)601262f27b2SOleksandr Tymoshenko static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
602262f27b2SOleksandr Tymoshenko 	SERVICE_CREATION_T *setup)
603262f27b2SOleksandr Tymoshenko {
604262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL);
605262f27b2SOleksandr Tymoshenko 
606262f27b2SOleksandr Tymoshenko 	(void)instance;
607262f27b2SOleksandr Tymoshenko 
608262f27b2SOleksandr Tymoshenko 	if (service) {
609262f27b2SOleksandr Tymoshenko 		if (vchiu_queue_init(&service->queue, 64)) {
610262f27b2SOleksandr Tymoshenko 			service->callback = setup->callback;
611262f27b2SOleksandr Tymoshenko 			service->callback_param = setup->callback_param;
612262f27b2SOleksandr Tymoshenko 		} else {
613262f27b2SOleksandr Tymoshenko 			kfree(service);
614262f27b2SOleksandr Tymoshenko 			service = NULL;
615262f27b2SOleksandr Tymoshenko 		}
616262f27b2SOleksandr Tymoshenko 	}
617262f27b2SOleksandr Tymoshenko 
618262f27b2SOleksandr Tymoshenko 	return service;
619262f27b2SOleksandr Tymoshenko }
620262f27b2SOleksandr Tymoshenko 
service_free(SHIM_SERVICE_T * service)621262f27b2SOleksandr Tymoshenko static void service_free(SHIM_SERVICE_T *service)
622262f27b2SOleksandr Tymoshenko {
623262f27b2SOleksandr Tymoshenko 	if (service) {
624262f27b2SOleksandr Tymoshenko 		vchiu_queue_delete(&service->queue);
625262f27b2SOleksandr Tymoshenko 		kfree(service);
626262f27b2SOleksandr Tymoshenko 	}
627262f27b2SOleksandr Tymoshenko }
628262f27b2SOleksandr Tymoshenko 
vchi_service_open(VCHI_INSTANCE_T instance_handle,SERVICE_CREATION_T * setup,VCHI_SERVICE_HANDLE_T * handle)629262f27b2SOleksandr Tymoshenko int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
630262f27b2SOleksandr Tymoshenko 	SERVICE_CREATION_T *setup,
631262f27b2SOleksandr Tymoshenko 	VCHI_SERVICE_HANDLE_T *handle)
632262f27b2SOleksandr Tymoshenko {
633262f27b2SOleksandr Tymoshenko 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
634262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = service_alloc(instance, setup);
635262f27b2SOleksandr Tymoshenko 
636262f27b2SOleksandr Tymoshenko 	*handle = (VCHI_SERVICE_HANDLE_T)service;
637262f27b2SOleksandr Tymoshenko 
638262f27b2SOleksandr Tymoshenko 	if (service) {
639262f27b2SOleksandr Tymoshenko 		VCHIQ_SERVICE_PARAMS_T params;
640262f27b2SOleksandr Tymoshenko 		VCHIQ_STATUS_T status;
641262f27b2SOleksandr Tymoshenko 
642262f27b2SOleksandr Tymoshenko 		memset(&params, 0, sizeof(params));
643262f27b2SOleksandr Tymoshenko 		params.fourcc = setup->service_id;
644262f27b2SOleksandr Tymoshenko 		params.callback = shim_callback;
645262f27b2SOleksandr Tymoshenko 		params.userdata = service;
646262f27b2SOleksandr Tymoshenko 		params.version = setup->version.version;
647262f27b2SOleksandr Tymoshenko 		params.version_min = setup->version.version_min;
648262f27b2SOleksandr Tymoshenko 
649262f27b2SOleksandr Tymoshenko 		status = vchiq_open_service(instance, &params,
650262f27b2SOleksandr Tymoshenko 			&service->handle);
651262f27b2SOleksandr Tymoshenko 		if (status != VCHIQ_SUCCESS) {
652262f27b2SOleksandr Tymoshenko 			service_free(service);
653262f27b2SOleksandr Tymoshenko 			service = NULL;
654262f27b2SOleksandr Tymoshenko 			*handle = NULL;
655262f27b2SOleksandr Tymoshenko 		}
656262f27b2SOleksandr Tymoshenko 	}
657262f27b2SOleksandr Tymoshenko 
658262f27b2SOleksandr Tymoshenko 	return (service != NULL) ? 0 : -1;
659262f27b2SOleksandr Tymoshenko }
660262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_service_open);
661262f27b2SOleksandr Tymoshenko 
vchi_service_create(VCHI_INSTANCE_T instance_handle,SERVICE_CREATION_T * setup,VCHI_SERVICE_HANDLE_T * handle)662262f27b2SOleksandr Tymoshenko int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
663262f27b2SOleksandr Tymoshenko 	SERVICE_CREATION_T *setup,
664262f27b2SOleksandr Tymoshenko 	VCHI_SERVICE_HANDLE_T *handle)
665262f27b2SOleksandr Tymoshenko {
666262f27b2SOleksandr Tymoshenko 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
667262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = service_alloc(instance, setup);
668262f27b2SOleksandr Tymoshenko 
669262f27b2SOleksandr Tymoshenko 	*handle = (VCHI_SERVICE_HANDLE_T)service;
670262f27b2SOleksandr Tymoshenko 
671262f27b2SOleksandr Tymoshenko 	if (service) {
672262f27b2SOleksandr Tymoshenko 		VCHIQ_SERVICE_PARAMS_T params;
673262f27b2SOleksandr Tymoshenko 		VCHIQ_STATUS_T status;
674262f27b2SOleksandr Tymoshenko 
675262f27b2SOleksandr Tymoshenko 		memset(&params, 0, sizeof(params));
676262f27b2SOleksandr Tymoshenko 		params.fourcc = setup->service_id;
677262f27b2SOleksandr Tymoshenko 		params.callback = shim_callback;
678262f27b2SOleksandr Tymoshenko 		params.userdata = service;
679262f27b2SOleksandr Tymoshenko 		params.version = setup->version.version;
680262f27b2SOleksandr Tymoshenko 		params.version_min = setup->version.version_min;
681262f27b2SOleksandr Tymoshenko 		status = vchiq_add_service(instance, &params, &service->handle);
682262f27b2SOleksandr Tymoshenko 
683262f27b2SOleksandr Tymoshenko 		if (status != VCHIQ_SUCCESS) {
684262f27b2SOleksandr Tymoshenko 			service_free(service);
685262f27b2SOleksandr Tymoshenko 			service = NULL;
686262f27b2SOleksandr Tymoshenko 			*handle = NULL;
687262f27b2SOleksandr Tymoshenko 		}
688262f27b2SOleksandr Tymoshenko 	}
689262f27b2SOleksandr Tymoshenko 
690262f27b2SOleksandr Tymoshenko 	return (service != NULL) ? 0 : -1;
691262f27b2SOleksandr Tymoshenko }
692262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_service_create);
693262f27b2SOleksandr Tymoshenko 
vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)694262f27b2SOleksandr Tymoshenko int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
695262f27b2SOleksandr Tymoshenko {
696262f27b2SOleksandr Tymoshenko 	int32_t ret = -1;
697262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
698262f27b2SOleksandr Tymoshenko 	if (service) {
699262f27b2SOleksandr Tymoshenko 		VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
700262f27b2SOleksandr Tymoshenko 		if (status == VCHIQ_SUCCESS) {
701262f27b2SOleksandr Tymoshenko 			service_free(service);
702262f27b2SOleksandr Tymoshenko 			service = NULL;
703262f27b2SOleksandr Tymoshenko 		}
704262f27b2SOleksandr Tymoshenko 
705262f27b2SOleksandr Tymoshenko 		ret = vchiq_status_to_vchi(status);
706262f27b2SOleksandr Tymoshenko 	}
707262f27b2SOleksandr Tymoshenko 	return ret;
708262f27b2SOleksandr Tymoshenko }
709262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_service_close);
710262f27b2SOleksandr Tymoshenko 
vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)711262f27b2SOleksandr Tymoshenko int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
712262f27b2SOleksandr Tymoshenko {
713262f27b2SOleksandr Tymoshenko 	int32_t ret = -1;
714262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
715262f27b2SOleksandr Tymoshenko 	if (service) {
716262f27b2SOleksandr Tymoshenko 		VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
717262f27b2SOleksandr Tymoshenko 		if (status == VCHIQ_SUCCESS) {
718262f27b2SOleksandr Tymoshenko 			service_free(service);
719262f27b2SOleksandr Tymoshenko 			service = NULL;
720262f27b2SOleksandr Tymoshenko 		}
721262f27b2SOleksandr Tymoshenko 
722262f27b2SOleksandr Tymoshenko 		ret = vchiq_status_to_vchi(status);
723262f27b2SOleksandr Tymoshenko 	}
724262f27b2SOleksandr Tymoshenko 	return ret;
725262f27b2SOleksandr Tymoshenko }
726262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_service_destroy);
727262f27b2SOleksandr Tymoshenko 
vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,VCHI_SERVICE_OPTION_T option,int value)728a0b87461SOleksandr Tymoshenko int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
729a0b87461SOleksandr Tymoshenko 				VCHI_SERVICE_OPTION_T option,
730a0b87461SOleksandr Tymoshenko 				int value)
731a0b87461SOleksandr Tymoshenko {
732a0b87461SOleksandr Tymoshenko 	int32_t ret = -1;
733a0b87461SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
734a0b87461SOleksandr Tymoshenko 	VCHIQ_SERVICE_OPTION_T vchiq_option;
735a0b87461SOleksandr Tymoshenko 	switch (option) {
736a0b87461SOleksandr Tymoshenko 	case VCHI_SERVICE_OPTION_TRACE:
737a0b87461SOleksandr Tymoshenko 		vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
738a0b87461SOleksandr Tymoshenko 		break;
739a0b87461SOleksandr Tymoshenko 	case VCHI_SERVICE_OPTION_SYNCHRONOUS:
740a0b87461SOleksandr Tymoshenko 		vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
741a0b87461SOleksandr Tymoshenko 		break;
742a0b87461SOleksandr Tymoshenko 	default:
743a0b87461SOleksandr Tymoshenko 		service = NULL;
744a0b87461SOleksandr Tymoshenko 		break;
745a0b87461SOleksandr Tymoshenko 	}
746a0b87461SOleksandr Tymoshenko 	if (service) {
747a0b87461SOleksandr Tymoshenko 		VCHIQ_STATUS_T status =
748a0b87461SOleksandr Tymoshenko 			vchiq_set_service_option(service->handle,
749a0b87461SOleksandr Tymoshenko 						vchiq_option,
750a0b87461SOleksandr Tymoshenko 						value);
751a0b87461SOleksandr Tymoshenko 
752a0b87461SOleksandr Tymoshenko 		ret = vchiq_status_to_vchi(status);
753a0b87461SOleksandr Tymoshenko 	}
754a0b87461SOleksandr Tymoshenko 	return ret;
755a0b87461SOleksandr Tymoshenko }
756a0b87461SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_service_set_option);
757a0b87461SOleksandr Tymoshenko 
vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle,short * peer_version)758262f27b2SOleksandr Tymoshenko int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version )
759262f27b2SOleksandr Tymoshenko {
760262f27b2SOleksandr Tymoshenko    int32_t ret = -1;
761262f27b2SOleksandr Tymoshenko    SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
762262f27b2SOleksandr Tymoshenko    if(service)
763262f27b2SOleksandr Tymoshenko    {
764262f27b2SOleksandr Tymoshenko       VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version);
765262f27b2SOleksandr Tymoshenko       ret = vchiq_status_to_vchi( status );
766262f27b2SOleksandr Tymoshenko    }
767262f27b2SOleksandr Tymoshenko    return ret;
768262f27b2SOleksandr Tymoshenko }
769262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_get_peer_version);
770262f27b2SOleksandr Tymoshenko 
771262f27b2SOleksandr Tymoshenko #ifdef notyet
772262f27b2SOleksandr Tymoshenko /* ----------------------------------------------------------------------
773262f27b2SOleksandr Tymoshenko  * read a uint32_t from buffer.
774262f27b2SOleksandr Tymoshenko  * network format is defined to be little endian
775262f27b2SOleksandr Tymoshenko  * -------------------------------------------------------------------- */
776262f27b2SOleksandr Tymoshenko uint32_t
vchi_readbuf_uint32(const void * _ptr)777262f27b2SOleksandr Tymoshenko vchi_readbuf_uint32(const void *_ptr)
778262f27b2SOleksandr Tymoshenko {
779262f27b2SOleksandr Tymoshenko 	const unsigned char *ptr = _ptr;
780262f27b2SOleksandr Tymoshenko 	return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
781262f27b2SOleksandr Tymoshenko }
782262f27b2SOleksandr Tymoshenko 
783262f27b2SOleksandr Tymoshenko /* ----------------------------------------------------------------------
784262f27b2SOleksandr Tymoshenko  * write a uint32_t to buffer.
785262f27b2SOleksandr Tymoshenko  * network format is defined to be little endian
786262f27b2SOleksandr Tymoshenko  * -------------------------------------------------------------------- */
787262f27b2SOleksandr Tymoshenko void
vchi_writebuf_uint32(void * _ptr,uint32_t value)788262f27b2SOleksandr Tymoshenko vchi_writebuf_uint32(void *_ptr, uint32_t value)
789262f27b2SOleksandr Tymoshenko {
790262f27b2SOleksandr Tymoshenko 	unsigned char *ptr = _ptr;
791262f27b2SOleksandr Tymoshenko 	ptr[0] = (unsigned char)((value >> 0)  & 0xFF);
792262f27b2SOleksandr Tymoshenko 	ptr[1] = (unsigned char)((value >> 8)  & 0xFF);
793262f27b2SOleksandr Tymoshenko 	ptr[2] = (unsigned char)((value >> 16) & 0xFF);
794262f27b2SOleksandr Tymoshenko 	ptr[3] = (unsigned char)((value >> 24) & 0xFF);
795262f27b2SOleksandr Tymoshenko }
796262f27b2SOleksandr Tymoshenko 
797262f27b2SOleksandr Tymoshenko /* ----------------------------------------------------------------------
798262f27b2SOleksandr Tymoshenko  * read a uint16_t from buffer.
799262f27b2SOleksandr Tymoshenko  * network format is defined to be little endian
800262f27b2SOleksandr Tymoshenko  * -------------------------------------------------------------------- */
801262f27b2SOleksandr Tymoshenko uint16_t
vchi_readbuf_uint16(const void * _ptr)802262f27b2SOleksandr Tymoshenko vchi_readbuf_uint16(const void *_ptr)
803262f27b2SOleksandr Tymoshenko {
804262f27b2SOleksandr Tymoshenko 	const unsigned char *ptr = _ptr;
805262f27b2SOleksandr Tymoshenko 	return ptr[0] | (ptr[1] << 8);
806262f27b2SOleksandr Tymoshenko }
807262f27b2SOleksandr Tymoshenko 
808262f27b2SOleksandr Tymoshenko /* ----------------------------------------------------------------------
809262f27b2SOleksandr Tymoshenko  * write a uint16_t into the buffer.
810262f27b2SOleksandr Tymoshenko  * network format is defined to be little endian
811262f27b2SOleksandr Tymoshenko  * -------------------------------------------------------------------- */
812262f27b2SOleksandr Tymoshenko void
vchi_writebuf_uint16(void * _ptr,uint16_t value)813262f27b2SOleksandr Tymoshenko vchi_writebuf_uint16(void *_ptr, uint16_t value)
814262f27b2SOleksandr Tymoshenko {
815262f27b2SOleksandr Tymoshenko 	unsigned char *ptr = _ptr;
816262f27b2SOleksandr Tymoshenko 	ptr[0] = (value >> 0)  & 0xFF;
817262f27b2SOleksandr Tymoshenko 	ptr[1] = (value >> 8)  & 0xFF;
818262f27b2SOleksandr Tymoshenko }
819262f27b2SOleksandr Tymoshenko #endif
820262f27b2SOleksandr Tymoshenko 
821262f27b2SOleksandr Tymoshenko /***********************************************************
822262f27b2SOleksandr Tymoshenko  * Name: vchi_service_use
823262f27b2SOleksandr Tymoshenko  *
824262f27b2SOleksandr Tymoshenko  * Arguments: const VCHI_SERVICE_HANDLE_T handle
825262f27b2SOleksandr Tymoshenko  *
826262f27b2SOleksandr Tymoshenko  * Description: Routine to increment refcount on a service
827262f27b2SOleksandr Tymoshenko  *
828262f27b2SOleksandr Tymoshenko  * Returns: void
829262f27b2SOleksandr Tymoshenko  *
830262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)831262f27b2SOleksandr Tymoshenko int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
832262f27b2SOleksandr Tymoshenko {
833262f27b2SOleksandr Tymoshenko 	int32_t ret = -1;
834262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
835262f27b2SOleksandr Tymoshenko 	if (service)
836262f27b2SOleksandr Tymoshenko 		ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
837262f27b2SOleksandr Tymoshenko 	return ret;
838262f27b2SOleksandr Tymoshenko }
839262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_service_use);
840262f27b2SOleksandr Tymoshenko 
841262f27b2SOleksandr Tymoshenko /***********************************************************
842262f27b2SOleksandr Tymoshenko  * Name: vchi_service_release
843262f27b2SOleksandr Tymoshenko  *
844262f27b2SOleksandr Tymoshenko  * Arguments: const VCHI_SERVICE_HANDLE_T handle
845262f27b2SOleksandr Tymoshenko  *
846262f27b2SOleksandr Tymoshenko  * Description: Routine to decrement refcount on a service
847262f27b2SOleksandr Tymoshenko  *
848262f27b2SOleksandr Tymoshenko  * Returns: void
849262f27b2SOleksandr Tymoshenko  *
850262f27b2SOleksandr Tymoshenko  ***********************************************************/
vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)851262f27b2SOleksandr Tymoshenko int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
852262f27b2SOleksandr Tymoshenko {
853262f27b2SOleksandr Tymoshenko 	int32_t ret = -1;
854262f27b2SOleksandr Tymoshenko 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
855262f27b2SOleksandr Tymoshenko 	if (service)
856262f27b2SOleksandr Tymoshenko 		ret = vchiq_status_to_vchi(
857262f27b2SOleksandr Tymoshenko 			vchiq_release_service(service->handle));
858262f27b2SOleksandr Tymoshenko 	return ret;
859262f27b2SOleksandr Tymoshenko }
860262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchi_service_release);
861