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