xref: /freebsd/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c (revision b626f5a73a48f44a31a200291b141e1da408a2ff)
1 /**
2  * Copyright (c) 2010-2012 Broadcom. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions, and the following disclaimer,
9  *    without modification.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The names of the above-listed copyright holders may not be used
14  *    to endorse or promote products derived from this software without
15  *    specific prior written permission.
16  *
17  * ALTERNATIVELY, this software may be distributed under the terms of the
18  * GNU General Public License ("GPL") version 2, as published by the Free
19  * Software Foundation.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <interface/compat/vchi_bsd.h>
35 
36 #include "interface/vchi/vchi.h"
37 #include "vchiq.h"
38 #include "vchiq_core.h"
39 
40 #include "vchiq_util.h"
41 
42 #define vchiq_status_to_vchi(status) ((int32_t)status)
43 
44 typedef struct {
45 	VCHIQ_SERVICE_HANDLE_T handle;
46 
47 	VCHIU_QUEUE_T queue;
48 
49 	VCHI_CALLBACK_T callback;
50 	void *callback_param;
51 } SHIM_SERVICE_T;
52 
53 /* ----------------------------------------------------------------------
54  * return pointer to the mphi message driver function table
55  * -------------------------------------------------------------------- */
56 const VCHI_MESSAGE_DRIVER_T *
vchi_mphi_message_driver_func_table(void)57 vchi_mphi_message_driver_func_table(void)
58 {
59 	return NULL;
60 }
61 
62 /* ----------------------------------------------------------------------
63  * return a pointer to the 'single' connection driver fops
64  * -------------------------------------------------------------------- */
65 const VCHI_CONNECTION_API_T *
single_get_func_table(void)66 single_get_func_table(void)
67 {
68 	return NULL;
69 }
70 
vchi_create_connection(const VCHI_CONNECTION_API_T * function_table,const VCHI_MESSAGE_DRIVER_T * low_level)71 VCHI_CONNECTION_T *vchi_create_connection(
72 	const VCHI_CONNECTION_API_T *function_table,
73 	const VCHI_MESSAGE_DRIVER_T *low_level)
74 {
75 	(void)function_table;
76 	(void)low_level;
77 	return NULL;
78 }
79 
80 /***********************************************************
81  * Name: vchi_msg_peek
82  *
83  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
84  *             void **data,
85  *             uint32_t *msg_size,
86 
87 
88  *             VCHI_FLAGS_T flags
89  *
90  * Description: Routine to return a pointer to the current message (to allow in
91  *              place processing). The message can be removed using
92  *              vchi_msg_remove when you're finished
93  *
94  * Returns: int32_t - success == 0
95  *
96  ***********************************************************/
vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags)97 int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
98 	void **data,
99 	uint32_t *msg_size,
100 	VCHI_FLAGS_T flags)
101 {
102 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
103 	VCHIQ_HEADER_T *header;
104 
105 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
106 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
107 
108 	if (flags == VCHI_FLAGS_NONE)
109 		if (vchiu_queue_is_empty(&service->queue))
110 			return -1;
111 
112 	header = vchiu_queue_peek(&service->queue);
113 
114 	*data = header->data;
115 	*msg_size = header->size;
116 
117 	return 0;
118 }
119 EXPORT_SYMBOL(vchi_msg_peek);
120 
121 /***********************************************************
122  * Name: vchi_msg_remove
123  *
124  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
125  *
126  * Description: Routine to remove a message (after it has been read with
127  *              vchi_msg_peek)
128  *
129  * Returns: int32_t - success == 0
130  *
131  ***********************************************************/
vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)132 int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
133 {
134 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
135 	VCHIQ_HEADER_T *header;
136 
137 	header = vchiu_queue_pop(&service->queue);
138 
139 	vchiq_release_message(service->handle, header);
140 
141 	return 0;
142 }
143 EXPORT_SYMBOL(vchi_msg_remove);
144 
145 /***********************************************************
146  * Name: vchi_msg_queue
147  *
148  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
149  *             const void *data,
150  *             uint32_t data_size,
151  *             VCHI_FLAGS_T flags,
152  *             void *msg_handle,
153  *
154  * Description: Thin wrapper to queue a message onto a connection
155  *
156  * Returns: int32_t - success == 0
157  *
158  ***********************************************************/
vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,const void * data,uint32_t data_size,VCHI_FLAGS_T flags,void * msg_handle)159 int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
160 	const void *data,
161 	uint32_t data_size,
162 	VCHI_FLAGS_T flags,
163 	void *msg_handle)
164 {
165 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
166 	VCHIQ_ELEMENT_T element = {data, data_size};
167 	VCHIQ_STATUS_T status;
168 
169 	(void)msg_handle;
170 
171 	WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
172 
173 	status = vchiq_queue_message(service->handle, &element, 1);
174 
175 	/* vchiq_queue_message() may return VCHIQ_RETRY, so we need to
176 	** implement a retry mechanism since this function is supposed
177 	** to block until queued
178 	*/
179 	while (status == VCHIQ_RETRY) {
180 		msleep(1);
181 		status = vchiq_queue_message(service->handle, &element, 1);
182 	}
183 
184 	return vchiq_status_to_vchi(status);
185 }
186 EXPORT_SYMBOL(vchi_msg_queue);
187 
188 /***********************************************************
189  * Name: vchi_bulk_queue_receive
190  *
191  * Arguments:  VCHI_BULK_HANDLE_T handle,
192  *             void *data_dst,
193  *             const uint32_t data_size,
194  *             VCHI_FLAGS_T flags
195  *             void *bulk_handle
196  *
197  * Description: Routine to setup a rcv buffer
198  *
199  * Returns: int32_t - success == 0
200  *
201  ***********************************************************/
vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,void * data_dst,uint32_t data_size,VCHI_FLAGS_T flags,void * bulk_handle)202 int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
203 	void *data_dst,
204 	uint32_t data_size,
205 	VCHI_FLAGS_T flags,
206 	void *bulk_handle)
207 {
208 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
209 	VCHIQ_BULK_MODE_T mode;
210 	VCHIQ_STATUS_T status;
211 
212 	switch ((int)flags) {
213 	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
214 		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
215 		WARN_ON(!service->callback);
216 		mode = VCHIQ_BULK_MODE_CALLBACK;
217 		break;
218 	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
219 		mode = VCHIQ_BULK_MODE_BLOCKING;
220 		break;
221 	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
222 	case VCHI_FLAGS_NONE:
223 		mode = VCHIQ_BULK_MODE_NOCALLBACK;
224 		break;
225 	default:
226 		WARN(1, "unsupported message\n");
227 		return vchiq_status_to_vchi(VCHIQ_ERROR);
228 	}
229 
230 	status = vchiq_bulk_receive(service->handle, data_dst, data_size,
231 		bulk_handle, mode);
232 
233 	/* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
234 	** implement a retry mechanism since this function is supposed
235 	** to block until queued
236 	*/
237 	while (status == VCHIQ_RETRY) {
238 		msleep(1);
239 		status = vchiq_bulk_receive(service->handle, data_dst,
240 			data_size, bulk_handle, mode);
241 	}
242 
243 	return vchiq_status_to_vchi(status);
244 }
245 EXPORT_SYMBOL(vchi_bulk_queue_receive);
246 
247 /***********************************************************
248  * Name: vchi_bulk_queue_transmit
249  *
250  * Arguments:  VCHI_BULK_HANDLE_T handle,
251  *             void *data_src,
252  *             uint32_t data_size,
253  *             VCHI_FLAGS_T flags,
254  *             void *bulk_handle
255  *
256  * Description: Routine to transmit some data
257  *
258  * Returns: int32_t - success == 0
259  *
260  ***********************************************************/
vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,void * data_src,uint32_t data_size,VCHI_FLAGS_T flags,void * bulk_handle)261 int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
262 	void *data_src,
263 	uint32_t data_size,
264 	VCHI_FLAGS_T flags,
265 	void *bulk_handle)
266 {
267 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
268 	VCHIQ_BULK_MODE_T mode;
269 	VCHIQ_STATUS_T status;
270 
271 	switch ((int)flags) {
272 	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
273 		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
274 		WARN_ON(!service->callback);
275 		mode = VCHIQ_BULK_MODE_CALLBACK;
276 		break;
277 	case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
278 	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
279 		mode = VCHIQ_BULK_MODE_BLOCKING;
280 		break;
281 	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
282 	case VCHI_FLAGS_NONE:
283 		mode = VCHIQ_BULK_MODE_NOCALLBACK;
284 		break;
285 	default:
286 		WARN(1, "unsupported message\n");
287 		return vchiq_status_to_vchi(VCHIQ_ERROR);
288 	}
289 
290 	status = vchiq_bulk_transmit(service->handle, data_src, data_size,
291 		bulk_handle, mode);
292 
293 	/* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
294 	** implement a retry mechanism since this function is supposed
295 	** to block until queued
296 	*/
297 	while (status == VCHIQ_RETRY) {
298 		msleep(1);
299 		status = vchiq_bulk_transmit(service->handle, data_src,
300 			data_size, bulk_handle, mode);
301 	}
302 
303 	return vchiq_status_to_vchi(status);
304 }
305 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
306 
307 /***********************************************************
308  * Name: vchi_msg_dequeue
309  *
310  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
311  *             void *data,
312  *             uint32_t max_data_size_to_read,
313  *             uint32_t *actual_msg_size
314  *             VCHI_FLAGS_T flags
315  *
316  * Description: Routine to dequeue a message into the supplied buffer
317  *
318  * Returns: int32_t - success == 0
319  *
320  ***********************************************************/
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)321 int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
322 	void *data,
323 	uint32_t max_data_size_to_read,
324 	uint32_t *actual_msg_size,
325 	VCHI_FLAGS_T flags)
326 {
327 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
328 	VCHIQ_HEADER_T *header;
329 
330 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
331 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
332 
333 	if (flags == VCHI_FLAGS_NONE)
334 		if (vchiu_queue_is_empty(&service->queue))
335 			return -1;
336 
337 	header = vchiu_queue_pop(&service->queue);
338 
339 	memcpy(data, header->data, header->size < max_data_size_to_read ?
340 		header->size : max_data_size_to_read);
341 
342 	*actual_msg_size = header->size;
343 
344 	vchiq_release_message(service->handle, header);
345 
346 	return 0;
347 }
348 EXPORT_SYMBOL(vchi_msg_dequeue);
349 
350 /***********************************************************
351  * Name: vchi_msg_queuev
352  *
353  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
354  *             VCHI_MSG_VECTOR_T *vector,
355  *             uint32_t count,
356  *             VCHI_FLAGS_T flags,
357  *             void *msg_handle
358  *
359  * Description: Thin wrapper to queue a message onto a connection
360  *
361  * Returns: int32_t - success == 0
362  *
363  ***********************************************************/
364 
365 vchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
366 vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) ==
367 	offsetof(VCHIQ_ELEMENT_T, data));
368 vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) ==
369 	offsetof(VCHIQ_ELEMENT_T, size));
370 
vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,VCHI_MSG_VECTOR_T * vector,uint32_t count,VCHI_FLAGS_T flags,void * msg_handle)371 int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,
372 	VCHI_MSG_VECTOR_T *vector,
373 	uint32_t count,
374 	VCHI_FLAGS_T flags,
375 	void *msg_handle)
376 {
377 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
378 
379 	(void)msg_handle;
380 
381 	WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
382 
383 	return vchiq_status_to_vchi(vchiq_queue_message(service->handle,
384 		(const VCHIQ_ELEMENT_T *)vector, count));
385 }
386 EXPORT_SYMBOL(vchi_msg_queuev);
387 
388 /***********************************************************
389  * Name: vchi_held_msg_release
390  *
391  * Arguments:  VCHI_HELD_MSG_T *message
392  *
393  * Description: Routine to release a held message (after it has been read with
394  *              vchi_msg_hold)
395  *
396  * Returns: int32_t - success == 0
397  *
398  ***********************************************************/
vchi_held_msg_release(VCHI_HELD_MSG_T * message)399 int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
400 {
401 	vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service,
402 		(VCHIQ_HEADER_T *)message->message);
403 
404 	return 0;
405 }
406 EXPORT_SYMBOL(vchi_held_msg_release);
407 
408 /***********************************************************
409  * Name: vchi_msg_hold
410  *
411  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
412  *             void **data,
413  *             uint32_t *msg_size,
414  *             VCHI_FLAGS_T flags,
415  *             VCHI_HELD_MSG_T *message_handle
416  *
417  * Description: Routine to return a pointer to the current message (to allow
418  *              in place processing). The message is dequeued - don't forget
419  *              to release the message using vchi_held_msg_release when you're
420  *              finished.
421  *
422  * Returns: int32_t - success == 0
423  *
424  ***********************************************************/
vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags,VCHI_HELD_MSG_T * message_handle)425 int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
426 	void **data,
427 	uint32_t *msg_size,
428 	VCHI_FLAGS_T flags,
429 	VCHI_HELD_MSG_T *message_handle)
430 {
431 	SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
432 	VCHIQ_HEADER_T *header;
433 
434 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
435 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
436 
437 	if (flags == VCHI_FLAGS_NONE)
438 		if (vchiu_queue_is_empty(&service->queue))
439 			return -1;
440 
441 	header = vchiu_queue_pop(&service->queue);
442 
443 	*data = header->data;
444 	*msg_size = header->size;
445 
446 	message_handle->service =
447 		(struct opaque_vchi_service_t *)service->handle;
448 	message_handle->message = header;
449 
450 	return 0;
451 }
452 EXPORT_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 
vchi_initialise(VCHI_INSTANCE_T * instance_handle)467 int32_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 }
478 EXPORT_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  ***********************************************************/
vchi_connect(VCHI_CONNECTION_T ** connections,const uint32_t num_connections,VCHI_INSTANCE_T instance_handle)493 int32_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 }
504 EXPORT_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  ***********************************************************/
vchi_disconnect(VCHI_INSTANCE_T instance_handle)518 int32_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 }
523 EXPORT_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 
shim_callback(VCHIQ_REASON_T reason,VCHIQ_HEADER_T * header,VCHIQ_SERVICE_HANDLE_T handle,void * bulk_user)540 static 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 
595 release:
596         vchiq_release_message(service->handle, header);
597 done:
598 	return VCHIQ_SUCCESS;
599 }
600 
service_alloc(VCHIQ_INSTANCE_T instance,SERVICE_CREATION_T * setup)601 static 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 
service_free(SHIM_SERVICE_T * service)621 static void service_free(SHIM_SERVICE_T *service)
622 {
623 	if (service) {
624 		vchiu_queue_delete(&service->queue);
625 		kfree(service);
626 	}
627 }
628 
vchi_service_open(VCHI_INSTANCE_T instance_handle,SERVICE_CREATION_T * setup,VCHI_SERVICE_HANDLE_T * handle)629 int32_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 }
660 EXPORT_SYMBOL(vchi_service_open);
661 
vchi_service_create(VCHI_INSTANCE_T instance_handle,SERVICE_CREATION_T * setup,VCHI_SERVICE_HANDLE_T * handle)662 int32_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 }
692 EXPORT_SYMBOL(vchi_service_create);
693 
vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)694 int32_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 }
709 EXPORT_SYMBOL(vchi_service_close);
710 
vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)711 int32_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 }
726 EXPORT_SYMBOL(vchi_service_destroy);
727 
vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,VCHI_SERVICE_OPTION_T option,int value)728 int32_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 }
756 EXPORT_SYMBOL(vchi_service_set_option);
757 
vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle,short * peer_version)758 int32_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 }
769 EXPORT_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  * -------------------------------------------------------------------- */
776 uint32_t
vchi_readbuf_uint32(const void * _ptr)777 vchi_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  * -------------------------------------------------------------------- */
787 void
vchi_writebuf_uint32(void * _ptr,uint32_t value)788 vchi_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  * -------------------------------------------------------------------- */
801 uint16_t
vchi_readbuf_uint16(const void * _ptr)802 vchi_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  * -------------------------------------------------------------------- */
812 void
vchi_writebuf_uint16(void * _ptr,uint16_t value)813 vchi_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  ***********************************************************/
vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)831 int32_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 }
839 EXPORT_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  ***********************************************************/
vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)851 int32_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 }
860 EXPORT_SYMBOL(vchi_service_release);
861