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 ©context,
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(¶ms, 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, ¶ms,
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(¶ms, 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, ¶ms, &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