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