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 *
vchi_mphi_message_driver_func_table(void)57 vchi_mphi_message_driver_func_table(void)
58 {
59           return NULL;
60 }
61 
62 /* ----------------------------------------------------------------------
63  * return a pointer to the 'single' connection driver fops
64  * -------------------------------------------------------------------- */
65 const VCHI_CONNECTION_API_T *
single_get_func_table(void)66 single_get_func_table(void)
67 {
68           return NULL;
69 }
70 
vchi_create_connection(const VCHI_CONNECTION_API_T * function_table,const VCHI_MESSAGE_DRIVER_T * low_level)71 VCHI_CONNECTION_T *vchi_create_connection(
72           const VCHI_CONNECTION_API_T *function_table,
73           const VCHI_MESSAGE_DRIVER_T *low_level)
74 {
75           (void)function_table;
76           (void)low_level;
77           return NULL;
78 }
79 
80 /***********************************************************
81  * Name: vchi_msg_peek
82  *
83  * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
84  *             void **data,
85  *             uint32_t *msg_size,
86 
87 
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  ***********************************************************/
vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags)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  ***********************************************************/
vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle)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  ***********************************************************/
vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,const void * data,uint32_t data_size,VCHI_FLAGS_T flags,void * msg_handle)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  ***********************************************************/
vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,void * data_dst,uint32_t data_size,VCHI_FLAGS_T flags,void * bulk_handle)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  ***********************************************************/
vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,void * data_src,uint32_t data_size,VCHI_FLAGS_T flags,void * bulk_handle)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  ***********************************************************/
vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,void * data,uint32_t max_data_size_to_read,uint32_t * actual_msg_size,VCHI_FLAGS_T flags)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 
vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,VCHI_MSG_VECTOR_T * vector,uint32_t count,VCHI_FLAGS_T flags,void * msg_handle)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_handle
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  ***********************************************************/
vchi_held_msg_release(VCHI_HELD_MSG_T * message_handle)399 int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message_handle)
400 {
401           SHIM_SERVICE_T *service;
402           VCHIQ_HEADER_T *header;
403 
404           service = (SHIM_SERVICE_T *)message_handle->service;
405           header = (VCHIQ_HEADER_T *)message_handle->message;
406 
407           vchiq_release_message(service->handle, header);
408 
409           return 0;
410 }
411 EXPORT_SYMBOL(vchi_held_msg_release);
412 
413 /***********************************************************
414  * Name: vchi_msg_hold
415  *
416  * Arguments:  VCHI_SERVICE_HANDLE_T handle,
417  *             void **data,
418  *             uint32_t *msg_size,
419  *             VCHI_FLAGS_T flags,
420  *             VCHI_HELD_MSG_T *message_handle
421  *
422  * Description: Routine to return a pointer to the current message (to allow
423  *              in place processing). The message is dequeued - don't forget
424  *              to release the message using vchi_held_msg_release when you're
425  *              finished.
426  *
427  * Returns: int32_t - success == 0
428  *
429  ***********************************************************/
vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,void ** data,uint32_t * msg_size,VCHI_FLAGS_T flags,VCHI_HELD_MSG_T * message_handle)430 int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
431           void **data,
432           uint32_t *msg_size,
433           VCHI_FLAGS_T flags,
434           VCHI_HELD_MSG_T *message_handle)
435 {
436           SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
437           VCHIQ_HEADER_T *header;
438 
439           WARN_ON((flags != VCHI_FLAGS_NONE) &&
440                     (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
441 
442           if (flags == VCHI_FLAGS_NONE)
443                     if (vchiu_queue_is_empty(&service->queue))
444                               return -1;
445 
446           header = vchiu_queue_pop(&service->queue);
447 
448           *data = header->data;
449           *msg_size = header->size;
450 
451           message_handle->service =
452                     (struct opaque_vchi_service_t *)(uintptr_t)service->handle;
453           message_handle->message = header;
454 
455           return 0;
456 }
457 EXPORT_SYMBOL(vchi_msg_hold);
458 
459 /***********************************************************
460  * Name: vchi_initialise
461  *
462  * Arguments: VCHI_INSTANCE_T *instance_handle
463  *
464  * Description: Initialises the hardware but does not transmit anything
465  *              When run as a Host App this will be called twice hence the need
466  *              to malloc the state information
467  *
468  * Returns: 0 if successful, failure otherwise
469  *
470  ***********************************************************/
471 
vchi_initialise(VCHI_INSTANCE_T * instance_handle)472 int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle)
473 {
474           VCHIQ_INSTANCE_T instance;
475           VCHIQ_STATUS_T status;
476 
477           status = vchiq_initialise(&instance);
478 
479           *instance_handle = (VCHI_INSTANCE_T)instance;
480 
481           return vchiq_status_to_vchi(status);
482 }
483 EXPORT_SYMBOL(vchi_initialise);
484 
485 /***********************************************************
486  * Name: vchi_connect
487  *
488  * Arguments: VCHI_CONNECTION_T **connections
489  *            const uint32_t num_connections
490  *            VCHI_INSTANCE_T instance_handle)
491  *
492  * Description: Starts the command service on each connection,
493  *              causing INIT messages to be pinged back and forth
494  *
495  * Returns: 0 if successful, failure otherwise
496  *
497  ***********************************************************/
vchi_connect(VCHI_CONNECTION_T ** connections,const uint32_t num_connections,VCHI_INSTANCE_T instance_handle)498 int32_t vchi_connect(VCHI_CONNECTION_T **connections,
499           const uint32_t num_connections,
500           VCHI_INSTANCE_T instance_handle)
501 {
502           VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
503 
504           (void)connections;
505           (void)num_connections;
506 
507           return vchiq_connect(instance);
508 }
509 EXPORT_SYMBOL(vchi_connect);
510 
511 
512 /***********************************************************
513  * Name: vchi_disconnect
514  *
515  * Arguments: VCHI_INSTANCE_T instance_handle
516  *
517  * Description: Stops the command service on each connection,
518  *              causing DE-INIT messages to be pinged back and forth
519  *
520  * Returns: 0 if successful, failure otherwise
521  *
522  ***********************************************************/
vchi_disconnect(VCHI_INSTANCE_T instance_handle)523 int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle)
524 {
525           VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
526           return vchiq_status_to_vchi(vchiq_shutdown(instance));
527 }
528 EXPORT_SYMBOL(vchi_disconnect);
529 
530 
531 /***********************************************************
532  * Name: vchi_service_open
533  * Name: vchi_service_create
534  *
535  * Arguments: VCHI_INSTANCE_T *instance_handle
536  *            SERVICE_CREATION_T *setup,
537  *            VCHI_SERVICE_HANDLE_T *handle
538  *
539  * Description: Routine to open a service
540  *
541  * Returns: int32_t - success == 0
542  *
543  ***********************************************************/
544 
shim_callback(VCHIQ_REASON_T reason,VCHIQ_HEADER_T * header,VCHIQ_SERVICE_HANDLE_T handle,void * bulk_user)545 static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason,
546           VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
547 {
548           SHIM_SERVICE_T *service =
549                     (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
550 
551         if (!service->callback)
552                     goto release;
553 
554           switch (reason) {
555           case VCHIQ_MESSAGE_AVAILABLE:
556                     vchiu_queue_push(&service->queue, header);
557 
558                     service->callback(service->callback_param,
559                                           VCHI_CALLBACK_MSG_AVAILABLE, NULL);
560 
561                     goto done;
562                     break;
563 
564           case VCHIQ_BULK_TRANSMIT_DONE:
565                     service->callback(service->callback_param,
566                                           VCHI_CALLBACK_BULK_SENT, bulk_user);
567                     break;
568 
569           case VCHIQ_BULK_RECEIVE_DONE:
570                     service->callback(service->callback_param,
571                                           VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
572                     break;
573 
574           case VCHIQ_SERVICE_CLOSED:
575                     service->callback(service->callback_param,
576                                           VCHI_CALLBACK_SERVICE_CLOSED, NULL);
577                     break;
578 
579           case VCHIQ_SERVICE_OPENED:
580                     /* No equivalent VCHI reason */
581                     break;
582 
583           case VCHIQ_BULK_TRANSMIT_ABORTED:
584                     service->callback(service->callback_param,
585                                           VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
586                                           bulk_user);
587                     break;
588 
589           case VCHIQ_BULK_RECEIVE_ABORTED:
590                     service->callback(service->callback_param,
591                                           VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
592                                           bulk_user);
593                     break;
594 
595           default:
596                     WARN(1, "not supported\n");
597                     break;
598           }
599 
600 release:
601         vchiq_release_message(service->handle, header);
602 done:
603           return VCHIQ_SUCCESS;
604 }
605 
service_alloc(VCHIQ_INSTANCE_T instance,SERVICE_CREATION_T * setup)606 static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
607           SERVICE_CREATION_T *setup)
608 {
609           SHIM_SERVICE_T *service = kzalloc(sizeof(SHIM_SERVICE_T), GFP_KERNEL);
610 
611           (void)instance;
612 
613           if (service) {
614                     if (vchiu_queue_init(&service->queue, 64)) {
615                               service->callback = setup->callback;
616                               service->callback_param = setup->callback_param;
617                     } else {
618                               kfree(service);
619                               service = NULL;
620                     }
621           }
622 
623           return service;
624 }
625 
service_free(SHIM_SERVICE_T * service)626 static void service_free(SHIM_SERVICE_T *service)
627 {
628           if (service) {
629                     vchiu_queue_delete(&service->queue);
630                     kfree(service);
631           }
632 }
633 
vchi_service_open(VCHI_INSTANCE_T instance_handle,SERVICE_CREATION_T * setup,VCHI_SERVICE_HANDLE_T * handle)634 int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
635           SERVICE_CREATION_T *setup,
636           VCHI_SERVICE_HANDLE_T *handle)
637 {
638           VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
639           SHIM_SERVICE_T *service = service_alloc(instance, setup);
640 
641           *handle = (VCHI_SERVICE_HANDLE_T)service;
642 
643           if (service) {
644                     VCHIQ_SERVICE_PARAMS_T params;
645                     VCHIQ_STATUS_T status;
646 
647                     memset(&params, 0, sizeof(params));
648                     params.fourcc = setup->service_id;
649                     params.callback = shim_callback;
650                     params.userdata = service;
651                     params.version = setup->version.version;
652                     params.version_min = setup->version.version_min;
653 
654                     status = vchiq_open_service(instance, &params,
655                               &service->handle);
656                     if (status != VCHIQ_SUCCESS) {
657                               service_free(service);
658                               service = NULL;
659                               *handle = NULL;
660                     }
661           }
662 
663           return (service != NULL) ? 0 : -1;
664 }
665 EXPORT_SYMBOL(vchi_service_open);
666 
vchi_service_create(VCHI_INSTANCE_T instance_handle,SERVICE_CREATION_T * setup,VCHI_SERVICE_HANDLE_T * handle)667 int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
668           SERVICE_CREATION_T *setup,
669           VCHI_SERVICE_HANDLE_T *handle)
670 {
671           VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
672           SHIM_SERVICE_T *service = service_alloc(instance, setup);
673 
674           *handle = (VCHI_SERVICE_HANDLE_T)service;
675 
676           if (service) {
677                     VCHIQ_SERVICE_PARAMS_T params;
678                     VCHIQ_STATUS_T status;
679 
680                     memset(&params, 0, sizeof(params));
681                     params.fourcc = setup->service_id;
682                     params.callback = shim_callback;
683                     params.userdata = service;
684                     params.version = setup->version.version;
685                     params.version_min = setup->version.version_min;
686                     status = vchiq_add_service(instance, &params, &service->handle);
687 
688                     if (status != VCHIQ_SUCCESS) {
689                               service_free(service);
690                               service = NULL;
691                               *handle = NULL;
692                     }
693           }
694 
695           return (service != NULL) ? 0 : -1;
696 }
697 EXPORT_SYMBOL(vchi_service_create);
698 
vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)699 int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
700 {
701           int32_t ret = -1;
702           SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
703           if (service) {
704                     VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
705                     if (status == VCHIQ_SUCCESS) {
706                               service_free(service);
707                               service = NULL;
708                     }
709 
710                     ret = vchiq_status_to_vchi(status);
711           }
712           return ret;
713 }
714 EXPORT_SYMBOL(vchi_service_close);
715 
vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)716 int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle)
717 {
718           int32_t ret = -1;
719           SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
720           if (service) {
721                     VCHIQ_STATUS_T status = vchiq_remove_service(service->handle);
722                     if (status == VCHIQ_SUCCESS) {
723                               service_free(service);
724                               service = NULL;
725                     }
726 
727                     ret = vchiq_status_to_vchi(status);
728           }
729           return ret;
730 }
731 EXPORT_SYMBOL(vchi_service_destroy);
732 
vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,VCHI_SERVICE_OPTION_T option,int value)733 int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
734                                         VCHI_SERVICE_OPTION_T option,
735                                         int value)
736 {
737           int32_t ret = -1;
738           SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
739           VCHIQ_SERVICE_OPTION_T vchiq_option;
740           switch (option) {
741           case VCHI_SERVICE_OPTION_TRACE:
742                     vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
743                     break;
744           case VCHI_SERVICE_OPTION_SYNCHRONOUS:
745                     vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
746                     break;
747           default:
748                     service = NULL;
749                     break;
750           }
751           if (service) {
752                     VCHIQ_STATUS_T status =
753                               vchiq_set_service_option(service->handle,
754                                                             vchiq_option,
755                                                             value);
756 
757                     ret = vchiq_status_to_vchi(status);
758           }
759           return ret;
760 }
761 EXPORT_SYMBOL(vchi_service_set_option);
762 
vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle,short * peer_version)763 int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version )
764 {
765    int32_t ret = -1;
766    SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
767    if(service)
768    {
769       VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version);
770       ret = vchiq_status_to_vchi( status );
771    }
772    return ret;
773 }
774 EXPORT_SYMBOL(vchi_get_peer_version);
775 
776 #if notyet
777 /* ----------------------------------------------------------------------
778  * read a uint32_t from buffer.
779  * network format is defined to be little endian
780  * -------------------------------------------------------------------- */
781 uint32_t
vchi_readbuf_uint32(const void * _ptr)782 vchi_readbuf_uint32(const void *_ptr)
783 {
784           const unsigned char *ptr = _ptr;
785           return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
786 }
787 
788 /* ----------------------------------------------------------------------
789  * write a uint32_t to buffer.
790  * network format is defined to be little endian
791  * -------------------------------------------------------------------- */
792 void
vchi_writebuf_uint32(void * _ptr,uint32_t value)793 vchi_writebuf_uint32(void *_ptr, uint32_t value)
794 {
795           unsigned char *ptr = _ptr;
796           ptr[0] = (unsigned char)((value >> 0)  & 0xFF);
797           ptr[1] = (unsigned char)((value >> 8)  & 0xFF);
798           ptr[2] = (unsigned char)((value >> 16) & 0xFF);
799           ptr[3] = (unsigned char)((value >> 24) & 0xFF);
800 }
801 
802 /* ----------------------------------------------------------------------
803  * read a uint16_t from buffer.
804  * network format is defined to be little endian
805  * -------------------------------------------------------------------- */
806 uint16_t
vchi_readbuf_uint16(const void * _ptr)807 vchi_readbuf_uint16(const void *_ptr)
808 {
809           const unsigned char *ptr = _ptr;
810           return ptr[0] | (ptr[1] << 8);
811 }
812 
813 /* ----------------------------------------------------------------------
814  * write a uint16_t into the buffer.
815  * network format is defined to be little endian
816  * -------------------------------------------------------------------- */
817 void
vchi_writebuf_uint16(void * _ptr,uint16_t value)818 vchi_writebuf_uint16(void *_ptr, uint16_t value)
819 {
820           unsigned char *ptr = _ptr;
821           ptr[0] = (value >> 0)  & 0xFF;
822           ptr[1] = (value >> 8)  & 0xFF;
823 }
824 #endif
825 
826 /***********************************************************
827  * Name: vchi_service_use
828  *
829  * Arguments: const VCHI_SERVICE_HANDLE_T handle
830  *
831  * Description: Routine to increment refcount on a service
832  *
833  * Returns: void
834  *
835  ***********************************************************/
vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)836 int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle)
837 {
838           int32_t ret = -1;
839           SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
840           if (service)
841                     ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
842           return ret;
843 }
844 EXPORT_SYMBOL(vchi_service_use);
845 
846 /***********************************************************
847  * Name: vchi_service_release
848  *
849  * Arguments: const VCHI_SERVICE_HANDLE_T handle
850  *
851  * Description: Routine to decrement refcount on a service
852  *
853  * Returns: void
854  *
855  ***********************************************************/
vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)856 int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
857 {
858           int32_t ret = -1;
859           SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
860           if (service)
861                     ret = vchiq_status_to_vchi(
862                               vchiq_release_service(service->handle));
863           return ret;
864 }
865 EXPORT_SYMBOL(vchi_service_release);
866