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