1278277Sgonzo/**
2278277Sgonzo * Copyright (c) 2010-2012 Broadcom. All rights reserved.
3278277Sgonzo *
4278277Sgonzo * Redistribution and use in source and binary forms, with or without
5278277Sgonzo * modification, are permitted provided that the following conditions
6278277Sgonzo * are met:
7278277Sgonzo * 1. Redistributions of source code must retain the above copyright
8278277Sgonzo *    notice, this list of conditions, and the following disclaimer,
9278277Sgonzo *    without modification.
10278277Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11278277Sgonzo *    notice, this list of conditions and the following disclaimer in the
12278277Sgonzo *    documentation and/or other materials provided with the distribution.
13278277Sgonzo * 3. The names of the above-listed copyright holders may not be used
14278277Sgonzo *    to endorse or promote products derived from this software without
15278277Sgonzo *    specific prior written permission.
16278277Sgonzo *
17278277Sgonzo * ALTERNATIVELY, this software may be distributed under the terms of the
18278277Sgonzo * GNU General Public License ("GPL") version 2, as published by the Free
19278277Sgonzo * Software Foundation.
20278277Sgonzo *
21278277Sgonzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22278277Sgonzo * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23278277Sgonzo * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24278277Sgonzo * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25278277Sgonzo * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26278277Sgonzo * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27278277Sgonzo * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28278277Sgonzo * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29278277Sgonzo * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30278277Sgonzo * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31278277Sgonzo * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32278277Sgonzo */
33278277Sgonzo
34278277Sgonzo#include <interface/compat/vchi_bsd.h>
35278277Sgonzo
36278277Sgonzo#include "interface/vchi/vchi.h"
37278277Sgonzo#include "vchiq.h"
38278277Sgonzo#include "vchiq_core.h"
39278277Sgonzo
40278277Sgonzo#include "vchiq_util.h"
41278277Sgonzo
42278277Sgonzo#define vchiq_status_to_vchi(status) ((int32_t)status)
43278277Sgonzo
44278277Sgonzotypedef struct {
45278277Sgonzo	VCHIQ_SERVICE_HANDLE_T handle;
46278277Sgonzo
47278277Sgonzo	VCHIU_QUEUE_T queue;
48278277Sgonzo
49278277Sgonzo	VCHI_CALLBACK_T callback;
50278277Sgonzo	void *callback_param;
51278277Sgonzo} SHIM_SERVICE_T;
52278277Sgonzo
53278277Sgonzo/* ----------------------------------------------------------------------
54278277Sgonzo * return pointer to the mphi message driver function table
55278277Sgonzo * -------------------------------------------------------------------- */
56278277Sgonzoconst VCHI_MESSAGE_DRIVER_T *
57278277Sgonzovchi_mphi_message_driver_func_table(void)
58278277Sgonzo{
59278277Sgonzo	return NULL;
60278277Sgonzo}
61278277Sgonzo
62278277Sgonzo/* ----------------------------------------------------------------------
63278277Sgonzo * return a pointer to the 'single' connection driver fops
64278277Sgonzo * -------------------------------------------------------------------- */
65278277Sgonzoconst VCHI_CONNECTION_API_T *
66278277Sgonzosingle_get_func_table(void)
67278277Sgonzo{
68278277Sgonzo	return NULL;
69278277Sgonzo}
70278277Sgonzo
71278277SgonzoVCHI_CONNECTION_T *vchi_create_connection(
72278277Sgonzo	const VCHI_CONNECTION_API_T *function_table,
73278277Sgonzo	const VCHI_MESSAGE_DRIVER_T *low_level)
74278277Sgonzo{
75278277Sgonzo	(void)function_table;
76278277Sgonzo	(void)low_level;
77278277Sgonzo	return NULL;
78278277Sgonzo}
79278277Sgonzo
80278277Sgonzo/***********************************************************
81278277Sgonzo * Name: vchi_msg_peek
82278277Sgonzo *
83278277Sgonzo * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
84278277Sgonzo *             void **data,
85278277Sgonzo *             uint32_t *msg_size,
86278277Sgonzo
87278277Sgonzo
88278277Sgonzo *             VCHI_FLAGS_T flags
89278277Sgonzo *
90278277Sgonzo * Description: Routine to return a pointer to the current message (to allow in
91278277Sgonzo *              place processing). The message can be removed using
92278277Sgonzo *              vchi_msg_remove when you're finished
93278277Sgonzo *
94278277Sgonzo * Returns: int32_t - success == 0
95278277Sgonzo *
96278277Sgonzo ***********************************************************/
97278277Sgonzoint32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
98278277Sgonzo	void **data,
99278277Sgonzo	uint32_t *msg_size,
100278277Sgonzo	VCHI_FLAGS_T flags)
101278277Sgonzo{
102278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
103278277Sgonzo	VCHIQ_HEADER_T *header;
104278277Sgonzo
105278277Sgonzo	WARN_ON((flags != VCHI_FLAGS_NONE) &&
106278277Sgonzo		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
107278277Sgonzo
108278277Sgonzo	if (flags == VCHI_FLAGS_NONE)
109278277Sgonzo		if (vchiu_queue_is_empty(&service->queue))
110278277Sgonzo			return -1;
111278277Sgonzo
112278277Sgonzo	header = vchiu_queue_peek(&service->queue);
113278277Sgonzo
114278277Sgonzo	*data = header->data;
115278277Sgonzo	*msg_size = header->size;
116278277Sgonzo
117278277Sgonzo	return 0;
118278277Sgonzo}
119278277SgonzoEXPORT_SYMBOL(vchi_msg_peek);
120278277Sgonzo
121278277Sgonzo/***********************************************************
122278277Sgonzo * Name: vchi_msg_remove
123278277Sgonzo *
124278277Sgonzo * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
125278277Sgonzo *
126278277Sgonzo * Description: Routine to remove a message (after it has been read with
127278277Sgonzo *              vchi_msg_peek)
128278277Sgonzo *
129278277Sgonzo * Returns: int32_t - success == 0
130278277Sgonzo *
131278277Sgonzo ***********************************************************/
132278277Sgonzoint32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
133278277Sgonzo{
134278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
135278277Sgonzo	VCHIQ_HEADER_T *header;
136278277Sgonzo
137278277Sgonzo	header = vchiu_queue_pop(&service->queue);
138278277Sgonzo
139278277Sgonzo	vchiq_release_message(service->handle, header);
140278277Sgonzo
141278277Sgonzo	return 0;
142278277Sgonzo}
143278277SgonzoEXPORT_SYMBOL(vchi_msg_remove);
144278277Sgonzo
145278277Sgonzo/***********************************************************
146278277Sgonzo * Name: vchi_msg_queue
147278277Sgonzo *
148278277Sgonzo * Arguments:  VCHI_SERVICE_HANDLE_T handle,
149278277Sgonzo *             const void *data,
150278277Sgonzo *             uint32_t data_size,
151278277Sgonzo *             VCHI_FLAGS_T flags,
152278277Sgonzo *             void *msg_handle,
153278277Sgonzo *
154278277Sgonzo * Description: Thin wrapper to queue a message onto a connection
155278277Sgonzo *
156278277Sgonzo * Returns: int32_t - success == 0
157278277Sgonzo *
158278277Sgonzo ***********************************************************/
159278277Sgonzoint32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
160278277Sgonzo	const void *data,
161278277Sgonzo	uint32_t data_size,
162278277Sgonzo	VCHI_FLAGS_T flags,
163278277Sgonzo	void *msg_handle)
164278277Sgonzo{
165278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
166278277Sgonzo	VCHIQ_ELEMENT_T element = {data, data_size};
167278277Sgonzo	VCHIQ_STATUS_T status;
168278277Sgonzo
169278277Sgonzo	(void)msg_handle;
170278277Sgonzo
171278277Sgonzo	WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
172278277Sgonzo
173278277Sgonzo	status = vchiq_queue_message(service->handle, &element, 1);
174278277Sgonzo
175278277Sgonzo	/* vchiq_queue_message() may return VCHIQ_RETRY, so we need to
176278277Sgonzo	** implement a retry mechanism since this function is supposed
177278277Sgonzo	** to block until queued
178278277Sgonzo	*/
179278277Sgonzo	while (status == VCHIQ_RETRY) {
180278277Sgonzo		msleep(1);
181278277Sgonzo		status = vchiq_queue_message(service->handle, &element, 1);
182278277Sgonzo	}
183278277Sgonzo
184278277Sgonzo	return vchiq_status_to_vchi(status);
185278277Sgonzo}
186278277SgonzoEXPORT_SYMBOL(vchi_msg_queue);
187278277Sgonzo
188278277Sgonzo/***********************************************************
189278277Sgonzo * Name: vchi_bulk_queue_receive
190278277Sgonzo *
191278277Sgonzo * Arguments:  VCHI_BULK_HANDLE_T handle,
192278277Sgonzo *             void *data_dst,
193278277Sgonzo *             const uint32_t data_size,
194278277Sgonzo *             VCHI_FLAGS_T flags
195278277Sgonzo *             void *bulk_handle
196278277Sgonzo *
197278277Sgonzo * Description: Routine to setup a rcv buffer
198278277Sgonzo *
199278277Sgonzo * Returns: int32_t - success == 0
200278277Sgonzo *
201278277Sgonzo ***********************************************************/
202278277Sgonzoint32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
203278277Sgonzo	void *data_dst,
204278277Sgonzo	uint32_t data_size,
205278277Sgonzo	VCHI_FLAGS_T flags,
206278277Sgonzo	void *bulk_handle)
207278277Sgonzo{
208278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
209278277Sgonzo	VCHIQ_BULK_MODE_T mode;
210278277Sgonzo	VCHIQ_STATUS_T status;
211278277Sgonzo
212278277Sgonzo	switch ((int)flags) {
213278277Sgonzo	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
214278277Sgonzo		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
215278277Sgonzo		WARN_ON(!service->callback);
216278277Sgonzo		mode = VCHIQ_BULK_MODE_CALLBACK;
217278277Sgonzo		break;
218278277Sgonzo	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
219278277Sgonzo		mode = VCHIQ_BULK_MODE_BLOCKING;
220278277Sgonzo		break;
221278277Sgonzo	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
222278277Sgonzo	case VCHI_FLAGS_NONE:
223278277Sgonzo		mode = VCHIQ_BULK_MODE_NOCALLBACK;
224278277Sgonzo		break;
225278277Sgonzo	default:
226278277Sgonzo		WARN(1, "unsupported message\n");
227278277Sgonzo		return vchiq_status_to_vchi(VCHIQ_ERROR);
228278277Sgonzo	}
229278277Sgonzo
230278277Sgonzo	status = vchiq_bulk_receive(service->handle, data_dst, data_size,
231278277Sgonzo		bulk_handle, mode);
232278277Sgonzo
233278277Sgonzo	/* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
234278277Sgonzo	** implement a retry mechanism since this function is supposed
235278277Sgonzo	** to block until queued
236278277Sgonzo	*/
237278277Sgonzo	while (status == VCHIQ_RETRY) {
238278277Sgonzo		msleep(1);
239278277Sgonzo		status = vchiq_bulk_receive(service->handle, data_dst,
240278277Sgonzo			data_size, bulk_handle, mode);
241278277Sgonzo	}
242278277Sgonzo
243278277Sgonzo	return vchiq_status_to_vchi(status);
244278277Sgonzo}
245278277SgonzoEXPORT_SYMBOL(vchi_bulk_queue_receive);
246278277Sgonzo
247278277Sgonzo/***********************************************************
248278277Sgonzo * Name: vchi_bulk_queue_transmit
249278277Sgonzo *
250278277Sgonzo * Arguments:  VCHI_BULK_HANDLE_T handle,
251278277Sgonzo *             void *data_src,
252278277Sgonzo *             uint32_t data_size,
253278277Sgonzo *             VCHI_FLAGS_T flags,
254278277Sgonzo *             void *bulk_handle
255278277Sgonzo *
256278277Sgonzo * Description: Routine to transmit some data
257278277Sgonzo *
258278277Sgonzo * Returns: int32_t - success == 0
259278277Sgonzo *
260278277Sgonzo ***********************************************************/
261278277Sgonzoint32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
262278277Sgonzo	void *data_src,
263278277Sgonzo	uint32_t data_size,
264278277Sgonzo	VCHI_FLAGS_T flags,
265278277Sgonzo	void *bulk_handle)
266278277Sgonzo{
267278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
268278277Sgonzo	VCHIQ_BULK_MODE_T mode;
269278277Sgonzo	VCHIQ_STATUS_T status;
270278277Sgonzo
271278277Sgonzo	switch ((int)flags) {
272278277Sgonzo	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
273278277Sgonzo		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
274278277Sgonzo		WARN_ON(!service->callback);
275278277Sgonzo		mode = VCHIQ_BULK_MODE_CALLBACK;
276278277Sgonzo		break;
277278277Sgonzo	case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
278278277Sgonzo	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
279278277Sgonzo		mode = VCHIQ_BULK_MODE_BLOCKING;
280278277Sgonzo		break;
281278277Sgonzo	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
282278277Sgonzo	case VCHI_FLAGS_NONE:
283278277Sgonzo		mode = VCHIQ_BULK_MODE_NOCALLBACK;
284278277Sgonzo		break;
285278277Sgonzo	default:
286278277Sgonzo		WARN(1, "unsupported message\n");
287278277Sgonzo		return vchiq_status_to_vchi(VCHIQ_ERROR);
288278277Sgonzo	}
289278277Sgonzo
290278277Sgonzo	status = vchiq_bulk_transmit(service->handle, data_src, data_size,
291278277Sgonzo		bulk_handle, mode);
292278277Sgonzo
293278277Sgonzo	/* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
294278277Sgonzo	** implement a retry mechanism since this function is supposed
295278277Sgonzo	** to block until queued
296278277Sgonzo	*/
297278277Sgonzo	while (status == VCHIQ_RETRY) {
298278277Sgonzo		msleep(1);
299278277Sgonzo		status = vchiq_bulk_transmit(service->handle, data_src,
300278277Sgonzo			data_size, bulk_handle, mode);
301278277Sgonzo	}
302278277Sgonzo
303278277Sgonzo	return vchiq_status_to_vchi(status);
304278277Sgonzo}
305278277SgonzoEXPORT_SYMBOL(vchi_bulk_queue_transmit);
306278277Sgonzo
307278277Sgonzo/***********************************************************
308278277Sgonzo * Name: vchi_msg_dequeue
309278277Sgonzo *
310278277Sgonzo * Arguments:  VCHI_SERVICE_HANDLE_T handle,
311278277Sgonzo *             void *data,
312278277Sgonzo *             uint32_t max_data_size_to_read,
313278277Sgonzo *             uint32_t *actual_msg_size
314278277Sgonzo *             VCHI_FLAGS_T flags
315278277Sgonzo *
316278277Sgonzo * Description: Routine to dequeue a message into the supplied buffer
317278277Sgonzo *
318278277Sgonzo * Returns: int32_t - success == 0
319278277Sgonzo *
320278277Sgonzo ***********************************************************/
321278277Sgonzoint32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
322278277Sgonzo	void *data,
323278277Sgonzo	uint32_t max_data_size_to_read,
324278277Sgonzo	uint32_t *actual_msg_size,
325278277Sgonzo	VCHI_FLAGS_T flags)
326278277Sgonzo{
327278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
328278277Sgonzo	VCHIQ_HEADER_T *header;
329278277Sgonzo
330278277Sgonzo	WARN_ON((flags != VCHI_FLAGS_NONE) &&
331278277Sgonzo		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
332278277Sgonzo
333278277Sgonzo	if (flags == VCHI_FLAGS_NONE)
334278277Sgonzo		if (vchiu_queue_is_empty(&service->queue))
335278277Sgonzo			return -1;
336278277Sgonzo
337278277Sgonzo	header = vchiu_queue_pop(&service->queue);
338278277Sgonzo
339278277Sgonzo	memcpy(data, header->data, header->size < max_data_size_to_read ?
340278277Sgonzo		header->size : max_data_size_to_read);
341278277Sgonzo
342278277Sgonzo	*actual_msg_size = header->size;
343278277Sgonzo
344278277Sgonzo	vchiq_release_message(service->handle, header);
345278277Sgonzo
346278277Sgonzo	return 0;
347278277Sgonzo}
348278277SgonzoEXPORT_SYMBOL(vchi_msg_dequeue);
349278277Sgonzo
350278277Sgonzo/***********************************************************
351278277Sgonzo * Name: vchi_msg_queuev
352278277Sgonzo *
353278277Sgonzo * Arguments:  VCHI_SERVICE_HANDLE_T handle,
354278277Sgonzo *             VCHI_MSG_VECTOR_T *vector,
355278277Sgonzo *             uint32_t count,
356278277Sgonzo *             VCHI_FLAGS_T flags,
357278277Sgonzo *             void *msg_handle
358278277Sgonzo *
359278277Sgonzo * Description: Thin wrapper to queue a message onto a connection
360278277Sgonzo *
361278277Sgonzo * Returns: int32_t - success == 0
362278277Sgonzo *
363278277Sgonzo ***********************************************************/
364278277Sgonzo
365278277Sgonzovchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
366278277Sgonzovchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) ==
367278277Sgonzo	offsetof(VCHIQ_ELEMENT_T, data));
368278277Sgonzovchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) ==
369278277Sgonzo	offsetof(VCHIQ_ELEMENT_T, size));
370278277Sgonzo
371278277Sgonzoint32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,
372278277Sgonzo	VCHI_MSG_VECTOR_T *vector,
373278277Sgonzo	uint32_t count,
374278277Sgonzo	VCHI_FLAGS_T flags,
375278277Sgonzo	void *msg_handle)
376278277Sgonzo{
377278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
378278277Sgonzo
379278277Sgonzo	(void)msg_handle;
380278277Sgonzo
381278277Sgonzo	WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
382278277Sgonzo
383278277Sgonzo	return vchiq_status_to_vchi(vchiq_queue_message(service->handle,
384278277Sgonzo		(const VCHIQ_ELEMENT_T *)vector, count));
385278277Sgonzo}
386278277SgonzoEXPORT_SYMBOL(vchi_msg_queuev);
387278277Sgonzo
388278277Sgonzo/***********************************************************
389278277Sgonzo * Name: vchi_held_msg_release
390278277Sgonzo *
391278277Sgonzo * Arguments:  VCHI_HELD_MSG_T *message
392278277Sgonzo *
393278277Sgonzo * Description: Routine to release a held message (after it has been read with
394278277Sgonzo *              vchi_msg_hold)
395278277Sgonzo *
396278277Sgonzo * Returns: int32_t - success == 0
397278277Sgonzo *
398278277Sgonzo ***********************************************************/
399278277Sgonzoint32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
400278277Sgonzo{
401278277Sgonzo	vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service,
402278277Sgonzo		(VCHIQ_HEADER_T *)message->message);
403278277Sgonzo
404278277Sgonzo	return 0;
405278277Sgonzo}
406290245SgonzoEXPORT_SYMBOL(vchi_held_msg_release);
407278277Sgonzo
408278277Sgonzo/***********************************************************
409278277Sgonzo * Name: vchi_msg_hold
410278277Sgonzo *
411278277Sgonzo * Arguments:  VCHI_SERVICE_HANDLE_T handle,
412278277Sgonzo *             void **data,
413278277Sgonzo *             uint32_t *msg_size,
414278277Sgonzo *             VCHI_FLAGS_T flags,
415278277Sgonzo *             VCHI_HELD_MSG_T *message_handle
416278277Sgonzo *
417278277Sgonzo * Description: Routine to return a pointer to the current message (to allow
418278277Sgonzo *              in place processing). The message is dequeued - don't forget
419278277Sgonzo *              to release the message using vchi_held_msg_release when you're
420278277Sgonzo *              finished.
421278277Sgonzo *
422278277Sgonzo * Returns: int32_t - success == 0
423278277Sgonzo *
424278277Sgonzo ***********************************************************/
425278277Sgonzoint32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
426278277Sgonzo	void **data,
427278277Sgonzo	uint32_t *msg_size,
428278277Sgonzo	VCHI_FLAGS_T flags,
429278277Sgonzo	VCHI_HELD_MSG_T *message_handle)
430278277Sgonzo{
431278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
432278277Sgonzo	VCHIQ_HEADER_T *header;
433278277Sgonzo
434278277Sgonzo	WARN_ON((flags != VCHI_FLAGS_NONE) &&
435278277Sgonzo		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
436278277Sgonzo
437278277Sgonzo	if (flags == VCHI_FLAGS_NONE)
438278277Sgonzo		if (vchiu_queue_is_empty(&service->queue))
439278277Sgonzo			return -1;
440278277Sgonzo
441278277Sgonzo	header = vchiu_queue_pop(&service->queue);
442278277Sgonzo
443278277Sgonzo	*data = header->data;
444278277Sgonzo	*msg_size = header->size;
445278277Sgonzo
446278277Sgonzo	message_handle->service =
447278277Sgonzo		(struct opaque_vchi_service_t *)service->handle;
448278277Sgonzo	message_handle->message = header;
449278277Sgonzo
450278277Sgonzo	return 0;
451278277Sgonzo}
452290245SgonzoEXPORT_SYMBOL(vchi_msg_hold);
453278277Sgonzo
454278277Sgonzo/***********************************************************
455278277Sgonzo * Name: vchi_initialise
456278277Sgonzo *
457278277Sgonzo * Arguments: VCHI_INSTANCE_T *instance_handle
458278277Sgonzo *
459278277Sgonzo * Description: Initialises the hardware but does not transmit anything
460278277Sgonzo *              When run as a Host App this will be called twice hence the need
461278277Sgonzo *              to malloc the state information
462278277Sgonzo *
463278277Sgonzo * Returns: 0 if successful, failure otherwise
464278277Sgonzo *
465278277Sgonzo ***********************************************************/
466278277Sgonzo
467278277Sgonzoint32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
468278277Sgonzo{
469278277Sgonzo	VCHIQ_INSTANCE_T instance;
470278277Sgonzo	VCHIQ_STATUS_T status;
471278277Sgonzo
472278277Sgonzo	status = vchiq_initialise(&instance);
473278277Sgonzo
474278277Sgonzo	*instance_handle = (VCHI_INSTANCE_T)instance;
475278277Sgonzo
476278277Sgonzo	return vchiq_status_to_vchi(status);
477278277Sgonzo}
478278277SgonzoEXPORT_SYMBOL(vchi_initialise);
479278277Sgonzo
480278277Sgonzo/***********************************************************
481278277Sgonzo * Name: vchi_connect
482278277Sgonzo *
483278277Sgonzo * Arguments: VCHI_CONNECTION_T **connections
484278277Sgonzo *            const uint32_t num_connections
485278277Sgonzo *            VCHI_INSTANCE_T instance_handle)
486278277Sgonzo *
487278277Sgonzo * Description: Starts the command service on each connection,
488278277Sgonzo *              causing INIT messages to be pinged back and forth
489278277Sgonzo *
490278277Sgonzo * Returns: 0 if successful, failure otherwise
491278277Sgonzo *
492278277Sgonzo ***********************************************************/
493278277Sgonzoint32_t vchi_connect(VCHI_CONNECTION_T **connections,
494278277Sgonzo	const uint32_t num_connections,
495278277Sgonzo	VCHI_INSTANCE_T instance_handle)
496278277Sgonzo{
497278277Sgonzo	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
498278277Sgonzo
499278277Sgonzo	(void)connections;
500278277Sgonzo	(void)num_connections;
501278277Sgonzo
502278277Sgonzo	return vchiq_connect(instance);
503278277Sgonzo}
504278277SgonzoEXPORT_SYMBOL(vchi_connect);
505278277Sgonzo
506278277Sgonzo
507278277Sgonzo/***********************************************************
508278277Sgonzo * Name: vchi_disconnect
509278277Sgonzo *
510278277Sgonzo * Arguments: VCHI_INSTANCE_T instance_handle
511278277Sgonzo *
512278277Sgonzo * Description: Stops the command service on each connection,
513278277Sgonzo *              causing DE-INIT messages to be pinged back and forth
514278277Sgonzo *
515278277Sgonzo * Returns: 0 if successful, failure otherwise
516278277Sgonzo *
517278277Sgonzo ***********************************************************/
518278277Sgonzoint32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
519278277Sgonzo{
520278277Sgonzo	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
521278277Sgonzo	return vchiq_status_to_vchi(vchiq_shutdown(instance));
522278277Sgonzo}
523278277SgonzoEXPORT_SYMBOL(vchi_disconnect);
524278277Sgonzo
525278277Sgonzo
526278277Sgonzo/***********************************************************
527278277Sgonzo * Name: vchi_service_open
528278277Sgonzo * Name: vchi_service_create
529278277Sgonzo *
530278277Sgonzo * Arguments: VCHI_INSTANCE_T *instance_handle
531278277Sgonzo *            SERVICE_CREATION_T *setup,
532278277Sgonzo *            VCHI_SERVICE_HANDLE_T *handle
533278277Sgonzo *
534278277Sgonzo * Description: Routine to open a service
535278277Sgonzo *
536278277Sgonzo * Returns: int32_t - success == 0
537278277Sgonzo *
538278277Sgonzo ***********************************************************/
539278277Sgonzo
540278277Sgonzostatic VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
541278277Sgonzo	VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
542278277Sgonzo{
543278277Sgonzo	SHIM_SERVICE_T *service =
544278277Sgonzo		(SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
545278277Sgonzo
546278277Sgonzo        if (!service->callback)
547278277Sgonzo		goto release;
548278277Sgonzo
549278277Sgonzo	switch (reason) {
550278277Sgonzo	case VCHIQ_MESSAGE_AVAILABLE:
551278277Sgonzo		vchiu_queue_push(&service->queue, header);
552278277Sgonzo
553278277Sgonzo		service->callback(service->callback_param,
554278277Sgonzo				  VCHI_CALLBACK_MSG_AVAILABLE, NULL);
555278277Sgonzo
556278277Sgonzo		goto done;
557278277Sgonzo		break;
558278277Sgonzo
559278277Sgonzo	case VCHIQ_BULK_TRANSMIT_DONE:
560278277Sgonzo		service->callback(service->callback_param,
561278277Sgonzo				  VCHI_CALLBACK_BULK_SENT, bulk_user);
562278277Sgonzo		break;
563278277Sgonzo
564278277Sgonzo	case VCHIQ_BULK_RECEIVE_DONE:
565278277Sgonzo		service->callback(service->callback_param,
566278277Sgonzo				  VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
567278277Sgonzo		break;
568278277Sgonzo
569278277Sgonzo	case VCHIQ_SERVICE_CLOSED:
570278277Sgonzo		service->callback(service->callback_param,
571278277Sgonzo				  VCHI_CALLBACK_SERVICE_CLOSED, NULL);
572278277Sgonzo		break;
573278277Sgonzo
574278277Sgonzo	case VCHIQ_SERVICE_OPENED:
575278277Sgonzo		/* No equivalent VCHI reason */
576278277Sgonzo		break;
577278277Sgonzo
578278277Sgonzo	case VCHIQ_BULK_TRANSMIT_ABORTED:
579278277Sgonzo		service->callback(service->callback_param,
580278277Sgonzo				  VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
581278277Sgonzo				  bulk_user);
582278277Sgonzo		break;
583278277Sgonzo
584278277Sgonzo	case VCHIQ_BULK_RECEIVE_ABORTED:
585278277Sgonzo		service->callback(service->callback_param,
586278277Sgonzo				  VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
587278277Sgonzo				  bulk_user);
588278277Sgonzo		break;
589278277Sgonzo
590278277Sgonzo	default:
591278277Sgonzo		WARN(1, "not supported\n");
592278277Sgonzo		break;
593278277Sgonzo	}
594278277Sgonzo
595278277Sgonzorelease:
596278277Sgonzo        vchiq_release_message(service->handle, header);
597278277Sgonzodone:
598278277Sgonzo	return VCHIQ_SUCCESS;
599278277Sgonzo}
600278277Sgonzo
601278277Sgonzostatic SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
602278277Sgonzo	SERVICE_CREATION_T *setup)
603278277Sgonzo{
604278277Sgonzo	SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL);
605278277Sgonzo
606278277Sgonzo	(void)instance;
607278277Sgonzo
608278277Sgonzo	if (service) {
609278277Sgonzo		if (vchiu_queue_init(&service->queue, 64)) {
610278277Sgonzo			service->callback = setup->callback;
611278277Sgonzo			service->callback_param = setup->callback_param;
612278277Sgonzo		} else {
613278277Sgonzo			kfree(service);
614278277Sgonzo			service = NULL;
615278277Sgonzo		}
616278277Sgonzo	}
617278277Sgonzo
618278277Sgonzo	return service;
619278277Sgonzo}
620278277Sgonzo
621278277Sgonzostatic void service_free(SHIM_SERVICE_T *service)
622278277Sgonzo{
623278277Sgonzo	if (service) {
624278277Sgonzo		vchiu_queue_delete(&service->queue);
625278277Sgonzo		kfree(service);
626278277Sgonzo	}
627278277Sgonzo}
628278277Sgonzo
629278277Sgonzoint32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
630278277Sgonzo	SERVICE_CREATION_T *setup,
631278277Sgonzo	VCHI_SERVICE_HANDLE_T *handle)
632278277Sgonzo{
633278277Sgonzo	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
634278277Sgonzo	SHIM_SERVICE_T *service = service_alloc(instance, setup);
635278277Sgonzo
636278277Sgonzo	*handle = (VCHI_SERVICE_HANDLE_T)service;
637278277Sgonzo
638278277Sgonzo	if (service) {
639278277Sgonzo		VCHIQ_SERVICE_PARAMS_T params;
640278277Sgonzo		VCHIQ_STATUS_T status;
641278277Sgonzo
642278277Sgonzo		memset(&params, 0, sizeof(params));
643278277Sgonzo		params.fourcc = setup->service_id;
644278277Sgonzo		params.callback = shim_callback;
645278277Sgonzo		params.userdata = service;
646278277Sgonzo		params.version = setup->version.version;
647278277Sgonzo		params.version_min = setup->version.version_min;
648278277Sgonzo
649278277Sgonzo		status = vchiq_open_service(instance, &params,
650278277Sgonzo			&service->handle);
651278277Sgonzo		if (status != VCHIQ_SUCCESS) {
652278277Sgonzo			service_free(service);
653278277Sgonzo			service = NULL;
654278277Sgonzo			*handle = NULL;
655278277Sgonzo		}
656278277Sgonzo	}
657278277Sgonzo
658278277Sgonzo	return (service != NULL) ? 0 : -1;
659278277Sgonzo}
660278277SgonzoEXPORT_SYMBOL(vchi_service_open);
661278277Sgonzo
662278277Sgonzoint32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
663278277Sgonzo	SERVICE_CREATION_T *setup,
664278277Sgonzo	VCHI_SERVICE_HANDLE_T *handle)
665278277Sgonzo{
666278277Sgonzo	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
667278277Sgonzo	SHIM_SERVICE_T *service = service_alloc(instance, setup);
668278277Sgonzo
669278277Sgonzo	*handle = (VCHI_SERVICE_HANDLE_T)service;
670278277Sgonzo
671278277Sgonzo	if (service) {
672278277Sgonzo		VCHIQ_SERVICE_PARAMS_T params;
673278277Sgonzo		VCHIQ_STATUS_T status;
674278277Sgonzo
675278277Sgonzo		memset(&params, 0, sizeof(params));
676278277Sgonzo		params.fourcc = setup->service_id;
677278277Sgonzo		params.callback = shim_callback;
678278277Sgonzo		params.userdata = service;
679278277Sgonzo		params.version = setup->version.version;
680278277Sgonzo		params.version_min = setup->version.version_min;
681278277Sgonzo		status = vchiq_add_service(instance, &params, &service->handle);
682278277Sgonzo
683278277Sgonzo		if (status != VCHIQ_SUCCESS) {
684278277Sgonzo			service_free(service);
685278277Sgonzo			service = NULL;
686278277Sgonzo			*handle = NULL;
687278277Sgonzo		}
688278277Sgonzo	}
689278277Sgonzo
690278277Sgonzo	return (service != NULL) ? 0 : -1;
691278277Sgonzo}
692278277SgonzoEXPORT_SYMBOL(vchi_service_create);
693278277Sgonzo
694278277Sgonzoint32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
695278277Sgonzo{
696278277Sgonzo	int32_t ret = -1;
697278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
698278277Sgonzo	if (service) {
699278277Sgonzo		VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
700278277Sgonzo		if (status == VCHIQ_SUCCESS) {
701278277Sgonzo			service_free(service);
702278277Sgonzo			service = NULL;
703278277Sgonzo		}
704278277Sgonzo
705278277Sgonzo		ret = vchiq_status_to_vchi(status);
706278277Sgonzo	}
707278277Sgonzo	return ret;
708278277Sgonzo}
709278277SgonzoEXPORT_SYMBOL(vchi_service_close);
710278277Sgonzo
711278277Sgonzoint32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
712278277Sgonzo{
713278277Sgonzo	int32_t ret = -1;
714278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
715278277Sgonzo	if (service) {
716278277Sgonzo		VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
717278277Sgonzo		if (status == VCHIQ_SUCCESS) {
718278277Sgonzo			service_free(service);
719278277Sgonzo			service = NULL;
720278277Sgonzo		}
721278277Sgonzo
722278277Sgonzo		ret = vchiq_status_to_vchi(status);
723278277Sgonzo	}
724278277Sgonzo	return ret;
725278277Sgonzo}
726278277SgonzoEXPORT_SYMBOL(vchi_service_destroy);
727278277Sgonzo
728290245Sgonzoint32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
729290245Sgonzo				VCHI_SERVICE_OPTION_T option,
730290245Sgonzo				int value)
731290245Sgonzo{
732290245Sgonzo	int32_t ret = -1;
733290245Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
734290245Sgonzo	VCHIQ_SERVICE_OPTION_T vchiq_option;
735290245Sgonzo	switch (option) {
736290245Sgonzo	case VCHI_SERVICE_OPTION_TRACE:
737290245Sgonzo		vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
738290245Sgonzo		break;
739290245Sgonzo	case VCHI_SERVICE_OPTION_SYNCHRONOUS:
740290245Sgonzo		vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
741290245Sgonzo		break;
742290245Sgonzo	default:
743290245Sgonzo		service = NULL;
744290245Sgonzo		break;
745290245Sgonzo	}
746290245Sgonzo	if (service) {
747290245Sgonzo		VCHIQ_STATUS_T status =
748290245Sgonzo			vchiq_set_service_option(service->handle,
749290245Sgonzo						vchiq_option,
750290245Sgonzo						value);
751290245Sgonzo
752290245Sgonzo		ret = vchiq_status_to_vchi(status);
753290245Sgonzo	}
754290245Sgonzo	return ret;
755290245Sgonzo}
756290245SgonzoEXPORT_SYMBOL(vchi_service_set_option);
757290245Sgonzo
758278277Sgonzoint32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version )
759278277Sgonzo{
760278277Sgonzo   int32_t ret = -1;
761278277Sgonzo   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
762278277Sgonzo   if(service)
763278277Sgonzo   {
764278277Sgonzo      VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version);
765278277Sgonzo      ret = vchiq_status_to_vchi( status );
766278277Sgonzo   }
767278277Sgonzo   return ret;
768278277Sgonzo}
769278277SgonzoEXPORT_SYMBOL(vchi_get_peer_version);
770278277Sgonzo
771278277Sgonzo#ifdef notyet
772278277Sgonzo/* ----------------------------------------------------------------------
773278277Sgonzo * read a uint32_t from buffer.
774278277Sgonzo * network format is defined to be little endian
775278277Sgonzo * -------------------------------------------------------------------- */
776278277Sgonzouint32_t
777278277Sgonzovchi_readbuf_uint32(const void *_ptr)
778278277Sgonzo{
779278277Sgonzo	const unsigned char *ptr = _ptr;
780278277Sgonzo	return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
781278277Sgonzo}
782278277Sgonzo
783278277Sgonzo/* ----------------------------------------------------------------------
784278277Sgonzo * write a uint32_t to buffer.
785278277Sgonzo * network format is defined to be little endian
786278277Sgonzo * -------------------------------------------------------------------- */
787278277Sgonzovoid
788278277Sgonzovchi_writebuf_uint32(void *_ptr, uint32_t value)
789278277Sgonzo{
790278277Sgonzo	unsigned char *ptr = _ptr;
791278277Sgonzo	ptr[0] = (unsigned char)((value >> 0)  & 0xFF);
792278277Sgonzo	ptr[1] = (unsigned char)((value >> 8)  & 0xFF);
793278277Sgonzo	ptr[2] = (unsigned char)((value >> 16) & 0xFF);
794278277Sgonzo	ptr[3] = (unsigned char)((value >> 24) & 0xFF);
795278277Sgonzo}
796278277Sgonzo
797278277Sgonzo/* ----------------------------------------------------------------------
798278277Sgonzo * read a uint16_t from buffer.
799278277Sgonzo * network format is defined to be little endian
800278277Sgonzo * -------------------------------------------------------------------- */
801278277Sgonzouint16_t
802278277Sgonzovchi_readbuf_uint16(const void *_ptr)
803278277Sgonzo{
804278277Sgonzo	const unsigned char *ptr = _ptr;
805278277Sgonzo	return ptr[0] | (ptr[1] << 8);
806278277Sgonzo}
807278277Sgonzo
808278277Sgonzo/* ----------------------------------------------------------------------
809278277Sgonzo * write a uint16_t into the buffer.
810278277Sgonzo * network format is defined to be little endian
811278277Sgonzo * -------------------------------------------------------------------- */
812278277Sgonzovoid
813278277Sgonzovchi_writebuf_uint16(void *_ptr, uint16_t value)
814278277Sgonzo{
815278277Sgonzo	unsigned char *ptr = _ptr;
816278277Sgonzo	ptr[0] = (value >> 0)  & 0xFF;
817278277Sgonzo	ptr[1] = (value >> 8)  & 0xFF;
818278277Sgonzo}
819278277Sgonzo#endif
820278277Sgonzo
821278277Sgonzo/***********************************************************
822278277Sgonzo * Name: vchi_service_use
823278277Sgonzo *
824278277Sgonzo * Arguments: const VCHI_SERVICE_HANDLE_T handle
825278277Sgonzo *
826278277Sgonzo * Description: Routine to increment refcount on a service
827278277Sgonzo *
828278277Sgonzo * Returns: void
829278277Sgonzo *
830278277Sgonzo ***********************************************************/
831278277Sgonzoint32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
832278277Sgonzo{
833278277Sgonzo	int32_t ret = -1;
834278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
835278277Sgonzo	if (service)
836278277Sgonzo		ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
837278277Sgonzo	return ret;
838278277Sgonzo}
839278277SgonzoEXPORT_SYMBOL(vchi_service_use);
840278277Sgonzo
841278277Sgonzo/***********************************************************
842278277Sgonzo * Name: vchi_service_release
843278277Sgonzo *
844278277Sgonzo * Arguments: const VCHI_SERVICE_HANDLE_T handle
845278277Sgonzo *
846278277Sgonzo * Description: Routine to decrement refcount on a service
847278277Sgonzo *
848278277Sgonzo * Returns: void
849278277Sgonzo *
850278277Sgonzo ***********************************************************/
851278277Sgonzoint32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
852278277Sgonzo{
853278277Sgonzo	int32_t ret = -1;
854278277Sgonzo	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
855278277Sgonzo	if (service)
856278277Sgonzo		ret = vchiq_status_to_vchi(
857278277Sgonzo			vchiq_release_service(service->handle));
858278277Sgonzo	return ret;
859278277Sgonzo}
860278277SgonzoEXPORT_SYMBOL(vchi_service_release);
861