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 #include <linux/module.h>
34 #include <linux/types.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 struct shim_service {
45 	VCHIQ_SERVICE_HANDLE_T handle;
46 
47 	VCHIU_QUEUE_T queue;
48 
49 	VCHI_CALLBACK_T callback;
50 	void *callback_param;
51 };
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  *             VCHI_FLAGS_T flags
88  *
89  * Description: Routine to return a pointer to the current message (to allow in
90  *              place processing). The message can be removed using
91  *              vchi_msg_remove when you're finished
92  *
93  * Returns: int32_t - success == 0
94  *
95  ***********************************************************/
vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags)96 int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
97 	void **data,
98 	uint32_t *msg_size,
99 	VCHI_FLAGS_T flags)
100 {
101 	struct shim_service *service = (struct shim_service *)handle;
102 	VCHIQ_HEADER_T *header;
103 
104 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
105 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
106 
107 	if (flags == VCHI_FLAGS_NONE)
108 		if (vchiu_queue_is_empty(&service->queue))
109 			return -1;
110 
111 	header = vchiu_queue_peek(&service->queue);
112 
113 	*data = header->data;
114 	*msg_size = header->size;
115 
116 	return 0;
117 }
118 EXPORT_SYMBOL(vchi_msg_peek);
119 
120 /***********************************************************
121  * Name: vchi_msg_remove
122  *
123  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
124  *
125  * Description: Routine to remove a message (after it has been read with
126  *              vchi_msg_peek)
127  *
128  * Returns: int32_t - success == 0
129  *
130  ***********************************************************/
vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)131 int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
132 {
133 	struct shim_service *service = (struct shim_service *)handle;
134 	VCHIQ_HEADER_T *header;
135 
136 	header = vchiu_queue_pop(&service->queue);
137 
138 	vchiq_release_message(service->handle, header);
139 
140 	return 0;
141 }
142 EXPORT_SYMBOL(vchi_msg_remove);
143 
144 /***********************************************************
145  * Name: vchi_msg_queue
146  *
147  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
148  *             ssize_t (*copy_callback)(void *context, void *dest,
149  *				        size_t offset, size_t maxsize),
150  *	       void *context,
151  *             uint32_t data_size
152  *
153  * Description: Thin wrapper to queue a message onto a connection
154  *
155  * Returns: int32_t - success == 0
156  *
157  ***********************************************************/
158 static
vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,ssize_t (* copy_callback)(void * context,void * dest,size_t offset,size_t maxsize),void * context,uint32_t data_size)159 int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
160 	ssize_t (*copy_callback)(void *context, void *dest,
161 				 size_t offset, size_t maxsize),
162 	void *context,
163 	uint32_t data_size)
164 {
165 	struct shim_service *service = (struct shim_service *)handle;
166 	VCHIQ_STATUS_T status;
167 
168 	while (1) {
169 		status = vchiq_queue_message(service->handle,
170 					     copy_callback,
171 					     context,
172 					     data_size);
173 
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 		if (status != VCHIQ_RETRY)
180 			break;
181 
182 		msleep(1);
183 	}
184 
185 	return vchiq_status_to_vchi(status);
186 }
187 
188 static ssize_t
vchi_queue_kernel_message_callback(void * context,void * dest,size_t offset,size_t maxsize)189 vchi_queue_kernel_message_callback(void *context,
190 				   void *dest,
191 				   size_t offset,
192 				   size_t maxsize)
193 {
194 	memcpy(dest, context + offset, maxsize);
195 	return maxsize;
196 }
197 
198 int
vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,void * data,unsigned int size)199 vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,
200 			  void *data,
201 			  unsigned int size)
202 {
203 	return vchi_msg_queue(handle,
204 			      vchi_queue_kernel_message_callback,
205 			      data,
206 			      size);
207 }
208 EXPORT_SYMBOL(vchi_queue_kernel_message);
209 
210 struct vchi_queue_user_message_context {
211 	void __user *data;
212 };
213 
214 static ssize_t
vchi_queue_user_message_callback(void * context,void * dest,size_t offset,size_t maxsize)215 vchi_queue_user_message_callback(void *context,
216 				 void *dest,
217 				 size_t offset,
218 				 size_t maxsize)
219 {
220 	struct vchi_queue_user_message_context *copycontext = context;
221 
222 	if (copy_from_user(dest, copycontext->data + offset, maxsize))
223 		return -EFAULT;
224 
225 	return maxsize;
226 }
227 
228 int
vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,void __user * data,unsigned int size)229 vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,
230 			void __user *data,
231 			unsigned int size)
232 {
233 	struct vchi_queue_user_message_context copycontext = {
234 		.data = data
235 	};
236 
237 	return vchi_msg_queue(handle,
238 			      vchi_queue_user_message_callback,
239 			      &copycontext,
240 			      size);
241 }
242 EXPORT_SYMBOL(vchi_queue_user_message);
243 
244 /***********************************************************
245  * Name: vchi_bulk_queue_receive
246  *
247  * Arguments:  VCHI_BULK_HANDLE_T handle,
248  *             void *data_dst,
249  *             const uint32_t data_size,
250  *             VCHI_FLAGS_T flags
251  *             void *bulk_handle
252  *
253  * Description: Routine to setup a rcv buffer
254  *
255  * Returns: int32_t - success == 0
256  *
257  ***********************************************************/
vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,void * data_dst,uint32_t data_size,VCHI_FLAGS_T flags,void * bulk_handle)258 int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
259 	void *data_dst,
260 	uint32_t data_size,
261 	VCHI_FLAGS_T flags,
262 	void *bulk_handle)
263 {
264 	struct shim_service *service = (struct shim_service *)handle;
265 	VCHIQ_BULK_MODE_T mode;
266 	VCHIQ_STATUS_T status;
267 
268 	switch ((int)flags) {
269 	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
270 		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
271 		WARN_ON(!service->callback);
272 		mode = VCHIQ_BULK_MODE_CALLBACK;
273 		break;
274 	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
275 		mode = VCHIQ_BULK_MODE_BLOCKING;
276 		break;
277 	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
278 	case VCHI_FLAGS_NONE:
279 		mode = VCHIQ_BULK_MODE_NOCALLBACK;
280 		break;
281 	default:
282 		WARN(1, "unsupported message\n");
283 		return vchiq_status_to_vchi(VCHIQ_ERROR);
284 	}
285 
286 	while (1) {
287 		status = vchiq_bulk_receive(service->handle, data_dst,
288 			data_size, bulk_handle, mode);
289 		/*
290 		 * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
291 		 * implement a retry mechanism since this function is supposed
292 		 * to block until queued
293 		 */
294 		if (status != VCHIQ_RETRY)
295 			break;
296 
297 		msleep(1);
298 	}
299 
300 	return vchiq_status_to_vchi(status);
301 }
302 EXPORT_SYMBOL(vchi_bulk_queue_receive);
303 
304 /***********************************************************
305  * Name: vchi_bulk_queue_transmit
306  *
307  * Arguments:  VCHI_BULK_HANDLE_T handle,
308  *             const void *data_src,
309  *             uint32_t data_size,
310  *             VCHI_FLAGS_T flags,
311  *             void *bulk_handle
312  *
313  * Description: Routine to transmit some data
314  *
315  * Returns: int32_t - success == 0
316  *
317  ***********************************************************/
vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,const void * data_src,uint32_t data_size,VCHI_FLAGS_T flags,void * bulk_handle)318 int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
319 	const void *data_src,
320 	uint32_t data_size,
321 	VCHI_FLAGS_T flags,
322 	void *bulk_handle)
323 {
324 	struct shim_service *service = (struct shim_service *)handle;
325 	VCHIQ_BULK_MODE_T mode;
326 	VCHIQ_STATUS_T status;
327 
328 	switch ((int)flags) {
329 	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
330 		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
331 		WARN_ON(!service->callback);
332 		mode = VCHIQ_BULK_MODE_CALLBACK;
333 		break;
334 	case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
335 	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
336 		mode = VCHIQ_BULK_MODE_BLOCKING;
337 		break;
338 	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
339 	case VCHI_FLAGS_NONE:
340 		mode = VCHIQ_BULK_MODE_NOCALLBACK;
341 		break;
342 	default:
343 		WARN(1, "unsupported message\n");
344 		return vchiq_status_to_vchi(VCHIQ_ERROR);
345 	}
346 
347 	while (1) {
348 		status = vchiq_bulk_transmit(service->handle, data_src,
349 			data_size, bulk_handle, mode);
350 
351 		/*
352 		 * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
353 		 * implement a retry mechanism since this function is supposed
354 		 * to block until queued
355 		 */
356 		if (status != VCHIQ_RETRY)
357 			break;
358 
359 		msleep(1);
360 	}
361 
362 	return vchiq_status_to_vchi(status);
363 }
364 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
365 
366 /***********************************************************
367  * Name: vchi_msg_dequeue
368  *
369  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
370  *             void *data,
371  *             uint32_t max_data_size_to_read,
372  *             uint32_t *actual_msg_size
373  *             VCHI_FLAGS_T flags
374  *
375  * Description: Routine to dequeue a message into the supplied buffer
376  *
377  * Returns: int32_t - success == 0
378  *
379  ***********************************************************/
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)380 int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
381 	void *data,
382 	uint32_t max_data_size_to_read,
383 	uint32_t *actual_msg_size,
384 	VCHI_FLAGS_T flags)
385 {
386 	struct shim_service *service = (struct shim_service *)handle;
387 	VCHIQ_HEADER_T *header;
388 
389 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
390 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
391 
392 	if (flags == VCHI_FLAGS_NONE)
393 		if (vchiu_queue_is_empty(&service->queue))
394 			return -1;
395 
396 	header = vchiu_queue_pop(&service->queue);
397 
398 	memcpy(data, header->data, header->size < max_data_size_to_read ?
399 		header->size : max_data_size_to_read);
400 
401 	*actual_msg_size = header->size;
402 
403 	vchiq_release_message(service->handle, header);
404 
405 	return 0;
406 }
407 EXPORT_SYMBOL(vchi_msg_dequeue);
408 
409 /***********************************************************
410  * Name: vchi_held_msg_release
411  *
412  * Arguments:  VCHI_HELD_MSG_T *message
413  *
414  * Description: Routine to release a held message (after it has been read with
415  *              vchi_msg_hold)
416  *
417  * Returns: int32_t - success == 0
418  *
419  ***********************************************************/
vchi_held_msg_release(VCHI_HELD_MSG_T * message)420 int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
421 {
422 	/*
423 	 * Convert the service field pointer back to an
424 	 * VCHIQ_SERVICE_HANDLE_T which is an int.
425 	 * This pointer is opaque to everything except
426 	 * vchi_msg_hold which simply upcasted the int
427 	 * to a pointer.
428 	 */
429 
430 	vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)(long)message->service,
431 			      (VCHIQ_HEADER_T *)message->message);
432 
433 	return 0;
434 }
435 EXPORT_SYMBOL(vchi_held_msg_release);
436 
437 /***********************************************************
438  * Name: vchi_msg_hold
439  *
440  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
441  *             void **data,
442  *             uint32_t *msg_size,
443  *             VCHI_FLAGS_T flags,
444  *             VCHI_HELD_MSG_T *message_handle
445  *
446  * Description: Routine to return a pointer to the current message (to allow
447  *              in place processing). The message is dequeued - don't forget
448  *              to release the message using vchi_held_msg_release when you're
449  *              finished.
450  *
451  * Returns: int32_t - success == 0
452  *
453  ***********************************************************/
vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags,VCHI_HELD_MSG_T * message_handle)454 int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
455 	void **data,
456 	uint32_t *msg_size,
457 	VCHI_FLAGS_T flags,
458 	VCHI_HELD_MSG_T *message_handle)
459 {
460 	struct shim_service *service = (struct shim_service *)handle;
461 	VCHIQ_HEADER_T *header;
462 
463 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
464 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
465 
466 	if (flags == VCHI_FLAGS_NONE)
467 		if (vchiu_queue_is_empty(&service->queue))
468 			return -1;
469 
470 	header = vchiu_queue_pop(&service->queue);
471 
472 	*data = header->data;
473 	*msg_size = header->size;
474 
475 	/*
476 	 * upcast the VCHIQ_SERVICE_HANDLE_T which is an int
477 	 * to a pointer and stuff it in the held message.
478 	 * This pointer is opaque to everything except
479 	 * vchi_held_msg_release which simply downcasts it back
480 	 * to an int.
481 	 */
482 
483 	message_handle->service =
484 		(struct opaque_vchi_service_t *)(long)service->handle;
485 	message_handle->message = header;
486 
487 	return 0;
488 }
489 EXPORT_SYMBOL(vchi_msg_hold);
490 
491 /***********************************************************
492  * Name: vchi_initialise
493  *
494  * Arguments: VCHI_INSTANCE_T *instance_handle
495  *
496  * Description: Initialises the hardware but does not transmit anything
497  *              When run as a Host App this will be called twice hence the need
498  *              to malloc the state information
499  *
500  * Returns: 0 if successful, failure otherwise
501  *
502  ***********************************************************/
503 
vchi_initialise(VCHI_INSTANCE_T * instance_handle)504 int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
505 {
506 	VCHIQ_INSTANCE_T instance;
507 	VCHIQ_STATUS_T status;
508 
509 	status = vchiq_initialise(&instance);
510 
511 	*instance_handle = (VCHI_INSTANCE_T)instance;
512 
513 	return vchiq_status_to_vchi(status);
514 }
515 EXPORT_SYMBOL(vchi_initialise);
516 
517 /***********************************************************
518  * Name: vchi_connect
519  *
520  * Arguments: VCHI_CONNECTION_T **connections
521  *            const uint32_t num_connections
522  *            VCHI_INSTANCE_T instance_handle)
523  *
524  * Description: Starts the command service on each connection,
525  *              causing INIT messages to be pinged back and forth
526  *
527  * Returns: 0 if successful, failure otherwise
528  *
529  ***********************************************************/
vchi_connect(VCHI_CONNECTION_T ** connections,const uint32_t num_connections,VCHI_INSTANCE_T instance_handle)530 int32_t vchi_connect(VCHI_CONNECTION_T **connections,
531 	const uint32_t num_connections,
532 	VCHI_INSTANCE_T instance_handle)
533 {
534 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
535 
536 	(void)connections;
537 	(void)num_connections;
538 
539 	return vchiq_connect(instance);
540 }
541 EXPORT_SYMBOL(vchi_connect);
542 
543 /***********************************************************
544  * Name: vchi_disconnect
545  *
546  * Arguments: VCHI_INSTANCE_T instance_handle
547  *
548  * Description: Stops the command service on each connection,
549  *              causing DE-INIT messages to be pinged back and forth
550  *
551  * Returns: 0 if successful, failure otherwise
552  *
553  ***********************************************************/
vchi_disconnect(VCHI_INSTANCE_T instance_handle)554 int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
555 {
556 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
557 
558 	return vchiq_status_to_vchi(vchiq_shutdown(instance));
559 }
560 EXPORT_SYMBOL(vchi_disconnect);
561 
562 /***********************************************************
563  * Name: vchi_service_open
564  * Name: vchi_service_create
565  *
566  * Arguments: VCHI_INSTANCE_T *instance_handle
567  *            SERVICE_CREATION_T *setup,
568  *            VCHI_SERVICE_HANDLE_T *handle
569  *
570  * Description: Routine to open a service
571  *
572  * Returns: int32_t - success == 0
573  *
574  ***********************************************************/
575 
shim_callback(VCHIQ_REASON_T reason,VCHIQ_HEADER_T * header,VCHIQ_SERVICE_HANDLE_T handle,void * bulk_user)576 static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
577 	VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
578 {
579 	struct shim_service *service =
580 		(struct shim_service *)VCHIQ_GET_SERVICE_USERDATA(handle);
581 
582 	if (!service->callback)
583 		goto release;
584 
585 	switch (reason) {
586 	case VCHIQ_MESSAGE_AVAILABLE:
587 		vchiu_queue_push(&service->queue, header);
588 
589 		service->callback(service->callback_param,
590 				  VCHI_CALLBACK_MSG_AVAILABLE, NULL);
591 
592 		goto done;
593 
594 	case VCHIQ_BULK_TRANSMIT_DONE:
595 		service->callback(service->callback_param,
596 				  VCHI_CALLBACK_BULK_SENT, bulk_user);
597 		break;
598 
599 	case VCHIQ_BULK_RECEIVE_DONE:
600 		service->callback(service->callback_param,
601 				  VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
602 		break;
603 
604 	case VCHIQ_SERVICE_CLOSED:
605 		service->callback(service->callback_param,
606 				  VCHI_CALLBACK_SERVICE_CLOSED, NULL);
607 		break;
608 
609 	case VCHIQ_SERVICE_OPENED:
610 		/* No equivalent VCHI reason */
611 		break;
612 
613 	case VCHIQ_BULK_TRANSMIT_ABORTED:
614 		service->callback(service->callback_param,
615 				  VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
616 				  bulk_user);
617 		break;
618 
619 	case VCHIQ_BULK_RECEIVE_ABORTED:
620 		service->callback(service->callback_param,
621 				  VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
622 				  bulk_user);
623 		break;
624 
625 	default:
626 		WARN(1, "not supported\n");
627 		break;
628 	}
629 
630 release:
631 	vchiq_release_message(service->handle, header);
632 done:
633 	return VCHIQ_SUCCESS;
634 }
635 
service_alloc(VCHIQ_INSTANCE_T instance,SERVICE_CREATION_T * setup)636 static struct shim_service *service_alloc(VCHIQ_INSTANCE_T instance,
637 	SERVICE_CREATION_T *setup)
638 {
639 	struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL);
640 
641 	(void)instance;
642 
643 	if (service) {
644 		if (vchiu_queue_init(&service->queue, 64)) {
645 			service->callback = setup->callback;
646 			service->callback_param = setup->callback_param;
647 		} else {
648 			kfree(service);
649 			service = NULL;
650 		}
651 	}
652 
653 	return service;
654 }
655 
service_free(struct shim_service * service)656 static void service_free(struct shim_service *service)
657 {
658 	if (service) {
659 		vchiu_queue_delete(&service->queue);
660 		kfree(service);
661 	}
662 }
663 
vchi_service_open(VCHI_INSTANCE_T instance_handle,SERVICE_CREATION_T * setup,VCHI_SERVICE_HANDLE_T * handle)664 int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
665 	SERVICE_CREATION_T *setup,
666 	VCHI_SERVICE_HANDLE_T *handle)
667 {
668 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
669 	struct shim_service *service = service_alloc(instance, setup);
670 
671 	*handle = (VCHI_SERVICE_HANDLE_T)service;
672 
673 	if (service) {
674 		VCHIQ_SERVICE_PARAMS_T params;
675 		VCHIQ_STATUS_T status;
676 
677 		memset(&params, 0, sizeof(params));
678 		params.fourcc = setup->service_id;
679 		params.callback = shim_callback;
680 		params.userdata = service;
681 		params.version = setup->version.version;
682 		params.version_min = setup->version.version_min;
683 
684 		status = vchiq_open_service(instance, &params,
685 			&service->handle);
686 		if (status != VCHIQ_SUCCESS) {
687 			service_free(service);
688 			service = NULL;
689 			*handle = NULL;
690 		}
691 	}
692 
693 	return (service != NULL) ? 0 : -1;
694 }
695 EXPORT_SYMBOL(vchi_service_open);
696 
vchi_service_create(VCHI_INSTANCE_T instance_handle,SERVICE_CREATION_T * setup,VCHI_SERVICE_HANDLE_T * handle)697 int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
698 	SERVICE_CREATION_T *setup,
699 	VCHI_SERVICE_HANDLE_T *handle)
700 {
701 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
702 	struct shim_service *service = service_alloc(instance, setup);
703 
704 	*handle = (VCHI_SERVICE_HANDLE_T)service;
705 
706 	if (service) {
707 		VCHIQ_SERVICE_PARAMS_T params;
708 		VCHIQ_STATUS_T status;
709 
710 		memset(&params, 0, sizeof(params));
711 		params.fourcc = setup->service_id;
712 		params.callback = shim_callback;
713 		params.userdata = service;
714 		params.version = setup->version.version;
715 		params.version_min = setup->version.version_min;
716 		status = vchiq_add_service(instance, &params, &service->handle);
717 
718 		if (status != VCHIQ_SUCCESS) {
719 			service_free(service);
720 			service = NULL;
721 			*handle = NULL;
722 		}
723 	}
724 
725 	return (service != NULL) ? 0 : -1;
726 }
727 EXPORT_SYMBOL(vchi_service_create);
728 
vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)729 int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
730 {
731 	int32_t ret = -1;
732 	struct shim_service *service = (struct shim_service *)handle;
733 
734 	if (service) {
735 		VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
736 		if (status == VCHIQ_SUCCESS) {
737 			service_free(service);
738 			service = NULL;
739 		}
740 
741 		ret = vchiq_status_to_vchi(status);
742 	}
743 	return ret;
744 }
745 EXPORT_SYMBOL(vchi_service_close);
746 
vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)747 int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
748 {
749 	int32_t ret = -1;
750 	struct shim_service *service = (struct shim_service *)handle;
751 
752 	if (service) {
753 		VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
754 
755 		if (status == VCHIQ_SUCCESS) {
756 			service_free(service);
757 			service = NULL;
758 		}
759 
760 		ret = vchiq_status_to_vchi(status);
761 	}
762 	return ret;
763 }
764 EXPORT_SYMBOL(vchi_service_destroy);
765 
vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,VCHI_SERVICE_OPTION_T option,int value)766 int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
767 				VCHI_SERVICE_OPTION_T option,
768 				int value)
769 {
770 	int32_t ret = -1;
771 	struct shim_service *service = (struct shim_service *)handle;
772 	VCHIQ_SERVICE_OPTION_T vchiq_option;
773 
774 	switch (option) {
775 	case VCHI_SERVICE_OPTION_TRACE:
776 		vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
777 		break;
778 	case VCHI_SERVICE_OPTION_SYNCHRONOUS:
779 		vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
780 		break;
781 	default:
782 		service = NULL;
783 		break;
784 	}
785 	if (service) {
786 		VCHIQ_STATUS_T status =
787 			vchiq_set_service_option(service->handle,
788 						vchiq_option,
789 						value);
790 
791 		ret = vchiq_status_to_vchi(status);
792 	}
793 	return ret;
794 }
795 EXPORT_SYMBOL(vchi_service_set_option);
796 
vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle,short * peer_version)797 int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, short *peer_version)
798 {
799 	int32_t ret = -1;
800 	struct shim_service *service = (struct shim_service *)handle;
801 
802 	if (service) {
803 		VCHIQ_STATUS_T status;
804 
805 		status = vchiq_get_peer_version(service->handle, peer_version);
806 		ret = vchiq_status_to_vchi(status);
807 	}
808 	return ret;
809 }
810 EXPORT_SYMBOL(vchi_get_peer_version);
811 
812 /***********************************************************
813  * Name: vchi_service_use
814  *
815  * Arguments: const VCHI_SERVICE_HANDLE_T handle
816  *
817  * Description: Routine to increment refcount on a service
818  *
819  * Returns: void
820  *
821  ***********************************************************/
vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)822 int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
823 {
824 	int32_t ret = -1;
825 
826 	struct shim_service *service = (struct shim_service *)handle;
827 	if (service)
828 		ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
829 	return ret;
830 }
831 EXPORT_SYMBOL(vchi_service_use);
832 
833 /***********************************************************
834  * Name: vchi_service_release
835  *
836  * Arguments: const VCHI_SERVICE_HANDLE_T handle
837  *
838  * Description: Routine to decrement refcount on a service
839  *
840  * Returns: void
841  *
842  ***********************************************************/
vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)843 int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
844 {
845 	int32_t ret = -1;
846 
847 	struct shim_service *service = (struct shim_service *)handle;
848 	if (service)
849 		ret = vchiq_status_to_vchi(
850 			vchiq_release_service(service->handle));
851 	return ret;
852 }
853 EXPORT_SYMBOL(vchi_service_release);
854