GNU Linux-libre 4.19.286-gnu1
[releases.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 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 *
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  *             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  ***********************************************************/
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  ***********************************************************/
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
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
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
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
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
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  ***********************************************************/
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  ***********************************************************/
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  ***********************************************************/
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  ***********************************************************/
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  ***********************************************************/
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
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  ***********************************************************/
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  ***********************************************************/
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
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
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
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
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
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
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
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
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
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  ***********************************************************/
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  ***********************************************************/
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);