1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
3 #include <linux/module.h>
4 #include <linux/types.h>
5 
6 #include "interface/vchi/vchi.h"
7 #include "vchiq.h"
8 #include "vchiq_core.h"
9 
10 #include "vchiq_util.h"
11 
12 #define vchiq_status_to_vchi(status) ((int32_t)status)
13 
14 struct shim_service {
15 	VCHIQ_SERVICE_HANDLE_T handle;
16 
17 	struct vchiu_queue queue;
18 
19 	VCHI_CALLBACK_T callback;
20 	void *callback_param;
21 };
22 
23 /***********************************************************
24  * Name: vchi_msg_peek
25  *
26  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
27  *             void **data,
28  *             uint32_t *msg_size,
29 
30  *             VCHI_FLAGS_T flags
31  *
32  * Description: Routine to return a pointer to the current message (to allow in
33  *              place processing). The message can be removed using
34  *              vchi_msg_remove when you're finished
35  *
36  * Returns: int32_t - success == 0
37  *
38  ***********************************************************/
vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags)39 int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
40 	void **data,
41 	uint32_t *msg_size,
42 	VCHI_FLAGS_T flags)
43 {
44 	struct shim_service *service = (struct shim_service *)handle;
45 	struct vchiq_header *header;
46 
47 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
48 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
49 
50 	if (flags == VCHI_FLAGS_NONE)
51 		if (vchiu_queue_is_empty(&service->queue))
52 			return -1;
53 
54 	header = vchiu_queue_peek(&service->queue);
55 
56 	*data = header->data;
57 	*msg_size = header->size;
58 
59 	return 0;
60 }
61 EXPORT_SYMBOL(vchi_msg_peek);
62 
63 /***********************************************************
64  * Name: vchi_msg_remove
65  *
66  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
67  *
68  * Description: Routine to remove a message (after it has been read with
69  *              vchi_msg_peek)
70  *
71  * Returns: int32_t - success == 0
72  *
73  ***********************************************************/
vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)74 int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)
75 {
76 	struct shim_service *service = (struct shim_service *)handle;
77 	struct vchiq_header *header;
78 
79 	header = vchiu_queue_pop(&service->queue);
80 
81 	vchiq_release_message(service->handle, header);
82 
83 	return 0;
84 }
85 EXPORT_SYMBOL(vchi_msg_remove);
86 
87 /***********************************************************
88  * Name: vchi_msg_queue
89  *
90  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
91  *             ssize_t (*copy_callback)(void *context, void *dest,
92  *				        size_t offset, size_t maxsize),
93  *	       void *context,
94  *             uint32_t data_size
95  *
96  * Description: Thin wrapper to queue a message onto a connection
97  *
98  * Returns: int32_t - success == 0
99  *
100  ***********************************************************/
101 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)102 int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
103 	ssize_t (*copy_callback)(void *context, void *dest,
104 				 size_t offset, size_t maxsize),
105 	void *context,
106 	uint32_t data_size)
107 {
108 	struct shim_service *service = (struct shim_service *)handle;
109 	VCHIQ_STATUS_T status;
110 
111 	while (1) {
112 		status = vchiq_queue_message(service->handle,
113 					     copy_callback,
114 					     context,
115 					     data_size);
116 
117 		/*
118 		 * vchiq_queue_message() may return VCHIQ_RETRY, so we need to
119 		 * implement a retry mechanism since this function is supposed
120 		 * to block until queued
121 		 */
122 		if (status != VCHIQ_RETRY)
123 			break;
124 
125 		msleep(1);
126 	}
127 
128 	return vchiq_status_to_vchi(status);
129 }
130 
131 static ssize_t
vchi_queue_kernel_message_callback(void * context,void * dest,size_t offset,size_t maxsize)132 vchi_queue_kernel_message_callback(void *context,
133 				   void *dest,
134 				   size_t offset,
135 				   size_t maxsize)
136 {
137 	memcpy(dest, context + offset, maxsize);
138 	return maxsize;
139 }
140 
141 int
vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,void * data,unsigned int size)142 vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,
143 			  void *data,
144 			  unsigned int size)
145 {
146 	return vchi_msg_queue(handle,
147 			      vchi_queue_kernel_message_callback,
148 			      data,
149 			      size);
150 }
151 EXPORT_SYMBOL(vchi_queue_kernel_message);
152 
153 struct vchi_queue_user_message_context {
154 	void __user *data;
155 };
156 
157 static ssize_t
vchi_queue_user_message_callback(void * context,void * dest,size_t offset,size_t maxsize)158 vchi_queue_user_message_callback(void *context,
159 				 void *dest,
160 				 size_t offset,
161 				 size_t maxsize)
162 {
163 	struct vchi_queue_user_message_context *copycontext = context;
164 
165 	if (copy_from_user(dest, copycontext->data + offset, maxsize))
166 		return -EFAULT;
167 
168 	return maxsize;
169 }
170 
171 int
vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,void __user * data,unsigned int size)172 vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,
173 			void __user *data,
174 			unsigned int size)
175 {
176 	struct vchi_queue_user_message_context copycontext = {
177 		.data = data
178 	};
179 
180 	return vchi_msg_queue(handle,
181 			      vchi_queue_user_message_callback,
182 			      &copycontext,
183 			      size);
184 }
185 EXPORT_SYMBOL(vchi_queue_user_message);
186 
187 /***********************************************************
188  * Name: vchi_bulk_queue_receive
189  *
190  * Arguments:  VCHI_BULK_HANDLE_T handle,
191  *             void *data_dst,
192  *             const uint32_t data_size,
193  *             VCHI_FLAGS_T flags
194  *             void *bulk_handle
195  *
196  * Description: Routine to setup a rcv buffer
197  *
198  * Returns: int32_t - success == 0
199  *
200  ***********************************************************/
vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,void * data_dst,uint32_t data_size,VCHI_FLAGS_T flags,void * bulk_handle)201 int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
202 	void *data_dst,
203 	uint32_t data_size,
204 	VCHI_FLAGS_T flags,
205 	void *bulk_handle)
206 {
207 	struct shim_service *service = (struct shim_service *)handle;
208 	VCHIQ_BULK_MODE_T mode;
209 	VCHIQ_STATUS_T status;
210 
211 	switch ((int)flags) {
212 	case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
213 		| VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
214 		WARN_ON(!service->callback);
215 		mode = VCHIQ_BULK_MODE_CALLBACK;
216 		break;
217 	case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
218 		mode = VCHIQ_BULK_MODE_BLOCKING;
219 		break;
220 	case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
221 	case VCHI_FLAGS_NONE:
222 		mode = VCHIQ_BULK_MODE_NOCALLBACK;
223 		break;
224 	default:
225 		WARN(1, "unsupported message\n");
226 		return vchiq_status_to_vchi(VCHIQ_ERROR);
227 	}
228 
229 	while (1) {
230 		status = vchiq_bulk_receive(service->handle, data_dst,
231 			data_size, 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 		if (status != VCHIQ_RETRY)
238 			break;
239 
240 		msleep(1);
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  *             const 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,const 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 	const void *data_src,
263 	uint32_t data_size,
264 	VCHI_FLAGS_T flags,
265 	void *bulk_handle)
266 {
267 	struct shim_service *service = (struct shim_service *)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 	while (1) {
291 		status = vchiq_bulk_transmit(service->handle, data_src,
292 			data_size, bulk_handle, mode);
293 
294 		/*
295 		 * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
296 		 * implement a retry mechanism since this function is supposed
297 		 * to block until queued
298 		 */
299 		if (status != VCHIQ_RETRY)
300 			break;
301 
302 		msleep(1);
303 	}
304 
305 	return vchiq_status_to_vchi(status);
306 }
307 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
308 
309 /***********************************************************
310  * Name: vchi_msg_dequeue
311  *
312  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
313  *             void *data,
314  *             uint32_t max_data_size_to_read,
315  *             uint32_t *actual_msg_size
316  *             VCHI_FLAGS_T flags
317  *
318  * Description: Routine to dequeue a message into the supplied buffer
319  *
320  * Returns: int32_t - success == 0
321  *
322  ***********************************************************/
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)323 int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
324 	void *data,
325 	uint32_t max_data_size_to_read,
326 	uint32_t *actual_msg_size,
327 	VCHI_FLAGS_T flags)
328 {
329 	struct shim_service *service = (struct shim_service *)handle;
330 	struct vchiq_header *header;
331 
332 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
333 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
334 
335 	if (flags == VCHI_FLAGS_NONE)
336 		if (vchiu_queue_is_empty(&service->queue))
337 			return -1;
338 
339 	header = vchiu_queue_pop(&service->queue);
340 
341 	memcpy(data, header->data, header->size < max_data_size_to_read ?
342 		header->size : max_data_size_to_read);
343 
344 	*actual_msg_size = header->size;
345 
346 	vchiq_release_message(service->handle, header);
347 
348 	return 0;
349 }
350 EXPORT_SYMBOL(vchi_msg_dequeue);
351 
352 /***********************************************************
353  * Name: vchi_held_msg_release
354  *
355  * Arguments:  struct vchi_held_msg *message
356  *
357  * Description: Routine to release a held message (after it has been read with
358  *              vchi_msg_hold)
359  *
360  * Returns: int32_t - success == 0
361  *
362  ***********************************************************/
vchi_held_msg_release(struct vchi_held_msg * message)363 int32_t vchi_held_msg_release(struct vchi_held_msg *message)
364 {
365 	/*
366 	 * Convert the service field pointer back to an
367 	 * VCHIQ_SERVICE_HANDLE_T which is an int.
368 	 * This pointer is opaque to everything except
369 	 * vchi_msg_hold which simply upcasted the int
370 	 * to a pointer.
371 	 */
372 
373 	vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)(long)message->service,
374 			      (struct vchiq_header *)message->message);
375 
376 	return 0;
377 }
378 EXPORT_SYMBOL(vchi_held_msg_release);
379 
380 /***********************************************************
381  * Name: vchi_msg_hold
382  *
383  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
384  *             void **data,
385  *             uint32_t *msg_size,
386  *             VCHI_FLAGS_T flags,
387  *             struct vchi_held_msg *message_handle
388  *
389  * Description: Routine to return a pointer to the current message (to allow
390  *              in place processing). The message is dequeued - don't forget
391  *              to release the message using vchi_held_msg_release when you're
392  *              finished.
393  *
394  * Returns: int32_t - success == 0
395  *
396  ***********************************************************/
vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags,struct vchi_held_msg * message_handle)397 int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
398 	void **data,
399 	uint32_t *msg_size,
400 	VCHI_FLAGS_T flags,
401 	struct vchi_held_msg *message_handle)
402 {
403 	struct shim_service *service = (struct shim_service *)handle;
404 	struct vchiq_header *header;
405 
406 	WARN_ON((flags != VCHI_FLAGS_NONE) &&
407 		(flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
408 
409 	if (flags == VCHI_FLAGS_NONE)
410 		if (vchiu_queue_is_empty(&service->queue))
411 			return -1;
412 
413 	header = vchiu_queue_pop(&service->queue);
414 
415 	*data = header->data;
416 	*msg_size = header->size;
417 
418 	/*
419 	 * upcast the VCHIQ_SERVICE_HANDLE_T which is an int
420 	 * to a pointer and stuff it in the held message.
421 	 * This pointer is opaque to everything except
422 	 * vchi_held_msg_release which simply downcasts it back
423 	 * to an int.
424 	 */
425 
426 	message_handle->service =
427 		(struct opaque_vchi_service_t *)(long)service->handle;
428 	message_handle->message = header;
429 
430 	return 0;
431 }
432 EXPORT_SYMBOL(vchi_msg_hold);
433 
434 /***********************************************************
435  * Name: vchi_initialise
436  *
437  * Arguments: VCHI_INSTANCE_T *instance_handle
438  *
439  * Description: Initialises the hardware but does not transmit anything
440  *              When run as a Host App this will be called twice hence the need
441  *              to malloc the state information
442  *
443  * Returns: 0 if successful, failure otherwise
444  *
445  ***********************************************************/
446 
vchi_initialise(VCHI_INSTANCE_T * instance_handle)447 int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
448 {
449 	VCHIQ_INSTANCE_T instance;
450 	VCHIQ_STATUS_T status;
451 
452 	status = vchiq_initialise(&instance);
453 
454 	*instance_handle = (VCHI_INSTANCE_T)instance;
455 
456 	return vchiq_status_to_vchi(status);
457 }
458 EXPORT_SYMBOL(vchi_initialise);
459 
460 /***********************************************************
461  * Name: vchi_connect
462  *
463  * Arguments: VCHI_INSTANCE_T instance_handle
464  *
465  * Description: Starts the command service on each connection,
466  *              causing INIT messages to be pinged back and forth
467  *
468  * Returns: 0 if successful, failure otherwise
469  *
470  ***********************************************************/
vchi_connect(VCHI_INSTANCE_T instance_handle)471 int32_t vchi_connect(VCHI_INSTANCE_T instance_handle)
472 {
473 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
474 
475 	return vchiq_connect(instance);
476 }
477 EXPORT_SYMBOL(vchi_connect);
478 
479 /***********************************************************
480  * Name: vchi_disconnect
481  *
482  * Arguments: VCHI_INSTANCE_T instance_handle
483  *
484  * Description: Stops the command service on each connection,
485  *              causing DE-INIT messages to be pinged back and forth
486  *
487  * Returns: 0 if successful, failure otherwise
488  *
489  ***********************************************************/
vchi_disconnect(VCHI_INSTANCE_T instance_handle)490 int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
491 {
492 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
493 
494 	return vchiq_status_to_vchi(vchiq_shutdown(instance));
495 }
496 EXPORT_SYMBOL(vchi_disconnect);
497 
498 /***********************************************************
499  * Name: vchi_service_open
500  * Name: vchi_service_create
501  *
502  * Arguments: VCHI_INSTANCE_T *instance_handle
503  *            struct service_creation *setup,
504  *            VCHI_SERVICE_HANDLE_T *handle
505  *
506  * Description: Routine to open a service
507  *
508  * Returns: int32_t - success == 0
509  *
510  ***********************************************************/
511 
shim_callback(VCHIQ_REASON_T reason,struct vchiq_header * header,VCHIQ_SERVICE_HANDLE_T handle,void * bulk_user)512 static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
513 				    struct vchiq_header *header,
514 				    VCHIQ_SERVICE_HANDLE_T handle,
515 				    void *bulk_user)
516 {
517 	struct shim_service *service =
518 		(struct shim_service *)VCHIQ_GET_SERVICE_USERDATA(handle);
519 
520 	if (!service->callback)
521 		goto release;
522 
523 	switch (reason) {
524 	case VCHIQ_MESSAGE_AVAILABLE:
525 		vchiu_queue_push(&service->queue, header);
526 
527 		service->callback(service->callback_param,
528 				  VCHI_CALLBACK_MSG_AVAILABLE, NULL);
529 
530 		goto done;
531 
532 	case VCHIQ_BULK_TRANSMIT_DONE:
533 		service->callback(service->callback_param,
534 				  VCHI_CALLBACK_BULK_SENT, bulk_user);
535 		break;
536 
537 	case VCHIQ_BULK_RECEIVE_DONE:
538 		service->callback(service->callback_param,
539 				  VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
540 		break;
541 
542 	case VCHIQ_SERVICE_CLOSED:
543 		service->callback(service->callback_param,
544 				  VCHI_CALLBACK_SERVICE_CLOSED, NULL);
545 		break;
546 
547 	case VCHIQ_SERVICE_OPENED:
548 		/* No equivalent VCHI reason */
549 		break;
550 
551 	case VCHIQ_BULK_TRANSMIT_ABORTED:
552 		service->callback(service->callback_param,
553 				  VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
554 				  bulk_user);
555 		break;
556 
557 	case VCHIQ_BULK_RECEIVE_ABORTED:
558 		service->callback(service->callback_param,
559 				  VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
560 				  bulk_user);
561 		break;
562 
563 	default:
564 		WARN(1, "not supported\n");
565 		break;
566 	}
567 
568 release:
569 	vchiq_release_message(service->handle, header);
570 done:
571 	return VCHIQ_SUCCESS;
572 }
573 
service_alloc(VCHIQ_INSTANCE_T instance,struct service_creation * setup)574 static struct shim_service *service_alloc(VCHIQ_INSTANCE_T instance,
575 	struct service_creation *setup)
576 {
577 	struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL);
578 
579 	(void)instance;
580 
581 	if (service) {
582 		if (vchiu_queue_init(&service->queue, 64)) {
583 			service->callback = setup->callback;
584 			service->callback_param = setup->callback_param;
585 		} else {
586 			kfree(service);
587 			service = NULL;
588 		}
589 	}
590 
591 	return service;
592 }
593 
service_free(struct shim_service * service)594 static void service_free(struct shim_service *service)
595 {
596 	if (service) {
597 		vchiu_queue_delete(&service->queue);
598 		kfree(service);
599 	}
600 }
601 
vchi_service_open(VCHI_INSTANCE_T instance_handle,struct service_creation * setup,VCHI_SERVICE_HANDLE_T * handle)602 int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
603 	struct service_creation *setup,
604 	VCHI_SERVICE_HANDLE_T *handle)
605 {
606 	VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
607 	struct shim_service *service = service_alloc(instance, setup);
608 
609 	*handle = (VCHI_SERVICE_HANDLE_T)service;
610 
611 	if (service) {
612 		struct vchiq_service_params params;
613 		VCHIQ_STATUS_T status;
614 
615 		memset(&params, 0, sizeof(params));
616 		params.fourcc = setup->service_id;
617 		params.callback = shim_callback;
618 		params.userdata = service;
619 		params.version = setup->version.version;
620 		params.version_min = setup->version.version_min;
621 
622 		status = vchiq_open_service(instance, &params,
623 			&service->handle);
624 		if (status != VCHIQ_SUCCESS) {
625 			service_free(service);
626 			service = NULL;
627 			*handle = NULL;
628 		}
629 	}
630 
631 	return (service != NULL) ? 0 : -1;
632 }
633 EXPORT_SYMBOL(vchi_service_open);
634 
vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)635 int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
636 {
637 	int32_t ret = -1;
638 	struct shim_service *service = (struct shim_service *)handle;
639 
640 	if (service) {
641 		VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
642 		if (status == VCHIQ_SUCCESS)
643 			service_free(service);
644 
645 		ret = vchiq_status_to_vchi(status);
646 	}
647 	return ret;
648 }
649 EXPORT_SYMBOL(vchi_service_close);
650 
vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)651 int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
652 {
653 	int32_t ret = -1;
654 	struct shim_service *service = (struct shim_service *)handle;
655 
656 	if (service) {
657 		VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
658 
659 		if (status == VCHIQ_SUCCESS) {
660 			service_free(service);
661 			service = NULL;
662 		}
663 
664 		ret = vchiq_status_to_vchi(status);
665 	}
666 	return ret;
667 }
668 EXPORT_SYMBOL(vchi_service_destroy);
669 
vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,VCHI_SERVICE_OPTION_T option,int value)670 int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
671 				VCHI_SERVICE_OPTION_T option,
672 				int value)
673 {
674 	int32_t ret = -1;
675 	struct shim_service *service = (struct shim_service *)handle;
676 	VCHIQ_SERVICE_OPTION_T vchiq_option;
677 
678 	switch (option) {
679 	case VCHI_SERVICE_OPTION_TRACE:
680 		vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
681 		break;
682 	case VCHI_SERVICE_OPTION_SYNCHRONOUS:
683 		vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
684 		break;
685 	default:
686 		service = NULL;
687 		break;
688 	}
689 	if (service) {
690 		VCHIQ_STATUS_T status =
691 			vchiq_set_service_option(service->handle,
692 						vchiq_option,
693 						value);
694 
695 		ret = vchiq_status_to_vchi(status);
696 	}
697 	return ret;
698 }
699 EXPORT_SYMBOL(vchi_service_set_option);
700 
vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle,short * peer_version)701 int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, short *peer_version)
702 {
703 	int32_t ret = -1;
704 	struct shim_service *service = (struct shim_service *)handle;
705 
706 	if (service) {
707 		VCHIQ_STATUS_T status;
708 
709 		status = vchiq_get_peer_version(service->handle, peer_version);
710 		ret = vchiq_status_to_vchi(status);
711 	}
712 	return ret;
713 }
714 EXPORT_SYMBOL(vchi_get_peer_version);
715 
716 /***********************************************************
717  * Name: vchi_service_use
718  *
719  * Arguments: const VCHI_SERVICE_HANDLE_T handle
720  *
721  * Description: Routine to increment refcount on a service
722  *
723  * Returns: void
724  *
725  ***********************************************************/
vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)726 int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
727 {
728 	int32_t ret = -1;
729 
730 	struct shim_service *service = (struct shim_service *)handle;
731 	if (service)
732 		ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
733 	return ret;
734 }
735 EXPORT_SYMBOL(vchi_service_use);
736 
737 /***********************************************************
738  * Name: vchi_service_release
739  *
740  * Arguments: const VCHI_SERVICE_HANDLE_T handle
741  *
742  * Description: Routine to decrement refcount on a service
743  *
744  * Returns: void
745  *
746  ***********************************************************/
vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)747 int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
748 {
749 	int32_t ret = -1;
750 
751 	struct shim_service *service = (struct shim_service *)handle;
752 	if (service)
753 		ret = vchiq_status_to_vchi(
754 			vchiq_release_service(service->handle));
755 	return ret;
756 }
757 EXPORT_SYMBOL(vchi_service_release);
758