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(¶ms, 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, ¶ms,
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(¶ms, 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, ¶ms, &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