vchiq_shim.c revision 290245
1345153Sdim/**
2345153Sdim * Copyright (c) 2010-2012 Broadcom. All rights reserved.
3345153Sdim *
4345153Sdim * Redistribution and use in source and binary forms, with or without
5345153Sdim * modification, are permitted provided that the following conditions
6345153Sdim * are met:
7353358Sdim * 1. Redistributions of source code must retain the above copyright
8353358Sdim *    notice, this list of conditions, and the following disclaimer,
9353358Sdim *    without modification.
10345153Sdim * 2. Redistributions in binary form must reproduce the above copyright
11345153Sdim *    notice, this list of conditions and the following disclaimer in the
12345153Sdim *    documentation and/or other materials provided with the distribution.
13345153Sdim * 3. The names of the above-listed copyright holders may not be used
14345153Sdim *    to endorse or promote products derived from this software without
15345153Sdim *    specific prior written permission.
16345153Sdim *
17345153Sdim * ALTERNATIVELY, this software may be distributed under the terms of the
18345153Sdim * GNU General Public License ("GPL") version 2, as published by the Free
19345153Sdim * Software Foundation.
20345153Sdim *
21345153Sdim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22345153Sdim * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23345153Sdim * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24345153Sdim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25345153Sdim * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26345153Sdim * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27345153Sdim * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28345153Sdim * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29345153Sdim * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30345153Sdim * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31353358Sdim * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32345153Sdim */
33345153Sdim
34345153Sdim#include <interface/compat/vchi_bsd.h>
35345153Sdim
36345153Sdim#include "interface/vchi/vchi.h"
37345153Sdim#include "vchiq.h"
38345153Sdim#include "vchiq_core.h"
39345153Sdim
40345153Sdim#include "vchiq_util.h"
41345153Sdim
42345153Sdim#define vchiq_status_to_vchi(status) ((int32_t)status)
43345153Sdim
44345153Sdimtypedef struct {
45345153Sdim	VCHIQ_SERVICE_HANDLE_T handle;
46345153Sdim
47345153Sdim	VCHIU_QUEUE_T queue;
48345153Sdim
49345153Sdim	VCHI_CALLBACK_T callback;
50345153Sdim	void *callback_param;
51345153Sdim} SHIM_SERVICE_T;
52345153Sdim
53345153Sdim/* ----------------------------------------------------------------------
54345153Sdim * return pointer to the mphi message driver function table
55345153Sdim * -------------------------------------------------------------------- */
56345153Sdimconst VCHI_MESSAGE_DRIVER_T *
57345153Sdimvchi_mphi_message_driver_func_table(void)
58345153Sdim{
59345153Sdim	return NULL;
60345153Sdim}
61345153Sdim
62345153Sdim/* ----------------------------------------------------------------------
63345153Sdim * return a pointer to the 'single' connection driver fops
64345153Sdim * -------------------------------------------------------------------- */
65345153Sdimconst VCHI_CONNECTION_API_T *
66345153Sdimsingle_get_func_table(void)
67345153Sdim{
68345153Sdim	return NULL;
69345153Sdim}
70345153Sdim
71345153SdimVCHI_CONNECTION_T *vchi_create_connection(
72345153Sdim	const VCHI_CONNECTION_API_T *function_table,
73345153Sdim	const VCHI_MESSAGE_DRIVER_T *low_level)
74345153Sdim{
75345153Sdim	(void)function_table;
76345153Sdim	(void)low_level;
77345153Sdim	return NULL;
78345153Sdim}
79345153Sdim
80345153Sdim/***********************************************************
81345153Sdim * Name: vchi_msg_peek
82345153Sdim *
83345153Sdim * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
84345153Sdim *             void **data,
85345153Sdim *             uint32_t *msg_size,
86345153Sdim
87345153Sdim
88345153Sdim *             VCHI_FLAGS_T flags
89345153Sdim *
90345153Sdim * Description: Routine to return a pointer to the current message (to allow in
91345153Sdim *              place processing). The message can be removed using
92345153Sdim *              vchi_msg_remove when you're finished
93345153Sdim *
94345153Sdim * Returns: int32_t - success == 0
95345153Sdim *
96345153Sdim ***********************************************************/
97345153Sdimint32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
98345153Sdim	void **data,
99345153Sdim	uint32_t *msg_size,
100345153Sdim	VCHI_FLAGS_T flags)
101345153Sdim{
102345153Sdim	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
103345153Sdim	VCHIQ_HEADER_T *header;
104345153Sdim
105345153Sdim	WARN_ON((flags != VCHI_FLAGS_NONE) &&
106345153Sdim		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
107345153Sdim
108345153Sdim	if (flags == VCHI_FLAGS_NONE)
109345153Sdim		if (vchiu_queue_is_empty(&service->queue))
110345153Sdim			return -1;
111345153Sdim
112345153Sdim	header = vchiu_queue_peek(&service->queue);
113345153Sdim
114345153Sdim	*data = header->data;
115345153Sdim	*msg_size = header->size;
116345153Sdim
117345153Sdim	return 0;
118345153Sdim}
119345153SdimEXPORT_SYMBOL(vchi_msg_peek);
120345153Sdim
121345153Sdim/***********************************************************
122345153Sdim * Name: vchi_msg_remove
123345153Sdim *
124345153Sdim * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
125345153Sdim *
126345153Sdim * Description: Routine to remove a message (after it has been read with
127345153Sdim *              vchi_msg_peek)
128345153Sdim *
129345153Sdim * Returns: int32_t - success == 0
130345153Sdim *
131345153Sdim ***********************************************************/
132345153Sdimint32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
133345153Sdim{
134345153Sdim	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
135345153Sdim	VCHIQ_HEADER_T *header;
136345153Sdim
137345153Sdim	header = vchiu_queue_pop(&service->queue);
138345153Sdim
139345153Sdim	vchiq_release_message(service->handle, header);
140345153Sdim
141345153Sdim	return 0;
142345153Sdim}
143345153SdimEXPORT_SYMBOL(vchi_msg_remove);
144345153Sdim
145345153Sdim/***********************************************************
146345153Sdim * Name: vchi_msg_queue
147345153Sdim *
148345153Sdim * Arguments:  VCHI_SERVICE_HANDLE_T handle,
149345153Sdim *             const void *data,
150345153Sdim *             uint32_t data_size,
151345153Sdim *             VCHI_FLAGS_T flags,
152345153Sdim *             void *msg_handle,
153345153Sdim *
154345153Sdim * Description: Thin wrapper to queue a message onto a connection
155345153Sdim *
156345153Sdim * Returns: int32_t - success == 0
157345153Sdim *
158345153Sdim ***********************************************************/
159345153Sdimint32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
160345153Sdim	const void *data,
161345153Sdim	uint32_t data_size,
162345153Sdim	VCHI_FLAGS_T flags,
163345153Sdim	void *msg_handle)
164345153Sdim{
165345153Sdim	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
166345153Sdim	VCHIQ_ELEMENT_T element = {data, data_size};
167345153Sdim	VCHIQ_STATUS_T status;
168345153Sdim
169345153Sdim	(void)msg_handle;
170345153Sdim
171345153Sdim	WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
172345153Sdim
173345153Sdim	status = vchiq_queue_message(service->handle, &element, 1);
174345153Sdim
175345153Sdim	/* vchiq_queue_message() may return VCHIQ_RETRY, so we need to
176345153Sdim	** implement a retry mechanism since this function is supposed
177345153Sdim	** to block until queued
178345153Sdim	*/
179345153Sdim	while (status == VCHIQ_RETRY) {
180345153Sdim		msleep(1);
181345153Sdim		status = vchiq_queue_message(service->handle, &element, 1);
182345153Sdim	}
183345153Sdim
184345153Sdim	return vchiq_status_to_vchi(status);
185345153Sdim}
186345153SdimEXPORT_SYMBOL(vchi_msg_queue);
187345153Sdim
188345153Sdim/***********************************************************
189345153Sdim * Name: vchi_bulk_queue_receive
190345153Sdim *
191345153Sdim * Arguments:  VCHI_BULK_HANDLE_T handle,
192345153Sdim *             void *data_dst,
193345153Sdim *             const uint32_t data_size,
194345153Sdim *             VCHI_FLAGS_T flags
195345153Sdim *             void *bulk_handle
196345153Sdim *
197345153Sdim * Description: Routine to setup a rcv buffer
198345153Sdim *
199345153Sdim * Returns: int32_t - success == 0
200345153Sdim *
201345153Sdim ***********************************************************/
202345153Sdimint32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
203345153Sdim	void *data_dst,
204345153Sdim	uint32_t data_size,
205345153Sdim	VCHI_FLAGS_T flags,
206345153Sdim	void *bulk_handle)
207345153Sdim{
208345153Sdim	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
209345153Sdim	VCHIQ_BULK_MODE_T mode;
210345153Sdim	VCHIQ_STATUS_T status;
211345153Sdim
212345153Sdim	switch ((int)flags) {
213345153Sdim	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
214345153Sdim		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
215353358Sdim		WARN_ON(!service->callback);
216345153Sdim		mode = VCHIQ_BULK_MODE_CALLBACK;
217345153Sdim		break;
218345153Sdim	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
219345153Sdim		mode = VCHIQ_BULK_MODE_BLOCKING;
220345153Sdim		break;
221345153Sdim	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
222345153Sdim	case VCHI_FLAGS_NONE:
223345153Sdim		mode = VCHIQ_BULK_MODE_NOCALLBACK;
224345153Sdim		break;
225345153Sdim	default:
226345153Sdim		WARN(1, "unsupported message\n");
227345153Sdim		return vchiq_status_to_vchi(VCHIQ_ERROR);
228345153Sdim	}
229345153Sdim
230345153Sdim	status = vchiq_bulk_receive(service->handle, data_dst, data_size,
231345153Sdim		bulk_handle, mode);
232345153Sdim
233345153Sdim	/* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
234345153Sdim	** implement a retry mechanism since this function is supposed
235345153Sdim	** to block until queued
236345153Sdim	*/
237345153Sdim	while (status == VCHIQ_RETRY) {
238345153Sdim		msleep(1);
239345153Sdim		status = vchiq_bulk_receive(service->handle, data_dst,
240345153Sdim			data_size, bulk_handle, mode);
241345153Sdim	}
242345153Sdim
243345153Sdim	return vchiq_status_to_vchi(status);
244345153Sdim}
245345153SdimEXPORT_SYMBOL(vchi_bulk_queue_receive);
246345153Sdim
247345153Sdim/***********************************************************
248345153Sdim * Name: vchi_bulk_queue_transmit
249345153Sdim *
250345153Sdim * Arguments:  VCHI_BULK_HANDLE_T handle,
251345153Sdim *             void *data_src,
252345153Sdim *             uint32_t data_size,
253345153Sdim *             VCHI_FLAGS_T flags,
254345153Sdim *             void *bulk_handle
255345153Sdim *
256353358Sdim * Description: Routine to transmit some data
257345153Sdim *
258345153Sdim * Returns: int32_t - success == 0
259345153Sdim *
260345153Sdim ***********************************************************/
261345153Sdimint32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
262345153Sdim	void *data_src,
263345153Sdim	uint32_t data_size,
264345153Sdim	VCHI_FLAGS_T flags,
265345153Sdim	void *bulk_handle)
266345153Sdim{
267345153Sdim	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
268353358Sdim	VCHIQ_BULK_MODE_T mode;
269353358Sdim	VCHIQ_STATUS_T status;
270345153Sdim
271345153Sdim	switch ((int)flags) {
272345153Sdim	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
273345153Sdim		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
274345153Sdim		WARN_ON(!service->callback);
275345153Sdim		mode = VCHIQ_BULK_MODE_CALLBACK;
276345153Sdim		break;
277345153Sdim	case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
278345153Sdim	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
279345153Sdim		mode = VCHIQ_BULK_MODE_BLOCKING;
280345153Sdim		break;
281353358Sdim	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
282353358Sdim	case VCHI_FLAGS_NONE:
283345153Sdim		mode = VCHIQ_BULK_MODE_NOCALLBACK;
284345153Sdim		break;
285345153Sdim	default:
286345153Sdim		WARN(1, "unsupported message\n");
287345153Sdim		return vchiq_status_to_vchi(VCHIQ_ERROR);
288345153Sdim	}
289345153Sdim
290345153Sdim	status = vchiq_bulk_transmit(service->handle, data_src, data_size,
291345153Sdim		bulk_handle, mode);
292345153Sdim
293345153Sdim	/* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
294345153Sdim	** implement a retry mechanism since this function is supposed
295345153Sdim	** to block until queued
296345153Sdim	*/
297345153Sdim	while (status == VCHIQ_RETRY) {
298345153Sdim		msleep(1);
299345153Sdim		status = vchiq_bulk_transmit(service->handle, data_src,
300345153Sdim			data_size, bulk_handle, mode);
301345153Sdim	}
302345153Sdim
303345153Sdim	return vchiq_status_to_vchi(status);
304345153Sdim}
305345153SdimEXPORT_SYMBOL(vchi_bulk_queue_transmit);
306345153Sdim
307345153Sdim/***********************************************************
308345153Sdim * Name: vchi_msg_dequeue
309345153Sdim *
310345153Sdim * Arguments:  VCHI_SERVICE_HANDLE_T handle,
311345153Sdim *             void *data,
312345153Sdim *             uint32_t max_data_size_to_read,
313345153Sdim *             uint32_t *actual_msg_size
314345153Sdim *             VCHI_FLAGS_T flags
315345153Sdim *
316345153Sdim * Description: Routine to dequeue a message into the supplied buffer
317345153Sdim *
318345153Sdim * Returns: int32_t - success == 0
319345153Sdim *
320345153Sdim ***********************************************************/
321345153Sdimint32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
322345153Sdim	void *data,
323345153Sdim	uint32_t max_data_size_to_read,
324345153Sdim	uint32_t *actual_msg_size,
325345153Sdim	VCHI_FLAGS_T flags)
326345153Sdim{
327345153Sdim	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
328345153Sdim	VCHIQ_HEADER_T *header;
329345153Sdim
330345153Sdim	WARN_ON((flags != VCHI_FLAGS_NONE) &&
331345153Sdim		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
332345153Sdim
333345153Sdim	if (flags == VCHI_FLAGS_NONE)
334345153Sdim		if (vchiu_queue_is_empty(&service->queue))
335345153Sdim			return -1;
336345153Sdim
337345153Sdim	header = vchiu_queue_pop(&service->queue);
338345153Sdim
339345153Sdim	memcpy(data, header->data, header->size < max_data_size_to_read ?
340345153Sdim		header->size : max_data_size_to_read);
341345153Sdim
342345153Sdim	*actual_msg_size = header->size;
343345153Sdim
344345153Sdim	vchiq_release_message(service->handle, header);
345345153Sdim
346345153Sdim	return 0;
347345153Sdim}
348345153SdimEXPORT_SYMBOL(vchi_msg_dequeue);
349345153Sdim
350345153Sdim/***********************************************************
351345153Sdim * Name: vchi_msg_queuev
352345153Sdim *
353345153Sdim * Arguments:  VCHI_SERVICE_HANDLE_T handle,
354345153Sdim *             VCHI_MSG_VECTOR_T *vector,
355345153Sdim *             uint32_t count,
356345153Sdim *             VCHI_FLAGS_T flags,
357345153Sdim *             void *msg_handle
358345153Sdim *
359345153Sdim * Description: Thin wrapper to queue a message onto a connection
360345153Sdim *
361345153Sdim * Returns: int32_t - success == 0
362345153Sdim *
363345153Sdim ***********************************************************/
364345153Sdim
365345153Sdimvchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
366345153Sdimvchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) ==
367345153Sdim	offsetof(VCHIQ_ELEMENT_T, data));
368345153Sdimvchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) ==
369345153Sdim	offsetof(VCHIQ_ELEMENT_T, size));
370345153Sdim
371345153Sdimint32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,
372345153Sdim	VCHI_MSG_VECTOR_T *vector,
373345153Sdim	uint32_t count,
374345153Sdim	VCHI_FLAGS_T flags,
375345153Sdim	void *msg_handle)
376345153Sdim{
377345153Sdim	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
378345153Sdim
379345153Sdim	(void)msg_handle;
380345153Sdim
381345153Sdim	WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
382345153Sdim
383345153Sdim	return vchiq_status_to_vchi(vchiq_queue_message(service->handle,
384345153Sdim		(const VCHIQ_ELEMENT_T *)vector, count));
385345153Sdim}
386345153SdimEXPORT_SYMBOL(vchi_msg_queuev);
387345153Sdim
388345153Sdim/***********************************************************
389345153Sdim * Name: vchi_held_msg_release
390353358Sdim *
391353358Sdim * Arguments:  VCHI_HELD_MSG_T *message
392345153Sdim *
393345153Sdim * Description: Routine to release a held message (after it has been read with
394345153Sdim *              vchi_msg_hold)
395345153Sdim *
396345153Sdim * Returns: int32_t - success == 0
397345153Sdim *
398345153Sdim ***********************************************************/
399345153Sdimint32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
400345153Sdim{
401345153Sdim	vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service,
402345153Sdim		(VCHIQ_HEADER_T *)message->message);
403345153Sdim
404345153Sdim	return 0;
405345153Sdim}
406345153SdimEXPORT_SYMBOL(vchi_held_msg_release);
407345153Sdim
408345153Sdim/***********************************************************
409345153Sdim * Name: vchi_msg_hold
410345153Sdim *
411345153Sdim * Arguments:  VCHI_SERVICE_HANDLE_T handle,
412345153Sdim *             void **data,
413345153Sdim *             uint32_t *msg_size,
414345153Sdim *             VCHI_FLAGS_T flags,
415345153Sdim *             VCHI_HELD_MSG_T *message_handle
416345153Sdim *
417345153Sdim * Description: Routine to return a pointer to the current message (to allow
418345153Sdim *              in place processing). The message is dequeued - don't forget
419345153Sdim *              to release the message using vchi_held_msg_release when you're
420345153Sdim *              finished.
421345153Sdim *
422345153Sdim * Returns: int32_t - success == 0
423345153Sdim *
424345153Sdim ***********************************************************/
425345153Sdimint32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
426345153Sdim	void **data,
427345153Sdim	uint32_t *msg_size,
428345153Sdim	VCHI_FLAGS_T flags,
429345153Sdim	VCHI_HELD_MSG_T *message_handle)
430345153Sdim{
431345153Sdim	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
432345153Sdim	VCHIQ_HEADER_T *header;
433345153Sdim
434345153Sdim	WARN_ON((flags != VCHI_FLAGS_NONE) &&
435345153Sdim		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
436345153Sdim
437345153Sdim	if (flags == VCHI_FLAGS_NONE)
438345153Sdim		if (vchiu_queue_is_empty(&service->queue))
439345153Sdim			return -1;
440345153Sdim
441345153Sdim	header = vchiu_queue_pop(&service->queue);
442345153Sdim
443345153Sdim	*data = header->data;
444345153Sdim	*msg_size = header->size;
445345153Sdim
446345153Sdim	message_handle->service =
447345153Sdim		(struct opaque_vchi_service_t *)service->handle;
448345153Sdim	message_handle->message = header;
449
450	return 0;
451}
452EXPORT_SYMBOL(vchi_msg_hold);
453
454/***********************************************************
455 * Name: vchi_initialise
456 *
457 * Arguments: VCHI_INSTANCE_T *instance_handle
458 *
459 * Description: Initialises the hardware but does not transmit anything
460 *              When run as a Host App this will be called twice hence the need
461 *              to malloc the state information
462 *
463 * Returns: 0 if successful, failure otherwise
464 *
465 ***********************************************************/
466
467int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
468{
469	VCHIQ_INSTANCE_T instance;
470	VCHIQ_STATUS_T status;
471
472	status = vchiq_initialise(&instance);
473
474	*instance_handle = (VCHI_INSTANCE_T)instance;
475
476	return vchiq_status_to_vchi(status);
477}
478EXPORT_SYMBOL(vchi_initialise);
479
480/***********************************************************
481 * Name: vchi_connect
482 *
483 * Arguments: VCHI_CONNECTION_T **connections
484 *            const uint32_t num_connections
485 *            VCHI_INSTANCE_T instance_handle)
486 *
487 * Description: Starts the command service on each connection,
488 *              causing INIT messages to be pinged back and forth
489 *
490 * Returns: 0 if successful, failure otherwise
491 *
492 ***********************************************************/
493int32_t vchi_connect(VCHI_CONNECTION_T **connections,
494	const uint32_t num_connections,
495	VCHI_INSTANCE_T instance_handle)
496{
497	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
498
499	(void)connections;
500	(void)num_connections;
501
502	return vchiq_connect(instance);
503}
504EXPORT_SYMBOL(vchi_connect);
505
506
507/***********************************************************
508 * Name: vchi_disconnect
509 *
510 * Arguments: VCHI_INSTANCE_T instance_handle
511 *
512 * Description: Stops the command service on each connection,
513 *              causing DE-INIT messages to be pinged back and forth
514 *
515 * Returns: 0 if successful, failure otherwise
516 *
517 ***********************************************************/
518int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
519{
520	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
521	return vchiq_status_to_vchi(vchiq_shutdown(instance));
522}
523EXPORT_SYMBOL(vchi_disconnect);
524
525
526/***********************************************************
527 * Name: vchi_service_open
528 * Name: vchi_service_create
529 *
530 * Arguments: VCHI_INSTANCE_T *instance_handle
531 *            SERVICE_CREATION_T *setup,
532 *            VCHI_SERVICE_HANDLE_T *handle
533 *
534 * Description: Routine to open a service
535 *
536 * Returns: int32_t - success == 0
537 *
538 ***********************************************************/
539
540static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
541	VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
542{
543	SHIM_SERVICE_T *service =
544		(SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
545
546        if (!service->callback)
547		goto release;
548
549	switch (reason) {
550	case VCHIQ_MESSAGE_AVAILABLE:
551		vchiu_queue_push(&service->queue, header);
552
553		service->callback(service->callback_param,
554				  VCHI_CALLBACK_MSG_AVAILABLE, NULL);
555
556		goto done;
557		break;
558
559	case VCHIQ_BULK_TRANSMIT_DONE:
560		service->callback(service->callback_param,
561				  VCHI_CALLBACK_BULK_SENT, bulk_user);
562		break;
563
564	case VCHIQ_BULK_RECEIVE_DONE:
565		service->callback(service->callback_param,
566				  VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
567		break;
568
569	case VCHIQ_SERVICE_CLOSED:
570		service->callback(service->callback_param,
571				  VCHI_CALLBACK_SERVICE_CLOSED, NULL);
572		break;
573
574	case VCHIQ_SERVICE_OPENED:
575		/* No equivalent VCHI reason */
576		break;
577
578	case VCHIQ_BULK_TRANSMIT_ABORTED:
579		service->callback(service->callback_param,
580				  VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
581				  bulk_user);
582		break;
583
584	case VCHIQ_BULK_RECEIVE_ABORTED:
585		service->callback(service->callback_param,
586				  VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
587				  bulk_user);
588		break;
589
590	default:
591		WARN(1, "not supported\n");
592		break;
593	}
594
595release:
596        vchiq_release_message(service->handle, header);
597done:
598	return VCHIQ_SUCCESS;
599}
600
601static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
602	SERVICE_CREATION_T *setup)
603{
604	SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL);
605
606	(void)instance;
607
608	if (service) {
609		if (vchiu_queue_init(&service->queue, 64)) {
610			service->callback = setup->callback;
611			service->callback_param = setup->callback_param;
612		} else {
613			kfree(service);
614			service = NULL;
615		}
616	}
617
618	return service;
619}
620
621static void service_free(SHIM_SERVICE_T *service)
622{
623	if (service) {
624		vchiu_queue_delete(&service->queue);
625		kfree(service);
626	}
627}
628
629int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
630	SERVICE_CREATION_T *setup,
631	VCHI_SERVICE_HANDLE_T *handle)
632{
633	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
634	SHIM_SERVICE_T *service = service_alloc(instance, setup);
635
636	*handle = (VCHI_SERVICE_HANDLE_T)service;
637
638	if (service) {
639		VCHIQ_SERVICE_PARAMS_T params;
640		VCHIQ_STATUS_T status;
641
642		memset(&params, 0, sizeof(params));
643		params.fourcc = setup->service_id;
644		params.callback = shim_callback;
645		params.userdata = service;
646		params.version = setup->version.version;
647		params.version_min = setup->version.version_min;
648
649		status = vchiq_open_service(instance, &params,
650			&service->handle);
651		if (status != VCHIQ_SUCCESS) {
652			service_free(service);
653			service = NULL;
654			*handle = NULL;
655		}
656	}
657
658	return (service != NULL) ? 0 : -1;
659}
660EXPORT_SYMBOL(vchi_service_open);
661
662int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
663	SERVICE_CREATION_T *setup,
664	VCHI_SERVICE_HANDLE_T *handle)
665{
666	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
667	SHIM_SERVICE_T *service = service_alloc(instance, setup);
668
669	*handle = (VCHI_SERVICE_HANDLE_T)service;
670
671	if (service) {
672		VCHIQ_SERVICE_PARAMS_T params;
673		VCHIQ_STATUS_T status;
674
675		memset(&params, 0, sizeof(params));
676		params.fourcc = setup->service_id;
677		params.callback = shim_callback;
678		params.userdata = service;
679		params.version = setup->version.version;
680		params.version_min = setup->version.version_min;
681		status = vchiq_add_service(instance, &params, &service->handle);
682
683		if (status != VCHIQ_SUCCESS) {
684			service_free(service);
685			service = NULL;
686			*handle = NULL;
687		}
688	}
689
690	return (service != NULL) ? 0 : -1;
691}
692EXPORT_SYMBOL(vchi_service_create);
693
694int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
695{
696	int32_t ret = -1;
697	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
698	if (service) {
699		VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
700		if (status == VCHIQ_SUCCESS) {
701			service_free(service);
702			service = NULL;
703		}
704
705		ret = vchiq_status_to_vchi(status);
706	}
707	return ret;
708}
709EXPORT_SYMBOL(vchi_service_close);
710
711int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
712{
713	int32_t ret = -1;
714	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
715	if (service) {
716		VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
717		if (status == VCHIQ_SUCCESS) {
718			service_free(service);
719			service = NULL;
720		}
721
722		ret = vchiq_status_to_vchi(status);
723	}
724	return ret;
725}
726EXPORT_SYMBOL(vchi_service_destroy);
727
728int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
729				VCHI_SERVICE_OPTION_T option,
730				int value)
731{
732	int32_t ret = -1;
733	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
734	VCHIQ_SERVICE_OPTION_T vchiq_option;
735	switch (option) {
736	case VCHI_SERVICE_OPTION_TRACE:
737		vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
738		break;
739	case VCHI_SERVICE_OPTION_SYNCHRONOUS:
740		vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
741		break;
742	default:
743		service = NULL;
744		break;
745	}
746	if (service) {
747		VCHIQ_STATUS_T status =
748			vchiq_set_service_option(service->handle,
749						vchiq_option,
750						value);
751
752		ret = vchiq_status_to_vchi(status);
753	}
754	return ret;
755}
756EXPORT_SYMBOL(vchi_service_set_option);
757
758int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version )
759{
760   int32_t ret = -1;
761   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
762   if(service)
763   {
764      VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version);
765      ret = vchiq_status_to_vchi( status );
766   }
767   return ret;
768}
769EXPORT_SYMBOL(vchi_get_peer_version);
770
771#ifdef notyet
772/* ----------------------------------------------------------------------
773 * read a uint32_t from buffer.
774 * network format is defined to be little endian
775 * -------------------------------------------------------------------- */
776uint32_t
777vchi_readbuf_uint32(const void *_ptr)
778{
779	const unsigned char *ptr = _ptr;
780	return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
781}
782
783/* ----------------------------------------------------------------------
784 * write a uint32_t to buffer.
785 * network format is defined to be little endian
786 * -------------------------------------------------------------------- */
787void
788vchi_writebuf_uint32(void *_ptr, uint32_t value)
789{
790	unsigned char *ptr = _ptr;
791	ptr[0] = (unsigned char)((value >> 0)  & 0xFF);
792	ptr[1] = (unsigned char)((value >> 8)  & 0xFF);
793	ptr[2] = (unsigned char)((value >> 16) & 0xFF);
794	ptr[3] = (unsigned char)((value >> 24) & 0xFF);
795}
796
797/* ----------------------------------------------------------------------
798 * read a uint16_t from buffer.
799 * network format is defined to be little endian
800 * -------------------------------------------------------------------- */
801uint16_t
802vchi_readbuf_uint16(const void *_ptr)
803{
804	const unsigned char *ptr = _ptr;
805	return ptr[0] | (ptr[1] << 8);
806}
807
808/* ----------------------------------------------------------------------
809 * write a uint16_t into the buffer.
810 * network format is defined to be little endian
811 * -------------------------------------------------------------------- */
812void
813vchi_writebuf_uint16(void *_ptr, uint16_t value)
814{
815	unsigned char *ptr = _ptr;
816	ptr[0] = (value >> 0)  & 0xFF;
817	ptr[1] = (value >> 8)  & 0xFF;
818}
819#endif
820
821/***********************************************************
822 * Name: vchi_service_use
823 *
824 * Arguments: const VCHI_SERVICE_HANDLE_T handle
825 *
826 * Description: Routine to increment refcount on a service
827 *
828 * Returns: void
829 *
830 ***********************************************************/
831int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
832{
833	int32_t ret = -1;
834	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
835	if (service)
836		ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
837	return ret;
838}
839EXPORT_SYMBOL(vchi_service_use);
840
841/***********************************************************
842 * Name: vchi_service_release
843 *
844 * Arguments: const VCHI_SERVICE_HANDLE_T handle
845 *
846 * Description: Routine to decrement refcount on a service
847 *
848 * Returns: void
849 *
850 ***********************************************************/
851int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
852{
853	int32_t ret = -1;
854	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
855	if (service)
856		ret = vchiq_status_to_vchi(
857			vchiq_release_service(service->handle));
858	return ret;
859}
860EXPORT_SYMBOL(vchi_service_release);
861