1 From a2e42fbc97cde9e851f5b036f46b8f34a5be6eb9 Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Tue, 17 Jan 2012 19:22:19 +0000
4 Subject: [PATCH 5/7] bcm2708 vchiq driver
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
8 drivers/misc/Kconfig | 1 +
9 drivers/misc/Makefile | 1 +
10 drivers/misc/vc04_services/Kconfig | 7 +
11 drivers/misc/vc04_services/Makefile | 19 +
12 .../misc/vc04_services/interface/vchi/vchi_mh.h | 19 +
13 .../misc/vc04_services/interface/vchiq_arm/vchiq.h | 27 +
14 .../vc04_services/interface/vchiq_arm/vchiq_2835.h | 27 +
15 .../interface/vchiq_arm/vchiq_2835_arm.c | 487 ++++
16 .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 1293 ++++++++++
17 .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 38 +
18 .../vc04_services/interface/vchiq_arm/vchiq_cfg.h | 43 +
19 .../interface/vchiq_arm/vchiq_connected.c | 101 +
20 .../interface/vchiq_arm/vchiq_connected.h | 32 +
21 .../vc04_services/interface/vchiq_arm/vchiq_core.c | 2604 ++++++++++++++++++++
22 .../vc04_services/interface/vchiq_arm/vchiq_core.h | 480 ++++
23 .../vc04_services/interface/vchiq_arm/vchiq_if.h | 148 ++
24 .../interface/vchiq_arm/vchiq_ioctl.h | 105 +
25 .../interface/vchiq_arm/vchiq_kern_lib.c | 297 +++
26 .../vc04_services/interface/vchiq_arm/vchiq_lib.c | 1518 ++++++++++++
27 .../interface/vchiq_arm/vchiq_memdrv.h | 45 +
28 .../interface/vchiq_arm/vchiq_pagelist.h | 43 +
29 .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 970 ++++++++
30 .../vc04_services/interface/vchiq_arm/vchiq_util.c | 97 +
31 .../vc04_services/interface/vchiq_arm/vchiq_util.h | 47 +
32 .../interface/vcos/generic/vcos_cmd.c | 681 +++++
33 .../interface/vcos/generic/vcos_common.h | 76 +
34 .../vcos/generic/vcos_generic_blockpool.h | 260 ++
35 .../vcos/generic/vcos_generic_event_flags.c | 297 +++
36 .../vcos/generic/vcos_generic_event_flags.h | 104 +
37 .../vcos/generic/vcos_generic_named_sem.h | 81 +
38 .../vcos/generic/vcos_generic_quickslow_mutex.h | 75 +
39 .../vcos/generic/vcos_generic_reentrant_mtx.h | 75 +
40 .../interface/vcos/generic/vcos_generic_tls.h | 144 ++
41 .../vcos/generic/vcos_joinable_thread_from_plain.h | 202 ++
42 .../interface/vcos/generic/vcos_latch_from_sem.h | 48 +
43 .../interface/vcos/generic/vcos_logcat.c | 549 +++++
44 .../interface/vcos/generic/vcos_mem_from_malloc.c | 73 +
45 .../interface/vcos/generic/vcos_mem_from_malloc.h | 54 +
46 .../vcos/generic/vcos_mutexes_are_reentrant.h | 68 +
47 .../interface/vcos/generic/vcos_thread_reaper.h | 35 +
48 .../interface/vcos/linuxkernel/stdint.h | 17 +
49 .../interface/vcos/linuxkernel/vcos_linuxkernel.c | 616 +++++
50 .../vcos/linuxkernel/vcos_linuxkernel_cfg.c | 332 +++
51 .../vcos/linuxkernel/vcos_linuxkernel_misc.c | 113 +
52 .../interface/vcos/linuxkernel/vcos_mod_init.c | 64 +
53 .../interface/vcos/linuxkernel/vcos_platform.h | 496 ++++
54 .../vcos/linuxkernel/vcos_platform_types.h | 47 +
55 .../interface/vcos/linuxkernel/vcos_thread_map.c | 129 +
56 .../interface/vcos/linuxkernel/vcos_thread_map.h | 39 +
57 drivers/misc/vc04_services/interface/vcos/vcos.h | 201 ++
58 .../vc04_services/interface/vcos/vcos_assert.h | 269 ++
59 .../interface/vcos/vcos_atomic_flags.h | 72 +
60 .../vc04_services/interface/vcos/vcos_build_info.h | 5 +
61 .../misc/vc04_services/interface/vcos/vcos_cfg.h | 113 +
62 .../misc/vc04_services/interface/vcos/vcos_cmd.h | 98 +
63 .../misc/vc04_services/interface/vcos/vcos_ctype.h | 29 +
64 .../misc/vc04_services/interface/vcos/vcos_dlfcn.h | 69 +
65 .../misc/vc04_services/interface/vcos/vcos_event.h | 97 +
66 .../interface/vcos/vcos_event_flags.h | 98 +
67 .../misc/vc04_services/interface/vcos/vcos_init.h | 43 +
68 .../vc04_services/interface/vcos/vcos_logging.h | 279 +++
69 .../interface/vcos/vcos_lowlevel_thread.h | 107 +
70 .../misc/vc04_services/interface/vcos/vcos_mem.h | 81 +
71 .../vc04_services/interface/vcos/vcos_msgqueue.h | 157 ++
72 .../misc/vc04_services/interface/vcos/vcos_mutex.h | 92 +
73 .../misc/vc04_services/interface/vcos/vcos_once.h | 42 +
74 .../vc04_services/interface/vcos/vcos_semaphore.h | 115 +
75 .../vc04_services/interface/vcos/vcos_stdbool.h | 17 +
76 .../vc04_services/interface/vcos/vcos_stdint.h | 193 ++
77 .../vc04_services/interface/vcos/vcos_string.h | 73 +
78 .../vc04_services/interface/vcos/vcos_thread.h | 259 ++
79 .../interface/vcos/vcos_thread_attr.h | 73 +
80 .../misc/vc04_services/interface/vcos/vcos_timer.h | 95 +
81 .../misc/vc04_services/interface/vcos/vcos_types.h | 197 ++
82 74 files changed, 15998 insertions(+), 0 deletions(-)
83 create mode 100644 drivers/misc/vc04_services/Kconfig
84 create mode 100644 drivers/misc/vc04_services/Makefile
85 create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_mh.h
86 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
87 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
88 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
89 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
90 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
91 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
92 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
93 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
94 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
95 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
96 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
97 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
98 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
99 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_lib.c
100 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
101 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
102 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
103 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
104 create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
105 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_cmd.c
106 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_common.h
107 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_blockpool.h
108 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.c
109 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.h
110 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_named_sem.h
111 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_quickslow_mutex.h
112 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_reentrant_mtx.h
113 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_tls.h
114 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_joinable_thread_from_plain.h
115 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_latch_from_sem.h
116 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_logcat.c
117 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.c
118 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.h
119 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_mutexes_are_reentrant.h
120 create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_thread_reaper.h
121 create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/stdint.h
122 create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel.c
123 create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_cfg.c
124 create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_misc.c
125 create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_mod_init.c
126 create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform.h
127 create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform_types.h
128 create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.c
129 create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.h
130 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos.h
131 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_assert.h
132 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_atomic_flags.h
133 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_build_info.h
134 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_cfg.h
135 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_cmd.h
136 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_ctype.h
137 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_dlfcn.h
138 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_event.h
139 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_event_flags.h
140 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_init.h
141 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_logging.h
142 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_lowlevel_thread.h
143 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_mem.h
144 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_msgqueue.h
145 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_mutex.h
146 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_once.h
147 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_semaphore.h
148 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_stdbool.h
149 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_stdint.h
150 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_string.h
151 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_thread.h
152 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_thread_attr.h
153 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_timer.h
154 create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_types.h
156 --- a/drivers/misc/Kconfig
157 +++ b/drivers/misc/Kconfig
158 @@ -506,4 +506,5 @@ source "drivers/misc/ti-st/Kconfig"
159 source "drivers/misc/lis3lv02d/Kconfig"
160 source "drivers/misc/carma/Kconfig"
161 source "drivers/misc/altera-stapl/Kconfig"
162 +source "drivers/misc/vc04_services/Kconfig"
164 --- a/drivers/misc/Makefile
165 +++ b/drivers/misc/Makefile
166 @@ -49,3 +49,5 @@ obj-y += carma/
167 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
168 obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
169 obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
170 +obj-y += vc04_services/
173 +++ b/drivers/misc/vc04_services/Kconfig
175 +config BCM2708_VCHIQ
176 + tristate "Videocore VCHIQ"
177 + depends on MACH_BCM2708
180 + Helper for communication for VideoCore.
183 +++ b/drivers/misc/vc04_services/Makefile
185 +obj-$(CONFIG_BCM2708_VCHIQ) += vchiq.o
188 + interface/vchiq_arm/vchiq_core.o \
189 + interface/vchiq_arm/vchiq_arm.o \
190 + interface/vchiq_arm/vchiq_kern_lib.o \
191 + interface/vchiq_arm/vchiq_2835_arm.o \
192 + interface/vcos/linuxkernel/vcos_linuxkernel.o \
193 + interface/vcos/linuxkernel/vcos_thread_map.o \
194 + interface/vcos/linuxkernel/vcos_linuxkernel_cfg.o \
195 + interface/vcos/generic/vcos_generic_event_flags.o \
196 + interface/vcos/generic/vcos_logcat.o \
197 + interface/vcos/generic/vcos_mem_from_malloc.o \
198 + interface/vcos/generic/vcos_cmd.o
200 +EXTRA_CFLAGS += -DVCOS_VERIFY_BKPTS=1 -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel
205 +++ b/drivers/misc/vc04_services/interface/vchi/vchi_mh.h
207 +/*=============================================================================
208 +Copyright (c) 2010 Broadcom Europe Limited. All rights reserved.
214 +Definitions for memory handle types.
215 +=============================================================================*/
220 +#include <interface/vcos/vcos.h>
222 +typedef int32_t VCHI_MEM_HANDLE_T;
223 +#define VCHI_MEM_HANDLE_INVALID 0
227 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
230 + * Copyright (c) 2010-2011 Broadcom. All rights reserved.
232 + * This program is free software; you can redistribute it and/or modify
233 + * it under the terms of the GNU General Public License as published by
234 + * the Free Software Foundation; either version 2 of the License, or
235 + * (at your option) any later version.
237 + * This program is distributed in the hope that it will be useful,
238 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
239 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
240 + * GNU General Public License for more details.
242 + * You should have received a copy of the GNU General Public License
243 + * along with this program; if not, write to the Free Software
244 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
247 +#ifndef VCHIQ_VCHIQ_H
248 +#define VCHIQ_VCHIQ_H
250 +#include "vchiq_if.h"
251 +#include "vchiq_util.h"
252 +#include "interface/vcos/vcos.h"
257 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
260 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
262 + * This program is free software; you can redistribute it and/or modify
263 + * it under the terms of the GNU General Public License as published by
264 + * the Free Software Foundation; either version 2 of the License, or
265 + * (at your option) any later version.
267 + * This program is distributed in the hope that it will be useful,
268 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
269 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
270 + * GNU General Public License for more details.
272 + * You should have received a copy of the GNU General Public License
273 + * along with this program; if not, write to the Free Software
274 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
277 +#ifndef VCHIQ_2835_H
278 +#define VCHIQ_2835_H
280 +#include "vchiq_pagelist.h"
282 +#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0
283 +#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1
285 +#endif /* VCHIQ_2835_H */
287 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
290 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
292 + * This program is free software; you can redistribute it and/or modify
293 + * it under the terms of the GNU General Public License as published by
294 + * the Free Software Foundation; either version 2 of the License, or
295 + * (at your option) any later version.
297 + * This program is distributed in the hope that it will be useful,
298 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
299 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
300 + * GNU General Public License for more details.
302 + * You should have received a copy of the GNU General Public License
303 + * along with this program; if not, write to the Free Software
304 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
307 +#include <linux/kernel.h>
308 +#include <linux/types.h>
309 +#include <linux/errno.h>
310 +#include <linux/interrupt.h>
311 +#include <linux/irq.h>
312 +#include <linux/pagemap.h>
313 +#include <linux/dma-mapping.h>
314 +#include <linux/version.h>
315 +#include <asm/pgtable.h>
317 +#include <asm/uaccess.h>
319 +#include <mach/irqs.h>
321 +#include <mach/platform.h>
322 +#include <mach/vcio.h>
324 +#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
326 +#define VCHIQ_DOORBELL_IRQ IRQ_ARM_DOORBELL_0
327 +#define VCHIQ_ARM_ADDRESS(x) __virt_to_bus(x)
329 +#include "vchiq_arm.h"
330 +#include "vchiq_2835.h"
332 +#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
334 +#define VCOS_LOG_CATEGORY (&vchiq_arm_log_category)
336 +static char *g_slot_mem;
337 +static int g_slot_mem_size;
338 +dma_addr_t g_slot_phys;
339 +static FRAGMENTS_T *g_fragments_base;
340 +static FRAGMENTS_T *g_free_fragments;
341 +struct semaphore g_free_fragments_sema;
343 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
344 +static DEFINE_SEMAPHORE(g_free_fragments_mutex);
346 +static DECLARE_MUTEX(g_free_fragments_mutex);
350 +vchiq_doorbell_irq(int irq, void *dev_id);
353 +create_pagelist(char __user *buf, size_t count, unsigned short type,
354 + struct task_struct *task, PAGELIST_T ** ppagelist);
357 +free_pagelist(PAGELIST_T *pagelist, int actual);
360 +vchiq_platform_vcos_init(void)
362 + return (vcos_init() == VCOS_SUCCESS) ? 0 : -EINVAL;
366 +vchiq_platform_init(VCHIQ_STATE_T *state)
368 + VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
373 + /* Allocate space for the channels in coherent memory */
374 + g_slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
375 + frag_mem_size = PAGE_ALIGN(sizeof(FRAGMENTS_T) * MAX_FRAGMENTS);
377 + g_slot_mem = dma_alloc_coherent(NULL, g_slot_mem_size + frag_mem_size,
378 + &g_slot_phys, GFP_ATOMIC);
381 + vcos_log_error("Unable to allocate channel memory");
386 + vcos_assert(((int)g_slot_mem & (PAGE_SIZE - 1)) == 0);
388 + vchiq_slot_zero = vchiq_init_slots(g_slot_mem, g_slot_mem_size);
389 + if (!vchiq_slot_zero)
392 + goto failed_init_slots;
395 + vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] = (int)g_slot_phys + g_slot_mem_size;
396 + vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] = MAX_FRAGMENTS;
398 + g_fragments_base = (FRAGMENTS_T *)(g_slot_mem + g_slot_mem_size);
399 + g_slot_mem_size += frag_mem_size;
401 + g_free_fragments = g_fragments_base;
402 + for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
403 + *(FRAGMENTS_T **) & g_fragments_base[i] =
404 + &g_fragments_base[i + 1];
406 + *(FRAGMENTS_T **) & g_fragments_base[i] = NULL;
407 + sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
409 + if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) !=
413 + goto failed_vchiq_init;
416 + err = request_irq(VCHIQ_DOORBELL_IRQ, vchiq_doorbell_irq,
417 + IRQF_IRQPOLL, "VCHIQ doorbell",
421 + printk( KERN_ERR "%s: failed to register irq=%d err=%d\n", __func__,
422 + VCHIQ_DOORBELL_IRQ, err );
423 + goto failed_request_irq;
426 + /* Send the base address of the slots to VideoCore */
428 + dsb(); /* Ensure all writes have completed */
430 + bcm_mailbox_write(MBOX_CHAN_VCHIQ, (unsigned int)g_slot_phys);
432 + vcos_log_info("vchiq_init - done (slots %x, phys %x)",
433 + (unsigned int)vchiq_slot_zero, g_slot_phys);
440 + dma_free_coherent(NULL, g_slot_mem_size, g_slot_mem, g_slot_phys);
447 +vchiq_platform_exit(VCHIQ_STATE_T *state)
449 + free_irq(VCHIQ_DOORBELL_IRQ, state);
450 + dma_free_coherent(NULL, g_slot_mem_size,
451 + g_slot_mem, g_slot_phys);
455 +remote_event_signal(REMOTE_EVENT_T *event)
459 + /* The test on the next line also ensures the write on the previous line
462 + if (event->armed) {
463 + /* trigger vc interrupt */
464 + dsb(); /* data barrier operation */
466 + writel(0, __io_address(ARM_0_BELL2));
471 +vchiq_copy_from_user(void *dst, const void *src, int size)
473 + return copy_from_user(dst, src, size);
477 +vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
478 + void *offset, int size, int dir)
480 + PAGELIST_T *pagelist;
483 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
485 + ret = create_pagelist((char __user *)offset, size,
486 + (dir == VCHIQ_BULK_RECEIVE)
492 + return VCHIQ_ERROR;
494 + bulk->handle = memhandle;
495 + bulk->data = VCHIQ_ARM_ADDRESS(pagelist);
497 + /* Store the pagelist address in remote_data, which isn't used by the
499 + bulk->remote_data = pagelist;
501 + return VCHIQ_SUCCESS;
505 +vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
507 + free_pagelist((PAGELIST_T *)bulk->remote_data, bulk->actual);
511 +vchiq_transfer_bulk(VCHIQ_BULK_T *bulk)
514 + * This should only be called on the master (VideoCore) side, but
515 + * provide an implementation to avoid the need for ifdefery.
517 + vcos_assert(!"This code should not be called by the ARM on BCM2835");
521 +vchiq_dump_platform_state(void *dump_context)
525 + len = vcos_snprintf(buf, sizeof(buf),
526 + " Platform: 2835 (VC master)");
527 + vchiq_dump(dump_context, buf, len + 1);
531 +vchiq_platform_paused(VCHIQ_STATE_T *state)
533 + vcos_unused(state);
534 + vcos_assert_msg(0, "Suspend/resume not supported");
538 +vchiq_platform_resumed(VCHIQ_STATE_T *state)
540 + vcos_unused(state);
541 + vcos_assert_msg(0, "Suspend/resume not supported");
545 +vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle)
547 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
549 + return VCHIQ_ERROR;
550 + return VCHIQ_SUCCESS;
554 +vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle)
556 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
558 + return VCHIQ_ERROR;
559 + return VCHIQ_SUCCESS;
563 +vchiq_check_service(VCHIQ_SERVICE_HANDLE_T handle)
565 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
567 + return VCHIQ_ERROR;
568 + return VCHIQ_SUCCESS;
576 +vchiq_doorbell_irq(int irq, void *dev_id)
578 + VCHIQ_STATE_T *state = dev_id;
579 + irqreturn_t ret = IRQ_NONE;
580 + unsigned int status;
582 + /* Read (and clear) the doorbell */
583 + status = readl(__io_address(ARM_0_BELL0));
585 + if (status & 0x4) { /* Was the doorbell rung? */
586 + remote_event_pollall(state);
593 +/* There is a potential problem with partial cache lines (pages?)
594 + at the ends of the block when reading. If the CPU accessed anything in
595 + the same line (page?) then it may have pulled old data into the cache,
596 + obscuring the new data underneath. We can solve this by transferring the
597 + partial cache lines separately, and allowing the ARM to copy into the
600 + N.B. This implementation plays slightly fast and loose with the Linux
601 + driver programming rules, e.g. its use of __virt_to_bus instead of
602 + dma_map_single, but it isn't a multi-platform driver and it benefits
603 + from increased speed as a result.
607 +create_pagelist(char __user *buf, size_t count, unsigned short type,
608 + struct task_struct *task, PAGELIST_T ** ppagelist)
610 + PAGELIST_T *pagelist;
611 + struct page **pages;
613 + unsigned long *addrs;
614 + unsigned int num_pages, offset, i;
615 + char *addr, *base_addr, *next_addr;
616 + int run, addridx, actual_pages;
618 + offset = (unsigned int)buf & (PAGE_SIZE - 1);
619 + num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE;
623 + /* Allocate enough storage to hold the page pointers and the page list */
624 + pagelist = (PAGELIST_T *) kmalloc(sizeof(PAGELIST_T) +
625 + (num_pages * sizeof(unsigned long)) +
626 + (num_pages * sizeof(pages[0])),
629 + vcos_log_trace("create_pagelist - %x", (unsigned int)pagelist);
633 + addrs = pagelist->addrs;
634 + pages = (struct page **)(addrs + num_pages);
636 + down_read(&task->mm->mmap_sem);
637 + actual_pages = get_user_pages(task, task->mm,
638 + (unsigned long)buf & ~(PAGE_SIZE - 1), num_pages,
639 + (type == PAGELIST_READ) /*Write */ , 0 /*Force */ ,
640 + pages, NULL /*vmas */ );
641 + up_read(&task->mm->mmap_sem);
643 + if (actual_pages != num_pages)
645 + for (i = 0; i < actual_pages; i++) {
646 + page_cache_release(pages[i]);
652 + pagelist->length = count;
653 + pagelist->type = type;
654 + pagelist->offset = offset;
656 + /* Group the pages into runs of contiguous pages */
658 + base_addr = VCHIQ_ARM_ADDRESS(page_address(pages[0]));
659 + next_addr = base_addr + PAGE_SIZE;
663 + for (i = 1; i < num_pages; i++) {
664 + addr = VCHIQ_ARM_ADDRESS(page_address(pages[i]));
665 + if ((addr == next_addr) && (run < (PAGE_SIZE - 1))) {
666 + next_addr += PAGE_SIZE;
669 + addrs[addridx] = (unsigned long)base_addr + run;
672 + next_addr = addr + PAGE_SIZE;
677 + addrs[addridx] = (unsigned long)base_addr + run;
680 + /* Partial cache lines (fragments) require special measures */
681 + if ((type == PAGELIST_READ) &&
682 + ((pagelist->offset & (CACHE_LINE_SIZE - 1)) ||
683 + ((pagelist->offset + pagelist->length) & (CACHE_LINE_SIZE - 1)))) {
684 + FRAGMENTS_T *fragments;
686 + if (down_interruptible(&g_free_fragments_sema) != 0) {
691 + vcos_assert(g_free_fragments != NULL);
693 + down(&g_free_fragments_mutex);
694 + fragments = (FRAGMENTS_T *) g_free_fragments;
695 + vcos_assert(fragments != NULL);
696 + g_free_fragments = *(FRAGMENTS_T **) g_free_fragments;
697 + up(&g_free_fragments_mutex);
699 + PAGELIST_READ_WITH_FRAGMENTS + (fragments -
703 + for (page = virt_to_page(pagelist);
704 + page <= virt_to_page(addrs + num_pages - 1); page++) {
705 + flush_dcache_page(page);
708 + *ppagelist = pagelist;
714 +free_pagelist(PAGELIST_T *pagelist, int actual)
716 + struct page **pages;
717 + unsigned int num_pages, i;
719 + vcos_log_trace("free_pagelist - %x, %d", (unsigned int)pagelist, actual);
722 + (pagelist->length + pagelist->offset + PAGE_SIZE - 1) / PAGE_SIZE;
724 + pages = (struct page **)(pagelist->addrs + num_pages);
726 + /* Deal with any partial cache lines (fragments) */
727 + if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
728 + FRAGMENTS_T *fragments =
729 + g_fragments_base + (pagelist->type -
730 + PAGELIST_READ_WITH_FRAGMENTS);
731 + int head_bytes, tail_bytes;
735 + if ((head_bytes = (CACHE_LINE_SIZE - pagelist->offset) & (CACHE_LINE_SIZE - 1)) != 0) {
736 + if (head_bytes > actual)
737 + head_bytes = actual;
739 + memcpy((char *)page_address(pages[0]) +
740 + pagelist->offset, fragments->headbuf,
743 + if ((head_bytes < actual) &&
745 + (pagelist->offset + actual) & (CACHE_LINE_SIZE -
747 + memcpy((char *)page_address(pages[num_pages - 1]) +
748 + ((pagelist->offset + actual) & (PAGE_SIZE -
749 + 1) & ~(CACHE_LINE_SIZE - 1)),
750 + fragments->tailbuf, tail_bytes);
754 + down(&g_free_fragments_mutex);
755 + *(FRAGMENTS_T **) fragments = g_free_fragments;
756 + g_free_fragments = fragments;
757 + up(&g_free_fragments_mutex);
758 + up(&g_free_fragments_sema);
761 + for (i = 0; i < num_pages; i++) {
762 + if (pagelist->type != PAGELIST_WRITE)
763 + set_page_dirty(pages[i]);
764 + page_cache_release(pages[i]);
771 +vchiq_platform_suspend(VCHIQ_STATE_T *state)
773 + vcos_unused(state);
774 + return VCHIQ_ERROR;
777 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
780 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
782 + * This program is free software; you can redistribute it and/or modify
783 + * it under the terms of the GNU General Public License as published by
784 + * the Free Software Foundation; either version 2 of the License, or
785 + * (at your option) any later version.
787 + * This program is distributed in the hope that it will be useful,
788 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
789 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
790 + * GNU General Public License for more details.
792 + * You should have received a copy of the GNU General Public License
793 + * along with this program; if not, write to the Free Software
794 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
797 +#include <linux/kernel.h>
798 +#include <linux/module.h>
799 +#include <linux/types.h>
800 +#include <linux/errno.h>
801 +#include <linux/cdev.h>
802 +#include <linux/fs.h>
803 +#include <linux/device.h>
805 +#include "vchiq_core.h"
806 +#include "vchiq_ioctl.h"
807 +#include "vchiq_arm.h"
809 +#define DEVICE_NAME "vchiq"
811 +/* Override the default prefix, which would be vchiq_arm (from the filename) */
812 +#undef MODULE_PARAM_PREFIX
813 +#define MODULE_PARAM_PREFIX DEVICE_NAME "."
815 +#define VCHIQ_MINOR 0
817 +/* Some per-instance constants */
818 +#define MAX_COMPLETIONS 16
819 +#define MAX_SERVICES 64
820 +#define MAX_ELEMENTS 8
821 +#define MSG_QUEUE_SIZE 64
823 +#define VCOS_LOG_CATEGORY (&vchiq_arm_log_category)
825 +typedef struct client_service_struct {
826 + VCHIQ_SERVICE_T *service;
828 + VCHIQ_INSTANCE_T instance;
831 + volatile int dequeue_pending;
832 + volatile int message_available_pos;
833 + volatile int msg_insert;
834 + volatile int msg_remove;
835 + VCOS_EVENT_T insert_event;
836 + VCOS_EVENT_T remove_event;
837 + VCHIQ_HEADER_T *msg_queue[MSG_QUEUE_SIZE];
840 +struct vchiq_instance_struct {
841 + VCHIQ_STATE_T *state;
842 + VCHIQ_COMPLETION_DATA_T completions[MAX_COMPLETIONS];
843 + volatile int completion_insert;
844 + volatile int completion_remove;
845 + VCOS_EVENT_T insert_event;
846 + VCOS_EVENT_T remove_event;
848 + USER_SERVICE_T services[MAX_SERVICES];
856 +typedef struct dump_context_struct
864 +VCOS_LOG_CAT_T vchiq_arm_log_category;
866 +static struct cdev vchiq_cdev;
867 +static dev_t vchiq_devid;
868 +static VCHIQ_STATE_T g_state;
869 +static struct class *vchiq_class;
870 +static struct device *vchiq_dev;
872 +static const char *ioctl_names[] =
879 + "QUEUE_BULK_TRANSMIT",
880 + "QUEUE_BULK_RECEIVE",
881 + "AWAIT_COMPLETION",
890 +VCOS_LOG_LEVEL_T vchiq_default_arm_log_level = VCOS_LOG_WARN;
892 +/****************************************************************************
894 +* find_service_by_handle
896 +***************************************************************************/
898 +static inline USER_SERVICE_T *find_service_by_handle(
899 + VCHIQ_INSTANCE_T instance, int handle )
901 + USER_SERVICE_T *user_service;
903 + if (( handle >= 0 )
904 + && ( handle < MAX_SERVICES ))
906 + user_service = &instance->services[ handle ];
908 + if ( user_service->service != NULL )
910 + return user_service;
917 +/****************************************************************************
919 +* find_avail_service_handle
921 +***************************************************************************/
923 +static inline USER_SERVICE_T *find_avail_service_handle(
924 + VCHIQ_INSTANCE_T instance)
928 + for ( handle = 0; handle < MAX_SERVICES; handle++ )
930 + if ( instance->services[handle].service == NULL )
932 + instance->services[handle].instance = instance;
933 + instance->services[handle].handle = handle;
935 + return &instance->services[handle];
941 +/****************************************************************************
945 +***************************************************************************/
947 +static VCHIQ_STATUS_T
948 +add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
949 + VCHIQ_HEADER_T *header, USER_SERVICE_T *service, void *bulk_userdata)
951 + VCHIQ_COMPLETION_DATA_T *completion;
952 + DEBUG_INITIALISE(g_state.local)
954 + while (instance->completion_insert ==
955 + (instance->completion_remove + MAX_COMPLETIONS)) {
956 + /* Out of space - wait for the client */
957 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
958 + vcos_log_trace("add_completion - completion queue full");
959 + DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
960 + if (vcos_event_wait(&instance->remove_event) != VCOS_SUCCESS) {
961 + vcos_log_info("service_callback interrupted");
962 + return VCHIQ_RETRY;
963 + } else if (instance->closing) {
964 + vcos_log_info("service_callback closing");
965 + return VCHIQ_ERROR;
967 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
972 + completions[instance->completion_insert & (MAX_COMPLETIONS - 1)];
974 + completion->header = header;
975 + completion->reason = reason;
976 + completion->service_userdata = service;
977 + completion->bulk_userdata = bulk_userdata;
979 + /* A write barrier is needed here to ensure that the entire completion
980 + record is written out before the insert point. */
981 + vcos_wmb(&completion->bulk_userdata);
983 + if (reason == VCHIQ_MESSAGE_AVAILABLE)
984 + service->message_available_pos = instance->completion_insert;
985 + instance->completion_insert++;
987 + vcos_event_signal(&instance->insert_event);
989 + return VCHIQ_SUCCESS;
992 +/****************************************************************************
996 +***************************************************************************/
998 +static VCHIQ_STATUS_T
999 +service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
1000 + VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
1002 + /* How do we ensure the callback goes to the right client?
1003 + The service_user data points to a USER_SERVICE_T record containing the
1004 + original callback and the user state structure, which contains a circular
1005 + buffer for completion records.
1007 + USER_SERVICE_T *service =
1008 + (USER_SERVICE_T *) VCHIQ_GET_SERVICE_USERDATA(handle);
1009 + VCHIQ_INSTANCE_T instance = service->instance;
1010 + DEBUG_INITIALISE(g_state.local)
1012 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1014 + ("service_callback - service %lx(%d), reason %d, header %lx, "
1015 + "instance %lx, bulk_userdata %lx",
1016 + (unsigned long)service, ((VCHIQ_SERVICE_T *) handle)->localport,
1017 + reason, (unsigned long)header,
1018 + (unsigned long)instance, (unsigned long)bulk_userdata);
1020 + if (!instance || instance->closing) {
1021 + return VCHIQ_SUCCESS;
1024 + if (header && service->is_vchi)
1026 + while (service->msg_insert == (service->msg_remove + MSG_QUEUE_SIZE))
1028 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1029 + DEBUG_COUNT(MSG_QUEUE_FULL_COUNT);
1030 + vcos_log_trace("service_callback - msg queue full");
1031 + /* If there is no MESSAGE_AVAILABLE in the completion queue, add one */
1032 + if ((service->message_available_pos - instance->completion_remove) < 0)
1034 + VCHIQ_STATUS_T status;
1035 + vcos_log_warn("Inserting extra MESSAGE_AVAILABLE");
1036 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1037 + status = add_completion(instance, reason, NULL, service, bulk_userdata);
1038 + if (status != VCHIQ_SUCCESS)
1040 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1045 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1046 + if (vcos_event_wait(&service->remove_event) != VCOS_SUCCESS) {
1047 + vcos_log_info("service_callback interrupted");
1048 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1049 + return VCHIQ_RETRY;
1050 + } else if (instance->closing) {
1051 + vcos_log_info("service_callback closing");
1052 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1053 + return VCHIQ_ERROR;
1055 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1058 + service->msg_queue[service->msg_insert & (MSG_QUEUE_SIZE - 1)] =
1061 + /* A write memory barrier is needed to ensure that the store of header
1062 + is completed before the insertion point is updated */
1063 + vcos_wmb(&service->msg_queue[service->msg_insert & (MSG_QUEUE_SIZE - 1)]);
1065 + service->msg_insert++;
1066 + vcos_event_signal(&service->insert_event);
1068 + /* If there is a thread waiting in DEQUEUE_MESSAGE, or if
1069 + there is a MESSAGE_AVAILABLE in the completion queue then
1070 + bypass the completion queue. */
1071 + if (((service->message_available_pos - instance->completion_remove) >= 0) ||
1072 + service->dequeue_pending)
1074 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1075 + service->dequeue_pending = 0;
1076 + return VCHIQ_SUCCESS;
1081 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1083 + return add_completion(instance, reason, header, service, bulk_userdata);
1086 +/****************************************************************************
1090 +***************************************************************************/
1093 +vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1095 + VCHIQ_INSTANCE_T instance = file->private_data;
1096 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
1099 + DEBUG_INITIALISE(g_state.local)
1101 + vcos_log_trace("vchiq_ioctl - instance %x, cmd %s, arg %lx",
1102 + (unsigned int)instance,
1103 + ((_IOC_TYPE(cmd) == VCHIQ_IOC_MAGIC) && (_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ?
1104 + ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
1107 + case VCHIQ_IOC_SHUTDOWN:
1108 + if (!instance->connected)
1111 + /* Remove all services */
1112 + for (i = 0; i < MAX_SERVICES; i++) {
1113 + USER_SERVICE_T *service = &instance->services[i];
1114 + if (service->service != NULL) {
1115 + status = vchiq_remove_service(&service->service->base);
1116 + if (status != VCHIQ_SUCCESS)
1118 + service->service = NULL;
1122 + if (status == VCHIQ_SUCCESS) {
1123 + /* Wake the completion thread and ask it to exit */
1124 + instance->closing = 1;
1125 + vcos_event_signal(&instance->insert_event);
1130 + case VCHIQ_IOC_CONNECT:
1131 + if (instance->connected) {
1135 + if ((rc=vcos_mutex_lock(&instance->state->mutex)) != VCOS_SUCCESS) {
1136 + vcos_log_error("vchiq: connect: could not lock mutex for state %d: %d",
1137 + instance->state->id, rc);
1141 + status = vchiq_connect_internal(instance->state, instance);
1142 + vcos_mutex_unlock(&instance->state->mutex);
1144 + if (status == VCHIQ_SUCCESS)
1145 + instance->connected = 1;
1147 + vcos_log_error("vchiq: could not connect: %d", status);
1150 + case VCHIQ_IOC_CREATE_SERVICE:
1152 + VCHIQ_CREATE_SERVICE_T args;
1153 + VCHIQ_SERVICE_T *service = NULL;
1154 + USER_SERVICE_T *user_service = NULL;
1158 + if (copy_from_user
1159 + (&args, (const void __user *)arg,
1160 + sizeof(args)) != 0) {
1165 + for (i = 0; i < MAX_SERVICES; i++) {
1166 + if (instance->services[i].service == NULL) {
1167 + user_service = &instance->services[i];
1172 + if (!user_service) {
1177 + if (args.is_open) {
1178 + if (instance->connected)
1179 + srvstate = VCHIQ_SRVSTATE_OPENING;
1186 + instance->connected ?
1187 + VCHIQ_SRVSTATE_LISTENING :
1188 + VCHIQ_SRVSTATE_HIDDEN;
1191 + vcos_mutex_lock(&instance->state->mutex);
1193 + userdata = args.params.userdata;
1194 + args.params.callback = service_callback;
1195 + args.params.userdata = user_service;
1197 + vchiq_add_service_internal(instance->state,
1198 + &args.params, srvstate,
1201 + vcos_mutex_unlock(&instance->state->mutex);
1203 + if (service != NULL) {
1204 + user_service->service = service;
1205 + user_service->userdata = userdata;
1206 + user_service->instance = instance;
1207 + user_service->handle = i;
1208 + user_service->is_vchi = args.is_vchi;
1209 + user_service->dequeue_pending = 0;
1210 + user_service->message_available_pos = instance->completion_remove - 1;
1211 + user_service->msg_insert = 0;
1212 + user_service->msg_remove = 0;
1213 + vcos_event_create(&user_service->insert_event, "insert_event");
1214 + vcos_event_create(&user_service->remove_event, "remove_event");
1216 + if (args.is_open) {
1218 + vchiq_open_service_internal
1219 + (service, instance->pid);
1220 + if (status != VCHIQ_SUCCESS) {
1221 + vchiq_remove_service
1225 + VCHIQ_RETRY) ? -EINTR :
1227 + user_service->service = NULL;
1228 + user_service->instance = NULL;
1229 + vcos_event_delete(&user_service->insert_event);
1230 + vcos_event_delete(&user_service->remove_event);
1235 + if (copy_to_user((void __user *)
1236 + &(((VCHIQ_CREATE_SERVICE_T __user
1238 + (const void *)&user_service->
1240 + sizeof(user_service->
1249 + case VCHIQ_IOC_CLOSE_SERVICE:
1251 + USER_SERVICE_T *user_service;
1252 + int handle = (int)arg;
1254 + user_service = find_service_by_handle(instance, handle);
1255 + if (user_service != NULL)
1257 + int is_server = (user_service->service->public_fourcc != VCHIQ_FOURCC_INVALID);
1260 + vchiq_close_service(&user_service->service->base);
1261 + if ((status == VCHIQ_SUCCESS) && !is_server)
1263 + vcos_event_delete(&user_service->insert_event);
1264 + vcos_event_delete(&user_service->remove_event);
1265 + user_service->service = NULL;
1272 + case VCHIQ_IOC_REMOVE_SERVICE:
1274 + USER_SERVICE_T *user_service;
1275 + int handle = (int)arg;
1277 + user_service = find_service_by_handle(instance, handle);
1278 + if (user_service != NULL)
1281 + vchiq_remove_service(&user_service->service->base);
1282 + if (status == VCHIQ_SUCCESS)
1284 + vcos_event_delete(&user_service->insert_event);
1285 + vcos_event_delete(&user_service->remove_event);
1286 + user_service->service = NULL;
1293 + case VCHIQ_IOC_USE_SERVICE:
1294 + case VCHIQ_IOC_RELEASE_SERVICE:
1296 + USER_SERVICE_T *user_service;
1297 + int handle = (int)arg;
1299 + user_service = find_service_by_handle(instance, handle);
1300 + if (user_service != NULL)
1302 + status = (cmd == VCHIQ_IOC_USE_SERVICE) ? vchiq_use_service(&user_service->service->base) : vchiq_release_service(&user_service->service->base);
1303 + if (status != VCHIQ_SUCCESS)
1305 + ret = -EINVAL; // ???
1311 + case VCHIQ_IOC_QUEUE_MESSAGE:
1313 + VCHIQ_QUEUE_MESSAGE_T args;
1314 + USER_SERVICE_T *user_service;
1316 + if (copy_from_user
1317 + (&args, (const void __user *)arg,
1318 + sizeof(args)) != 0) {
1322 + user_service = find_service_by_handle(instance, args.handle);
1323 + if ((user_service != NULL) && (args.count <= MAX_ELEMENTS))
1325 + /* Copy elements into kernel space */
1326 + VCHIQ_ELEMENT_T elements[MAX_ELEMENTS];
1327 + if (copy_from_user
1328 + (elements, args.elements,
1329 + args.count * sizeof(VCHIQ_ELEMENT_T)) == 0)
1331 + vchiq_queue_message
1332 + (&user_service->service->base,
1333 + elements, args.count);
1342 + case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
1343 + case VCHIQ_IOC_QUEUE_BULK_RECEIVE:
1345 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
1346 + USER_SERVICE_T *user_service;
1347 + VCHIQ_BULK_DIR_T dir =
1348 + (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
1349 + VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
1351 + if (copy_from_user
1352 + (&args, (const void __user *)arg,
1353 + sizeof(args)) != 0) {
1357 + user_service = find_service_by_handle(instance, args.handle);
1358 + if (user_service != NULL)
1361 + vchiq_bulk_transfer
1362 + ((VCHIQ_SERVICE_T *)user_service->service,
1363 + VCHI_MEM_HANDLE_INVALID,
1364 + args.data, args.size,
1365 + args.userdata, args.mode,
1373 + case VCHIQ_IOC_AWAIT_COMPLETION:
1375 + VCHIQ_AWAIT_COMPLETION_T args;
1377 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1378 + if (!instance->connected) {
1383 + if (copy_from_user
1384 + (&args, (const void __user *)arg,
1385 + sizeof(args)) != 0) {
1389 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1390 + while ((instance->completion_remove ==
1391 + instance->completion_insert)
1392 + && !instance->closing) {
1393 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1394 + if (vcos_event_wait(&instance->insert_event) !=
1396 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1398 + ("AWAIT_COMPLETION interrupted");
1403 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1405 + /* A read memory barrier is needed to stop prefetch of a stale
1406 + completion record */
1410 + int msgbufcount = args.msgbufcount;
1411 + for (ret = 0; ret < args.count; ret++) {
1412 + VCHIQ_COMPLETION_DATA_T *completion;
1413 + USER_SERVICE_T *service;
1414 + VCHIQ_HEADER_T *header;
1415 + if (instance->completion_remove ==
1416 + instance->completion_insert)
1421 + [instance->completion_remove &
1422 + (MAX_COMPLETIONS - 1)];
1424 + service = (USER_SERVICE_T *)completion->service_userdata;
1425 + completion->service_userdata = service->userdata;
1427 + header = completion->header;
1430 + void __user *msgbuf;
1433 + msglen = header->size + sizeof(VCHIQ_HEADER_T);
1434 + /* This must be a VCHIQ-style service */
1435 + if (args.msgbufsize < msglen)
1437 + vcos_log_error("header %x: msgbufsize %x < msglen %x",
1438 + (unsigned int)header, args.msgbufsize, msglen);
1444 + if (msgbufcount <= 0)
1446 + /* Stall here for lack of a buffer for the message */
1449 + /* Get the pointer from user space */
1451 + if (copy_from_user(&msgbuf,
1452 + (const void __user *)&args.msgbufs[msgbufcount],
1453 + sizeof(msgbuf)) != 0)
1460 + /* Copy the message to user space */
1461 + if (copy_to_user(msgbuf, header, msglen) != 0)
1468 + /* Now it has been copied, the message can be released. */
1469 + vchiq_release_message(&service->service->base, header);
1471 + /* The completion must point to the msgbuf */
1472 + completion->header = msgbuf;
1476 + ((void __user *)((size_t) args.buf +
1479 + (VCHIQ_COMPLETION_DATA_T)),
1481 + sizeof(VCHIQ_COMPLETION_DATA_T)) !=
1487 + instance->completion_remove++;
1490 + if (msgbufcount != args.msgbufcount)
1492 + if (copy_to_user((void __user *)
1493 + &((VCHIQ_AWAIT_COMPLETION_T *)arg)->msgbufcount,
1494 + &msgbufcount, sizeof(msgbufcount)) != 0)
1503 + vcos_event_signal(&instance->remove_event);
1504 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1508 + case VCHIQ_IOC_DEQUEUE_MESSAGE:
1510 + VCHIQ_DEQUEUE_MESSAGE_T args;
1511 + USER_SERVICE_T *user_service;
1512 + VCHIQ_HEADER_T *header;
1514 + DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1515 + if (copy_from_user
1516 + (&args, (const void __user *)arg,
1517 + sizeof(args)) != 0) {
1521 + user_service = &instance->services[args.handle];
1522 + if ((args.handle < 0) || (args.handle >= MAX_SERVICES) ||
1523 + (user_service->service == NULL) ||
1524 + (user_service->is_vchi == 0)) {
1528 + if (user_service->msg_remove == user_service->msg_insert)
1530 + if (!args.blocking)
1532 + DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1533 + ret = -EWOULDBLOCK;
1536 + user_service->dequeue_pending = 1;
1538 + DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1539 + if (vcos_event_wait(&user_service->insert_event) !=
1541 + vcos_log_info("DEQUEUE_MESSAGE interrupted");
1546 + while (user_service->msg_remove == user_service->msg_insert);
1549 + /* A read memory barrier is needed to stop prefetch of a stale
1553 + header = user_service->msg_queue[user_service->msg_remove &
1554 + (MSG_QUEUE_SIZE - 1)];
1555 + if (header == NULL)
1557 + else if (header->size <= args.bufsize)
1559 + /* Copy to user space if msgbuf is not NULL */
1560 + if ((args.buf == NULL) ||
1561 + (copy_to_user((void __user *)args.buf, header->data,
1562 + header->size) == 0))
1564 + ret = header->size;
1565 + vchiq_release_message(&user_service->service->base,
1567 + user_service->msg_remove++;
1568 + vcos_event_signal(&user_service->remove_event);
1575 + vcos_log_error("header %x: bufsize %x < size %x",
1576 + (unsigned int)header, args.bufsize, header->size);
1580 + DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1584 + case VCHIQ_IOC_GET_CLIENT_ID:
1586 + USER_SERVICE_T *user_service;
1587 + int handle = (int)arg;
1589 + user_service = find_service_by_handle(instance, handle);
1590 + if (user_service != NULL)
1591 + ret = vchiq_get_client_id(&user_service->service->base);
1597 + case VCHIQ_IOC_GET_CONFIG:
1599 + VCHIQ_GET_CONFIG_T args;
1600 + VCHIQ_CONFIG_T config;
1602 + if (copy_from_user
1603 + (&args, (const void __user *)arg,
1604 + sizeof(args)) != 0) {
1608 + if (args.config_size > sizeof(config))
1613 + status = vchiq_get_config(instance, args.config_size, &config);
1614 + if (status == VCHIQ_SUCCESS)
1616 + if (copy_to_user((void __user *)args.pconfig,
1617 + &config, args.config_size) != 0)
1626 + case VCHIQ_IOC_SET_SERVICE_OPTION:
1628 + VCHIQ_SET_SERVICE_OPTION_T args;
1629 + USER_SERVICE_T *user_service;
1631 + if (copy_from_user(
1632 + &args, (const void __user *)arg,
1633 + sizeof(args)) != 0)
1639 + user_service = find_service_by_handle(instance, args.handle);
1640 + if (user_service != NULL)
1642 + status = vchiq_set_service_option(
1643 + &user_service->service->base,
1644 + args.option, args.value);
1659 + if (status == VCHIQ_ERROR)
1661 + else if (status == VCHIQ_RETRY)
1665 + if ((ret < 0) && (ret != -EINTR) && (ret != -EWOULDBLOCK))
1666 + vcos_log_warn(" ioctl instance %lx, cmd %s -> status %d, %ld",
1667 + (unsigned long)instance,
1668 + (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ? ioctl_names[_IOC_NR(cmd)] :
1669 + "<invalid>", status, ret);
1671 + vcos_log_trace(" ioctl instance %lx, cmd %s -> status %d, %ld",
1672 + (unsigned long)instance,
1673 + (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ? ioctl_names[_IOC_NR(cmd)] :
1674 + "<invalid>", status, ret);
1679 +/****************************************************************************
1683 +***************************************************************************/
1686 +vchiq_open(struct inode *inode, struct file *file)
1688 + int dev = iminor(inode) & 0x0f;
1689 + vcos_log_info("vchiq_open");
1693 + VCHIQ_STATE_T *state = vchiq_get_state();
1694 + VCHIQ_INSTANCE_T instance;
1698 + vcos_log_error( "vchiq has no connection to VideoCore");
1702 + instance = kzalloc(sizeof(*instance), GFP_KERNEL);
1706 + instance->state = state;
1707 + instance->pid = current->tgid;
1708 + vcos_event_create(&instance->insert_event, DEVICE_NAME);
1709 + vcos_event_create(&instance->remove_event, DEVICE_NAME);
1711 + file->private_data = instance;
1716 + vcos_log_error("Unknown minor device: %d", dev);
1723 +/****************************************************************************
1727 +***************************************************************************/
1730 +vchiq_release(struct inode *inode, struct file *file)
1732 + int dev = iminor(inode) & 0x0f;
1737 + VCHIQ_INSTANCE_T instance = file->private_data;
1740 + vcos_log_info("vchiq_release: instance=%lx",
1741 + (unsigned long)instance);
1743 + instance->closing = 1;
1745 + /* Wake the slot handler if the completion queue is full */
1746 + vcos_event_signal(&instance->remove_event);
1748 + /* Mark all services for termination... */
1750 + for (i = 0; i < MAX_SERVICES; i++) {
1751 + USER_SERVICE_T *user_service =
1752 + &instance->services[i];
1753 + if (user_service->service != NULL)
1755 + /* Wake the slot handler if the msg queue is full */
1756 + vcos_event_signal(&user_service->remove_event);
1758 + if ((user_service->service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) &&
1759 + (user_service->service->srvstate != VCHIQ_SRVSTATE_LISTENING))
1761 + vchiq_terminate_service_internal(user_service->service);
1766 + /* ...and wait for them to die */
1768 + for (i = 0; i < MAX_SERVICES; i++) {
1769 + USER_SERVICE_T *user_service =
1770 + &instance->services[i];
1771 + if (user_service->service != NULL)
1773 + /* Wait in this non-portable fashion because interruptible
1774 + calls will not block in this context. */
1775 + while ((user_service->service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) &&
1776 + (user_service->service->srvstate != VCHIQ_SRVSTATE_LISTENING))
1778 + down(&user_service->service->remove_event);
1781 + vchiq_free_service_internal
1782 + (user_service->service);
1786 + vcos_event_delete(&instance->insert_event);
1787 + vcos_event_delete(&instance->remove_event);
1790 + file->private_data = NULL;
1795 + vcos_log_error("Unknown minor device: %d", dev);
1802 +/****************************************************************************
1806 +***************************************************************************/
1809 +vchiq_dump(void *dump_context, const char *str, int len)
1811 + DUMP_CONTEXT_T *context = (DUMP_CONTEXT_T *)dump_context;
1813 + if ((context->actual >= 0) && (context->actual < context->space))
1816 + if (context->offset > 0)
1818 + int skip_bytes = vcos_min(len, context->offset);
1819 + str += skip_bytes;
1820 + len -= skip_bytes;
1821 + context->offset -= skip_bytes;
1822 + if (context->offset > 0)
1825 + copy_bytes = vcos_min(len, context->space - context->actual);
1826 + if (copy_bytes == 0)
1828 + if (copy_to_user(context->buf + context->actual, str, copy_bytes))
1829 + context->actual = -EFAULT;
1830 + context->actual += copy_bytes;
1831 + len -= copy_bytes;
1833 + /* If tne terminating NUL is included in the length, then it marks
1834 + * the end of a line and should be replaced with a carriage return.
1836 + if ((len == 0) && (str[copy_bytes - 1] == '\0'))
1839 + if (copy_to_user(context->buf + context->actual - 1, &cr, 1))
1841 + context->actual = -EFAULT;
1847 +/****************************************************************************
1849 +* vchiq_dump_platform_instance_state
1851 +***************************************************************************/
1854 +vchiq_dump_platform_instances(void *dump_context)
1856 + VCHIQ_STATE_T *state = vchiq_get_state();
1861 + /* There is no list of instances, so instead scan all services,
1862 + marking those that have been dumped. */
1864 + for (i = 0; i < state->unused_service; i++)
1866 + VCHIQ_SERVICE_T *service = state->services[i];
1867 + VCHIQ_INSTANCE_T instance;
1870 + && ((instance = service->instance) != NULL)
1871 + && (service->base.callback == service_callback))
1872 + instance->mark = 0;
1875 + for (i = 0; i < state->unused_service; i++)
1877 + VCHIQ_SERVICE_T *service = state->services[i];
1878 + VCHIQ_INSTANCE_T instance;
1881 + && ((instance = service->instance) != NULL)
1882 + && (service->base.callback == service_callback))
1884 + if (!instance->mark)
1886 + len = vcos_snprintf(buf, sizeof(buf),
1887 + "Instance %x: pid %d,%s completions %d/%d",
1888 + (unsigned int)instance, instance->pid,
1889 + instance->connected ? " connected," : "",
1890 + instance->completion_insert - instance->completion_remove,
1893 + vchiq_dump(dump_context, buf, len + 1);
1895 + instance->mark = 1;
1901 +/****************************************************************************
1903 +* vchiq_dump_platform_service_state
1905 +***************************************************************************/
1908 +vchiq_dump_platform_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
1910 + USER_SERVICE_T *user_service = (USER_SERVICE_T *)service->base.userdata;
1914 + len = vcos_snprintf(buf, sizeof(buf), " instance %x",
1915 + service->instance);
1917 + if ((service->base.callback == service_callback) && user_service->is_vchi)
1919 + len += vcos_snprintf(buf + len, sizeof(buf) - len,
1920 + ", %d/%d messages",
1921 + user_service->msg_insert - user_service->msg_remove,
1924 + if (user_service->dequeue_pending)
1925 + len += vcos_snprintf(buf + len, sizeof(buf) - len,
1926 + " (dequeue pending)");
1929 + vchiq_dump(dump_context, buf, len + 1);
1932 +/****************************************************************************
1936 +***************************************************************************/
1939 +vchiq_read(struct file * file, char __user * buf,
1940 + size_t count, loff_t *ppos)
1942 + DUMP_CONTEXT_T context;
1943 + context.buf = buf;
1944 + context.actual = 0;
1945 + context.space = count;
1946 + context.offset = *ppos;
1948 + vchiq_dump_state(&context, &g_state);
1950 + if (context.actual >= 0)
1951 + *ppos += context.actual;
1953 + return context.actual;
1957 +vchiq_get_state(void)
1960 + if (g_state.remote == NULL)
1962 + printk( "%s: g_state.remote == NULL\n", __func__ );
1966 + if ( g_state.remote->initialised != 1)
1968 + printk( "%s: g_state.remote->initialised != 1 (%d)\n", __func__, g_state.remote->initialised );
1972 + return ((g_state.remote != NULL) &&
1973 + (g_state.remote->initialised == 1)) ? &g_state : NULL;
1976 +static const struct file_operations
1978 + .owner = THIS_MODULE,
1979 + .unlocked_ioctl = vchiq_ioctl,
1980 + .open = vchiq_open,
1981 + .release = vchiq_release,
1982 + .read = vchiq_read
1985 +/****************************************************************************
1987 +* vchiq_init - called when the module is loaded.
1989 +***************************************************************************/
1997 + err = vchiq_platform_vcos_init();
1999 + goto failed_platform_vcos_init;
2001 + vcos_log_set_level(VCOS_LOG_CATEGORY, vchiq_default_arm_log_level);
2002 + vcos_log_register("vchiq_arm", VCOS_LOG_CATEGORY);
2005 + alloc_chrdev_region(&vchiq_devid, VCHIQ_MINOR, 1,
2006 + DEVICE_NAME)) != 0) {
2007 + vcos_log_error("Unable to allocate device number");
2008 + goto failed_alloc_chrdev;
2010 + cdev_init(&vchiq_cdev, &vchiq_fops);
2011 + vchiq_cdev.owner = THIS_MODULE;
2012 + if ((err = cdev_add(&vchiq_cdev, vchiq_devid, 1)) != 0) {
2013 + vcos_log_error("Unable to register device");
2014 + goto failed_cdev_add;
2017 + /* create sysfs entries */
2018 + vchiq_class = class_create(THIS_MODULE, DEVICE_NAME);
2019 + if (IS_ERR(ptr_err = vchiq_class))
2020 + goto failed_class_create;
2022 + vchiq_dev = device_create(vchiq_class, NULL,
2023 + vchiq_devid, NULL, "vchiq");
2024 + if (IS_ERR(ptr_err = vchiq_dev))
2025 + goto failed_device_create;
2027 + err = vchiq_platform_init(&g_state);
2029 + goto failed_platform_init;
2031 + vcos_log_error("vchiq: initialised - version %d (min %d), device %d.%d",
2032 + VCHIQ_VERSION, VCHIQ_VERSION_MIN,
2033 + MAJOR(vchiq_devid), MINOR(vchiq_devid));
2037 +failed_platform_init:
2038 + device_destroy(vchiq_class, vchiq_devid);
2039 +failed_device_create:
2040 + class_destroy(vchiq_class);
2041 +failed_class_create:
2042 + cdev_del(&vchiq_cdev);
2043 + err = PTR_ERR(ptr_err);
2045 + unregister_chrdev_region(vchiq_devid, 1);
2046 +failed_alloc_chrdev:
2047 +failed_platform_vcos_init:
2048 + printk(KERN_WARNING "could not load vchiq\n");
2051 +/****************************************************************************
2053 +* vchiq_exit - called when the module is unloaded.
2055 +***************************************************************************/
2060 + vchiq_platform_exit(&g_state);
2061 + device_destroy(vchiq_class, vchiq_devid);
2062 + class_destroy(vchiq_class);
2063 + cdev_del(&vchiq_cdev);
2064 + unregister_chrdev_region(vchiq_devid, 1);
2065 + vcos_log_unregister(VCOS_LOG_CATEGORY);
2068 +module_init(vchiq_init);
2069 +module_exit(vchiq_exit);
2070 +MODULE_LICENSE("GPL");
2071 +MODULE_AUTHOR("Broadcom Corporation");
2073 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
2076 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
2078 + * This program is free software; you can redistribute it and/or modify
2079 + * it under the terms of the GNU General Public License as published by
2080 + * the Free Software Foundation; either version 2 of the License, or
2081 + * (at your option) any later version.
2083 + * This program is distributed in the hope that it will be useful,
2084 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2085 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2086 + * GNU General Public License for more details.
2088 + * You should have received a copy of the GNU General Public License
2089 + * along with this program; if not, write to the Free Software
2090 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2093 +#ifndef VCHIQ_ARM_H
2094 +#define VCHIQ_ARM_H
2096 +#include "vchiq_core.h"
2098 +extern VCOS_LOG_CAT_T vchiq_arm_log_category;
2101 +vchiq_platform_vcos_init(void);
2104 +vchiq_platform_init(VCHIQ_STATE_T *state);
2107 +vchiq_platform_exit(VCHIQ_STATE_T *state);
2109 +extern VCHIQ_STATE_T *
2110 +vchiq_get_state(void);
2112 +#endif /* VCHIQ_ARM_H */
2114 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
2117 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
2119 + * This program is free software; you can redistribute it and/or modify
2120 + * it under the terms of the GNU General Public License as published by
2121 + * the Free Software Foundation; either version 2 of the License, or
2122 + * (at your option) any later version.
2124 + * This program is distributed in the hope that it will be useful,
2125 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2126 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2127 + * GNU General Public License for more details.
2129 + * You should have received a copy of the GNU General Public License
2130 + * along with this program; if not, write to the Free Software
2131 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2134 +#ifndef VCHIQ_CFG_H
2135 +#define VCHIQ_CFG_H
2137 +#define VCHIQ_MAGIC VCHIQ_MAKE_FOURCC('V','C','H','I')
2138 +/* The version of VCHIQ - change with any non-trivial change */
2139 +#define VCHIQ_VERSION 2
2140 +/* The minimum compatible version - update to match VCHIQ_VERSION with any incompatible change */
2141 +#define VCHIQ_VERSION_MIN 2
2143 +#define VCHIQ_MAX_SERVICES 4096
2144 +#define VCHIQ_MAX_SLOTS 128
2145 +#define VCHIQ_MAX_SLOTS_PER_SIDE 64
2147 +#define VCHIQ_NUM_CURRENT_BULKS 32
2148 +#define VCHIQ_NUM_SERVICE_BULKS 4
2150 +#ifndef VCHIQ_ENABLE_DEBUG
2151 +#define VCHIQ_ENABLE_DEBUG 1
2154 +#ifndef VCHIQ_ENABLE_STATS
2155 +#define VCHIQ_ENABLE_STATS 1
2158 +#endif /* VCHIQ_CFG_H */
2160 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
2162 +/*****************************************************************************
2163 +* Copyright 2001 - 2010 Broadcom Corporation. All rights reserved.
2165 +* Unless you and Broadcom execute a separate written software license
2166 +* agreement governing use of this software, this software is licensed to you
2167 +* under the terms of the GNU General Public License version 2, available at
2168 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2170 +* Notwithstanding the above, under no circumstances may you combine this
2171 +* software in any way with any other Broadcom software provided under a
2172 +* license other than the GPL, without Broadcom's express prior written
2174 +*****************************************************************************/
2177 +#include "vchiq_connected.h"
2178 +#include <linux/module.h>
2180 +#define MAX_CALLBACKS 10
2182 +static int g_connected = 0;
2183 +static int g_num_deferred_callbacks;
2184 +static VCHIQ_CONNECTED_CALLBACK_T g_deferred_callback[ MAX_CALLBACKS ];
2185 +static VCOS_ONCE_T g_once_init;
2186 +static VCOS_MUTEX_T g_connected_mutex;
2188 +extern VCOS_LOG_CAT_T vchiq_core_log_category;
2189 +#define VCOS_LOG_CATEGORY (&vchiq_core_log_category)
2191 +/****************************************************************************
2193 +* Function to initialize our lock.
2195 +***************************************************************************/
2197 +static void connected_init( void )
2199 + vcos_mutex_create( &g_connected_mutex, "connected_mutex");
2202 +/****************************************************************************
2204 +* This function is used to defer initialization until the vchiq stack is
2205 +* initialized. If the stack is already initialized, then the callback will
2206 +* be made immediately, otherwise it will be deferred until
2207 +* vchiq_call_connected_callbacks is called.
2209 +***************************************************************************/
2211 +void vchiq_add_connected_callback( VCHIQ_CONNECTED_CALLBACK_T callback )
2213 + vcos_once( &g_once_init, connected_init );
2215 + vcos_mutex_lock( &g_connected_mutex );
2217 + if ( g_connected )
2219 + // We're already connected. Call the callback immediately.
2225 + if ( g_num_deferred_callbacks >= MAX_CALLBACKS )
2227 + vcos_log_error( "There already %d callback registered - please increase MAX_CALLBACKS",
2228 + g_num_deferred_callbacks );
2232 + g_deferred_callback[ g_num_deferred_callbacks ] = callback;
2233 + g_num_deferred_callbacks++;
2236 + vcos_mutex_unlock( &g_connected_mutex );
2239 +/****************************************************************************
2241 +* This function is called by the vchiq stack once it has been connected to
2242 +* the videocore and clients can start to use the stack.
2244 +***************************************************************************/
2246 +void vchiq_call_connected_callbacks( void )
2250 + vcos_once( &g_once_init, connected_init );
2252 + vcos_mutex_lock( &g_connected_mutex );
2253 + for ( i = 0; i < g_num_deferred_callbacks; i++ )\
2255 + g_deferred_callback[i]();
2257 + g_num_deferred_callbacks = 0;
2259 + vcos_mutex_unlock( &g_connected_mutex );
2262 +EXPORT_SYMBOL( vchiq_add_connected_callback );
2264 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
2266 +/*****************************************************************************
2267 +* Copyright 2001 - 2010 Broadcom Corporation. All rights reserved.
2269 +* Unless you and Broadcom execute a separate written software license
2270 +* agreement governing use of this software, this software is licensed to you
2271 +* under the terms of the GNU General Public License version 2, available at
2272 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2274 +* Notwithstanding the above, under no circumstances may you combine this
2275 +* software in any way with any other Broadcom software provided under a
2276 +* license other than the GPL, without Broadcom's express prior written
2278 +*****************************************************************************/
2280 +#ifndef VCHIQ_CONNECTED_H
2281 +#define VCHIQ_CONNECTED_H
2283 +/* ---- Include Files ----------------------------------------------------- */
2285 +/* ---- Constants and Types ---------------------------------------------- */
2287 +typedef void (*VCHIQ_CONNECTED_CALLBACK_T)( void );
2289 +/* ---- Variable Externs ------------------------------------------------- */
2291 +/* ---- Function Prototypes ---------------------------------------------- */
2293 +void vchiq_add_connected_callback( VCHIQ_CONNECTED_CALLBACK_T callback );
2294 +void vchiq_call_connected_callbacks( void );
2296 +#endif /* VCHIQ_CONNECTED_H */
2299 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
2302 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
2304 + * This program is free software; you can redistribute it and/or modify
2305 + * it under the terms of the GNU General Public License as published by
2306 + * the Free Software Foundation; either version 2 of the License, or
2307 + * (at your option) any later version.
2309 + * This program is distributed in the hope that it will be useful,
2310 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2311 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2312 + * GNU General Public License for more details.
2314 + * You should have received a copy of the GNU General Public License
2315 + * along with this program; if not, write to the Free Software
2316 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2319 +#include "vchiq_core.h"
2321 +#define VCHIQ_SLOT_HANDLER_STACK 8192
2323 +#define SLOT_INFO_FROM_INDEX(state, index) (state->slot_info + (index))
2324 +#define SLOT_DATA_FROM_INDEX(state, index) (state->slot_data + (index))
2325 +#define SLOT_INDEX_FROM_DATA(state, data) (((unsigned int)((char *)data - (char *)state->slot_data)) / VCHIQ_SLOT_SIZE)
2326 +#define SLOT_INDEX_FROM_INFO(state, info) ((unsigned int)(info - state->slot_info))
2327 +#define SLOT_QUEUE_INDEX_FROM_POS(pos) ((int)((unsigned int)(pos) / VCHIQ_SLOT_SIZE))
2329 +#define VCOS_LOG_CATEGORY (&vchiq_core_log_category)
2331 +#define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1))
2333 +typedef struct bulk_waiter_struct
2335 + VCOS_EVENT_T event;
2339 +typedef struct vchiq_open_payload_struct{
2343 + short version_min;
2344 +} VCHIQ_OPEN_PAYLOAD_T;
2346 +vcos_static_assert(sizeof(VCHIQ_HEADER_T) == 8); /* we require this for consistency between endpoints */
2347 +vcos_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T)));
2348 +vcos_static_assert(IS_POW2(VCHIQ_NUM_CURRENT_BULKS));
2349 +vcos_static_assert(IS_POW2(VCHIQ_NUM_SERVICE_BULKS));
2351 +VCOS_LOG_CAT_T vchiq_core_log_category;
2352 +VCOS_LOG_CAT_T vchiq_core_msg_log_category;
2353 +VCOS_LOG_LEVEL_T vchiq_default_core_log_level = VCOS_LOG_WARN;
2354 +VCOS_LOG_LEVEL_T vchiq_default_core_msg_log_level = VCOS_LOG_WARN;
2356 +static const char *const srvstate_names[] =
2368 +static const char *const reason_names[] =
2372 + "MESSAGE_AVAILABLE",
2373 + "BULK_TRANSMIT_DONE",
2374 + "BULK_RECEIVE_DONE",
2375 + "BULK_TRANSMIT_ABORTED",
2376 + "BULK_RECEIVE_ABORTED"
2379 +static const char *const conn_state_names[] =
2389 +static const char *msg_type_str( unsigned int msg_type )
2391 + switch (msg_type) {
2392 + case VCHIQ_MSG_PADDING: return "PADDING";
2393 + case VCHIQ_MSG_CONNECT: return "CONNECT";
2394 + case VCHIQ_MSG_OPEN: return "OPEN";
2395 + case VCHIQ_MSG_OPENACK: return "OPENACK";
2396 + case VCHIQ_MSG_CLOSE: return "CLOSE";
2397 + case VCHIQ_MSG_DATA: return "DATA";
2398 + case VCHIQ_MSG_BULK_RX: return "BULK_RX";
2399 + case VCHIQ_MSG_BULK_TX: return "BULK_TX";
2400 + case VCHIQ_MSG_BULK_RX_DONE: return "BULK_RX_DONE";
2401 + case VCHIQ_MSG_BULK_TX_DONE: return "BULK_TX_DONE";
2402 + case VCHIQ_MSG_PAUSE: return "PAUSE";
2403 + case VCHIQ_MSG_RESUME: return "RESUME";
2409 +vchiq_set_service_state(VCHIQ_SERVICE_T *service, int newstate)
2411 + vcos_log_info("%d: srv:%d %s->%s", service->state->id, service->localport,
2412 + srvstate_names[service->srvstate],
2413 + srvstate_names[newstate]);
2414 + service->srvstate = newstate;
2417 +static inline VCHIQ_STATUS_T
2418 +make_service_callback(VCHIQ_SERVICE_T *service, VCHIQ_REASON_T reason,
2419 + VCHIQ_HEADER_T *header, void *bulk_userdata)
2421 + vcos_log_trace("%d: callback:%d (%s, %x, %x)", service->state->id,
2422 + service->localport, reason_names[reason],
2423 + (unsigned int)header, (unsigned int)bulk_userdata);
2424 + return service->base.callback(reason, header, &service->base, bulk_userdata);
2428 +vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate)
2430 + vcos_log_info("%d: %s->%s", state->id,
2431 + conn_state_names[state->conn_state],
2432 + conn_state_names[newstate]);
2433 + state->conn_state = newstate;
2437 +remote_event_create(REMOTE_EVENT_T *event)
2440 + /* Don't clear the 'fired' flag because it may already have been set by the other side */
2441 + vcos_event_create(event->event, "vchiq");
2445 +remote_event_destroy(REMOTE_EVENT_T *event)
2447 + vcos_event_delete(event->event);
2451 +remote_event_wait(REMOTE_EVENT_T *event)
2453 + if (!event->fired)
2456 + if (event->fired) /* Also ensures the write has completed */
2458 + else if (vcos_event_wait(event->event) != VCOS_SUCCESS)
2467 +remote_event_signal_local(REMOTE_EVENT_T *event)
2470 + vcos_event_signal(event->event);
2474 +remote_event_poll(REMOTE_EVENT_T *event)
2477 + remote_event_signal_local(event);
2481 +remote_event_pollall(VCHIQ_STATE_T *state)
2483 + remote_event_poll(&state->local->trigger);
2484 + remote_event_poll(&state->local->recycle);
2487 +/* Round up message sizes so that any space at the end of a slot is always big
2488 + enough for a header. This relies on header size being a power of two, which
2489 + has been verified earlier by a static assertion. */
2491 +static inline unsigned int
2492 +calc_stride(unsigned int size)
2494 + /* Allow room for the header */
2495 + size += sizeof(VCHIQ_HEADER_T);
2498 + return (size + sizeof(VCHIQ_HEADER_T) - 1) & ~(sizeof(VCHIQ_HEADER_T) - 1);
2501 +static VCHIQ_SERVICE_T *
2502 +get_listening_service(VCHIQ_STATE_T *state, int fourcc)
2506 + vcos_assert(fourcc != VCHIQ_FOURCC_INVALID);
2508 + for (i = 0; i < state->unused_service; i++)
2510 + VCHIQ_SERVICE_T *service = state->services[i];
2512 + (service->public_fourcc == fourcc) &&
2513 + ((service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
2514 + ((service->srvstate == VCHIQ_SRVSTATE_OPEN) &&
2515 + (service->remoteport == VCHIQ_PORT_FREE))))
2522 +static VCHIQ_SERVICE_T *
2523 +get_connected_service(VCHIQ_STATE_T *state, unsigned int port)
2526 + for (i = 0; i < state->unused_service; i++) {
2527 + VCHIQ_SERVICE_T *service = state->services[i];
2528 + if (service && (service->srvstate == VCHIQ_SRVSTATE_OPEN)
2529 + && (service->remoteport == port)) {
2537 +request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type)
2541 + vcos_atomic_flags_or(&service->poll_flags, (1 << poll_type));
2542 + vcos_atomic_flags_or(&state->poll_services[service->localport>>5],
2543 + (1 <<(service->localport & 0x1f)));
2546 + state->poll_needed = 1;
2547 + vcos_wmb(&state->poll_needed);
2549 + /* ... and ensure the slot handler runs. */
2550 + remote_event_signal_local(&state->local->trigger);
2553 +/* Called from queue_message, by the slot handler and application threads,
2554 + with slot_mutex held */
2555 +static VCHIQ_HEADER_T *
2556 +reserve_space(VCHIQ_STATE_T *state, int space, int is_blocking)
2558 + VCHIQ_SHARED_STATE_T *local = state->local;
2559 + int tx_pos = state->local_tx_pos;
2560 + int slot_space = VCHIQ_SLOT_SIZE - (tx_pos & VCHIQ_SLOT_MASK);
2562 + if (space > slot_space) {
2563 + VCHIQ_HEADER_T *header;
2564 + /* Fill the remaining space with padding */
2565 + vcos_assert(state->tx_data != NULL);
2566 + header = (VCHIQ_HEADER_T *) (state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
2567 + header->msgid = VCHIQ_MSGID_PADDING;
2568 + header->size = slot_space - sizeof(VCHIQ_HEADER_T);
2570 + tx_pos += slot_space;
2573 + /* If necessary, get the next slot. */
2574 + if ((tx_pos & VCHIQ_SLOT_MASK) == 0)
2578 + /* If there is no free slot... */
2579 + if (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE))
2581 + /* ...wait for one. */
2582 + VCHIQ_STATS_INC(state, slot_stalls);
2584 + /* But first, flush through the last slot. */
2585 + local->tx_pos = tx_pos;
2586 + remote_event_signal(&state->remote->trigger);
2589 + if (!is_blocking ||
2590 + (vcos_event_wait(&state->slot_available_event) != VCOS_SUCCESS))
2592 + return NULL; /* No space available now */
2595 + while (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE));
2598 + slot_index = local->slot_queue[SLOT_QUEUE_INDEX_FROM_POS(tx_pos) & VCHIQ_SLOT_QUEUE_MASK];
2599 + state->tx_data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
2602 + state->local_tx_pos = tx_pos + space;
2604 + return (VCHIQ_HEADER_T *)(state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
2607 +/* Called with slot_mutex held */
2609 +process_free_queue(VCHIQ_STATE_T *state)
2611 + VCHIQ_SHARED_STATE_T *local = state->local;
2612 + BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
2613 + int slot_queue_available;
2615 + /* Use a read memory barrier to ensure that any state that may have
2616 + been modified by another thread is not masked by stale prefetched
2620 + /* Find slots which have been freed by the other side, and return them to
2621 + the available queue. */
2622 + slot_queue_available = state->slot_queue_available;
2624 + while (slot_queue_available != local->slot_queue_recycle)
2627 + int slot_index = local->slot_queue[slot_queue_available++ & VCHIQ_SLOT_QUEUE_MASK];
2628 + char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
2630 + vcos_log_trace("%d: pfq %d=%x %x %x", state->id, slot_index,
2631 + (unsigned int)data, local->slot_queue_recycle,
2632 + slot_queue_available);
2634 + /* Initialise the bitmask for services which have used this slot */
2635 + BITSET_ZERO(service_found);
2639 + while (pos < VCHIQ_SLOT_SIZE)
2641 + VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)(data + pos);
2642 + int msgid = header->msgid;
2643 + if (VCHIQ_MSG_TYPE(msgid) == VCHIQ_MSG_DATA)
2645 + int port = VCHIQ_MSG_SRCPORT(msgid);
2646 + if (!BITSET_IS_SET(service_found, port))
2648 + VCHIQ_SERVICE_QUOTA_T *service_quota =
2649 + &state->service_quotas[port];
2651 + /* Set the found bit for this service */
2652 + BITSET_SET(service_found, port);
2654 + if (service_quota->slot_use_count > 0)
2656 + service_quota->slot_use_count--;
2657 + /* Signal the service in case it has dropped below its quota */
2658 + vcos_event_signal(&service_quota->quota_event);
2659 + vcos_log_trace("%d: pfq:%d %x@%x - slot_use->%d",
2661 + header->size, (unsigned int)header,
2662 + service_quota->slot_use_count);
2666 + vcos_log_error("service %d slot_use_count=%d (header %x,"
2667 + " msgid %x, header->msgid %x, header->size %x)",
2668 + port, service_quota->slot_use_count,
2669 + (unsigned int)header, msgid, header->msgid,
2676 + pos += calc_stride(header->size);
2677 + if (pos > VCHIQ_SLOT_SIZE)
2679 + vcos_log_error("pos %x: header %x, msgid %x, header->msgid %x, header->size %x",
2680 + pos, (unsigned int)header, msgid, header->msgid, header->size);
2686 + if (slot_queue_available != state->slot_queue_available)
2688 + state->slot_queue_available = slot_queue_available;
2689 + vcos_wmb(&state->slot_queue_available);
2690 + vcos_event_signal(&state->slot_available_event);
2694 +/* Called by the slot handler and application threads */
2695 +static VCHIQ_STATUS_T
2696 +queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
2697 + int msgid, const VCHIQ_ELEMENT_T *elements,
2698 + int count, int size, int is_blocking)
2700 + VCHIQ_SHARED_STATE_T *local;
2701 + VCHIQ_SERVICE_QUOTA_T *service_quota = NULL;
2702 + VCHIQ_HEADER_T *header;
2704 + unsigned int stride;
2706 + local = state->local;
2708 + stride = calc_stride(size);
2710 + vcos_assert(stride <= VCHIQ_SLOT_SIZE);
2712 + /* On platforms where vcos_mutex_lock cannot fail, the return will never
2713 + be taken and the compiler may optimise out that code. Let Coverity
2714 + know this is intentional.
2716 + /* coverity[constant_expression_result] */
2717 + if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) &&
2718 + (vcos_mutex_lock(&state->slot_mutex) != VCOS_SUCCESS))
2719 + return VCHIQ_RETRY;
2723 + int tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1);
2725 + if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
2727 + /* The service has been closed, probably while waiting for the mutex */
2728 + vcos_mutex_unlock(&state->slot_mutex);
2729 + return VCHIQ_ERROR;
2732 + service_quota = &state->service_quotas[service->localport];
2734 + /* ...ensure it doesn't use more than its quota of slots */
2735 + while ((tx_end_index != service_quota->previous_tx_index) &&
2736 + (service_quota->slot_use_count == service_quota->slot_quota))
2738 + vcos_log_trace("%d: qm:%d %s,%x - quota stall",
2739 + state->id, service->localport,
2740 + msg_type_str(VCHIQ_MSG_TYPE(msgid)), size);
2741 + VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
2742 + vcos_mutex_unlock(&state->slot_mutex);
2743 + if (vcos_event_wait(&service_quota->quota_event) != VCOS_SUCCESS)
2744 + return VCHIQ_RETRY;
2745 + if (vcos_mutex_lock(&state->slot_mutex) != VCOS_SUCCESS)
2746 + return VCHIQ_RETRY;
2747 + vcos_assert(service_quota->slot_use_count <= service_quota->slot_quota);
2748 + tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1);
2752 + header = reserve_space(state, stride, is_blocking);
2756 + VCHIQ_SERVICE_STATS_INC(service, slot_stalls);
2757 + vcos_mutex_unlock(&state->slot_mutex);
2758 + return VCHIQ_RETRY;
2765 + vcos_log_info("%d: qm %s@%x,%x (%d->%d)", state->id,
2766 + msg_type_str(VCHIQ_MSG_TYPE(msgid)),
2767 + (unsigned int)header, size,
2768 + VCHIQ_MSG_SRCPORT(msgid),
2769 + VCHIQ_MSG_DSTPORT(msgid));
2771 + for (i = 0, pos = 0; i < (unsigned int)count;
2772 + pos += elements[i++].size)
2773 + if (elements[i].size) {
2774 + if (vchiq_copy_from_user
2775 + (header->data + pos, elements[i].data,
2776 + (size_t) elements[i].size) !=
2778 + vcos_mutex_unlock(&state->slot_mutex);
2779 + VCHIQ_SERVICE_STATS_INC(service, error_count);
2780 + return VCHIQ_ERROR;
2783 + vcos_log_dump_mem( &vchiq_core_msg_log_category,
2784 + "Sent", 0, header->data + pos,
2785 + vcos_min( 64, elements[0].size ));
2789 + /* If this transmission can't fit in the last slot used by this service... */
2790 + tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos - 1);
2791 + if (tx_end_index != service_quota->previous_tx_index)
2793 + service_quota->slot_use_count++;
2794 + vcos_log_trace("%d: qm:%d %s,%x - slot_use->%d",
2795 + state->id, service->localport,
2796 + msg_type_str(VCHIQ_MSG_TYPE(msgid)), size,
2797 + service_quota->slot_use_count);
2800 + service_quota->previous_tx_index = tx_end_index;
2801 + VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
2802 + VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
2804 + vcos_log_info("%d: qm %s@%x,%x (%d->%d)", state->id,
2805 + msg_type_str(VCHIQ_MSG_TYPE(msgid)),
2806 + (unsigned int)header, size,
2807 + VCHIQ_MSG_SRCPORT(msgid),
2808 + VCHIQ_MSG_DSTPORT(msgid));
2811 + vcos_assert((count == 1) && (size == elements[0].size));
2812 + memcpy(header->data, elements[0].data, elements[0].size);
2814 + VCHIQ_STATS_INC(state, ctrl_tx_count);
2817 + header->msgid = msgid;
2818 + header->size = size;
2820 + if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
2824 + svc_fourcc = service
2825 + ? service->base.fourcc
2826 + : VCHIQ_MAKE_FOURCC('?','?','?','?');
2828 + vcos_log_impl( &vchiq_core_msg_log_category,
2830 + "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
2831 + msg_type_str(VCHIQ_MSG_TYPE(msgid)),
2832 + VCHIQ_MSG_TYPE(msgid),
2833 + VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
2834 + VCHIQ_MSG_SRCPORT(msgid),
2835 + VCHIQ_MSG_DSTPORT(msgid),
2839 + /* Make the new tx_pos visible to the peer. */
2840 + local->tx_pos = state->local_tx_pos;
2841 + vcos_wmb(&local->tx_pos);
2843 + if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
2844 + vcos_mutex_unlock(&state->slot_mutex);
2846 + remote_event_signal(&state->remote->trigger);
2848 + return VCHIQ_SUCCESS;
2852 +claim_slot(VCHIQ_SLOT_INFO_T *slot)
2854 + slot->use_count++;
2858 +release_slot(VCHIQ_STATE_T *state, VCHIQ_SLOT_INFO_T *slot_info)
2860 + int release_count;
2861 + vcos_mutex_lock(&state->recycle_mutex);
2863 + release_count = slot_info->release_count;
2864 + slot_info->release_count = ++release_count;
2866 + if (release_count == slot_info->use_count)
2868 + int slot_queue_recycle;
2869 + /* Add to the freed queue */
2871 + /* A read barrier is necessary here to prevent speculative fetches of
2872 + remote->slot_queue_recycle from overtaking the mutex. */
2875 + slot_queue_recycle = state->remote->slot_queue_recycle;
2876 + state->remote->slot_queue[slot_queue_recycle & VCHIQ_SLOT_QUEUE_MASK] =
2877 + SLOT_INDEX_FROM_INFO(state, slot_info);
2878 + state->remote->slot_queue_recycle = slot_queue_recycle + 1;
2879 + vcos_log_info("%d: release_slot %d - recycle->%x",
2880 + state->id, SLOT_INDEX_FROM_INFO(state, slot_info),
2881 + state->remote->slot_queue_recycle);
2883 + /* A write barrier is necessary, but remote_event_signal contains one. */
2884 + remote_event_signal(&state->remote->recycle);
2887 + vcos_mutex_unlock(&state->recycle_mutex);
2890 +/* Called by the slot handler - don't hold the bulk mutex */
2891 +static VCHIQ_STATUS_T
2892 +notify_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
2894 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
2896 + vcos_log_trace("%d: nb:%d %cx - p=%x rn=%x r=%x",
2897 + service->state->id, service->localport,
2898 + (queue == &service->bulk_tx) ? 't' : 'r',
2899 + queue->process, queue->remote_notify, queue->remove);
2901 + if (service->state->is_master)
2903 + while (queue->remote_notify != queue->process)
2905 + VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->remote_notify)];
2906 + int msgtype = (bulk->dir == VCHIQ_BULK_TRANSMIT) ?
2907 + VCHIQ_MSG_BULK_RX_DONE : VCHIQ_MSG_BULK_TX_DONE;
2908 + int msgid = VCHIQ_MAKE_MSG(msgtype, service->localport, service->remoteport);
2909 + VCHIQ_ELEMENT_T element = { &bulk->actual, 4 };
2910 + /* Only reply to non-dummy bulk requests */
2911 + if (bulk->remote_data)
2913 + status = queue_message(service->state, NULL, msgid, &element, 1, 4, 0);
2914 + if (status != VCHIQ_SUCCESS)
2917 + queue->remote_notify++;
2922 + queue->remote_notify = queue->process;
2925 + if (status == VCHIQ_SUCCESS)
2927 + while (queue->remove != queue->remote_notify)
2929 + VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->remove)];
2931 + /* Only generate callbacks for non-dummy bulk requests */
2934 + if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED)
2936 + if (bulk->dir == VCHIQ_BULK_TRANSMIT)
2938 + VCHIQ_SERVICE_STATS_INC(service, bulk_tx_count);
2939 + VCHIQ_SERVICE_STATS_ADD(service, bulk_tx_bytes, bulk->actual);
2943 + VCHIQ_SERVICE_STATS_INC(service, bulk_rx_count);
2944 + VCHIQ_SERVICE_STATS_ADD(service, bulk_rx_bytes, bulk->actual);
2949 + VCHIQ_SERVICE_STATS_INC(service, bulk_aborted_count);
2951 + if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING)
2953 + BULK_WAITER_T *waiter = (BULK_WAITER_T *)bulk->userdata;
2956 + waiter->actual = bulk->actual;
2957 + vcos_event_signal(&waiter->event);
2960 + else if (bulk->mode == VCHIQ_BULK_MODE_CALLBACK)
2962 + VCHIQ_REASON_T reason = (bulk->dir == VCHIQ_BULK_TRANSMIT) ?
2963 + ((bulk->actual == VCHIQ_BULK_ACTUAL_ABORTED) ?
2964 + VCHIQ_BULK_TRANSMIT_ABORTED : VCHIQ_BULK_TRANSMIT_DONE) :
2965 + ((bulk->actual == VCHIQ_BULK_ACTUAL_ABORTED) ?
2966 + VCHIQ_BULK_RECEIVE_ABORTED : VCHIQ_BULK_RECEIVE_DONE);
2967 + status = make_service_callback(service, reason,
2968 + NULL, bulk->userdata);
2969 + if (status == VCHIQ_RETRY)
2975 + vcos_event_signal(&service->bulk_remove_event);
2979 + if (status != VCHIQ_SUCCESS)
2980 + request_poll(service->state, service, (queue == &service->bulk_tx) ?
2981 + VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
2986 +/* Called by the slot handler thread */
2988 +poll_services(VCHIQ_STATE_T *state)
2992 + for (group = 0; group < BITSET_SIZE(state->unused_service); group++)
2995 + flags = vcos_atomic_flags_get_and_clear(&state->poll_services[group]);
2996 + for (i = 0; flags; i++)
2998 + if (flags & (1 << i))
3000 + VCHIQ_SERVICE_T *service = state->services[(group<<5) + i];
3001 + uint32_t service_flags =
3002 + vcos_atomic_flags_get_and_clear(&service->poll_flags);
3003 + if (service_flags & (1 << VCHIQ_POLL_TERMINATE))
3005 + vcos_log_info("%d: ps - terminate %d<->%d", state->id, service->localport, service->remoteport);
3006 + if (vchiq_close_service_internal(service, 0/*!close_recvd*/) != VCHIQ_SUCCESS)
3007 + request_poll(state, service, VCHIQ_POLL_TERMINATE);
3009 + if (service_flags & (1 << VCHIQ_POLL_TXNOTIFY))
3010 + notify_bulks(service, &service->bulk_tx);
3011 + if (service_flags & (1 << VCHIQ_POLL_RXNOTIFY))
3012 + notify_bulks(service, &service->bulk_rx);
3013 + flags &= ~(1 << i);
3019 +/* Called by the slot handler or application threads, holding the bulk mutex. */
3021 +resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
3023 + VCHIQ_STATE_T *state = service->state;
3026 + while ((queue->process != queue->local_insert) &&
3027 + (queue->process != queue->remote_insert))
3029 + VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
3031 + vcos_log_trace("%d: rb:%d %cx - li=%x ri=%x p=%x",
3032 + state->id, service->localport,
3033 + (queue == &service->bulk_tx) ? 't' : 'r',
3034 + queue->local_insert, queue->remote_insert,
3037 + vcos_assert((int)(queue->local_insert - queue->process) > 0);
3038 + vcos_assert((int)(queue->remote_insert - queue->process) > 0);
3039 + vchiq_transfer_bulk(bulk);
3041 + if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3043 + const char *header = (queue == &service->bulk_tx) ?
3044 + "Send Bulk to" : "Recv Bulk from";
3045 + if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED)
3046 + vcos_log_impl( &vchiq_core_msg_log_category,
3048 + "%s %c%c%c%c d:%d len:%d %x<->%x",
3050 + VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3051 + service->remoteport,
3053 + (unsigned int)bulk->data,
3054 + (unsigned int)bulk->remote_data );
3056 + vcos_log_impl( &vchiq_core_msg_log_category,
3058 + "%s %c%c%c%c d:%d ABORTED - tx len:%d, rx len:%d %x<->%x",
3060 + VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3061 + service->remoteport,
3063 + bulk->remote_size,
3064 + (unsigned int)bulk->data,
3065 + (unsigned int)bulk->remote_data );
3068 + vchiq_complete_bulk(bulk);
3075 +/* Called with the bulk_mutex held */
3077 +abort_outstanding_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
3079 + int is_tx = (queue == &service->bulk_tx);
3080 + vcos_log_trace("%d: aob:%d %cx - li=%x ri=%x p=%x",
3081 + service->state->id, service->localport, is_tx ? 't' : 'r',
3082 + queue->local_insert, queue->remote_insert, queue->process);
3084 + vcos_assert((int)(queue->local_insert - queue->process) >= 0);
3085 + vcos_assert((int)(queue->remote_insert - queue->process) >= 0);
3087 + while ((queue->process != queue->local_insert) ||
3088 + (queue->process != queue->remote_insert))
3090 + VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
3092 + if (queue->process == queue->remote_insert)
3094 + /* fabricate a matching dummy bulk */
3095 + bulk->remote_data = NULL;
3096 + bulk->remote_size = 0;
3097 + queue->remote_insert++;
3100 + if (queue->process != queue->local_insert)
3102 + vchiq_complete_bulk(bulk);
3104 + if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3106 + vcos_log_impl( &vchiq_core_msg_log_category,
3108 + "%s %c%c%c%c d:%d ABORTED - tx len:%d, rx len:%d",
3109 + is_tx ? "Send Bulk to" : "Recv Bulk from",
3110 + VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3111 + service->remoteport,
3113 + bulk->remote_size );
3118 + /* fabricate a matching dummy bulk */
3119 + bulk->data = NULL;
3121 + bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
3122 + bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
3123 + queue->local_insert++;
3131 +pause_bulks(VCHIQ_STATE_T *state)
3135 + /* Block bulk transfers from all services */
3136 + for (i = 0; i < state->unused_service; i++)
3138 + VCHIQ_SERVICE_T *service = state->services[i];
3139 + if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN))
3142 + vcos_log_trace("locking bulk_mutex for service %d", i);
3143 + vcos_mutex_lock(&service->bulk_mutex);
3148 +resume_bulks(VCHIQ_STATE_T *state)
3152 + /* Poll all services in case any bulk transfers have been
3154 + for (i = 0; i < state->unused_service; i++)
3156 + VCHIQ_SERVICE_T *service = state->services[i];
3157 + if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN))
3160 + if (resolve_bulks(service, &service->bulk_tx))
3161 + request_poll(state, service, VCHIQ_POLL_TXNOTIFY);
3162 + if (resolve_bulks(service, &service->bulk_rx))
3163 + request_poll(state, service, VCHIQ_POLL_RXNOTIFY);
3164 + vcos_log_trace("unlocking bulk_mutex for service %d", i);
3165 + vcos_mutex_unlock(&service->bulk_mutex);
3169 +/* Called by the slot handler thread */
3171 +parse_rx_slots(VCHIQ_STATE_T *state)
3173 + VCHIQ_SHARED_STATE_T *remote = state->remote;
3175 + DEBUG_INITIALISE(state->local)
3177 + tx_pos = remote->tx_pos;
3179 + while (state->rx_pos != tx_pos) {
3180 + VCHIQ_SERVICE_T *service = NULL;
3181 + VCHIQ_HEADER_T *header;
3184 + unsigned int localport, remoteport;
3186 + DEBUG_TRACE(PARSE_LINE);
3187 + if (!state->rx_data)
3190 + vcos_assert((state->rx_pos & VCHIQ_SLOT_MASK) == 0);
3191 + rx_index = remote->slot_queue[SLOT_QUEUE_INDEX_FROM_POS(state->rx_pos) & VCHIQ_SLOT_QUEUE_MASK];
3192 + state->rx_data = (char *)SLOT_DATA_FROM_INDEX(state, rx_index);
3193 + state->rx_info = SLOT_INFO_FROM_INDEX(state, rx_index);
3195 + /* Initialise use_count to one, and increment release_count at the end
3196 + of the slot to avoid releasing the slot prematurely. */
3197 + state->rx_info->use_count = 1;
3198 + state->rx_info->release_count = 0;
3201 + header = (VCHIQ_HEADER_T *)(state->rx_data + (state->rx_pos & VCHIQ_SLOT_MASK));
3202 + DEBUG_VALUE(PARSE_HEADER, (int)header);
3203 + msgid = header->msgid;
3204 + DEBUG_VALUE(PARSE_MSGID, msgid);
3205 + size = header->size;
3206 + type = VCHIQ_MSG_TYPE(msgid);
3207 + localport = VCHIQ_MSG_DSTPORT(msgid);
3208 + remoteport = VCHIQ_MSG_SRCPORT(msgid);
3210 + if (type != VCHIQ_MSG_DATA)
3212 + VCHIQ_STATS_INC(state, ctrl_rx_count);
3217 + case VCHIQ_MSG_OPENACK:
3218 + case VCHIQ_MSG_CLOSE:
3219 + case VCHIQ_MSG_DATA:
3220 + case VCHIQ_MSG_BULK_RX:
3221 + case VCHIQ_MSG_BULK_TX:
3222 + case VCHIQ_MSG_BULK_RX_DONE:
3223 + case VCHIQ_MSG_BULK_TX_DONE:
3224 + if (localport <= VCHIQ_PORT_MAX)
3226 + service = state->services[localport];
3227 + if (service && (service->srvstate == VCHIQ_SRVSTATE_FREE))
3233 + "%d: prs %s@%x (%d->%d) - invalid/closed service %d",
3234 + state->id, msg_type_str(type), (unsigned int)header,
3235 + remoteport, localport, localport);
3236 + goto skip_message;
3242 + if ( vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3246 + svc_fourcc = service
3247 + ? service->base.fourcc
3248 + : VCHIQ_MAKE_FOURCC('?','?','?','?');
3249 + vcos_log_impl( &vchiq_core_msg_log_category,
3251 + "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d len:%d",
3252 + msg_type_str(type), type,
3253 + VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
3254 + remoteport, localport, size );
3256 + vcos_log_dump_mem( &vchiq_core_msg_log_category,
3257 + "Rcvd", 0, header->data,
3258 + vcos_min( 64, size ));
3262 + if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size) > VCHIQ_SLOT_SIZE)
3264 + vcos_log_error("header %x (msgid %x) - size %x too big for slot",
3265 + (unsigned int)header, (unsigned int)msgid, (unsigned int)size);
3270 + case VCHIQ_MSG_OPEN:
3271 + vcos_assert(VCHIQ_MSG_DSTPORT(msgid) == 0);
3272 + if (vcos_verify(size == sizeof(VCHIQ_OPEN_PAYLOAD_T))) {
3273 + const VCHIQ_OPEN_PAYLOAD_T *payload = (VCHIQ_OPEN_PAYLOAD_T *)header->data;
3274 + unsigned int fourcc;
3276 + fourcc = payload->fourcc;
3277 + vcos_log_info("%d: prs OPEN@%x (%d->'%c%c%c%c')",
3278 + state->id, (unsigned int)header,
3280 + VCHIQ_FOURCC_AS_4CHARS(fourcc));
3282 + service = get_listening_service(state, fourcc);
3286 + /* A matching service exists */
3287 + short version = payload->version;
3288 + short version_min = payload->version_min;
3289 + if ((service->version < version_min) ||
3290 + (version < service->version_min))
3292 + /* Version mismatch */
3293 + vcos_log_error("%d: service %d (%c%c%c%c) version mismatch -"
3294 + " local (%d, min %d) vs. remote (%d, min %d)",
3295 + state->id, service->localport,
3296 + VCHIQ_FOURCC_AS_4CHARS(fourcc),
3297 + service->version, service->version_min,
3298 + version, version_min);
3301 + if (service->srvstate == VCHIQ_SRVSTATE_LISTENING)
3303 + /* Acknowledge the OPEN */
3304 + if (queue_message(state, NULL,
3305 + VCHIQ_MAKE_MSG(VCHIQ_MSG_OPENACK, service->localport, remoteport),
3306 + NULL, 0, 0, 0) == VCHIQ_RETRY)
3307 + return; /* Bail out if not ready */
3309 + /* The service is now open */
3310 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_OPEN);
3313 + service->remoteport = remoteport;
3314 + service->client_id = ((int *)header->data)[1];
3315 + if (make_service_callback(service, VCHIQ_SERVICE_OPENED,
3316 + NULL, NULL) == VCHIQ_RETRY)
3318 + /* Bail out if not ready */
3319 + service->remoteport = VCHIQ_PORT_FREE;
3323 + /* Break out, and skip the failure handling */
3328 + /* No available service, or an invalid request - send a CLOSE */
3329 + if (queue_message(state, NULL,
3330 + VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE, 0, VCHIQ_MSG_SRCPORT(msgid)),
3331 + NULL, 0, 0, 0) == VCHIQ_RETRY)
3332 + return; /* Bail out if not ready */
3334 + case VCHIQ_MSG_OPENACK:
3336 + vcos_log_info("%d: prs OPENACK@%x (%d->%d)",
3337 + state->id, (unsigned int)header,
3338 + remoteport, localport);
3339 + if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
3340 + service->remoteport = remoteport;
3341 + vchiq_set_service_state(service,
3342 + VCHIQ_SRVSTATE_OPEN);
3343 + vcos_event_signal(&service->remove_event);
3347 + case VCHIQ_MSG_CLOSE:
3349 + vcos_assert(size == 0); /* There should be no data */
3351 + vcos_log_info("%d: prs CLOSE@%x (%d->%d)",
3352 + state->id, (unsigned int)header,
3353 + remoteport, localport);
3355 + if ((service->remoteport != remoteport) &&
3356 + VCHIQ_PORT_IS_VALID(service->remoteport)) {
3357 + /* This could be from a client which hadn't yet received
3358 + the OPENACK - look for the connected service */
3359 + service = get_connected_service(state, remoteport);
3364 + if (vchiq_close_service_internal(service,
3365 + 1/*close_recvd*/) == VCHIQ_RETRY)
3366 + return; /* Bail out if not ready */
3368 + if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3370 + vcos_log_impl( &vchiq_core_msg_log_category,
3372 + "Close Service %c%c%c%c s:%u d:%d",
3373 + VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3374 + service->localport,
3375 + service->remoteport );
3379 + case VCHIQ_MSG_DATA:
3381 + vcos_log_trace("%d: prs DATA@%x,%x (%d->%d)",
3382 + state->id, (unsigned int)header, size,
3383 + remoteport, localport);
3385 + if ((service->remoteport == remoteport)
3386 + && (service->srvstate ==
3387 + VCHIQ_SRVSTATE_OPEN)) {
3388 + header->msgid = msgid | VCHIQ_MSGID_CLAIMED;
3389 + claim_slot(state->rx_info);
3390 + DEBUG_TRACE(PARSE_LINE);
3391 + if (make_service_callback(service,
3392 + VCHIQ_MESSAGE_AVAILABLE, header,
3393 + NULL) == VCHIQ_RETRY)
3395 + DEBUG_TRACE(PARSE_LINE);
3396 + return; /* Bail out if not ready */
3398 + VCHIQ_SERVICE_STATS_INC(service, ctrl_rx_count);
3399 + VCHIQ_SERVICE_STATS_ADD(service, ctrl_rx_bytes, size);
3403 + VCHIQ_STATS_INC(state, error_count);
3407 + case VCHIQ_MSG_CONNECT:
3408 + vcos_log_info("%d: prs CONNECT@%x",
3409 + state->id, (unsigned int)header);
3410 + vcos_event_signal(&state->connect);
3412 + case VCHIQ_MSG_BULK_RX:
3413 + case VCHIQ_MSG_BULK_TX:
3415 + VCHIQ_BULK_QUEUE_T *queue;
3416 + vcos_assert(state->is_master);
3417 + queue = (type == VCHIQ_MSG_BULK_RX) ?
3418 + &service->bulk_tx : &service->bulk_rx;
3419 + if ((service->remoteport == remoteport)
3420 + && (service->srvstate ==
3421 + VCHIQ_SRVSTATE_OPEN))
3423 + VCHIQ_BULK_T *bulk;
3426 + vcos_assert(queue->remote_insert < queue->remove +
3427 + VCHIQ_NUM_SERVICE_BULKS);
3428 + bulk = &queue->bulks[BULK_INDEX(queue->remote_insert)];
3429 + bulk->remote_data = (void *)((int *)header->data)[0];
3430 + bulk->remote_size = ((int *)header->data)[1];
3432 + vcos_log_info("%d: prs %s@%x (%d->%d) %x@%x",
3433 + state->id, msg_type_str(type),
3434 + (unsigned int)header,
3435 + remoteport, localport,
3436 + bulk->remote_size,
3437 + (unsigned int)bulk->remote_data);
3439 + queue->remote_insert++;
3441 + if (state->conn_state != VCHIQ_CONNSTATE_CONNECTED)
3444 + DEBUG_TRACE(PARSE_LINE);
3445 + if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
3447 + DEBUG_TRACE(PARSE_LINE);
3450 + DEBUG_TRACE(PARSE_LINE);
3451 + resolved = resolve_bulks(service, queue);
3452 + vcos_mutex_unlock(&service->bulk_mutex);
3454 + notify_bulks(service, queue);
3458 + case VCHIQ_MSG_BULK_RX_DONE:
3459 + case VCHIQ_MSG_BULK_TX_DONE:
3461 + vcos_assert(!state->is_master);
3462 + if ((service->remoteport == remoteport)
3463 + && (service->srvstate !=
3464 + VCHIQ_SRVSTATE_FREE)) {
3465 + VCHIQ_BULK_QUEUE_T *queue;
3466 + VCHIQ_BULK_T *bulk;
3468 + queue = (type == VCHIQ_MSG_BULK_RX_DONE) ?
3469 + &service->bulk_rx : &service->bulk_tx;
3471 + bulk = &queue->bulks[BULK_INDEX(queue->process)];
3472 + bulk->actual = *(int *)header->data;
3474 + vcos_log_info("%d: prs %s@%x (%d->%d) %x@%x",
3475 + state->id, msg_type_str(type),
3476 + (unsigned int)header,
3477 + remoteport, localport,
3478 + bulk->actual, (unsigned int)bulk->data);
3480 + vcos_log_trace("%d: prs:%d %cx li=%x ri=%x p=%x",
3481 + state->id, localport,
3482 + (type == VCHIQ_MSG_BULK_RX_DONE) ? 'r' : 't',
3483 + queue->local_insert,
3484 + queue->remote_insert, queue->process);
3486 + DEBUG_TRACE(PARSE_LINE);
3487 + if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
3489 + DEBUG_TRACE(PARSE_LINE);
3492 + DEBUG_TRACE(PARSE_LINE);
3493 + vcos_assert(queue->process != queue->local_insert);
3494 + vchiq_complete_bulk(bulk);
3496 + vcos_mutex_unlock(&service->bulk_mutex);
3497 + DEBUG_TRACE(PARSE_LINE);
3498 + notify_bulks(service, queue);
3499 + DEBUG_TRACE(PARSE_LINE);
3503 + case VCHIQ_MSG_PADDING:
3504 + vcos_log_trace("%d: prs PADDING@%x,%x",
3505 + state->id, (unsigned int)header, size);
3507 + case VCHIQ_MSG_PAUSE:
3508 + /* If initiated, signal the application thread */
3509 + vcos_log_trace("%d: prs PAUSE@%x,%x",
3510 + state->id, (unsigned int)header, size);
3511 + if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT)
3513 + /* Send a PAUSE in response */
3514 + if (queue_message(state, NULL,
3515 + VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
3516 + NULL, 0, 0, 0) == VCHIQ_RETRY)
3517 + return; /* Bail out if not ready */
3518 + if (state->is_master)
3519 + pause_bulks(state);
3521 + /* At this point slot_mutex is held */
3522 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
3523 + vchiq_platform_paused(state);
3525 + case VCHIQ_MSG_RESUME:
3526 + vcos_log_trace("%d: prs RESUME@%x,%x",
3527 + state->id, (unsigned int)header, size);
3528 + /* Release the slot mutex */
3529 + vcos_mutex_unlock(&state->slot_mutex);
3530 + if (state->is_master)
3531 + resume_bulks(state);
3532 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
3533 + vchiq_platform_resumed(state);
3536 + vcos_log_error("%d: prs invalid msgid %x@%x,%x",
3537 + state->id, msgid, (unsigned int)header, size);
3543 + state->rx_pos += calc_stride(size);
3545 + DEBUG_TRACE(PARSE_LINE);
3546 + /* Perform some housekeeping when the end of the slot is reached. */
3547 + if ((state->rx_pos & VCHIQ_SLOT_MASK) == 0)
3549 + /* Remove the extra reference count. */
3550 + release_slot(state, state->rx_info);
3551 + state->rx_data = NULL;
3556 +/* Called by the slot handler thread */
3558 +slot_handler_func(void *v)
3560 + VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
3561 + VCHIQ_SHARED_STATE_T *local = state->local;
3562 + DEBUG_INITIALISE(local)
3565 + DEBUG_COUNT(SLOT_HANDLER_COUNT);
3566 + DEBUG_TRACE(SLOT_HANDLER_LINE);
3567 + remote_event_wait(&local->trigger);
3571 + DEBUG_TRACE(SLOT_HANDLER_LINE);
3572 + if (state->poll_needed)
3574 + state->poll_needed = 0;
3576 + /* Handle service polling and other rare conditions here out
3577 + of the mainline code */
3578 + switch (state->conn_state)
3580 + case VCHIQ_CONNSTATE_CONNECTED:
3581 + /* Poll the services as requested */
3582 + poll_services(state);
3585 + case VCHIQ_CONNSTATE_PAUSING:
3586 + if (queue_message(state, NULL,
3587 + VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), NULL, 0, 0, 0)
3590 + if (state->is_master)
3591 + pause_bulks(state);
3592 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSE_SENT);
3596 + state->poll_needed = 1; /* Retry later */
3600 + case VCHIQ_CONNSTATE_RESUMING:
3601 + if (queue_message(state, NULL,
3602 + VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0), NULL, 0, 0, 0)
3605 + if (state->is_master)
3606 + resume_bulks(state);
3607 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
3608 + vchiq_platform_resumed(state);
3612 + /* This should really be impossible, since the PAUSE should
3613 + have flushed through outstanding messages. */
3614 + vcos_log_error("Failed to send RESUME message");
3623 + DEBUG_TRACE(SLOT_HANDLER_LINE);
3624 + parse_rx_slots(state);
3629 +extern VCHIQ_STATUS_T
3630 +vchiq_platform_suspend(VCHIQ_STATE_T *state);
3632 +/* Called by the recycle thread */
3634 +recycle_func(void *v)
3636 + VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
3637 + VCHIQ_SHARED_STATE_T *local = state->local;
3640 + remote_event_wait(&local->recycle);
3642 + vcos_mutex_lock(&state->slot_mutex);
3644 + process_free_queue(state);
3646 + vcos_mutex_unlock(&state->slot_mutex);
3651 +/* Called by the lp thread */
3655 + VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
3658 + vcos_event_wait(&state->lp_evt);
3659 + vcos_mutex_lock(&state->use_count_mutex);
3660 + if (state->videocore_use_count == 0)
3662 + vchiq_platform_suspend(state);
3664 + vcos_mutex_unlock(&state->use_count_mutex);
3670 +init_bulk_queue(VCHIQ_BULK_QUEUE_T *queue)
3672 + queue->local_insert = 0;
3673 + queue->remote_insert = 0;
3674 + queue->process = 0;
3675 + queue->remote_notify = 0;
3676 + queue->remove = 0;
3679 +VCHIQ_SLOT_ZERO_T *
3680 +vchiq_init_slots(void *mem_base, int mem_size)
3682 + int mem_align = (VCHIQ_SLOT_SIZE - (int)mem_base) & VCHIQ_SLOT_MASK;
3683 + VCHIQ_SLOT_ZERO_T *slot_zero = (VCHIQ_SLOT_ZERO_T *)((char *)mem_base + mem_align);
3684 + int num_slots = (mem_size - mem_align)/VCHIQ_SLOT_SIZE;
3685 + int first_data_slot = VCHIQ_SLOT_ZERO_SLOTS;
3687 + /* Ensure there is enough memory to run an absolutely minimum system */
3688 + num_slots -= first_data_slot;
3690 + if (num_slots < 4)
3692 + vcos_log_error("vchiq_init_slots - insufficient memory %x bytes", mem_size);
3696 + memset(slot_zero, 0, sizeof(VCHIQ_SLOT_ZERO_T));
3698 + slot_zero->magic = VCHIQ_MAGIC;
3699 + slot_zero->version = VCHIQ_VERSION;
3700 + slot_zero->version_min = VCHIQ_VERSION_MIN;
3701 + slot_zero->slot_zero_size = sizeof(VCHIQ_SLOT_ZERO_T);
3702 + slot_zero->slot_size = VCHIQ_SLOT_SIZE;
3703 + slot_zero->max_slots = VCHIQ_MAX_SLOTS;
3704 + slot_zero->max_slots_per_side = VCHIQ_MAX_SLOTS_PER_SIDE;
3706 + slot_zero->master.slot_first = first_data_slot;
3707 + slot_zero->slave.slot_first = first_data_slot + (num_slots/2);
3708 + slot_zero->master.slot_last = slot_zero->slave.slot_first - 1;
3709 + slot_zero->slave.slot_last = first_data_slot + num_slots - 1;
3715 +vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, int is_master)
3717 + VCHIQ_SHARED_STATE_T *local;
3718 + VCHIQ_SHARED_STATE_T *remote;
3719 + VCOS_THREAD_ATTR_T attrs;
3720 + char threadname[10];
3721 + static int id = 0;
3724 + vcos_log_set_level(&vchiq_core_log_category, vchiq_default_core_log_level);
3725 + vcos_log_set_level(&vchiq_core_msg_log_category, vchiq_default_core_msg_log_level);
3726 + vcos_log_register("vchiq_core", &vchiq_core_log_category);
3727 + vcos_log_register("vchiq_core_msg", &vchiq_core_msg_log_category);
3729 + vcos_log_warn( "%s: slot_zero = 0x%08lx, is_master = %d\n", __func__, (unsigned long)slot_zero, is_master );
3731 + /* Check the input configuration */
3733 + if (slot_zero->magic != VCHIQ_MAGIC)
3735 + vcos_log_error("slot_zero=%x: magic=%x (expected %x)",
3736 + (unsigned int)slot_zero, slot_zero->magic, VCHIQ_MAGIC);
3737 + return VCHIQ_ERROR;
3740 + if (slot_zero->version < VCHIQ_VERSION_MIN)
3742 + vcos_log_error("slot_zero=%x: peer_version=%x (minimum %x)",
3743 + (unsigned int)slot_zero, slot_zero->version, VCHIQ_VERSION_MIN);
3744 + return VCHIQ_ERROR;
3747 + if (VCHIQ_VERSION < slot_zero->version_min)
3749 + vcos_log_error("slot_zero=%x: version=%x (peer minimum %x)",
3750 + (unsigned int)slot_zero, VCHIQ_VERSION, slot_zero->version_min);
3751 + return VCHIQ_ERROR;
3754 + if (slot_zero->slot_zero_size != sizeof(VCHIQ_SLOT_ZERO_T))
3756 + vcos_log_error("slot_zero=%x: slot_zero_size=%x (expected %x)",
3757 + (unsigned int)slot_zero, slot_zero->slot_zero_size, sizeof(VCHIQ_SLOT_ZERO_T));
3758 + return VCHIQ_ERROR;
3761 + if (slot_zero->slot_size != VCHIQ_SLOT_SIZE)
3763 + vcos_log_error("slot_zero=%x: slot_size=%d (expected %d",
3764 + (unsigned int)slot_zero, slot_zero->slot_size, VCHIQ_SLOT_SIZE);
3765 + return VCHIQ_ERROR;
3768 + if (slot_zero->max_slots != VCHIQ_MAX_SLOTS)
3770 + vcos_log_error("slot_zero=%x: max_slots=%d (expected %d)",
3771 + (unsigned int)slot_zero, slot_zero->max_slots, VCHIQ_MAX_SLOTS);
3772 + return VCHIQ_ERROR;
3775 + if (slot_zero->max_slots_per_side != VCHIQ_MAX_SLOTS_PER_SIDE)
3777 + vcos_log_error("slot_zero=%x: max_slots_per_side=%d (expected %d)",
3778 + (unsigned int)slot_zero, slot_zero->max_slots_per_side,
3779 + VCHIQ_MAX_SLOTS_PER_SIDE);
3780 + return VCHIQ_ERROR;
3785 + local = &slot_zero->master;
3786 + remote = &slot_zero->slave;
3790 + local = &slot_zero->slave;
3791 + remote = &slot_zero->master;
3794 + if (local->initialised)
3796 + if (remote->initialised)
3797 + vcos_log_error("vchiq: FATAL: local state has already been initialised");
3799 + vcos_log_error("vchiq: FATAL: master/slave mismatch - two %ss", is_master ? "master" : "slave");
3800 + return VCHIQ_ERROR;
3803 + memset(state, 0, sizeof(VCHIQ_STATE_T));
3805 + state->is_master = is_master;
3808 + initialize shared state pointers
3811 + state->local = local;
3812 + state->remote = remote;
3813 + state->slot_data = (VCHIQ_SLOT_T *)slot_zero;
3816 + initialize events and mutexes
3819 + vcos_event_create(&state->connect, "v.connect");
3820 + vcos_mutex_create(&state->mutex, "v.mutex");
3821 + vcos_event_create(&state->trigger_event, "v.trigger_event");
3822 + vcos_event_create(&state->recycle_event, "v.recycle_event");
3824 + vcos_mutex_create(&state->slot_mutex, "v.slot_mutex");
3825 + vcos_mutex_create(&state->recycle_mutex, "v.recycle_mutex");
3826 + vcos_mutex_create(&state->use_count_mutex, "v.use_count_mutex");
3827 + vcos_mutex_create(&state->suspend_resume_mutex, "v.susp_res_mutex");
3829 + vcos_event_create(&state->slot_available_event, "v.slot_available_event");
3830 + vcos_event_create(&state->slot_remove_event, "v.slot_remove_event");
3832 + state->slot_queue_available = 0;
3834 + for (i = 0; i < VCHIQ_MAX_SERVICES; i++)
3836 + VCHIQ_SERVICE_QUOTA_T *service_quota = &state->service_quotas[i];
3837 + vcos_event_create(&service_quota->quota_event, "v.quota_event");
3840 + for (i = local->slot_first; i <= local->slot_last; i++)
3842 + local->slot_queue[state->slot_queue_available++] = i;
3845 + state->default_slot_quota = state->slot_queue_available/2;
3847 + local->trigger.event = &state->trigger_event;
3848 + remote_event_create(&local->trigger);
3849 + local->tx_pos = 0;
3851 + local->recycle.event = &state->recycle_event;
3852 + remote_event_create(&local->recycle);
3853 + local->slot_queue_recycle = state->slot_queue_available;
3855 + vcos_event_create(&state->lp_evt, "LP_EVT");
3857 + local->debug[DEBUG_ENTRIES] = DEBUG_MAX;
3860 + bring up slot handler thread
3863 + vcos_thread_attr_init(&attrs);
3864 + vcos_thread_attr_setstacksize(&attrs, VCHIQ_SLOT_HANDLER_STACK);
3865 + vcos_thread_attr_setpriority(&attrs, VCOS_THREAD_PRI_REALTIME);
3866 + vcos_snprintf(threadname, sizeof(threadname), "VCHIQ-%d", state->id);
3867 + if (vcos_thread_create(&state->slot_handler_thread, threadname,
3868 + &attrs, slot_handler_func, state) != VCOS_SUCCESS)
3869 + return VCHIQ_ERROR;
3871 + vcos_thread_attr_init(&attrs);
3872 + vcos_thread_attr_setstacksize(&attrs, VCHIQ_SLOT_HANDLER_STACK);
3873 + vcos_thread_attr_setpriority(&attrs, VCOS_THREAD_PRI_REALTIME);
3874 + vcos_snprintf(threadname, sizeof(threadname), "VCHIQr-%d", state->id);
3875 + if (vcos_thread_create(&state->recycle_thread, threadname,
3876 + &attrs, recycle_func, state) != VCOS_SUCCESS)
3877 + return VCHIQ_ERROR;
3879 + vcos_thread_attr_init(&attrs);
3880 + vcos_thread_attr_setstacksize(&attrs, VCHIQ_SLOT_HANDLER_STACK);
3881 + vcos_thread_attr_setpriority(&attrs, VCOS_THREAD_PRI_LOWEST);
3882 + vcos_snprintf(threadname, sizeof(threadname), "VCHIQl-%d", state->id);
3883 + if (vcos_thread_create(&state->lp_thread, threadname,
3884 + &attrs, lp_func, state) != VCOS_SUCCESS)
3885 + return VCHIQ_ERROR;
3887 + /* Indicate readiness to the other side */
3888 + local->initialised = 1;
3890 + return VCHIQ_SUCCESS;
3893 +/* Called from application thread when a client or server service is created. */
3895 +vchiq_add_service_internal(VCHIQ_STATE_T *state,
3896 + const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
3897 + VCHIQ_INSTANCE_T instance)
3899 + VCHIQ_SERVICE_T **pservice = NULL;
3900 + VCHIQ_SERVICE_T *service = NULL;
3903 + /* Prepare to use a previously unused service */
3904 + if (state->unused_service < VCHIQ_MAX_SERVICES)
3906 + pservice = &state->services[state->unused_service];
3909 + if (srvstate == VCHIQ_SRVSTATE_OPENING) {
3910 + for (i = 0; i < state->unused_service; i++) {
3911 + VCHIQ_SERVICE_T *srv = state->services[i];
3914 + pservice = &state->services[i];
3917 + if (srv->srvstate == VCHIQ_SRVSTATE_FREE) {
3923 + for (i = (state->unused_service - 1); i >= 0; i--) {
3924 + VCHIQ_SERVICE_T *srv = state->services[i];
3926 + pservice = &state->services[i];
3927 + else if (srv->srvstate == VCHIQ_SRVSTATE_FREE) {
3929 + } else if ((srv->public_fourcc == params->fourcc) &&
3930 + ((srv->instance != instance)
3931 + || (srv->base.callback != params->callback))) {
3932 + /* There is another server using this fourcc which doesn't match */
3939 + if (pservice && !service)
3941 + service = vcos_malloc(sizeof(VCHIQ_SERVICE_T), "VCHIQ service");
3944 + service->srvstate = VCHIQ_SRVSTATE_FREE;
3945 + service->localport = (pservice - state->services);
3946 + vcos_event_create(&service->remove_event, "v.remove_event");
3947 + vcos_event_create(&service->bulk_remove_event, "v.bulk_remove_event");
3948 + vcos_mutex_create(&service->bulk_mutex, "v.bulk_mutex");
3949 + *pservice = service;
3953 + vcos_log_error("vchiq: Out of memory");
3958 + VCHIQ_SERVICE_QUOTA_T *service_quota =
3959 + &state->service_quotas[service->localport];
3960 + if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO)) {
3961 + vcos_log_impl( &vchiq_core_msg_log_category,
3963 + "%s Service %c%c%c%c SrcPort:%d",
3964 + ( srvstate == VCHIQ_SRVSTATE_OPENING )
3966 + VCHIQ_FOURCC_AS_4CHARS(params->fourcc),
3967 + service->localport );
3969 + service->state = state;
3970 + service->base.fourcc = params->fourcc;
3971 + service->base.callback = params->callback;
3972 + service->base.userdata = params->userdata;
3973 + service->version = params->version;
3974 + service->version_min = params->version_min;
3975 + vchiq_set_service_state(service, srvstate);
3976 + service->public_fourcc =
3978 + VCHIQ_SRVSTATE_OPENING) ? VCHIQ_FOURCC_INVALID : params->fourcc;
3979 + service->instance = instance;
3980 + service->remoteport = VCHIQ_PORT_FREE;
3981 + service->client_id = 0;
3982 + service->auto_close = 1;
3983 + service->service_use_count = 0;
3984 + init_bulk_queue(&service->bulk_tx);
3985 + init_bulk_queue(&service->bulk_rx);
3986 + service_quota->slot_quota = state->default_slot_quota;
3987 + if (service_quota->slot_use_count == 0)
3988 + service_quota->previous_tx_index =
3989 + SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos) - 1;
3990 + memset(&service->stats, 0, sizeof(service->stats));
3991 + vcos_atomic_flags_create(&service->poll_flags);
3993 + /* Ensure the events are unsignalled */
3994 + while (vcos_event_try(&service->remove_event) == VCOS_SUCCESS)
3996 + while (vcos_event_try(&service_quota->quota_event) == VCOS_SUCCESS)
3999 + if (pservice == &state->services[state->unused_service])
4000 + state->unused_service++;
4007 +vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id)
4009 + VCHIQ_OPEN_PAYLOAD_T payload = {
4010 + service->base.fourcc,
4013 + service->version_min
4015 + VCHIQ_ELEMENT_T body = { &payload, sizeof(payload) };
4016 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4018 + service->client_id = client_id;
4019 + vchiq_use_service(&service->base);
4020 + status = queue_message(service->state, NULL,
4021 + VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0),
4022 + &body, 1, sizeof(payload), 1);
4023 + if (status == VCHIQ_SUCCESS) {
4024 + if (vcos_event_wait(&service->remove_event) != VCOS_SUCCESS) {
4025 + status = VCHIQ_RETRY;
4026 + vchiq_release_service(&service->base);
4027 + } else if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
4028 + vcos_log_info("%d: osi - srvstate = %d", service->state->id, service->srvstate);
4029 + vcos_assert(service->srvstate == VCHIQ_SRVSTATE_CLOSEWAIT);
4030 + status = VCHIQ_ERROR;
4031 + VCHIQ_SERVICE_STATS_INC(service, error_count);
4032 + vchiq_release_service(&service->base);
4038 +/* Called by the slot handler */
4040 +vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd)
4042 + VCHIQ_STATE_T *state = service->state;
4043 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4045 + vcos_log_trace("%d: csi:%d (%s)",
4046 + service->state->id, service->localport,
4047 + srvstate_names[service->srvstate]);
4049 + switch (service->srvstate)
4051 + case VCHIQ_SRVSTATE_OPENING:
4054 + /* The open was rejected - tell the user */
4055 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSEWAIT);
4056 + vcos_event_signal(&service->remove_event);
4060 + /* Shutdown mid-open - let the other side know */
4061 + status = queue_message(state, NULL,
4064 + service->localport,
4065 + VCHIQ_MSG_DSTPORT(service->remoteport)),
4068 + if (status == VCHIQ_SUCCESS)
4069 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
4073 + case VCHIQ_SRVSTATE_OPEN:
4074 + if (state->is_master)
4076 + /* Abort any outstanding bulk transfers */
4077 + vcos_mutex_lock(&service->bulk_mutex);
4078 + abort_outstanding_bulks(service, &service->bulk_tx);
4079 + abort_outstanding_bulks(service, &service->bulk_rx);
4080 + status = notify_bulks(service, &service->bulk_tx);
4081 + if (status == VCHIQ_SUCCESS)
4082 + status = notify_bulks(service, &service->bulk_rx);
4083 + vcos_mutex_unlock(&service->bulk_mutex);
4086 + if (status == VCHIQ_SUCCESS)
4087 + status = queue_message(state, NULL,
4090 + service->localport,
4091 + VCHIQ_MSG_DSTPORT(service->remoteport)),
4094 + if (status == VCHIQ_SUCCESS)
4097 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSING);
4099 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
4103 + case VCHIQ_SRVSTATE_CLOSESENT:
4104 + vcos_assert(close_recvd);
4106 + if (!state->is_master)
4108 + /* Abort any outstanding bulk transfers */
4109 + vcos_mutex_lock(&service->bulk_mutex);
4110 + abort_outstanding_bulks(service, &service->bulk_tx);
4111 + abort_outstanding_bulks(service, &service->bulk_rx);
4112 + status = notify_bulks(service, &service->bulk_tx);
4113 + if (status == VCHIQ_SUCCESS)
4114 + status = notify_bulks(service, &service->bulk_rx);
4115 + vcos_mutex_unlock(&service->bulk_mutex);
4118 + if (status == VCHIQ_SUCCESS)
4119 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSING);
4122 + case VCHIQ_SRVSTATE_CLOSING:
4123 + /* We may come here after a retry */
4124 + vcos_assert(!close_recvd);
4128 + vcos_log_error("vchiq_close_service_internal(%d) called in state %s",
4129 + close_recvd, srvstate_names[service->srvstate]);
4134 + if (service->srvstate == VCHIQ_SRVSTATE_CLOSING)
4136 + /* Complete the close process */
4137 + vchiq_release_service(&service->base);
4139 + service->client_id = 0;
4141 + /* Now tell the client that the services is closed */
4142 + if (service->instance)
4144 + int oldstate = service->srvstate;
4146 + /* Change the service state now for the benefit of the callback */
4147 + vchiq_set_service_state(service,
4148 + ((service->public_fourcc == VCHIQ_FOURCC_INVALID) ||
4149 + !service->auto_close) ?
4150 + VCHIQ_SRVSTATE_CLOSEWAIT :
4151 + VCHIQ_SRVSTATE_LISTENING);
4153 + status = make_service_callback(service, VCHIQ_SERVICE_CLOSED, NULL, NULL);
4155 + if (status == VCHIQ_RETRY)
4157 + /* Restore the old state, to be retried later */
4158 + vchiq_set_service_state(service, oldstate);
4162 + if (status == VCHIQ_ERROR) {
4163 + /* Signal an error (fatal, since the other end will probably have closed) */
4164 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_OPEN);
4169 + if (status != VCHIQ_RETRY)
4171 + if (service->srvstate == VCHIQ_SRVSTATE_CLOSING)
4172 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSEWAIT);
4173 + vcos_event_signal(&service->remove_event);
4180 +/* Called from the application process upon process death */
4182 +vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service)
4184 + VCHIQ_STATE_T *state = service->state;
4186 + vcos_log_info("%d: tsi - (%d<->%d)", state->id, service->localport, service->remoteport);
4188 + /* Disconnect from the instance, to prevent any callbacks */
4189 + service->instance = NULL;
4191 + /* Mark the service for termination by the slot handler */
4192 + request_poll(state, service, VCHIQ_POLL_TERMINATE);
4195 +/* Called from the application process upon process death, and from
4196 + vchiq_remove_service */
4198 +vchiq_free_service_internal(VCHIQ_SERVICE_T *service)
4200 + VCHIQ_STATE_T *state = service->state;
4201 + int slot_last = state->remote->slot_last;
4204 + vcos_log_info("%d: fsi - (%d)", state->id, service->localport);
4206 + vcos_mutex_lock(&state->mutex);
4208 + /* Release any claimed messages */
4209 + for (i = state->remote->slot_first; i <= slot_last; i++)
4211 + VCHIQ_SLOT_INFO_T *slot_info = SLOT_INFO_FROM_INDEX(state, i);
4212 + if (slot_info->release_count != slot_info->use_count)
4214 + char *data = (char *)SLOT_DATA_FROM_INDEX(state, i);
4217 + end = VCHIQ_SLOT_SIZE;
4218 + if (data == state->rx_data)
4220 + /* This buffer is still being read from - stop at the current read position */
4221 + end = state->rx_pos & VCHIQ_SLOT_MASK;
4228 + VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)(data + pos);
4229 + int msgid = header->msgid;
4230 + int port = VCHIQ_MSG_DSTPORT(msgid);
4231 + if (port == service->localport)
4233 + if (msgid & VCHIQ_MSGID_CLAIMED)
4235 + header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
4236 + vcos_log_info(" fsi - hdr %x", (unsigned int)header);
4237 + release_slot(state, slot_info);
4240 + pos += calc_stride(header->size);
4245 + vcos_assert(state->services[service->localport] == service);
4246 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_FREE);
4247 + state->services[service->localport] = NULL;
4248 + vcos_free(service);
4249 + vcos_mutex_unlock(&state->mutex);
4253 +vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
4257 + /* Find all services registered to this client and enable them. */
4258 + for (i = 0; i < state->unused_service; i++)
4260 + VCHIQ_SERVICE_T *service = state->services[i];
4261 + if (service && (service->instance == instance)) {
4262 + if (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)
4263 + vchiq_set_service_state(service,
4264 + VCHIQ_SRVSTATE_LISTENING);
4268 + if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) {
4269 + if (queue_message(state, NULL,
4270 + VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0,
4271 + 0, 1) == VCHIQ_RETRY)
4272 + return VCHIQ_RETRY;
4273 + vcos_event_wait(&state->connect);
4275 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
4278 + return VCHIQ_SUCCESS;
4282 +vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
4284 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4287 + /* Find all services registered to this client and close them. */
4288 + for (i = 0; i < state->unused_service; i++)
4290 + VCHIQ_SERVICE_T *service = state->services[i];
4291 + if (service && (service->instance == instance) &&
4292 + ((service->srvstate == VCHIQ_SRVSTATE_OPEN) ||
4293 + (service->srvstate == VCHIQ_SRVSTATE_LISTENING)))
4295 + status = vchiq_remove_service(&service->base);
4296 + if (status != VCHIQ_SUCCESS)
4305 +vchiq_pause_internal(VCHIQ_STATE_T *state)
4307 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4309 + switch (state->conn_state)
4311 + case VCHIQ_CONNSTATE_CONNECTED:
4312 + /* Request a pause */
4313 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSING);
4314 + request_poll(state, NULL, 0);
4316 + case VCHIQ_CONNSTATE_PAUSED:
4319 + status = VCHIQ_ERROR;
4320 + VCHIQ_STATS_INC(state, error_count);
4328 +vchiq_resume_internal(VCHIQ_STATE_T *state)
4330 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4332 + if (state->conn_state == VCHIQ_CONNSTATE_PAUSED)
4334 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_RESUMING);
4335 + request_poll(state, NULL, 0);
4339 + status = VCHIQ_ERROR;
4340 + VCHIQ_STATS_INC(state, error_count);
4347 +vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
4349 + /* Unregister the service */
4350 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *) handle;
4351 + VCHIQ_STATUS_T status = VCHIQ_ERROR;
4353 + if (service == NULL)
4354 + return VCHIQ_ERROR;
4356 + vcos_log_info("%d: close_service:%d", service->state->id, service->localport);
4358 + if (service->public_fourcc != VCHIQ_FOURCC_INVALID)
4360 + if (service->srvstate == VCHIQ_SRVSTATE_CLOSEWAIT)
4362 + /* This is a non-auto-close server */
4363 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_LISTENING);
4364 + status = VCHIQ_SUCCESS;
4369 + /* For clients, make it an alias of vchiq_remove_service */
4370 + status = vchiq_remove_service(handle);
4377 +vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
4379 + /* Unregister the service */
4380 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *) handle;
4381 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4383 + if (service == NULL)
4384 + return VCHIQ_ERROR;
4386 + vcos_log_info("%d: remove_service:%d", service->state->id, service->localport);
4388 + switch (service->srvstate)
4390 + case VCHIQ_SRVSTATE_OPENING:
4391 + case VCHIQ_SRVSTATE_OPEN:
4392 + /* Mark the service for termination by the slot handler */
4393 + request_poll(service->state, service, VCHIQ_POLL_TERMINATE);
4395 + /* Drop through... */
4396 + case VCHIQ_SRVSTATE_CLOSESENT:
4397 + case VCHIQ_SRVSTATE_CLOSING:
4398 + while ((service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) &&
4399 + (service->srvstate != VCHIQ_SRVSTATE_LISTENING))
4401 + if (vcos_event_wait(&service->remove_event) != VCOS_SUCCESS) {
4402 + status = VCHIQ_RETRY;
4412 + if (status == VCHIQ_SUCCESS) {
4413 + if (service->srvstate == VCHIQ_SRVSTATE_OPEN)
4414 + status = VCHIQ_ERROR;
4417 + service->instance = NULL;
4418 + vchiq_free_service_internal(service);
4427 +vchiq_bulk_transfer(VCHIQ_SERVICE_T *service,
4428 + VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
4429 + VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir)
4431 + VCHIQ_BULK_QUEUE_T *queue = (dir == VCHIQ_BULK_TRANSMIT) ?
4432 + &service->bulk_tx : &service->bulk_rx;
4433 + VCHIQ_BULK_T *bulk;
4434 + VCHIQ_STATE_T *state;
4435 + BULK_WAITER_T bulk_waiter;
4436 + const char dir_char = (dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r';
4437 + const int dir_msgtype = (dir == VCHIQ_BULK_TRANSMIT) ? VCHIQ_MSG_BULK_TX : VCHIQ_MSG_BULK_RX;
4438 + VCHIQ_STATUS_T status = VCHIQ_ERROR;
4440 + if ((service == NULL) ||
4441 + ((memhandle == VCHI_MEM_HANDLE_INVALID) && (offset == NULL)))
4442 + return VCHIQ_ERROR;
4444 + state = service->state;
4446 + if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
4447 + return VCHIQ_ERROR; /* Must be connected */
4449 + if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
4450 + return VCHIQ_RETRY;
4452 + if (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS)
4454 + VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
4456 + vcos_mutex_unlock(&service->bulk_mutex);
4457 + if (vcos_event_wait(&service->bulk_remove_event) != VCOS_SUCCESS)
4458 + return VCHIQ_RETRY;
4459 + if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
4460 + return VCHIQ_RETRY;
4461 + } while (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS);
4464 + bulk = &queue->bulks[BULK_INDEX(queue->local_insert)];
4466 + if (mode == VCHIQ_BULK_MODE_BLOCKING)
4468 + vcos_event_create(&bulk_waiter.event, "bulk_waiter");
4469 + bulk_waiter.actual = 0;
4470 + userdata = &bulk_waiter;
4473 + bulk->mode = mode;
4475 + bulk->userdata = userdata;
4476 + bulk->size = size;
4477 + bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
4479 + if (vchiq_prepare_bulk_data(bulk, memhandle, offset, size, dir) != VCHIQ_SUCCESS)
4484 + vcos_log_info("%d: bt (%d->%d) %cx %x@%x %x", state->id,
4485 + service->localport, service->remoteport, dir_char,
4486 + size, (unsigned int)bulk->data, (unsigned int)userdata);
4488 + if (state->is_master)
4490 + queue->local_insert++;
4491 + if (resolve_bulks(service, queue))
4492 + request_poll(state, service, (dir == VCHIQ_BULK_TRANSMIT) ?
4493 + VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
4497 + int payload[2] = { (int)bulk->data, bulk->size };
4498 + VCHIQ_ELEMENT_T element = { payload, sizeof(payload) };
4500 + if (queue_message(state, NULL,
4501 + VCHIQ_MAKE_MSG(dir_msgtype,
4502 + service->localport, service->remoteport),
4503 + &element, 1, sizeof(payload), 1) != VCHIQ_SUCCESS)
4505 + vchiq_complete_bulk(bulk);
4508 + queue->local_insert++;
4509 + queue->remote_insert++;
4512 + vcos_mutex_unlock(&service->bulk_mutex);
4514 + vcos_log_trace("%d: bt:%d %cx li=%x ri=%x p=%x", state->id,
4515 + service->localport, dir_char,
4516 + queue->local_insert, queue->remote_insert, queue->process);
4518 + status = VCHIQ_SUCCESS;
4520 + if (mode == VCHIQ_BULK_MODE_BLOCKING)
4522 + if (vcos_event_wait(&bulk_waiter.event) != VCOS_SUCCESS)
4524 + vcos_log_info("bulk wait interrupted");
4525 + /* Stop notify_bulks signalling a non-existent waiter */
4526 + bulk->userdata = NULL;
4527 + status = VCHIQ_ERROR;
4529 + else if (bulk_waiter.actual == VCHIQ_BULK_ACTUAL_ABORTED)
4530 + status = VCHIQ_ERROR;
4532 + vcos_event_delete(&bulk_waiter.event);
4538 + if (mode == VCHIQ_BULK_MODE_BLOCKING)
4539 + vcos_event_delete(&bulk_waiter.event);
4540 + vcos_mutex_unlock(&service->bulk_mutex);
4546 +vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
4547 + const void *data, int size, void *userdata)
4549 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4550 + VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
4551 + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
4555 +vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, int size,
4558 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4559 + VCHI_MEM_HANDLE_INVALID, data, size, userdata,
4560 + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
4564 +vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
4565 + VCHI_MEM_HANDLE_T memhandle, const void *offset, int size, void *userdata)
4567 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4568 + memhandle, (void *)offset, size, userdata,
4569 + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
4573 +vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
4574 + VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata)
4576 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4577 + memhandle, offset, size, userdata,
4578 + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
4582 +vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, int size,
4583 + void *userdata, VCHIQ_BULK_MODE_T mode)
4585 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4586 + VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
4587 + mode, VCHIQ_BULK_TRANSMIT);
4591 +vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, int size,
4592 + void *userdata, VCHIQ_BULK_MODE_T mode)
4594 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4595 + VCHI_MEM_HANDLE_INVALID, data, size, userdata,
4596 + mode, VCHIQ_BULK_RECEIVE);
4600 +vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
4601 + VCHI_MEM_HANDLE_T memhandle, const void *offset, int size, void *userdata,
4602 + VCHIQ_BULK_MODE_T mode)
4604 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4605 + memhandle, (void *)offset, size, userdata,
4606 + mode, VCHIQ_BULK_TRANSMIT);
4610 +vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
4611 + VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
4612 + VCHIQ_BULK_MODE_T mode)
4614 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4615 + memhandle, offset, size, userdata,
4616 + mode, VCHIQ_BULK_RECEIVE);
4620 +vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
4621 + const VCHIQ_ELEMENT_T *elements, int count)
4623 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *) handle;
4625 + unsigned int size = 0;
4628 + if ((service == NULL) ||
4629 + (service->srvstate != VCHIQ_SRVSTATE_OPEN))
4630 + return VCHIQ_ERROR;
4632 + for (i = 0; i < (unsigned int)count; i++)
4634 + if (elements[i].size)
4636 + if (elements[i].data == NULL)
4638 + VCHIQ_SERVICE_STATS_INC(service, error_count);
4639 + return VCHIQ_ERROR;
4641 + size += elements[i].size;
4645 + if (size > VCHIQ_MAX_MSG_SIZE)
4647 + VCHIQ_SERVICE_STATS_INC(service, error_count);
4648 + return VCHIQ_ERROR;
4651 + return queue_message(service->state, service,
4652 + VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA, service->localport,
4653 + service->remoteport), elements, count, size, 1);
4657 +vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle, VCHIQ_HEADER_T *header)
4659 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
4660 + VCHIQ_STATE_T *state;
4664 + if (service == NULL)
4667 + state = service->state;
4669 + slot_index = SLOT_INDEX_FROM_DATA(state, (void *)header);
4671 + if ((slot_index >= state->remote->slot_first) &&
4672 + (slot_index <= state->remote->slot_last) &&
4673 + ((msgid = header->msgid) & VCHIQ_MSGID_CLAIMED))
4675 + VCHIQ_SLOT_INFO_T *slot_info = SLOT_INFO_FROM_INDEX(state, slot_index);
4677 + /* Rewrite the message header to prevent a double release */
4678 + header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
4680 + release_slot(state, slot_info);
4685 +vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
4687 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
4688 + return service ? service->client_id : 0;
4692 +vchiq_get_config(VCHIQ_INSTANCE_T instance,
4693 + int config_size, VCHIQ_CONFIG_T *pconfig)
4695 + VCHIQ_CONFIG_T config;
4697 + vcos_unused(instance);
4699 + config.max_msg_size = VCHIQ_MAX_MSG_SIZE;
4700 + config.bulk_threshold = VCHIQ_MAX_MSG_SIZE;
4701 + config.max_outstanding_bulks = VCHIQ_NUM_SERVICE_BULKS;
4702 + config.max_services = VCHIQ_MAX_SERVICES;
4703 + config.version = VCHIQ_VERSION;
4704 + config.version_min = VCHIQ_VERSION_MIN;
4706 + if (config_size > sizeof(VCHIQ_CONFIG_T))
4707 + return VCHIQ_ERROR;
4709 + memcpy(pconfig, &config, vcos_min(config_size, sizeof(VCHIQ_CONFIG_T)));
4711 + return VCHIQ_SUCCESS;
4715 +vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
4716 + VCHIQ_SERVICE_OPTION_T option, int value)
4718 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
4719 + VCHIQ_STATUS_T status = VCHIQ_ERROR;
4725 + case VCHIQ_SERVICE_OPTION_AUTOCLOSE:
4726 + service->auto_close = value;
4727 + status = VCHIQ_SUCCESS;
4739 +vchiq_dump_shared_state(void *dump_context, VCHIQ_STATE_T *state,
4740 + VCHIQ_SHARED_STATE_T *shared, const char *label)
4742 + static const char *const debug_names[] =
4745 + "SLOT_HANDLER_COUNT",
4746 + "SLOT_HANDLER_LINE",
4750 + "AWAIT_COMPLETION_LINE",
4751 + "DEQUEUE_MESSAGE_LINE",
4752 + "SERVICE_CALLBACK_LINE",
4753 + "MSG_QUEUE_FULL_COUNT",
4754 + "COMPLETION_QUEUE_FULL_COUNT"
4760 + len = vcos_snprintf(buf, sizeof(buf),
4761 + " %s: slots %d-%d tx_pos=%x recycle=%x",
4762 + label, shared->slot_first, shared->slot_last,
4763 + shared->tx_pos, shared->slot_queue_recycle);
4764 + vchiq_dump(dump_context, buf, len + 1);
4766 + len = vcos_snprintf(buf, sizeof(buf),
4767 + " Slots claimed:");
4768 + vchiq_dump(dump_context, buf, len + 1);
4770 + for (i = shared->slot_first; i <= shared->slot_last; i++)
4772 + VCHIQ_SLOT_INFO_T slot_info = *SLOT_INFO_FROM_INDEX(state, i);
4773 + if (slot_info.use_count != slot_info.release_count)
4775 + len = vcos_snprintf(buf, sizeof(buf),
4776 + " %d: %d/%d", i, slot_info.use_count, slot_info.release_count);
4777 + vchiq_dump(dump_context, buf, len + 1);
4781 + for (i = 1; i < shared->debug[DEBUG_ENTRIES]; i++)
4783 + len = vcos_snprintf(buf, sizeof(buf), " DEBUG: %s = %d(%x)",
4784 + debug_names[i], shared->debug[i], shared->debug[i]);
4785 + vchiq_dump(dump_context, buf, len + 1);
4790 +vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state)
4796 + len = vcos_snprintf(buf, sizeof(buf), "State %d: %s", state->id,
4797 + conn_state_names[state->conn_state]);
4798 + vchiq_dump(dump_context, buf, len + 1);
4800 + len = vcos_snprintf(buf, sizeof(buf),
4801 + " tx_pos=%x(@%x), rx_pos=%x(@%x)",
4802 + state->id, state->local->tx_pos,
4803 + (uint32_t)state->tx_data + (state->local_tx_pos & VCHIQ_SLOT_MASK),
4805 + (uint32_t)state->rx_data + (state->rx_pos & VCHIQ_SLOT_MASK));
4806 + vchiq_dump(dump_context, buf, len + 1);
4808 + len = vcos_snprintf(buf, sizeof(buf),
4809 + " Version: %d (min %d)",
4810 + VCHIQ_VERSION, VCHIQ_VERSION_MIN);
4811 + vchiq_dump(dump_context, buf, len + 1);
4813 + if (VCHIQ_ENABLE_STATS)
4815 + len = vcos_snprintf(buf, sizeof(buf),
4816 + " Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, error_count=%d",
4817 + state->stats.ctrl_tx_count, state->stats.ctrl_rx_count,
4818 + state->stats.slot_stalls);
4819 + vchiq_dump(dump_context, buf, len + 1);
4822 + len = vcos_snprintf(buf, sizeof(buf),
4823 + " Slots: %d available, %d recyclable, %d stalls",
4824 + state->slot_queue_available - SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos),
4825 + state->local->slot_queue_recycle - state->slot_queue_available,
4826 + state->stats.slot_stalls);
4827 + vchiq_dump(dump_context, buf, len + 1);
4829 + vchiq_dump_platform_state(dump_context);
4831 + vchiq_dump_shared_state(dump_context, state, state->local, "Local");
4832 + vchiq_dump_shared_state(dump_context, state, state->remote, "Remote");
4834 + vchiq_dump_platform_instances(dump_context);
4836 + for (i = 0; i < state->unused_service; i++) {
4837 + VCHIQ_SERVICE_T *service = state->services[i];
4839 + if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE))
4840 + vchiq_dump_service_state(dump_context, service);
4845 +vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
4850 + len = vcos_snprintf(buf, sizeof(buf), "Service %d: %s",
4851 + service->localport, srvstate_names[service->srvstate]);
4853 + if (service->srvstate != VCHIQ_SRVSTATE_FREE)
4855 + char remoteport[30];
4856 + VCHIQ_SERVICE_QUOTA_T *service_quota =
4857 + &service->state->service_quotas[service->localport];
4858 + int fourcc = service->base.fourcc;
4859 + if (service->remoteport != VCHIQ_PORT_FREE)
4861 + int len2 = vcos_snprintf(remoteport, sizeof(remoteport), "%d",
4862 + service->remoteport);
4863 + if (service->public_fourcc != VCHIQ_FOURCC_INVALID)
4864 + vcos_snprintf(remoteport + len2, sizeof(remoteport) - len2,
4865 + " (client %x)", service->client_id);
4868 + vcos_strcpy(remoteport, "n/a");
4870 + len += vcos_snprintf(buf + len, sizeof(buf) - len,
4871 + " '%c%c%c%c' remote %s (slot use %d/%d)",
4872 + VCHIQ_FOURCC_AS_4CHARS(fourcc),
4874 + service_quota->slot_use_count,
4875 + service_quota->slot_quota);
4877 + if (VCHIQ_ENABLE_STATS)
4879 + vchiq_dump(dump_context, buf, len + 1);
4881 + len = vcos_snprintf(buf, sizeof(buf),
4882 + " Ctrl: tx_count=%d, tx_bytes=%" PRIu64 ", rx_count=%d, rx_bytes=%" PRIu64,
4883 + service->stats.ctrl_tx_count, service->stats.ctrl_tx_bytes,
4884 + service->stats.ctrl_rx_count, service->stats.ctrl_rx_bytes);
4885 + vchiq_dump(dump_context, buf, len + 1);
4887 + len = vcos_snprintf(buf, sizeof(buf),
4888 + " Bulk: tx_count=%d, tx_bytes=%" PRIu64 ", rx_count=%d, rx_bytes=%" PRIu64,
4889 + service->stats.bulk_tx_count, service->stats.bulk_tx_bytes,
4890 + service->stats.bulk_rx_count, service->stats.bulk_rx_bytes);
4891 + vchiq_dump(dump_context, buf, len + 1);
4893 + len = vcos_snprintf(buf, sizeof(buf),
4894 + " %d quota stalls, %d slot stalls, %d bulk stalls, %d aborted, %d errors",
4895 + service->stats.quota_stalls, service->stats.slot_stalls,
4896 + service->stats.bulk_stalls, service->stats.bulk_aborted_count,
4897 + service->stats.error_count);
4901 + vchiq_dump(dump_context, buf, len + 1);
4903 + vchiq_dump_platform_service_state(dump_context, service);
4906 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
4909 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
4911 + * This program is free software; you can redistribute it and/or modify
4912 + * it under the terms of the GNU General Public License as published by
4913 + * the Free Software Foundation; either version 2 of the License, or
4914 + * (at your option) any later version.
4916 + * This program is distributed in the hope that it will be useful,
4917 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4918 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4919 + * GNU General Public License for more details.
4921 + * You should have received a copy of the GNU General Public License
4922 + * along with this program; if not, write to the Free Software
4923 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4926 +#ifndef VCHIQ_CORE_H
4927 +#define VCHIQ_CORE_H
4929 +#include "vchiq_cfg.h"
4933 +#define IS_POW2(x) (x && ((x & (x - 1)) == 0))
4935 +/* Ensure that the slot size and maximum number of slots are powers of 2 */
4936 +vcos_static_assert(IS_POW2(VCHIQ_SLOT_SIZE));
4937 +vcos_static_assert(IS_POW2(VCHIQ_MAX_SLOTS));
4938 +vcos_static_assert(IS_POW2(VCHIQ_MAX_SLOTS_PER_SIDE));
4940 +#define VCHIQ_SLOT_MASK (VCHIQ_SLOT_SIZE - 1)
4941 +#define VCHIQ_SLOT_QUEUE_MASK (VCHIQ_MAX_SLOTS_PER_SIDE - 1)
4942 +#define VCHIQ_SLOT_ZERO_SLOTS ((sizeof(VCHIQ_SLOT_ZERO_T) + \
4943 + VCHIQ_SLOT_SIZE - 1) / VCHIQ_SLOT_SIZE)
4945 +#define VCHIQ_MSG_PADDING 0 // -
4946 +#define VCHIQ_MSG_CONNECT 1 // -
4947 +#define VCHIQ_MSG_OPEN 2 // + (srcport, -), fourcc, client_id
4948 +#define VCHIQ_MSG_OPENACK 3 // + (srcport, dstport)
4949 +#define VCHIQ_MSG_CLOSE 4 // + (srcport, dstport)
4950 +#define VCHIQ_MSG_DATA 5 // + (srcport, dstport)
4951 +#define VCHIQ_MSG_BULK_RX 6 // + (srcport, dstport), data, size
4952 +#define VCHIQ_MSG_BULK_TX 7 // + (srcport, dstport), data, size
4953 +#define VCHIQ_MSG_BULK_RX_DONE 8 // + (srcport, dstport), actual
4954 +#define VCHIQ_MSG_BULK_TX_DONE 9 // + (srcport, dstport), actual
4955 +#define VCHIQ_MSG_PAUSE 10 // -
4956 +#define VCHIQ_MSG_RESUME 11 // -
4958 +#define VCHIQ_PORT_MAX (VCHIQ_MAX_SERVICES - 1)
4959 +#define VCHIQ_PORT_FREE 0x1000
4960 +#define VCHIQ_PORT_IS_VALID(port) (port < VCHIQ_PORT_FREE)
4961 +#define VCHIQ_MAKE_MSG(type,srcport,dstport) ((type<<24) | (srcport<<12) | (dstport<<0))
4962 +#define VCHIQ_MSG_TYPE(msgid) ((unsigned int)msgid >> 24)
4963 +#define VCHIQ_MSG_SRCPORT(msgid) (unsigned short)(((unsigned int)msgid >> 12) & 0xfff)
4964 +#define VCHIQ_MSG_DSTPORT(msgid) ((unsigned short)msgid & 0xfff)
4966 +#define VCHIQ_FOURCC_AS_4CHARS(fourcc) \
4967 + ((fourcc) >> 24) & 0xff, \
4968 + ((fourcc) >> 16) & 0xff, \
4969 + ((fourcc) >> 8) & 0xff, \
4970 + ((fourcc) ) & 0xff
4972 +/* Ensure the fields are wide enough */
4973 +vcos_static_assert(VCHIQ_MSG_SRCPORT(VCHIQ_MAKE_MSG(0,0,VCHIQ_PORT_MAX)) == 0);
4974 +vcos_static_assert(VCHIQ_MSG_TYPE(VCHIQ_MAKE_MSG(0,VCHIQ_PORT_MAX,0)) == 0);
4975 +vcos_static_assert((unsigned int)VCHIQ_PORT_MAX < (unsigned int)VCHIQ_PORT_FREE);
4977 +#define VCHIQ_MSGID_PADDING VCHIQ_MAKE_MSG(VCHIQ_MSG_PADDING,0,0)
4978 +#define VCHIQ_MSGID_CLAIMED 0x40000000
4980 +#define VCHIQ_FOURCC_INVALID 0x00000000
4981 +#define VCHIQ_FOURCC_IS_LEGAL(fourcc) (fourcc != VCHIQ_FOURCC_INVALID)
4983 +#define VCHIQ_BULK_ACTUAL_ABORTED -1
4985 +typedef uint32_t BITSET_T;
4987 +vcos_static_assert((sizeof(BITSET_T) * 8) == 32);
4989 +#define BITSET_SIZE(b) ((b + 31) >> 5)
4990 +#define BITSET_WORD(b) (b >> 5)
4991 +#define BITSET_BIT(b) (1 << (b & 31))
4992 +#define BITSET_ZERO(bs) memset(bs, 0, sizeof(bs))
4993 +#define BITSET_IS_SET(bs, b) (bs[BITSET_WORD(b)] & BITSET_BIT(b))
4994 +#define BITSET_SET(bs, b) (bs[BITSET_WORD(b)] |= BITSET_BIT(b))
4995 +#define BITSET_CLR(bs, b) (bs[BITSET_WORD(b)] &= ~BITSET_BIT(b))
4997 +#if VCHIQ_ENABLE_STATS
4998 +#define VCHIQ_STATS_INC(state, stat) (state->stats. stat ++)
4999 +#define VCHIQ_SERVICE_STATS_INC(service, stat) (service->stats. stat ++)
5000 +#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) (service->stats. stat += addend)
5002 +#define VCHIQ_STATS_INC(state, stat) ((void)0)
5003 +#define VCHIQ_SERVICE_STATS_INC(service, stat) ((void)0)
5004 +#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) ((void)0)
5010 +#if VCHIQ_ENABLE_DEBUG
5011 + DEBUG_SLOT_HANDLER_COUNT,
5012 + DEBUG_SLOT_HANDLER_LINE,
5014 + DEBUG_PARSE_HEADER,
5015 + DEBUG_PARSE_MSGID,
5016 + DEBUG_AWAIT_COMPLETION_LINE,
5017 + DEBUG_DEQUEUE_MESSAGE_LINE,
5018 + DEBUG_SERVICE_CALLBACK_LINE,
5019 + DEBUG_MSG_QUEUE_FULL_COUNT,
5020 + DEBUG_COMPLETION_QUEUE_FULL_COUNT,
5025 +#if VCHIQ_ENABLE_DEBUG
5027 +#define DEBUG_INITIALISE(local) volatile int *debug_ptr = (local)->debug;
5028 +#define DEBUG_TRACE(d) debug_ptr[DEBUG_ ## d] = __LINE__
5029 +#define DEBUG_VALUE(d,v) debug_ptr[DEBUG_ ## d] = (v)
5030 +#define DEBUG_COUNT(d) debug_ptr[DEBUG_ ## d]++
5032 +#else /* VCHIQ_ENABLE_DEBUG */
5034 +#define DEBUG_INITIALISE(local)
5035 +#define DEBUG_TRACE(d)
5036 +#define DEBUG_VALUE(d,v)
5037 +#define DEBUG_COUNT(d)
5039 +#endif /* VCHIQ_ENABLE_DEBUG */
5043 + VCHIQ_CONNSTATE_DISCONNECTED,
5044 + VCHIQ_CONNSTATE_CONNECTED,
5045 + VCHIQ_CONNSTATE_PAUSING,
5046 + VCHIQ_CONNSTATE_PAUSE_SENT,
5047 + VCHIQ_CONNSTATE_PAUSED,
5048 + VCHIQ_CONNSTATE_RESUMING
5049 +} VCHIQ_CONNSTATE_T;
5053 + VCHIQ_SRVSTATE_FREE,
5054 + VCHIQ_SRVSTATE_HIDDEN,
5055 + VCHIQ_SRVSTATE_LISTENING,
5056 + VCHIQ_SRVSTATE_OPENING,
5057 + VCHIQ_SRVSTATE_OPEN,
5058 + VCHIQ_SRVSTATE_CLOSESENT,
5059 + VCHIQ_SRVSTATE_CLOSING,
5060 + VCHIQ_SRVSTATE_CLOSEWAIT
5065 + VCHIQ_POLL_TERMINATE,
5066 + VCHIQ_POLL_TXNOTIFY,
5067 + VCHIQ_POLL_RXNOTIFY,
5073 + VCHIQ_BULK_TRANSMIT,
5074 + VCHIQ_BULK_RECEIVE
5075 +} VCHIQ_BULK_DIR_T;
5077 +typedef struct vchiq_bulk_struct {
5081 + VCHI_MEM_HANDLE_T handle;
5084 + void *remote_data;
5089 +typedef struct vchiq_bulk_queue_struct {
5090 + int local_insert; /* Where to insert the next local bulk */
5091 + int remote_insert; /* Where to insert the next remote bulk (master) */
5092 + int process; /* Bulk to transfer next */
5093 + int remote_notify; /* Bulk to notify the remote client of next (master) */
5094 + int remove; /* Bulk to notify the local client of, and remove, next */
5095 + VCHIQ_BULK_T bulks[VCHIQ_NUM_SERVICE_BULKS];
5096 +} VCHIQ_BULK_QUEUE_T;
5098 +typedef struct remote_event_struct {
5099 + volatile int armed;
5100 + volatile int fired;
5101 + VCOS_EVENT_T * event;
5104 +typedef struct vchiq_state_struct VCHIQ_STATE_T;
5106 +typedef struct vchiq_slot_struct {
5107 + char data[VCHIQ_SLOT_SIZE];
5110 +typedef struct vchiq_slot_info_struct {
5111 + /* Use two counters rather than one to avoid the need for a mutex. */
5112 + volatile short use_count;
5113 + volatile short release_count;
5114 +} VCHIQ_SLOT_INFO_T;
5116 +typedef struct vchiq_service_struct {
5117 + VCHIQ_SERVICE_BASE_T base;
5118 + volatile int srvstate;
5119 + unsigned int localport;
5120 + unsigned int remoteport;
5121 + int public_fourcc;
5124 + VCOS_ATOMIC_FLAGS_T poll_flags;
5126 + short version_min;
5128 + VCHIQ_STATE_T *state;
5129 + VCHIQ_INSTANCE_T instance;
5131 + int service_use_count;
5133 + VCHIQ_BULK_QUEUE_T bulk_tx;
5134 + VCHIQ_BULK_QUEUE_T bulk_rx;
5136 + VCOS_EVENT_T remove_event;
5137 + VCOS_EVENT_T bulk_remove_event;
5138 + VCOS_MUTEX_T bulk_mutex;
5140 + struct service_stats_struct
5146 + int ctrl_tx_count;
5147 + int ctrl_rx_count;
5148 + int bulk_tx_count;
5149 + int bulk_rx_count;
5150 + int bulk_aborted_count;
5151 + uint64_t ctrl_tx_bytes;
5152 + uint64_t ctrl_rx_bytes;
5153 + uint64_t bulk_tx_bytes;
5154 + uint64_t bulk_rx_bytes;
5158 +/* The quota information is outside VCHIQ_SERVICE_T so that it can be
5159 + statically allocated, since for accounting reasons a service's slot
5160 + usage is carried over between users of the same port number.
5162 +typedef struct vchiq_service_quota_struct {
5164 + int slot_use_count;
5165 + VCOS_EVENT_T quota_event;
5166 + int previous_tx_index;
5167 +} VCHIQ_SERVICE_QUOTA_T;
5169 +typedef struct vchiq_shared_state_struct {
5171 + /* A non-zero value here indicates that the content is valid. */
5174 + /* The first and last (inclusive) slots allocated to the owner. */
5178 + /* Signalling this event indicates that owner's slot handler thread should
5180 + REMOTE_EVENT_T trigger;
5182 + /* Indicates the byte position within the stream where the next message
5183 + will be written. The least significant bits are an index into the slot.
5184 + The next bits are the index of the slot in slot_queue. */
5185 + volatile int tx_pos;
5187 + /* This event should be signalled when a slot is recycled. */
5188 + REMOTE_EVENT_T recycle;
5190 + /* The slot_queue index where the next recycled slot will be written. */
5191 + volatile int slot_queue_recycle;
5193 + /* A circular buffer of slot indexes. */
5194 + int slot_queue[VCHIQ_MAX_SLOTS_PER_SIDE];
5196 + /* Debugging state */
5197 + volatile int debug[DEBUG_MAX];
5198 +} VCHIQ_SHARED_STATE_T;
5200 +typedef struct vchiq_slot_zero_struct {
5203 + short version_min;
5204 + int slot_zero_size;
5207 + int max_slots_per_side;
5208 + int platform_data[2];
5209 + VCHIQ_SHARED_STATE_T master;
5210 + VCHIQ_SHARED_STATE_T slave;
5211 + VCHIQ_SLOT_INFO_T slots[VCHIQ_MAX_SLOTS];
5212 +} VCHIQ_SLOT_ZERO_T;
5214 +struct vchiq_state_struct {
5217 + VCHIQ_CONNSTATE_T conn_state;
5220 + VCHIQ_SHARED_STATE_T *local;
5221 + VCHIQ_SHARED_STATE_T *remote;
5222 + VCHIQ_SLOT_T *slot_data;
5224 + int default_slot_quota;
5226 + VCOS_EVENT_T connect; // event indicating connect message received
5227 + VCOS_MUTEX_T mutex; // mutex protecting services
5228 + VCHIQ_INSTANCE_T *instance;
5230 + VCOS_THREAD_T slot_handler_thread; // processes incoming messages
5231 + VCOS_THREAD_T recycle_thread; // processes recycled slots
5232 + VCOS_THREAD_T lp_thread; // processes low priority messages (eg suspend)
5234 + /* Local implementation of the trigger remote event */
5235 + VCOS_EVENT_T trigger_event;
5237 + /* Local implementation of the recycle remote event */
5238 + VCOS_EVENT_T recycle_event;
5240 + VCOS_EVENT_T lp_evt;
5244 + VCHIQ_SLOT_INFO_T *rx_info;
5246 + VCOS_MUTEX_T slot_mutex;
5248 + VCOS_MUTEX_T recycle_mutex;
5250 + VCOS_MUTEX_T suspend_resume_mutex;
5251 + VCOS_MUTEX_T use_count_mutex;
5253 + /* Global use count for videocore.
5254 + * This is equal to the sum of the use counts for all services. When this hits
5255 + * zero the videocore suspend procedure will be initiated. */
5256 + int videocore_use_count;
5258 + /* Flag to indicate whether videocore is currently suspended */
5259 + int videocore_suspended;
5261 + /* Indicates the byte position within the stream from where the next message
5262 + will be read. The least significant bits are an index into the slot.
5263 + The next bits are the index of the slot in remote->slot_queue. */
5266 + /* A cached copy of local->tx_pos. Only write to local->tx_pos, and read
5267 + from remote->tx_pos. */
5270 + /* The slot_queue index of the slot to become available next. */
5271 + int slot_queue_available;
5273 + /* A flag to indicate if any poll has been requested */
5276 + /* An array of bit sets indicating which services must be polled. */
5277 + VCOS_ATOMIC_FLAGS_T poll_services[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
5279 + /* The number of the first unused service */
5280 + int unused_service;
5282 + /* Signalled when a free slot becomes available. */
5283 + VCOS_EVENT_T slot_available_event;
5285 + VCOS_EVENT_T slot_remove_event;
5287 + struct state_stats_struct
5290 + int ctrl_tx_count;
5291 + int ctrl_rx_count;
5295 + VCHIQ_SERVICE_T *services[VCHIQ_MAX_SERVICES];
5296 + VCHIQ_SERVICE_QUOTA_T service_quotas[VCHIQ_MAX_SERVICES];
5297 + VCHIQ_SLOT_INFO_T slot_info[VCHIQ_MAX_SLOTS];
5300 +extern VCHIQ_SLOT_ZERO_T *
5301 +vchiq_init_slots(void *mem_base, int mem_size);
5303 +extern VCHIQ_STATUS_T
5304 +vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, int is_master);
5306 +extern VCHIQ_STATUS_T
5307 +vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
5309 +extern VCHIQ_SERVICE_T *
5310 +vchiq_add_service_internal(VCHIQ_STATE_T *state,
5311 + const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
5312 + VCHIQ_INSTANCE_T instance);
5314 +extern VCHIQ_STATUS_T
5315 +vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id);
5317 +extern VCHIQ_STATUS_T
5318 +vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd);
5321 +vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service);
5324 +vchiq_free_service_internal(VCHIQ_SERVICE_T *service);
5326 +extern VCHIQ_STATUS_T
5327 +vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
5329 +extern VCHIQ_STATUS_T
5330 +vchiq_pause_internal(VCHIQ_STATE_T *state);
5332 +extern VCHIQ_STATUS_T
5333 +vchiq_resume_internal(VCHIQ_STATE_T *state);
5336 +remote_event_pollall(VCHIQ_STATE_T *state);
5338 +extern VCHIQ_STATUS_T
5339 +vchiq_bulk_transfer(VCHIQ_SERVICE_T *service,
5340 + VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
5341 + VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir);
5344 +vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state);
5347 +vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service);
5349 +/* The following functions are called from vchiq_core, and external
5350 + implementations must be provided. */
5352 +extern VCHIQ_STATUS_T
5353 +vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk,
5354 + VCHI_MEM_HANDLE_T memhandle, void *offset, int size, int dir);
5357 +vchiq_transfer_bulk(VCHIQ_BULK_T *bulk);
5360 +vchiq_complete_bulk(VCHIQ_BULK_T *bulk);
5362 +extern VCHIQ_STATUS_T
5363 +vchiq_copy_from_user(void *dst, const void *src, int size);
5366 +remote_event_signal(REMOTE_EVENT_T *event);
5369 +vchiq_platform_paused(VCHIQ_STATE_T *state);
5372 +vchiq_platform_resumed(VCHIQ_STATE_T *state);
5375 +vchiq_dump(void *dump_context, const char *str, int len);
5378 +vchiq_dump_platform_state(void *dump_context);
5381 +vchiq_dump_platform_instances(void *dump_context);
5384 +vchiq_dump_platform_service_state(void *dump_context,
5385 + VCHIQ_SERVICE_T *service);
5389 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
5392 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
5394 + * This program is free software; you can redistribute it and/or modify
5395 + * it under the terms of the GNU General Public License as published by
5396 + * the Free Software Foundation; either version 2 of the License, or
5397 + * (at your option) any later version.
5399 + * This program is distributed in the hope that it will be useful,
5400 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5401 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5402 + * GNU General Public License for more details.
5404 + * You should have received a copy of the GNU General Public License
5405 + * along with this program; if not, write to the Free Software
5406 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5412 +#include "interface/vchi/vchi_mh.h"
5414 +#define VCHIQ_SLOT_SIZE 4096
5415 +#define VCHIQ_MAX_MSG_SIZE (VCHIQ_SLOT_SIZE - sizeof(VCHIQ_HEADER_T))
5416 +#define VCHIQ_CHANNEL_SIZE VCHIQ_MAX_MSG_SIZE /* For backwards compatibility */
5418 +#define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3) (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3))
5419 +#define VCHIQ_GET_SERVICE_USERDATA(service) (service->userdata)
5420 +#define VCHIQ_GET_SERVICE_FOURCC(service) (service->fourcc)
5423 + VCHIQ_SERVICE_OPENED, // service, -, -
5424 + VCHIQ_SERVICE_CLOSED, // service, -, -
5425 + VCHIQ_MESSAGE_AVAILABLE, // service, header, -
5426 + VCHIQ_BULK_TRANSMIT_DONE, // service, -, bulk_userdata
5427 + VCHIQ_BULK_RECEIVE_DONE, // service, -, bulk_userdata
5428 + VCHIQ_BULK_TRANSMIT_ABORTED, // service, -, bulk_userdata
5429 + VCHIQ_BULK_RECEIVE_ABORTED // service, -, bulk_userdata
5435 + VCHIQ_SUCCESS = 0,
5441 + VCHIQ_BULK_MODE_CALLBACK,
5442 + VCHIQ_BULK_MODE_BLOCKING,
5443 + VCHIQ_BULK_MODE_NOCALLBACK
5444 +} VCHIQ_BULK_MODE_T;
5448 + VCHIQ_SERVICE_OPTION_AUTOCLOSE
5449 +} VCHIQ_SERVICE_OPTION_T;
5452 +/* Allow zero-sized arrays without warnings */
5453 +#pragma warning (push)
5454 +#pragma warning (disable : 4200)
5457 +typedef struct vchiq_header_struct {
5458 + /* The message identifier - opaque to applications. */
5461 + /* Size of message data. */
5462 + unsigned int size;
5464 + char data[0]; /* message */
5468 +#pragma warning (pop)
5476 +typedef const struct vchiq_service_base_struct *VCHIQ_SERVICE_HANDLE_T;
5478 +typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, VCHIQ_HEADER_T *, VCHIQ_SERVICE_HANDLE_T, void *);
5480 +typedef struct vchiq_service_base_struct {
5482 + VCHIQ_CALLBACK_T callback;
5484 +} VCHIQ_SERVICE_BASE_T;
5486 +typedef struct vchiq_service_params_struct {
5488 + VCHIQ_CALLBACK_T callback;
5490 + short version; /* Increment for non-trivial changes */
5491 + short version_min; /* Update for incompatible changes */
5492 +} VCHIQ_SERVICE_PARAMS_T;
5494 +typedef struct vchiq_config_struct {
5496 + int bulk_threshold; /* The message size aboce which it is better to use
5497 + a bulk transfer (<= max_msg_size) */
5498 + int max_outstanding_bulks;
5500 + short version; /* The version of VCHIQ */
5501 + short version_min; /* The minimum compatible version of VCHIQ */
5504 +typedef struct vchiq_instance_struct *VCHIQ_INSTANCE_T;
5506 +extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance);
5507 +extern VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance);
5508 +extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance);
5509 +extern VCHIQ_STATUS_T vchiq_add_service(VCHIQ_INSTANCE_T instance, int fourcc, VCHIQ_CALLBACK_T callback, void *userdata, VCHIQ_SERVICE_HANDLE_T *pservice);
5510 +extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance, int fourcc, VCHIQ_CALLBACK_T callback, void *userdata, VCHIQ_SERVICE_HANDLE_T *pservice);
5511 +extern VCHIQ_STATUS_T vchiq_add_service_params(VCHIQ_INSTANCE_T instance,
5512 + const VCHIQ_SERVICE_PARAMS_T *params,
5513 + VCHIQ_SERVICE_HANDLE_T *pservice);
5514 +extern VCHIQ_STATUS_T vchiq_open_service_params(VCHIQ_INSTANCE_T instance,
5515 + const VCHIQ_SERVICE_PARAMS_T *params,
5516 + VCHIQ_SERVICE_HANDLE_T *pservice);
5517 +extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service);
5518 +extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service);
5519 +extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
5520 +extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
5522 +extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service, const VCHIQ_ELEMENT_T *elements, int count);
5523 +extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service, VCHIQ_HEADER_T *header);
5524 +extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, const void *data, int size, void *userdata);
5525 +extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service, void *data, int size, void *userdata);
5526 +extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, const void *offset, int size, void *userdata);
5527 +extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, void *offset, int size, void *userdata);
5528 +extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, const void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
5529 +extern VCHIQ_STATUS_T vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T service, void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
5530 +extern VCHIQ_STATUS_T vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, const void *offset, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
5531 +extern VCHIQ_STATUS_T vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, void *offset, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
5532 +extern int vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T service);
5533 +extern VCHIQ_STATUS_T vchiq_get_config(VCHIQ_INSTANCE_T instance, int config_size, VCHIQ_CONFIG_T *pconfig);
5534 +extern VCHIQ_STATUS_T vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T service, VCHIQ_SERVICE_OPTION_T option, int value);
5536 +extern VCHIQ_STATUS_T vchiq_dump_phys_mem( VCHIQ_SERVICE_HANDLE_T service, void *ptr, size_t num_bytes );
5538 +#endif /* VCHIQ_IF_H */
5540 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
5543 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
5545 + * This program is free software; you can redistribute it and/or modify
5546 + * it under the terms of the GNU General Public License as published by
5547 + * the Free Software Foundation; either version 2 of the License, or
5548 + * (at your option) any later version.
5550 + * This program is distributed in the hope that it will be useful,
5551 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5552 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5553 + * GNU General Public License for more details.
5555 + * You should have received a copy of the GNU General Public License
5556 + * along with this program; if not, write to the Free Software
5557 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5560 +#ifndef VCHIQ_IOCTLS_H
5561 +#define VCHIQ_IOCTLS_H
5563 +#include <linux/ioctl.h>
5564 +#include "vchiq_if.h"
5566 +#define VCHIQ_IOC_MAGIC 0xc4
5567 +#define VCHIQ_INVALID_HANDLE -1
5570 + VCHIQ_SERVICE_PARAMS_T params;
5573 + int handle; /* OUT */
5574 +} VCHIQ_CREATE_SERVICE_T;
5579 + const VCHIQ_ELEMENT_T *elements;
5580 +} VCHIQ_QUEUE_MESSAGE_T;
5587 + VCHIQ_BULK_MODE_T mode;
5588 +} VCHIQ_QUEUE_BULK_TRANSFER_T;
5591 + VCHIQ_REASON_T reason;
5592 + VCHIQ_HEADER_T *header;
5593 + void *service_userdata;
5594 + void *bulk_userdata;
5595 +} VCHIQ_COMPLETION_DATA_T;
5599 + VCHIQ_COMPLETION_DATA_T *buf;
5601 + int msgbufcount; /* IN/OUT */
5603 +} VCHIQ_AWAIT_COMPLETION_T;
5610 +} VCHIQ_DEQUEUE_MESSAGE_T;
5614 + VCHIQ_CONFIG_T *pconfig;
5615 +} VCHIQ_GET_CONFIG_T;
5619 + VCHIQ_SERVICE_OPTION_T option;
5621 +} VCHIQ_SET_SERVICE_OPTION_T;
5626 +} VCHIQ_DUMP_MEM_T;
5628 +#define VCHIQ_IOC_CONNECT _IO(VCHIQ_IOC_MAGIC, 0)
5629 +#define VCHIQ_IOC_SHUTDOWN _IO(VCHIQ_IOC_MAGIC, 1)
5630 +#define VCHIQ_IOC_CREATE_SERVICE _IOWR(VCHIQ_IOC_MAGIC, 2, VCHIQ_CREATE_SERVICE_T)
5631 +#define VCHIQ_IOC_REMOVE_SERVICE _IO(VCHIQ_IOC_MAGIC, 3)
5632 +#define VCHIQ_IOC_QUEUE_MESSAGE _IOW(VCHIQ_IOC_MAGIC, 4, VCHIQ_QUEUE_MESSAGE_T)
5633 +#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT _IOW(VCHIQ_IOC_MAGIC, 5, VCHIQ_QUEUE_BULK_TRANSFER_T)
5634 +#define VCHIQ_IOC_QUEUE_BULK_RECEIVE _IOW(VCHIQ_IOC_MAGIC, 6, VCHIQ_QUEUE_BULK_TRANSFER_T)
5635 +#define VCHIQ_IOC_AWAIT_COMPLETION _IOW(VCHIQ_IOC_MAGIC, 7, VCHIQ_AWAIT_COMPLETION_T)
5636 +#define VCHIQ_IOC_DEQUEUE_MESSAGE _IOW(VCHIQ_IOC_MAGIC, 8, VCHIQ_DEQUEUE_MESSAGE_T)
5637 +#define VCHIQ_IOC_GET_CLIENT_ID _IO(VCHIQ_IOC_MAGIC, 9)
5638 +#define VCHIQ_IOC_GET_CONFIG _IOW(VCHIQ_IOC_MAGIC, 10, VCHIQ_GET_CONFIG_T)
5639 +#define VCHIQ_IOC_CLOSE_SERVICE _IO(VCHIQ_IOC_MAGIC, 11)
5640 +#define VCHIQ_IOC_USE_SERVICE _IO(VCHIQ_IOC_MAGIC, 12)
5641 +#define VCHIQ_IOC_RELEASE_SERVICE _IO(VCHIQ_IOC_MAGIC, 13)
5642 +#define VCHIQ_IOC_SET_SERVICE_OPTION _IOW(VCHIQ_IOC_MAGIC, 14, VCHIQ_SET_SERVICE_OPTION_T)
5643 +#define VCHIQ_IOC_DUMP_PHYS_MEM _IOW(VCHIQ_IOC_MAGIC, 15, VCHIQ_DUMP_MEM_T)
5644 +#define VCHIQ_IOC_MAX 15
5648 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
5650 +/*****************************************************************************
5651 +* Copyright 2001 - 2011 Broadcom Corporation. All rights reserved.
5653 +* Unless you and Broadcom execute a separate written software license
5654 +* agreement governing use of this software, this software is licensed to you
5655 +* under the terms of the GNU General Public License version 2, available at
5656 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
5658 +* Notwithstanding the above, under no circumstances may you combine this
5659 +* software in any way with any other Broadcom software provided under a
5660 +* license other than the GPL, without Broadcom's express prior written
5662 +*****************************************************************************/
5664 +/* ---- Include Files ---------------------------------------------------- */
5666 +#include <linux/kernel.h>
5667 +#include <linux/module.h>
5669 +#include "vchiq_core.h"
5670 +#include "vchiq_arm.h"
5671 +#include "interface/vcos/vcos_logging.h"
5673 +/* ---- Public Variables ------------------------------------------------- */
5675 +extern VCOS_LOG_CAT_T vchiq_core_log_category;
5676 +#define VCOS_LOG_CATEGORY (&vchiq_core_log_category)
5678 +/* ---- Private Constants and Types -------------------------------------- */
5680 +struct vchiq_instance_struct {
5681 + VCHIQ_STATE_T *state;
5686 +/****************************************************************************
5690 +***************************************************************************/
5692 +VCHIQ_STATUS_T vchiq_initialise( VCHIQ_INSTANCE_T *instanceOut )
5694 + VCHIQ_STATUS_T status = VCHIQ_ERROR;
5695 + VCHIQ_STATE_T *state;
5696 + VCHIQ_INSTANCE_T instance = NULL;
5698 + vcos_log_trace( "%s called", __func__ );
5700 + state = vchiq_get_state();
5703 + printk( KERN_ERR "%s: videocore not initialized\n", __func__ );
5707 + instance = kzalloc( sizeof(*instance), GFP_KERNEL );
5710 + printk( KERN_ERR "%s: error allocating vchiq instance\n", __func__ );
5714 + instance->connected = 0;
5715 + instance->state = state;
5717 + *instanceOut = instance;
5719 + status = VCHIQ_SUCCESS;
5722 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5727 +/****************************************************************************
5731 +***************************************************************************/
5733 +VCHIQ_STATUS_T vchiq_shutdown( VCHIQ_INSTANCE_T instance )
5735 + VCHIQ_STATUS_T status;
5736 + VCHIQ_STATE_T *state = instance->state;
5738 + vcos_log_trace( "%s(%p) called", __func__, instance );
5740 + vcos_mutex_lock(&state->mutex);
5742 + /* Remove all services */
5743 + status = vchiq_shutdown_internal(state, instance);
5745 + vcos_mutex_unlock(&state->mutex);
5747 + if (status == VCHIQ_SUCCESS)
5750 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5755 +/****************************************************************************
5757 +* vchiq_is_connected
5759 +***************************************************************************/
5761 +int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
5763 + return instance->connected;
5766 +/****************************************************************************
5770 +***************************************************************************/
5772 +VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
5774 + VCHIQ_STATUS_T status;
5775 + VCHIQ_STATE_T *state = instance->state;
5777 + vcos_log_trace( "%s(%p) called", __func__, instance );
5779 + if (vcos_mutex_lock(&state->mutex) != VCOS_SUCCESS) {
5780 + vcos_log_trace( "%s: call to vcos_mutex_lock failed", __func__ );
5781 + status = VCHIQ_RETRY;
5784 + status = vchiq_connect_internal(state, instance);
5786 + if (status == VCHIQ_SUCCESS)
5787 + instance->connected = 1;
5789 + vcos_mutex_unlock(&state->mutex);
5792 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5797 +/****************************************************************************
5799 +* vchiq_add_service
5801 +***************************************************************************/
5803 +VCHIQ_STATUS_T vchiq_add_service(
5804 + VCHIQ_INSTANCE_T instance,
5806 + VCHIQ_CALLBACK_T callback,
5808 + VCHIQ_SERVICE_HANDLE_T *pservice)
5810 + VCHIQ_SERVICE_PARAMS_T params;
5812 + params.fourcc = fourcc;
5813 + params.callback = callback;
5814 + params.userdata = userdata;
5815 + params.version = 0;
5816 + params.version_min = 0;
5818 + return vchiq_add_service_params(instance, ¶ms, pservice);
5821 +/****************************************************************************
5823 +* vchiq_open_service
5825 +***************************************************************************/
5827 +VCHIQ_STATUS_T vchiq_open_service(
5828 + VCHIQ_INSTANCE_T instance,
5830 + VCHIQ_CALLBACK_T callback,
5832 + VCHIQ_SERVICE_HANDLE_T *pservice)
5834 + VCHIQ_SERVICE_PARAMS_T params;
5836 + params.fourcc = fourcc;
5837 + params.callback = callback;
5838 + params.userdata = userdata;
5839 + params.version = 0;
5840 + params.version_min = 0;
5842 + return vchiq_open_service_params(instance, ¶ms, pservice);
5845 +/****************************************************************************
5847 +* vchiq_add_service_params
5849 +***************************************************************************/
5851 +VCHIQ_STATUS_T vchiq_add_service_params(
5852 + VCHIQ_INSTANCE_T instance,
5853 + const VCHIQ_SERVICE_PARAMS_T *params,
5854 + VCHIQ_SERVICE_HANDLE_T *pservice)
5856 + VCHIQ_STATUS_T status;
5857 + VCHIQ_STATE_T *state = instance->state;
5858 + VCHIQ_SERVICE_T *service;
5861 + vcos_log_trace( "%s(%p) called", __func__, instance );
5865 + srvstate = vchiq_is_connected( instance )
5866 + ? VCHIQ_SRVSTATE_LISTENING
5867 + : VCHIQ_SRVSTATE_HIDDEN;
5869 + vcos_mutex_lock(&state->mutex);
5871 + service = vchiq_add_service_internal(
5877 + vcos_mutex_unlock(&state->mutex);
5881 + *pservice = &service->base;
5882 + status = VCHIQ_SUCCESS;
5886 + status = VCHIQ_ERROR;
5889 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5894 +/****************************************************************************
5896 +* vchiq_open_service_params
5898 +***************************************************************************/
5900 +VCHIQ_STATUS_T vchiq_open_service_params(
5901 + VCHIQ_INSTANCE_T instance,
5902 + const VCHIQ_SERVICE_PARAMS_T *params,
5903 + VCHIQ_SERVICE_HANDLE_T *pservice)
5905 + VCHIQ_STATUS_T status = VCHIQ_ERROR;
5906 + VCHIQ_STATE_T *state = instance->state;
5907 + VCHIQ_SERVICE_T *service;
5909 + vcos_log_trace( "%s(%p) called", __func__, instance );
5913 + if (!vchiq_is_connected(instance))
5916 + vcos_mutex_lock(&state->mutex);
5918 + service = vchiq_add_service_internal(state,
5920 + VCHIQ_SRVSTATE_OPENING,
5923 + vcos_mutex_unlock(&state->mutex);
5927 + status = vchiq_open_service_internal(service, current->pid);
5928 + if ( status == VCHIQ_SUCCESS )
5929 + *pservice = &service->base;
5931 + vchiq_remove_service(&service->base);
5935 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5940 +EXPORT_SYMBOL(vchiq_initialise);
5941 +EXPORT_SYMBOL(vchiq_shutdown);
5942 +EXPORT_SYMBOL(vchiq_connect);
5943 +EXPORT_SYMBOL(vchiq_add_service);
5944 +EXPORT_SYMBOL(vchiq_open_service);
5945 +EXPORT_SYMBOL(vchiq_add_service_params);
5946 +EXPORT_SYMBOL(vchiq_open_service_params);
5948 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_lib.c
5951 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
5953 + * This program is free software; you can redistribute it and/or modify
5954 + * it under the terms of the GNU General Public License as published by
5955 + * the Free Software Foundation; either version 2 of the License, or
5956 + * (at your option) any later version.
5958 + * This program is distributed in the hope that it will be useful,
5959 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5960 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5961 + * GNU General Public License for more details.
5963 + * You should have received a copy of the GNU General Public License
5964 + * along with this program; if not, write to the Free Software
5965 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5968 +#include <unistd.h>
5970 +#include <sys/ioctl.h>
5974 +#include "vchiq_cfg.h"
5975 +#include "vchiq_ioctl.h"
5976 +#include "interface/vchi/vchi.h"
5977 +#include "interface/vchi/common/endian.h"
5978 +#include "interface/vcos/vcos.h"
5980 +#define VCHIQ_MAX_INSTANCE_SERVICES 32
5981 +#define MSGBUF_SIZE (VCHIQ_MAX_MSG_SIZE + sizeof(VCHIQ_HEADER_T))
5983 +#define RETRY(r,x) do { r = x; } while ((r == -1) && (errno == EINTR))
5985 +#define VCOS_LOG_CATEGORY (&vchiq_lib_log_category)
5987 +typedef struct vchiq_service_struct
5989 + VCHIQ_SERVICE_BASE_T base;
5992 + VCHI_CALLBACK_T vchi_callback;
5998 +typedef struct vchiq_service_struct VCHI_SERVICE_T;
6000 +struct vchiq_instance_struct
6005 + VCOS_THREAD_T completion_thread;
6006 + VCOS_MUTEX_T mutex;
6007 + int used_services;
6008 + VCHIQ_SERVICE_T services[VCHIQ_MAX_INSTANCE_SERVICES];
6011 +typedef struct vchiq_instance_struct VCHI_STATE_T;
6014 +static VCOS_LOG_LEVEL_T vchiq_default_lib_log_level = VCOS_LOG_WARN;
6015 +static VCOS_LOG_CAT_T vchiq_lib_log_category;
6016 +static VCOS_MUTEX_T vchiq_lib_mutex;
6017 +static void *free_msgbufs;
6020 +/* Local utility functions */
6021 +static VCHIQ_INSTANCE_T
6022 +vchiq_lib_init(void);
6024 +static void *completion_thread(void *);
6026 +static VCHIQ_STATUS_T
6027 +create_service(VCHIQ_INSTANCE_T instance,
6028 + const VCHIQ_SERVICE_PARAMS_T *params,
6029 + VCHI_CALLBACK_T vchi_callback,
6031 + VCHIQ_SERVICE_HANDLE_T *pservice);
6034 +fill_peek_buf(VCHI_SERVICE_T *service,
6035 + VCHI_FLAGS_T flags);
6038 +alloc_msgbuf(void);
6041 +free_msgbuf(void *buf);
6043 +static __inline int
6044 +is_valid_instance(VCHIQ_INSTANCE_T instance)
6046 + return (instance == &vchiq_instance) && (instance->initialised > 0);
6054 +vchiq_initialise(VCHIQ_INSTANCE_T *pinstance)
6056 + VCHIQ_INSTANCE_T instance;
6058 + instance = vchiq_lib_init();
6060 + vcos_log_trace( "%s: returning instance handle %p", __func__, instance );
6062 + *pinstance = instance;
6064 + return (instance != NULL) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6068 +vchiq_shutdown(VCHIQ_INSTANCE_T instance)
6070 + vcos_log_trace( "%s called", __func__ );
6072 + if (!is_valid_instance(instance))
6073 + return VCHIQ_ERROR;
6075 + vcos_mutex_lock(&instance->mutex);
6077 + if (instance->initialised == 1)
6081 + instance->initialised = -1; /* Enter limbo */
6083 + /* Remove all services */
6085 + for (i = 0; i < instance->used_services; i++)
6087 + if (instance->services[i].handle != VCHIQ_INVALID_HANDLE)
6089 + vchiq_remove_service(&instance->services[i].base);
6090 + instance->services[i].handle = VCHIQ_INVALID_HANDLE;
6094 + if (instance->connected)
6097 + RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_SHUTDOWN, 0));
6098 + vcos_assert(ret == 0);
6099 + vcos_thread_join(&instance->completion_thread, NULL);
6100 + instance->connected = 0;
6103 + close(instance->fd);
6104 + instance->fd = -1;
6106 + else if (instance->initialised > 1)
6108 + instance->initialised--;
6111 + vcos_mutex_unlock(&instance->mutex);
6113 + vcos_global_lock();
6115 + if (instance->initialised == -1)
6117 + vcos_mutex_delete(&instance->mutex);
6118 + instance->initialised = 0;
6121 + vcos_global_unlock();
6123 + vcos_log_trace( "%s returning", __func__ );
6125 + return VCHIQ_SUCCESS;
6129 +vchiq_connect(VCHIQ_INSTANCE_T instance)
6131 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
6133 + vcos_log_trace( "%s called", __func__ );
6135 + if (!is_valid_instance(instance))
6136 + return VCHIQ_ERROR;
6138 + vcos_mutex_lock(&instance->mutex);
6140 + if (!instance->connected)
6142 + int ret = ioctl(instance->fd, VCHIQ_IOC_CONNECT, 0);
6145 + VCOS_THREAD_ATTR_T attrs;
6146 + instance->connected = 1;
6147 + vcos_thread_attr_init(&attrs);
6148 + vcos_thread_create(&instance->completion_thread, "VCHIQ completion",
6149 + &attrs, completion_thread, instance);
6153 + status = VCHIQ_ERROR;
6157 + vcos_mutex_unlock(&instance->mutex);
6163 +vchiq_add_service(VCHIQ_INSTANCE_T instance,
6165 + VCHIQ_CALLBACK_T callback,
6167 + VCHIQ_SERVICE_HANDLE_T *pservice)
6169 + VCHIQ_SERVICE_PARAMS_T params;
6171 + params.fourcc = fourcc;
6172 + params.callback = callback;
6173 + params.userdata = userdata;
6174 + params.version = 0;
6175 + params.version_min = 0;
6177 + return vchiq_add_service_params(instance, ¶ms, pservice);
6181 +vchiq_open_service(VCHIQ_INSTANCE_T instance,
6183 + VCHIQ_CALLBACK_T callback,
6185 + VCHIQ_SERVICE_HANDLE_T *pservice)
6187 + VCHIQ_SERVICE_PARAMS_T params;
6189 + params.fourcc = fourcc;
6190 + params.callback = callback;
6191 + params.userdata = userdata;
6192 + params.version = 0;
6193 + params.version_min = 0;
6195 + return vchiq_open_service_params(instance, ¶ms, pservice);
6199 +vchiq_add_service_params(VCHIQ_INSTANCE_T instance,
6200 + const VCHIQ_SERVICE_PARAMS_T *params,
6201 + VCHIQ_SERVICE_HANDLE_T *pservice)
6203 + VCHIQ_STATUS_T status;
6205 + vcos_log_trace( "%s called fourcc = 0x%08x (%c%c%c%c)",
6208 + (params->fourcc >> 24) & 0xff,
6209 + (params->fourcc >> 16) & 0xff,
6210 + (params->fourcc >> 8) & 0xff,
6211 + (params->fourcc ) & 0xff );
6213 + if (!params->callback)
6214 + return VCHIQ_ERROR;
6216 + if (!is_valid_instance(instance))
6217 + return VCHIQ_ERROR;
6219 + status = create_service(instance,
6221 + NULL/*vchi_callback*/,
6225 + vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*pservice );
6231 +vchiq_open_service_params(VCHIQ_INSTANCE_T instance,
6232 + const VCHIQ_SERVICE_PARAMS_T *params,
6233 + VCHIQ_SERVICE_HANDLE_T *pservice)
6235 + VCHIQ_STATUS_T status;
6237 + vcos_log_trace( "%s called fourcc = 0x%08x (%c%c%c%c)",
6240 + (params->fourcc >> 24) & 0xff,
6241 + (params->fourcc >> 16) & 0xff,
6242 + (params->fourcc >> 8) & 0xff,
6243 + (params->fourcc ) & 0xff );
6245 + if (!params->callback)
6246 + return VCHIQ_ERROR;
6248 + if (!is_valid_instance(instance))
6249 + return VCHIQ_ERROR;
6251 + status = create_service(instance,
6253 + NULL/*vchi_callback*/,
6257 + vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*pservice );
6263 +vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
6265 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6268 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6270 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_CLOSE_SERVICE, service->handle));
6273 + return VCHIQ_ERROR;
6275 + service->handle = VCHIQ_INVALID_HANDLE;
6276 + return VCHIQ_SUCCESS;
6280 +vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
6282 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6285 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6287 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
6290 + return VCHIQ_ERROR;
6292 + service->handle = VCHIQ_INVALID_HANDLE;
6293 + return VCHIQ_SUCCESS;
6297 +vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
6298 + const VCHIQ_ELEMENT_T *elements,
6301 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6302 + VCHIQ_QUEUE_MESSAGE_T args;
6305 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6307 + args.handle = service->handle;
6308 + args.elements = elements;
6309 + args.count = count;
6310 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
6312 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6316 +vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle,
6317 + VCHIQ_HEADER_T *header)
6319 + vcos_log_trace( "%s handle=%08x, header=%x", __func__, (uint32_t)handle, (uint32_t)header );
6321 + free_msgbuf(header);
6325 +vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
6330 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6331 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6334 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6336 + args.handle = service->handle;
6337 + args.data = (void *)data;
6339 + args.userdata = userdata;
6340 + args.mode = VCHIQ_BULK_MODE_CALLBACK;
6341 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
6343 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6347 +vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
6352 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6353 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6356 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6358 + args.handle = service->handle;
6361 + args.userdata = userdata;
6362 + args.mode = VCHIQ_BULK_MODE_CALLBACK;
6363 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
6365 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6369 +vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
6370 + VCHI_MEM_HANDLE_T memhandle,
6371 + const void *offset,
6375 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6377 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6379 + return vchiq_queue_bulk_transmit(handle, offset, size, userdata);
6383 +vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
6384 + VCHI_MEM_HANDLE_T memhandle,
6389 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6391 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6393 + return vchiq_queue_bulk_receive(handle, offset, size, userdata);
6397 +vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
6401 + VCHIQ_BULK_MODE_T mode)
6403 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6404 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6407 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6409 + args.handle = service->handle;
6410 + args.data = (void *)data;
6412 + args.userdata = userdata;
6414 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
6416 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6420 +vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
6424 + VCHIQ_BULK_MODE_T mode)
6426 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6427 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6430 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6432 + args.handle = service->handle;
6435 + args.userdata = userdata;
6437 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
6439 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6443 +vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
6444 + VCHI_MEM_HANDLE_T memhandle,
6445 + const void *offset,
6448 + VCHIQ_BULK_MODE_T mode)
6450 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6452 + return vchiq_bulk_transmit(handle, offset, size, userdata, mode);
6456 +vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
6457 + VCHI_MEM_HANDLE_T memhandle,
6461 + VCHIQ_BULK_MODE_T mode)
6463 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6465 + return vchiq_bulk_receive(handle, offset, size, userdata, mode);
6469 +vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
6471 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6473 + return ioctl(service->fd, VCHIQ_IOC_GET_CLIENT_ID, service->handle);
6477 +vchiq_get_config(VCHIQ_INSTANCE_T instance,
6479 + VCHIQ_CONFIG_T *pconfig)
6481 + VCHIQ_GET_CONFIG_T args;
6484 + if (!is_valid_instance(instance))
6485 + return VCHIQ_ERROR;
6487 + args.config_size = config_size;
6488 + args.pconfig = pconfig;
6490 + RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_GET_CONFIG, &args));
6492 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6496 +vchiq_use_service( const VCHIQ_SERVICE_HANDLE_T handle )
6498 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6500 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
6505 +vchiq_release_service( const VCHIQ_SERVICE_HANDLE_T handle )
6507 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6509 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
6514 +vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
6515 + VCHIQ_SERVICE_OPTION_T option, int value)
6517 + VCHIQ_SET_SERVICE_OPTION_T args;
6518 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6521 + args.handle = service->handle;
6522 + args.option = option;
6523 + args.value = value;
6525 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_SET_SERVICE_OPTION, &args));
6527 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6534 +/* ----------------------------------------------------------------------
6535 + * return pointer to the mphi message driver function table
6536 + * -------------------------------------------------------------------- */
6537 +const VCHI_MESSAGE_DRIVER_T *
6538 +vchi_mphi_message_driver_func_table( void )
6543 +/* ----------------------------------------------------------------------
6544 + * return a pointer to the 'single' connection driver fops
6545 + * -------------------------------------------------------------------- */
6546 +const VCHI_CONNECTION_API_T *
6547 +single_get_func_table( void )
6552 +VCHI_CONNECTION_T *
6553 +vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
6554 + const VCHI_MESSAGE_DRIVER_T * low_level )
6556 + vcos_unused(function_table);
6557 + vcos_unused(low_level);
6562 +/***********************************************************
6563 + * Name: vchi_msg_peek
6565 + * Arguments: const VCHI_SERVICE_HANDLE_T handle,
6567 + * uint32_t *msg_size,
6568 + * VCHI_FLAGS_T flags
6570 + * Description: Routine to return a pointer to the current message (to allow in place processing)
6571 + * The message can be removed using vchi_msg_remove when you're finished
6573 + * Returns: int32_t - success == 0
6575 + ***********************************************************/
6577 +vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
6579 + uint32_t *msg_size,
6580 + VCHI_FLAGS_T flags )
6582 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6585 + ret = fill_peek_buf(service, flags);
6589 + *data = service->peek_buf;
6590 + *msg_size = service->peek_size;
6596 +/***********************************************************
6597 + * Name: vchi_msg_remove
6599 + * Arguments: const VCHI_SERVICE_HANDLE_T handle,
6601 + * Description: Routine to remove a message (after it has been read with vchi_msg_peek)
6603 + * Returns: int32_t - success == 0
6605 + ***********************************************************/
6607 +vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle )
6609 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6611 + /* Why would you call vchi_msg_remove without calling vchi_msg_peek first? */
6612 + vcos_assert(service->peek_size >= 0);
6614 + /* Invalidate the content but reuse the buffer */
6615 + service->peek_size = -1;
6620 +/***********************************************************
6621 + * Name: vchi_msg_queue
6623 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
6624 + * const void *data,
6625 + * uint32_t data_size,
6626 + * VCHI_FLAGS_T flags,
6627 + * void *msg_handle,
6629 + * Description: Thin wrapper to queue a message onto a connection
6631 + * Returns: int32_t - success == 0
6633 + ***********************************************************/
6635 +vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
6636 + const void * data,
6637 + uint32_t data_size,
6638 + VCHI_FLAGS_T flags,
6639 + void * msg_handle )
6641 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6642 + VCHIQ_QUEUE_MESSAGE_T args;
6643 + VCHIQ_ELEMENT_T element = {data, data_size};
6646 + vcos_unused(msg_handle);
6647 + vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
6649 + args.handle = service->handle;
6650 + args.elements = &element;
6652 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
6657 +/***********************************************************
6658 + * Name: vchi_bulk_queue_receive
6660 + * Arguments: VCHI_BULK_HANDLE_T handle,
6662 + * const uint32_t data_size,
6663 + * VCHI_FLAGS_T flags
6664 + * void *bulk_handle
6666 + * Description: Routine to setup a rcv buffer
6668 + * Returns: int32_t - success == 0
6670 + ***********************************************************/
6672 +vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
6674 + uint32_t data_size,
6675 + VCHI_FLAGS_T flags,
6676 + void * bulk_handle )
6678 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6679 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6682 + switch ((int)flags) {
6683 + case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6684 + args.mode = VCHIQ_BULK_MODE_CALLBACK;
6686 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
6687 + args.mode = VCHIQ_BULK_MODE_BLOCKING;
6689 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6690 + case VCHI_FLAGS_NONE:
6691 + args.mode = VCHIQ_BULK_MODE_NOCALLBACK;
6698 + args.handle = service->handle;
6699 + args.data = data_dst;
6700 + args.size = data_size;
6701 + args.userdata = bulk_handle;
6702 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
6707 +/***********************************************************
6708 + * Name: vchi_bulk_queue_transmit
6710 + * Arguments: VCHI_BULK_HANDLE_T handle,
6711 + * const void *data_src,
6712 + * uint32_t data_size,
6713 + * VCHI_FLAGS_T flags,
6714 + * void *bulk_handle
6716 + * Description: Routine to transmit some data
6718 + * Returns: int32_t - success == 0
6720 + ***********************************************************/
6722 +vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
6723 + const void * data_src,
6724 + uint32_t data_size,
6725 + VCHI_FLAGS_T flags,
6726 + void * bulk_handle )
6728 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6729 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6732 + switch ((int)flags) {
6733 + case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6734 + args.mode = VCHIQ_BULK_MODE_CALLBACK;
6736 + case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
6737 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
6738 + args.mode = VCHIQ_BULK_MODE_BLOCKING;
6740 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6741 + case VCHI_FLAGS_NONE:
6742 + args.mode = VCHIQ_BULK_MODE_NOCALLBACK;
6749 + args.handle = service->handle;
6750 + args.data = (void *)data_src;
6751 + args.size = data_size;
6752 + args.userdata = bulk_handle;
6753 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
6758 +/***********************************************************
6759 + * Name: vchi_msg_dequeue
6761 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
6763 + * uint32_t max_data_size_to_read,
6764 + * uint32_t *actual_msg_size
6765 + * VCHI_FLAGS_T flags
6767 + * Description: Routine to dequeue a message into the supplied buffer
6769 + * Returns: int32_t - success == 0
6771 + ***********************************************************/
6773 +vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
6775 + uint32_t max_data_size_to_read,
6776 + uint32_t *actual_msg_size,
6777 + VCHI_FLAGS_T flags )
6779 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6780 + VCHIQ_DEQUEUE_MESSAGE_T args;
6783 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
6785 + if (service->peek_size >= 0)
6787 + fprintf(stderr, "vchi_msg_dequeue -> using peek buffer\n");
6788 + if ((uint32_t)service->peek_size <= max_data_size_to_read)
6790 + memcpy(data, service->peek_buf, service->peek_size);
6791 + *actual_msg_size = service->peek_size;
6792 + /* Invalidate the peek data, but retain the buffer */
6793 + service->peek_size = -1;
6803 + args.handle = service->handle;
6804 + args.blocking = (flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
6805 + args.bufsize = max_data_size_to_read;
6807 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_DEQUEUE_MESSAGE, &args));
6810 + *actual_msg_size = ret;
6815 + if ((ret < 0) && (errno != EWOULDBLOCK))
6816 + fprintf(stderr, "vchi_msg_dequeue -> %d(%d)\n", ret, errno);
6821 +/***********************************************************
6822 + * Name: vchi_msg_queuev
6824 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
6825 + * const void *data,
6826 + * uint32_t data_size,
6827 + * VCHI_FLAGS_T flags,
6828 + * void *msg_handle
6830 + * Description: Thin wrapper to queue a message onto a connection
6832 + * Returns: int32_t - success == 0
6834 + ***********************************************************/
6836 +vcos_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
6837 +vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == offsetof(VCHIQ_ELEMENT_T, data));
6838 +vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == offsetof(VCHIQ_ELEMENT_T, size));
6841 +vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
6842 + VCHI_MSG_VECTOR_T * vector,
6844 + VCHI_FLAGS_T flags,
6845 + void *msg_handle )
6847 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6848 + VCHIQ_QUEUE_MESSAGE_T args;
6851 + vcos_unused(msg_handle);
6853 + vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
6855 + args.handle = service->handle;
6856 + args.elements = (const VCHIQ_ELEMENT_T *)vector;
6857 + args.count = count;
6858 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
6863 +/***********************************************************
6864 + * Name: vchi_held_msg_release
6866 + * Arguments: VCHI_HELD_MSG_T *message
6868 + * Description: Routine to release a held message (after it has been read with vchi_msg_hold)
6870 + * Returns: int32_t - success == 0
6872 + ***********************************************************/
6874 +vchi_held_msg_release( VCHI_HELD_MSG_T *message )
6878 + if (message && message->message && !message->service)
6880 + free_msgbuf(message->message);
6887 +/***********************************************************
6888 + * Name: vchi_msg_hold
6890 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
6892 + * uint32_t *msg_size,
6893 + * VCHI_FLAGS_T flags,
6894 + * VCHI_HELD_MSG_T *message_handle
6896 + * Description: Routine to return a pointer to the current message (to allow in place processing)
6897 + * The message is dequeued - don't forget to release the message using
6898 + * vchi_held_msg_release when you're finished
6900 + * Returns: int32_t - success == 0
6902 + ***********************************************************/
6904 +vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
6906 + uint32_t *msg_size,
6907 + VCHI_FLAGS_T flags,
6908 + VCHI_HELD_MSG_T *message_handle )
6910 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6913 + ret = fill_peek_buf(service, flags);
6917 + *data = service->peek_buf;
6918 + *msg_size = service->peek_size;
6920 + message_handle->message = service->peek_buf;
6921 + message_handle->service = NULL;
6923 + service->peek_size = -1;
6924 + service->peek_buf = NULL;
6930 +/***********************************************************
6931 + * Name: vchi_initialise
6933 + * Arguments: VCHI_INSTANCE_T *instance_handle
6934 + * VCHI_CONNECTION_T **connections
6935 + * const uint32_t num_connections
6937 + * Description: Initialises the hardware but does not transmit anything
6938 + * When run as a Host App this will be called twice hence the need
6939 + * to malloc the state information
6941 + * Returns: 0 if successful, failure otherwise
6943 + ***********************************************************/
6945 +vchi_initialise( VCHI_INSTANCE_T *instance_handle )
6947 + VCHIQ_INSTANCE_T instance;
6949 + instance = vchiq_lib_init();
6951 + vcos_log_trace( "%s: returning instance handle %p", __func__, instance );
6953 + *instance_handle = (VCHI_INSTANCE_T)instance;
6955 + return (instance != NULL) ? 0 : -1;
6958 +/***********************************************************
6959 + * Name: vchi_connect
6961 + * Arguments: VCHI_CONNECTION_T **connections
6962 + * const uint32_t num_connections
6963 + * VCHI_INSTANCE_T instance_handle )
6965 + * Description: Starts the command service on each connection,
6966 + * causing INIT messages to be pinged back and forth
6968 + * Returns: 0 if successful, failure otherwise
6970 + ***********************************************************/
6972 +vchi_connect( VCHI_CONNECTION_T **connections,
6973 + const uint32_t num_connections,
6974 + VCHI_INSTANCE_T instance_handle )
6976 + VCHIQ_STATUS_T status;
6978 + vcos_unused(connections);
6979 + vcos_unused(num_connections);
6981 + status = vchiq_connect((VCHIQ_INSTANCE_T)instance_handle);
6983 + return (status == VCHIQ_SUCCESS) ? 0 : -1;
6987 +/***********************************************************
6988 + * Name: vchi_disconnect
6990 + * Arguments: VCHI_INSTANCE_T instance_handle
6992 + * Description: Stops the command service on each connection,
6993 + * causing DE-INIT messages to be pinged back and forth
6995 + * Returns: 0 if successful, failure otherwise
6997 + ***********************************************************/
6999 +vchi_disconnect( VCHI_INSTANCE_T instance_handle )
7001 + VCHIQ_STATUS_T status;
7003 + status = vchiq_shutdown((VCHIQ_INSTANCE_T)instance_handle);
7005 + return (status == VCHIQ_SUCCESS) ? 0 : -1;
7009 +/***********************************************************
7010 + * Name: vchi_service_open
7011 + * Name: vchi_service_create
7013 + * Arguments: VCHI_INSTANCE_T *instance_handle
7014 + * SERVICE_CREATION_T *setup,
7015 + * VCHI_SERVICE_HANDLE_T *handle
7017 + * Description: Routine to open a service
7019 + * Returns: int32_t - success == 0
7021 + ***********************************************************/
7023 +vchi_service_open( VCHI_INSTANCE_T instance_handle,
7024 + SERVICE_CREATION_T *setup,
7025 + VCHI_SERVICE_HANDLE_T *handle )
7027 + VCHIQ_SERVICE_PARAMS_T params;
7028 + VCHIQ_STATUS_T status;
7030 + memset(¶ms, 0, sizeof(params));
7031 + params.fourcc = setup->service_id;
7032 + params.userdata = setup->callback_param;
7034 + status = create_service((VCHIQ_INSTANCE_T)instance_handle,
7038 + (VCHIQ_SERVICE_HANDLE_T *)handle);
7040 + return (status == VCHIQ_SUCCESS) ? 0 : -1;
7044 +vchi_service_create( VCHI_INSTANCE_T instance_handle,
7045 + SERVICE_CREATION_T *setup, VCHI_SERVICE_HANDLE_T *handle )
7047 + VCHIQ_SERVICE_PARAMS_T params;
7048 + VCHIQ_STATUS_T status;
7050 + memset(¶ms, 0, sizeof(params));
7051 + params.fourcc = setup->service_id;
7052 + params.userdata = setup->callback_param;
7054 + status = create_service((VCHIQ_INSTANCE_T)instance_handle,
7058 + (VCHIQ_SERVICE_HANDLE_T *)handle);
7060 + return (status == VCHIQ_SUCCESS) ? 0 : -1;
7064 +vchi_service_close( const VCHI_SERVICE_HANDLE_T handle )
7066 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7068 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
7071 + service->handle = VCHIQ_INVALID_HANDLE;
7077 +vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle )
7079 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7081 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
7084 + service->handle = VCHIQ_INVALID_HANDLE;
7089 +/* ----------------------------------------------------------------------
7090 + * read a uint32_t from buffer.
7091 + * network format is defined to be little endian
7092 + * -------------------------------------------------------------------- */
7094 +vchi_readbuf_uint32( const void *_ptr )
7096 + const unsigned char *ptr = _ptr;
7097 + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
7100 +/* ----------------------------------------------------------------------
7101 + * write a uint32_t to buffer.
7102 + * network format is defined to be little endian
7103 + * -------------------------------------------------------------------- */
7105 +vchi_writebuf_uint32( void *_ptr, uint32_t value )
7107 + unsigned char *ptr = _ptr;
7108 + ptr[0] = (unsigned char)((value >> 0) & 0xFF);
7109 + ptr[1] = (unsigned char)((value >> 8) & 0xFF);
7110 + ptr[2] = (unsigned char)((value >> 16) & 0xFF);
7111 + ptr[3] = (unsigned char)((value >> 24) & 0xFF);
7114 +/* ----------------------------------------------------------------------
7115 + * read a uint16_t from buffer.
7116 + * network format is defined to be little endian
7117 + * -------------------------------------------------------------------- */
7119 +vchi_readbuf_uint16( const void *_ptr )
7121 + const unsigned char *ptr = _ptr;
7122 + return ptr[0] | (ptr[1] << 8);
7125 +/* ----------------------------------------------------------------------
7126 + * write a uint16_t into the buffer.
7127 + * network format is defined to be little endian
7128 + * -------------------------------------------------------------------- */
7130 +vchi_writebuf_uint16( void *_ptr, uint16_t value )
7132 + unsigned char *ptr = _ptr;
7133 + ptr[0] = (value >> 0) & 0xFF;
7134 + ptr[1] = (value >> 8) & 0xFF;
7137 +/***********************************************************
7138 + * Name: vchi_service_use
7140 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
7142 + * Description: Routine to increment refcount on a service
7146 + ***********************************************************/
7148 +vchi_service_use( const VCHI_SERVICE_HANDLE_T handle )
7150 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7152 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
7156 +/***********************************************************
7157 + * Name: vchi_service_release
7159 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
7161 + * Description: Routine to decrement refcount on a service
7165 + ***********************************************************/
7166 +int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle )
7168 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7170 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
7175 + * Support functions
7178 +static VCHIQ_INSTANCE_T
7179 +vchiq_lib_init(void)
7181 + static int mutex_initialised = 0;
7182 + static VCOS_MUTEX_T vchiq_lib_mutex;
7183 + VCHIQ_INSTANCE_T instance = &vchiq_instance;
7185 + vcos_global_lock();
7186 + if (!mutex_initialised)
7188 + vcos_mutex_create(&vchiq_lib_mutex, "vchiq-init");
7190 + vcos_log_set_level( &vchiq_lib_log_category, vchiq_default_lib_log_level );
7191 + vcos_log_register( "vchiq_lib", &vchiq_lib_log_category );
7193 + mutex_initialised = 1;
7195 + vcos_global_unlock();
7197 + vcos_mutex_lock(&vchiq_lib_mutex);
7199 + if (instance->initialised == 0)
7201 + instance->fd = open("/dev/vchiq", O_RDWR);
7202 + if (instance->fd >= 0)
7204 + VCHIQ_GET_CONFIG_T args;
7205 + VCHIQ_CONFIG_T config;
7207 + args.config_size = sizeof(config);
7208 + args.pconfig = &config;
7209 + RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_GET_CONFIG, &args));
7210 + if ((ret == 0) && (config.version >= VCHIQ_VERSION_MIN) && (config.version_min <= VCHIQ_VERSION))
7212 + instance->used_services = 0;
7213 + vcos_mutex_create(&instance->mutex, "VCHIQ instance");
7214 + instance->initialised = 1;
7220 + vcos_log_error("Incompatible VCHIQ library - driver version %d (min %d), library version %d (min %d)",
7221 + config.version, config.version_min, VCHIQ_VERSION, VCHIQ_VERSION_MIN);
7225 + vcos_log_error("Very incompatible VCHIQ library - cannot retrieve driver version");
7227 + close(instance->fd);
7236 + else if (instance->initialised > 0)
7238 + instance->initialised++;
7241 + vcos_mutex_unlock(&vchiq_lib_mutex);
7247 +completion_thread(void *arg)
7249 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)arg;
7250 + VCHIQ_AWAIT_COMPLETION_T args;
7251 + VCHIQ_COMPLETION_DATA_T completions[8];
7254 + static const VCHI_CALLBACK_REASON_T vchiq_reason_to_vchi[] =
7256 + VCHI_CALLBACK_SERVICE_OPENED, // VCHIQ_SERVICE_OPENED
7257 + VCHI_CALLBACK_SERVICE_CLOSED, // VCHIQ_SERVICE_CLOSED
7258 + VCHI_CALLBACK_MSG_AVAILABLE, // VCHIQ_MESSAGE_AVAILABLE
7259 + VCHI_CALLBACK_BULK_SENT, // VCHIQ_BULK_TRANSMIT_DONE
7260 + VCHI_CALLBACK_BULK_RECEIVED, // VCHIQ_BULK_RECEIVE_DONE
7261 + VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, // VCHIQ_BULK_TRANSMIT_ABORTED
7262 + VCHI_CALLBACK_BULK_RECEIVE_ABORTED, // VCHIQ_BULK_RECEIVE_ABORTED
7265 + args.count = vcos_countof(completions);
7266 + args.buf = completions;
7267 + args.msgbufsize = MSGBUF_SIZE;
7268 + args.msgbufcount = 0;
7269 + args.msgbufs = msgbufs;
7275 + while ((unsigned int)args.msgbufcount < vcos_countof(msgbufs))
7277 + void *msgbuf = alloc_msgbuf();
7280 + msgbufs[args.msgbufcount++] = msgbuf;
7284 + fprintf(stderr, "vchiq_lib: failed to allocate a message buffer\n");
7285 + vcos_demand(args.msgbufcount != 0);
7289 + RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_AWAIT_COMPLETION, &args));
7294 + for (i = 0; i < ret; i++)
7296 + VCHIQ_COMPLETION_DATA_T *completion = &completions[i];
7297 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)completion->service_userdata;
7298 + if (service->base.callback)
7300 + vcos_log_trace( "callback(%x, %x, %x, %x)",
7301 + completion->reason, (uint32_t)completion->header,
7302 + (uint32_t)&service->base, (uint32_t)completion->bulk_userdata );
7303 + service->base.callback(completion->reason, completion->header,
7304 + &service->base, completion->bulk_userdata);
7306 + else if (service->vchi_callback)
7308 + VCHI_CALLBACK_REASON_T vchi_reason =
7309 + vchiq_reason_to_vchi[completion->reason];
7310 + service->vchi_callback(service->base.userdata, vchi_reason, completion->bulk_userdata);
7317 +static VCHIQ_STATUS_T
7318 +create_service(VCHIQ_INSTANCE_T instance,
7319 + const VCHIQ_SERVICE_PARAMS_T *params,
7320 + VCHI_CALLBACK_T vchi_callback,
7322 + VCHIQ_SERVICE_HANDLE_T *pservice)
7324 + VCHIQ_SERVICE_T *service = NULL;
7325 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
7328 + if (!is_valid_instance(instance))
7329 + return VCHIQ_ERROR;
7331 + vcos_mutex_lock(&instance->mutex);
7333 + /* Find a free service */
7336 + /* Find a free service */
7337 + for (i = 0; i < instance->used_services; i++)
7339 + if (instance->services[i].handle == VCHIQ_INVALID_HANDLE)
7341 + service = &instance->services[i];
7348 + for (i = (instance->used_services - 1); i >= 0; i--)
7350 + VCHIQ_SERVICE_T *srv = &instance->services[i];
7351 + if (srv->handle == VCHIQ_INVALID_HANDLE)
7356 + (srv->base.fourcc == params->fourcc) &&
7357 + ((srv->base.callback != params->callback) ||
7358 + (srv->vchi_callback != vchi_callback)))
7360 + /* There is another server using this fourcc which doesn't match */
7362 + status = VCHIQ_ERROR;
7368 + if (!service && (status == VCHIQ_SUCCESS) &&
7369 + (instance->used_services < VCHIQ_MAX_INSTANCE_SERVICES))
7370 + service = &instance->services[instance->used_services++];
7374 + VCHIQ_CREATE_SERVICE_T args;
7376 + service->base.fourcc = params->fourcc;
7377 + service->base.callback = params->callback;
7378 + service->vchi_callback = vchi_callback;
7379 + service->base.userdata = params->userdata;
7380 + service->fd = instance->fd;
7381 + service->peek_size = -1;
7382 + service->peek_buf = NULL;
7384 + args.params = *params;
7385 + args.params.userdata = service;
7386 + args.is_open = is_open;
7387 + args.is_vchi = (params->callback == NULL);
7388 + args.handle = -1; /* OUT parameter */
7389 + RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_CREATE_SERVICE, &args));
7391 + service->handle = args.handle;
7393 + status = VCHIQ_ERROR;
7396 + *pservice = (status == VCHIQ_SUCCESS) ? &service->base : NULL;
7398 + vcos_mutex_unlock(&instance->mutex);
7404 +fill_peek_buf(VCHI_SERVICE_T *service,
7405 + VCHI_FLAGS_T flags)
7407 + VCHIQ_DEQUEUE_MESSAGE_T args;
7410 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
7412 + if (service->peek_size < 0)
7414 + if (!service->peek_buf)
7415 + service->peek_buf = alloc_msgbuf();
7417 + if (service->peek_buf)
7419 + args.handle = service->handle;
7420 + args.blocking = (flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
7421 + args.bufsize = MSGBUF_SIZE;
7422 + args.buf = service->peek_buf;
7424 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_DEQUEUE_MESSAGE, &args));
7428 + service->peek_size = ret;
7450 + vcos_mutex_lock(&vchiq_lib_mutex);
7451 + msgbuf = free_msgbufs;
7453 + free_msgbufs = *(void **)msgbuf;
7454 + vcos_mutex_unlock(&vchiq_lib_mutex);
7456 + msgbuf = malloc(MSGBUF_SIZE);
7461 +free_msgbuf(void *buf)
7463 + vcos_mutex_lock(&vchiq_lib_mutex);
7464 + *(void **)buf = free_msgbufs;
7465 + free_msgbufs = buf;
7466 + vcos_mutex_unlock(&vchiq_lib_mutex);
7469 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
7471 +/*****************************************************************************
7472 +* Copyright 2001 - 2010 Broadcom Corporation. All rights reserved.
7474 +* Unless you and Broadcom execute a separate written software license
7475 +* agreement governing use of this software, this software is licensed to you
7476 +* under the terms of the GNU General Public License version 2, available at
7477 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
7479 +* Notwithstanding the above, under no circumstances may you combine this
7480 +* software in any way with any other Broadcom software provided under a
7481 +* license other than the GPL, without Broadcom's express prior written
7483 +*****************************************************************************/
7485 +#ifndef VCHIQ_MEMDRV_H
7486 +#define VCHIQ_MEMDRV_H
7488 +/* ---- Include Files ----------------------------------------------------- */
7490 +#include <linux/kernel.h>
7491 +#include "vchiq_if.h"
7493 +/* ---- Constants and Types ---------------------------------------------- */
7497 + void *armSharedMemVirt;
7498 + dma_addr_t armSharedMemPhys;
7499 + size_t armSharedMemSize;
7501 + void *vcSharedMemVirt;
7502 + dma_addr_t vcSharedMemPhys;
7503 + size_t vcSharedMemSize;
7505 +} VCHIQ_SHARED_MEM_INFO_T;
7507 +/* ---- Variable Externs ------------------------------------------------- */
7509 +/* ---- Function Prototypes ---------------------------------------------- */
7511 +void vchiq_get_shared_mem_info( VCHIQ_SHARED_MEM_INFO_T *info );
7513 +VCHIQ_STATUS_T vchiq_memdrv_initialise(void);
7517 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
7520 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
7522 + * This program is free software; you can redistribute it and/or modify
7523 + * it under the terms of the GNU General Public License as published by
7524 + * the Free Software Foundation; either version 2 of the License, or
7525 + * (at your option) any later version.
7527 + * This program is distributed in the hope that it will be useful,
7528 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7529 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7530 + * GNU General Public License for more details.
7532 + * You should have received a copy of the GNU General Public License
7533 + * along with this program; if not, write to the Free Software
7534 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
7537 +#ifndef VCHIQ_PAGELIST_H
7538 +#define VCHIQ_PAGELIST_H
7541 +#define PAGE_SIZE 4096
7543 +#define CACHE_LINE_SIZE 32
7544 +#define PAGELIST_WRITE 0
7545 +#define PAGELIST_READ 1
7546 +#define PAGELIST_READ_WITH_FRAGMENTS 2
7548 +typedef struct pagelist_struct {
7549 + unsigned long length;
7550 + unsigned short type;
7551 + unsigned short offset;
7552 + unsigned long addrs[1]; /* N.B. 12 LSBs hold the number of following
7553 + pages at consecutive addresses. */
7556 +typedef struct fragments_struct {
7557 + char headbuf[CACHE_LINE_SIZE];
7558 + char tailbuf[CACHE_LINE_SIZE];
7561 +#endif /* VCHIQ_PAGELIST_H */
7563 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
7566 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
7568 + * This program is free software; you can redistribute it and/or modify
7569 + * it under the terms of the GNU General Public License as published by
7570 + * the Free Software Foundation; either version 2 of the License, or
7571 + * (at your option) any later version.
7573 + * This program is distributed in the hope that it will be useful,
7574 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7575 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7576 + * GNU General Public License for more details.
7578 + * You should have received a copy of the GNU General Public License
7579 + * along with this program; if not, write to the Free Software
7580 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
7583 +#include "interface/vchi/vchi.h"
7585 +#include "vchiq_core.h"
7587 +#include "vchiq_util.h"
7589 +#include <stddef.h>
7591 +#if defined(__KERNEL__)
7592 +#include <linux/module.h>
7595 +#define vchiq_status_to_vchi(status) ((int32_t)status)
7598 + VCHIQ_SERVICE_HANDLE_T handle;
7600 + VCHIU_QUEUE_T queue;
7602 + VCHI_CALLBACK_T callback;
7603 + void *callback_param;
7606 +/* ----------------------------------------------------------------------
7607 + * return pointer to the mphi message driver function table
7608 + * -------------------------------------------------------------------- */
7610 +const VCHI_MESSAGE_DRIVER_T *
7611 +mphi_get_func_table( void )
7617 +/* ----------------------------------------------------------------------
7618 + * return pointer to the mphi message driver function table
7619 + * -------------------------------------------------------------------- */
7620 +const VCHI_MESSAGE_DRIVER_T *
7621 +vchi_mphi_message_driver_func_table( void )
7626 +/* ----------------------------------------------------------------------
7627 + * return a pointer to the 'single' connection driver fops
7628 + * -------------------------------------------------------------------- */
7629 +const VCHI_CONNECTION_API_T *
7630 +single_get_func_table( void )
7635 +VCHI_CONNECTION_T * vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
7636 + const VCHI_MESSAGE_DRIVER_T * low_level)
7638 + vcos_unused(function_table);
7639 + vcos_unused(low_level);
7643 +/***********************************************************
7644 + * Name: vchi_msg_peek
7646 + * Arguments: const VCHI_SERVICE_HANDLE_T handle,
7648 + * uint32_t *msg_size,
7649 + * VCHI_FLAGS_T flags
7651 + * Description: Routine to return a pointer to the current message (to allow in place processing)
7652 + * The message can be removed using vchi_msg_remove when you're finished
7654 + * Returns: int32_t - success == 0
7656 + ***********************************************************/
7657 +int32_t vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
7659 + uint32_t *msg_size,
7660 + VCHI_FLAGS_T flags )
7662 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7663 + VCHIQ_HEADER_T *header;
7665 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
7667 + if (flags == VCHI_FLAGS_NONE)
7668 + if (vchiu_queue_is_empty(&service->queue))
7671 + header = vchiu_queue_peek(&service->queue);
7673 + *data = header->data;
7674 + *msg_size = header->size;
7679 +/***********************************************************
7680 + * Name: vchi_msg_remove
7682 + * Arguments: const VCHI_SERVICE_HANDLE_T handle,
7684 + * Description: Routine to remove a message (after it has been read with vchi_msg_peek)
7686 + * Returns: int32_t - success == 0
7688 + ***********************************************************/
7689 +int32_t vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle )
7691 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7692 + VCHIQ_HEADER_T *header;
7694 + header = vchiu_queue_pop(&service->queue);
7696 + vchiq_release_message(service->handle, header);
7701 +/***********************************************************
7702 + * Name: vchi_msg_queue
7704 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
7705 + * const void *data,
7706 + * uint32_t data_size,
7707 + * VCHI_FLAGS_T flags,
7708 + * void *msg_handle,
7710 + * Description: Thin wrapper to queue a message onto a connection
7712 + * Returns: int32_t - success == 0
7714 + ***********************************************************/
7715 +int32_t vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
7716 + const void * data,
7717 + uint32_t data_size,
7718 + VCHI_FLAGS_T flags,
7719 + void * msg_handle )
7721 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7722 + VCHIQ_ELEMENT_T element = {data, data_size};
7723 + VCHIQ_STATUS_T status;
7725 + vcos_unused(msg_handle);
7727 + vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
7729 + status = vchiq_queue_message(service->handle, &element, 1);
7731 + // On some platforms, like linux kernel, vchiq_queue_message() may return
7732 + // VCHIQ_RETRY, so we need to implment a retry mechanism since this
7733 + // function is supposed to block until queued
7734 + while ( status == VCHIQ_RETRY )
7737 + status = vchiq_queue_message(service->handle, &element, 1);
7740 + return vchiq_status_to_vchi(status);
7743 +/***********************************************************
7744 + * Name: vchi_bulk_queue_receive
7746 + * Arguments: VCHI_BULK_HANDLE_T handle,
7748 + * const uint32_t data_size,
7749 + * VCHI_FLAGS_T flags
7750 + * void *bulk_handle
7752 + * Description: Routine to setup a rcv buffer
7754 + * Returns: int32_t - success == 0
7756 + ***********************************************************/
7757 +int32_t vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
7759 + uint32_t data_size,
7760 + VCHI_FLAGS_T flags,
7761 + void * bulk_handle )
7763 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7764 + VCHIQ_BULK_MODE_T mode;
7765 + VCHIQ_STATUS_T status;
7767 + switch ((int)flags) {
7768 + case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7769 + vcos_assert(service->callback);
7770 + mode = VCHIQ_BULK_MODE_CALLBACK;
7772 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7773 + mode = VCHIQ_BULK_MODE_BLOCKING;
7775 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7776 + case VCHI_FLAGS_NONE:
7777 + mode = VCHIQ_BULK_MODE_NOCALLBACK;
7781 + return vchiq_status_to_vchi(VCHIQ_ERROR);
7784 + status = vchiq_bulk_receive(service->handle, data_dst, data_size,
7785 + bulk_handle, mode);
7787 + // On some platforms, like linux kernel, vchiq_bulk_receive() may return
7788 + // VCHIQ_RETRY, so we need to implment a retry mechanism since this
7789 + // function is supposed to block until queued
7790 + while ( status == VCHIQ_RETRY )
7793 + status = vchiq_bulk_receive(service->handle, data_dst, data_size,
7794 + bulk_handle, mode);
7797 + return vchiq_status_to_vchi(status);
7800 +/***********************************************************
7801 + * Name: vchi_bulk_queue_receive_reloc
7803 + * Arguments: VCHI_BULK_HANDLE_T handle,
7804 + * VCHI_MEM_HANDLE_T h
7806 + * const uint32_t data_size,
7807 + * VCHI_FLAGS_T flags
7808 + * void *bulk_handle
7810 + * Description: Routine to setup a relocatable rcv buffer
7812 + * Returns: int32_t - success == 0
7814 + ***********************************************************/
7815 +int32_t vchi_bulk_queue_receive_reloc( const VCHI_SERVICE_HANDLE_T handle,
7816 + VCHI_MEM_HANDLE_T h,
7818 + uint32_t data_size,
7819 + const VCHI_FLAGS_T flags,
7820 + void * const bulk_handle )
7822 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7823 + VCHIQ_BULK_MODE_T mode;
7824 + VCHIQ_STATUS_T status;
7826 + switch ((int)flags) {
7827 + case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7828 + vcos_assert(service->callback);
7829 + mode = VCHIQ_BULK_MODE_CALLBACK;
7831 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7832 + mode = VCHIQ_BULK_MODE_BLOCKING;
7834 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7835 + case VCHI_FLAGS_NONE:
7836 + mode = VCHIQ_BULK_MODE_NOCALLBACK;
7840 + return vchiq_status_to_vchi(VCHIQ_ERROR);
7843 + status = vchiq_bulk_receive_handle(service->handle, h, (void*)offset,
7844 + data_size, bulk_handle, mode);
7846 + // On some platforms, like linux kernel, vchiq_bulk_receive_handle() may
7847 + // return VCHIQ_RETRY, so we need to implment a retry mechanism since
7848 + // this function is supposed to block until queued
7849 + while ( status == VCHIQ_RETRY )
7852 + status = vchiq_bulk_receive_handle(service->handle, h, (void*)offset,
7853 + data_size, bulk_handle, mode);
7856 + return vchiq_status_to_vchi(status);
7859 +/***********************************************************
7860 + * Name: vchi_bulk_queue_transmit
7862 + * Arguments: VCHI_BULK_HANDLE_T handle,
7863 + * const void *data_src,
7864 + * uint32_t data_size,
7865 + * VCHI_FLAGS_T flags,
7866 + * void *bulk_handle
7868 + * Description: Routine to transmit some data
7870 + * Returns: int32_t - success == 0
7872 + ***********************************************************/
7873 +int32_t vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
7874 + const void * data_src,
7875 + uint32_t data_size,
7876 + VCHI_FLAGS_T flags,
7877 + void * bulk_handle )
7879 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7880 + VCHIQ_BULK_MODE_T mode;
7881 + VCHIQ_STATUS_T status;
7883 + switch ((int)flags) {
7884 + case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7885 + vcos_assert(service->callback);
7886 + mode = VCHIQ_BULK_MODE_CALLBACK;
7888 + case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
7889 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7890 + mode = VCHIQ_BULK_MODE_BLOCKING;
7892 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7893 + case VCHI_FLAGS_NONE:
7894 + mode = VCHIQ_BULK_MODE_NOCALLBACK;
7898 + return vchiq_status_to_vchi(VCHIQ_ERROR);
7901 + status = vchiq_bulk_transmit(service->handle, data_src, data_size,
7902 + bulk_handle, mode);
7904 + // On some platforms, like linux kernel, vchiq_bulk_transmit() may return
7905 + // VCHIQ_RETRY, so we need to implment a retry mechanism since this
7906 + // function is supposed to block until queued
7907 + while ( status == VCHIQ_RETRY )
7910 + status = vchiq_bulk_transmit(service->handle, data_src, data_size,
7911 + bulk_handle, mode);
7914 + return vchiq_status_to_vchi(status);
7917 +/***********************************************************
7918 + * Name: vchi_bulk_queue_transmit_reloc
7920 + * Arguments: VCHI_BULK_HANDLE_T handle,
7921 + * VCHI_MEM_HANDLE_T h_src,
7922 + * uint32_t offset,
7923 + * uint32_t data_size,
7924 + * VCHI_FLAGS_T flags,
7925 + * void *bulk_handle
7927 + * Description: Routine to transmit some data from a relocatable buffer
7929 + * Returns: int32_t - success == 0
7931 + ***********************************************************/
7933 +int32_t vchi_bulk_queue_transmit_reloc( VCHI_SERVICE_HANDLE_T handle,
7934 + VCHI_MEM_HANDLE_T h_src,
7936 + uint32_t data_size,
7937 + VCHI_FLAGS_T flags,
7938 + void * const bulk_handle )
7940 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7941 + VCHIQ_BULK_MODE_T mode;
7942 + VCHIQ_STATUS_T status;
7944 + switch ((int)flags) {
7945 + case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7946 + vcos_assert(service->callback);
7947 + mode = VCHIQ_BULK_MODE_CALLBACK;
7949 + case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
7950 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7951 + mode = VCHIQ_BULK_MODE_BLOCKING;
7953 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7954 + case VCHI_FLAGS_NONE:
7955 + mode = VCHIQ_BULK_MODE_NOCALLBACK;
7959 + return vchiq_status_to_vchi(VCHIQ_ERROR);
7962 + status = vchiq_bulk_transmit_handle(service->handle, h_src, (void*)offset,
7963 + data_size, bulk_handle, mode);
7965 + // On some platforms, like linux kernel, vchiq_bulk_transmit_handle() may
7966 + // return VCHIQ_RETRY, so we need to implment a retry mechanism since this
7967 + // function is supposed to block until queued
7968 + while ( status == VCHIQ_RETRY )
7971 + status = vchiq_bulk_transmit_handle(service->handle, h_src, (void*)offset,
7972 + data_size, bulk_handle, mode);
7975 + return vchiq_status_to_vchi(status);
7978 +/***********************************************************
7979 + * Name: vchi_msg_dequeue
7981 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
7983 + * uint32_t max_data_size_to_read,
7984 + * uint32_t *actual_msg_size
7985 + * VCHI_FLAGS_T flags
7987 + * Description: Routine to dequeue a message into the supplied buffer
7989 + * Returns: int32_t - success == 0
7991 + ***********************************************************/
7992 +int32_t vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
7994 + uint32_t max_data_size_to_read,
7995 + uint32_t *actual_msg_size,
7996 + VCHI_FLAGS_T flags )
7998 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7999 + VCHIQ_HEADER_T *header;
8001 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
8003 + if (flags == VCHI_FLAGS_NONE)
8004 + if (vchiu_queue_is_empty(&service->queue))
8007 + header = vchiu_queue_pop(&service->queue);
8009 + memcpy(data, header->data, header->size < max_data_size_to_read ? header->size : max_data_size_to_read);
8011 + *actual_msg_size = header->size;
8013 + vchiq_release_message(service->handle, header);
8018 +/***********************************************************
8019 + * Name: vchi_msg_queuev
8021 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
8022 + * const void *data,
8023 + * uint32_t data_size,
8024 + * VCHI_FLAGS_T flags,
8025 + * void *msg_handle
8027 + * Description: Thin wrapper to queue a message onto a connection
8029 + * Returns: int32_t - success == 0
8031 + ***********************************************************/
8033 +vcos_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
8034 +vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == offsetof(VCHIQ_ELEMENT_T, data));
8035 +vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == offsetof(VCHIQ_ELEMENT_T, size));
8037 +int32_t vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
8038 + VCHI_MSG_VECTOR_T * vector,
8040 + VCHI_FLAGS_T flags,
8041 + void *msg_handle )
8043 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8045 + vcos_unused(msg_handle);
8047 + vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
8049 + return vchiq_status_to_vchi(vchiq_queue_message(service->handle, (const VCHIQ_ELEMENT_T *)vector, count));
8054 +/***********************************************************
8055 + * Name: vchi_msg_queuev_ex
8057 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
8058 + * VCHI_MSG_VECTOR_EX_T *vector
8060 + * VCHI_FLAGS_T flags,
8061 + * void *msg_handle
8063 + * Description: Thin wrapper to queue an array of messages onto a connection
8064 + * Supports resolving MEM_HANDLE's at last possible moment to avoid deadlocks.
8066 + * Currently just a shim, so deadlocks are still possible!
8068 + * Returns: int32_t - success == 0
8070 + ***********************************************************/
8071 +int32_t vchi_msg_queuev_ex( const VCHI_SERVICE_HANDLE_T handle,
8072 + VCHI_MSG_VECTOR_EX_T * const vector,
8073 + const uint32_t count,
8074 + const VCHI_FLAGS_T flags,
8075 + void * const msg_handle )
8077 + int32_t success = -1;
8078 + // For now, we don't actually support sending anything other than
8079 + // a pointer, so handles have to be patched up; this is likely
8080 + // to cause deadlocks. This code is not designed to be either
8081 + // pretty, efficient, or deadlock-free.
8083 + #define max_vecs 16
8084 + VCHI_MSG_VECTOR_T copy[max_vecs];
8085 + const uint8_t *orig[max_vecs];
8088 + vcos_unused(msg_handle);
8090 + if (count > sizeof(copy)/sizeof(copy[0]))
8096 + for (i=0; i<count; i++)
8098 + VCHI_MSG_VECTOR_EX_T *v = vector+i;
8100 + switch (vector[i].type)
8102 + case VCHI_VEC_POINTER:
8103 + copy[i].vec_base = v->u.ptr.vec_base;
8104 + copy[i].vec_len = v->u.ptr.vec_len;
8106 + case VCHI_VEC_HANDLE:
8107 + vcos_assert(v->u.handle.offset+v->u.handle.vec_len <= mem_get_size(v->u.handle.handle));
8108 + copy[i].vec_base = (uint8_t*)mem_lock(v->u.handle.handle) + v->u.handle.offset;
8109 + orig[i] = copy[i].vec_base;
8110 + copy[i].vec_len = v->u.handle.vec_len;
8112 + case VCHI_VEC_LIST:
8113 + vcos_assert(0); // FIXME: implement this
8119 + success = vchi_msg_queuev( handle,
8122 + flags &~ VCHI_FLAGS_INTERNAL,
8124 + if (vcos_verify(success == 0))
8126 + // now we need to patch up the vectors if any have been only partially consumed, and
8127 + // unlock memory handles.
8129 + for (i=0; i<count; i++)
8131 + VCHI_MSG_VECTOR_EX_T *v = vector+i;
8133 + switch (vector[i].type)
8135 + case VCHI_VEC_POINTER:
8136 + if (flags & VCHI_FLAGS_ALLOW_PARTIAL)
8138 + v->u.ptr.vec_base = copy[i].vec_base;
8139 + v->u.ptr.vec_len = copy[i].vec_len;
8142 + case VCHI_VEC_HANDLE:
8143 + mem_unlock(v->u.handle.handle);
8144 + if (flags & VCHI_FLAGS_ALLOW_PARTIAL)
8146 + const uint8_t *old = orig[i];
8147 + uint32_t change = (const uint8_t*)copy[i].vec_base-old;
8148 + v->u.handle.offset += change;
8149 + v->u.handle.vec_len -= change;
8158 + return vchiq_status_to_vchi(success);
8163 +/***********************************************************
8164 + * Name: vchi_held_msg_release
8166 + * Arguments: VCHI_HELD_MSG_T *message
8168 + * Description: Routine to release a held message (after it has been read with vchi_msg_hold)
8170 + * Returns: int32_t - success == 0
8172 + ***********************************************************/
8173 +int32_t vchi_held_msg_release( VCHI_HELD_MSG_T *message )
8175 + vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service, (VCHIQ_HEADER_T *)message->message);
8180 +/***********************************************************
8181 + * Name: vchi_msg_hold
8183 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
8185 + * uint32_t *msg_size,
8186 + * VCHI_FLAGS_T flags,
8187 + * VCHI_HELD_MSG_T *message_handle
8189 + * Description: Routine to return a pointer to the current message (to allow in place processing)
8190 + * The message is dequeued - don't forget to release the message using
8191 + * vchi_held_msg_release when you're finished
8193 + * Returns: int32_t - success == 0
8195 + ***********************************************************/
8196 +int32_t vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
8198 + uint32_t *msg_size,
8199 + VCHI_FLAGS_T flags,
8200 + VCHI_HELD_MSG_T *message_handle )
8202 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8203 + VCHIQ_HEADER_T *header;
8205 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
8207 + if (flags == VCHI_FLAGS_NONE)
8208 + if (vchiu_queue_is_empty(&service->queue))
8211 + header = vchiu_queue_pop(&service->queue);
8213 + *data = header->data;
8214 + *msg_size = header->size;
8216 + message_handle->service = (struct opaque_vchi_service_t *)service->handle;
8217 + message_handle->message = header;
8222 +/***********************************************************
8223 + * Name: vchi_initialise
8225 + * Arguments: VCHI_INSTANCE_T *instance_handle
8226 + * VCHI_CONNECTION_T **connections
8227 + * const uint32_t num_connections
8229 + * Description: Initialises the hardware but does not transmit anything
8230 + * When run as a Host App this will be called twice hence the need
8231 + * to malloc the state information
8233 + * Returns: 0 if successful, failure otherwise
8235 + ***********************************************************/
8237 +int32_t vchi_initialise( VCHI_INSTANCE_T *instance_handle )
8239 + VCHIQ_INSTANCE_T instance;
8240 + VCHIQ_STATUS_T status;
8242 + status = vchiq_initialise(&instance);
8244 + *instance_handle = (VCHI_INSTANCE_T)instance;
8246 + return vchiq_status_to_vchi(status);
8249 +/***********************************************************
8250 + * Name: vchi_connect
8252 + * Arguments: VCHI_CONNECTION_T **connections
8253 + * const uint32_t num_connections
8254 + * VCHI_INSTANCE_T instance_handle )
8256 + * Description: Starts the command service on each connection,
8257 + * causing INIT messages to be pinged back and forth
8259 + * Returns: 0 if successful, failure otherwise
8261 + ***********************************************************/
8262 +int32_t vchi_connect( VCHI_CONNECTION_T **connections,
8263 + const uint32_t num_connections,
8264 + VCHI_INSTANCE_T instance_handle )
8266 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8268 + vcos_unused(connections);
8269 + vcos_unused(num_connections);
8271 + return vchiq_connect(instance);
8275 +/***********************************************************
8276 + * Name: vchi_disconnect
8278 + * Arguments: VCHI_INSTANCE_T instance_handle
8280 + * Description: Stops the command service on each connection,
8281 + * causing DE-INIT messages to be pinged back and forth
8283 + * Returns: 0 if successful, failure otherwise
8285 + ***********************************************************/
8286 +int32_t vchi_disconnect( VCHI_INSTANCE_T instance_handle )
8288 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8289 + return vchiq_status_to_vchi(vchiq_shutdown(instance));
8293 +/***********************************************************
8294 + * Name: vchi_service_open
8295 + * Name: vchi_service_create
8297 + * Arguments: VCHI_INSTANCE_T *instance_handle
8298 + * SERVICE_CREATION_T *setup,
8299 + * VCHI_SERVICE_HANDLE_T *handle
8301 + * Description: Routine to open a service
8303 + * Returns: int32_t - success == 0
8305 + ***********************************************************/
8307 +static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
8309 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
8312 + case VCHIQ_MESSAGE_AVAILABLE:
8313 + vchiu_queue_push(&service->queue, header);
8315 + if (service->callback)
8316 + service->callback(service->callback_param, VCHI_CALLBACK_MSG_AVAILABLE, NULL);
8318 + case VCHIQ_BULK_TRANSMIT_DONE:
8319 + if (service->callback)
8320 + service->callback(service->callback_param, VCHI_CALLBACK_BULK_SENT, bulk_user);
8322 + case VCHIQ_BULK_RECEIVE_DONE:
8323 + if (service->callback)
8324 + service->callback(service->callback_param, VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
8326 + case VCHIQ_SERVICE_CLOSED:
8327 + if (service->callback)
8328 + service->callback(service->callback_param, VCHI_CALLBACK_SERVICE_CLOSED, NULL);
8330 + case VCHIQ_SERVICE_OPENED:
8331 + /* No equivalent VCHI reason */
8333 + case VCHIQ_BULK_TRANSMIT_ABORTED:
8334 + if (service->callback)
8335 + service->callback(service->callback_param, VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, bulk_user);
8337 + case VCHIQ_BULK_RECEIVE_ABORTED:
8338 + if (service->callback)
8339 + service->callback(service->callback_param, VCHI_CALLBACK_BULK_RECEIVE_ABORTED, bulk_user);
8346 + return VCHIQ_SUCCESS;
8349 +static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
8350 + SERVICE_CREATION_T *setup)
8352 + SHIM_SERVICE_T *service = vcos_calloc(1, sizeof(SHIM_SERVICE_T), "vchiq_shim");
8354 + vcos_unused(instance);
8358 + if (vchiu_queue_init(&service->queue, 64))
8360 + service->callback = setup->callback;
8361 + service->callback_param = setup->callback_param;
8365 + vcos_free(service);
8373 +static void service_free(SHIM_SERVICE_T *service)
8377 + vchiu_queue_delete(&service->queue);
8378 + vcos_free((void*)service);
8382 +int32_t vchi_service_open( VCHI_INSTANCE_T instance_handle,
8383 + SERVICE_CREATION_T *setup,
8384 + VCHI_SERVICE_HANDLE_T *handle)
8386 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8387 + SHIM_SERVICE_T *service = service_alloc(instance, setup);
8390 + VCHIQ_STATUS_T status = vchiq_open_service(instance, setup->service_id, shim_callback, service, &service->handle);
8391 + if (status != VCHIQ_SUCCESS)
8393 + service_free(service);
8398 + *handle = (VCHI_SERVICE_HANDLE_T)service;
8400 + return (service != NULL) ? 0 : -1;
8403 +int32_t vchi_service_create( VCHI_INSTANCE_T instance_handle,
8404 + SERVICE_CREATION_T *setup,
8405 + VCHI_SERVICE_HANDLE_T *handle )
8407 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8408 + SHIM_SERVICE_T *service = service_alloc(instance, setup);
8411 + VCHIQ_STATUS_T status = vchiq_add_service(instance, setup->service_id, shim_callback, service, &service->handle);
8412 + if (status != VCHIQ_SUCCESS)
8414 + service_free(service);
8419 + *handle = (VCHI_SERVICE_HANDLE_T)service;
8421 + return (service != NULL) ? 0 : -1;
8424 +int32_t vchi_service_close( const VCHI_SERVICE_HANDLE_T handle )
8426 + vcos_unused(handle);
8432 +/* ----------------------------------------------------------------------
8433 + * read a uint32_t from buffer.
8434 + * network format is defined to be little endian
8435 + * -------------------------------------------------------------------- */
8437 +vchi_readbuf_uint32( const void *_ptr )
8439 + const unsigned char *ptr = _ptr;
8440 + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
8443 +/* ----------------------------------------------------------------------
8444 + * write a uint32_t to buffer.
8445 + * network format is defined to be little endian
8446 + * -------------------------------------------------------------------- */
8448 +vchi_writebuf_uint32( void *_ptr, uint32_t value )
8450 + unsigned char *ptr = _ptr;
8451 + ptr[0] = (unsigned char)((value >> 0) & 0xFF);
8452 + ptr[1] = (unsigned char)((value >> 8) & 0xFF);
8453 + ptr[2] = (unsigned char)((value >> 16) & 0xFF);
8454 + ptr[3] = (unsigned char)((value >> 24) & 0xFF);
8457 +/* ----------------------------------------------------------------------
8458 + * read a uint16_t from buffer.
8459 + * network format is defined to be little endian
8460 + * -------------------------------------------------------------------- */
8462 +vchi_readbuf_uint16( const void *_ptr )
8464 + const unsigned char *ptr = _ptr;
8465 + return ptr[0] | (ptr[1] << 8);
8468 +/* ----------------------------------------------------------------------
8469 + * write a uint16_t into the buffer.
8470 + * network format is defined to be little endian
8471 + * -------------------------------------------------------------------- */
8473 +vchi_writebuf_uint16( void *_ptr, uint16_t value )
8475 + unsigned char *ptr = _ptr;
8476 + ptr[0] = (value >> 0) & 0xFF;
8477 + ptr[1] = (value >> 8) & 0xFF;
8480 +/***********************************************************
8481 + * Name: vchi_service_use
8483 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
8485 + * Description: Routine to increment refcount on a service
8489 + ***********************************************************/
8490 +int32_t vchi_service_use( const VCHI_SERVICE_HANDLE_T handle )
8493 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8496 + ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
8501 +/***********************************************************
8502 + * Name: vchi_service_release
8504 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
8506 + * Description: Routine to decrement refcount on a service
8510 + ***********************************************************/
8511 +int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle )
8514 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8517 + ret = vchiq_status_to_vchi(vchiq_release_service(service->handle));
8522 +#if defined(__KERNEL__)
8523 +EXPORT_SYMBOL(vchi_initialise);
8524 +EXPORT_SYMBOL(vchi_connect);
8525 +EXPORT_SYMBOL(vchi_bulk_queue_transmit);
8526 +EXPORT_SYMBOL(vchi_msg_dequeue);
8527 +EXPORT_SYMBOL(vchi_msg_queue);
8528 +EXPORT_SYMBOL(vchi_msg_queuev);
8529 +EXPORT_SYMBOL(vchi_service_close);
8530 +EXPORT_SYMBOL(vchi_service_open);
8531 +EXPORT_SYMBOL(vchi_service_create);
8532 +EXPORT_SYMBOL(vchi_service_use);
8533 +EXPORT_SYMBOL(vchi_service_release);
8536 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
8539 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
8541 + * This program is free software; you can redistribute it and/or modify
8542 + * it under the terms of the GNU General Public License as published by
8543 + * the Free Software Foundation; either version 2 of the License, or
8544 + * (at your option) any later version.
8546 + * This program is distributed in the hope that it will be useful,
8547 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8548 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8549 + * GNU General Public License for more details.
8551 + * You should have received a copy of the GNU General Public License
8552 + * along with this program; if not, write to the Free Software
8553 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
8556 +#include "vchiq_util.h"
8558 +#if !defined(__KERNEL__)
8559 +#include <stdlib.h>
8562 +static __inline int is_pow2(int i)
8564 + return i && !(i & (i - 1));
8567 +int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size)
8569 + vcos_assert(is_pow2(size));
8571 + queue->size = size;
8575 + vcos_event_create(&queue->pop, "vchiu");
8576 + vcos_event_create(&queue->push, "vchiu");
8578 + queue->storage = vcos_malloc(size * sizeof(VCHIQ_HEADER_T *), VCOS_FUNCTION);
8579 + if (queue->storage == NULL)
8581 + vchiu_queue_delete(queue);
8587 +void vchiu_queue_delete(VCHIU_QUEUE_T *queue)
8589 + vcos_event_delete(&queue->pop);
8590 + vcos_event_delete(&queue->push);
8591 + if (queue->storage != NULL)
8592 + vcos_free(queue->storage);
8595 +int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue)
8597 + return queue->read == queue->write;
8600 +void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header)
8602 + while (queue->write == queue->read + queue->size)
8603 + vcos_event_wait(&queue->pop);
8605 + queue->storage[queue->write & (queue->size - 1)] = header;
8609 + vcos_event_signal(&queue->push);
8612 +VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue)
8614 + while (queue->write == queue->read)
8615 + vcos_event_wait(&queue->push);
8617 + return queue->storage[queue->read & (queue->size - 1)];
8620 +VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue)
8622 + VCHIQ_HEADER_T *header;
8624 + while (queue->write == queue->read)
8625 + vcos_event_wait(&queue->push);
8627 + header = queue->storage[queue->read & (queue->size - 1)];
8631 + vcos_event_signal(&queue->pop);
8636 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
8639 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
8641 + * This program is free software; you can redistribute it and/or modify
8642 + * it under the terms of the GNU General Public License as published by
8643 + * the Free Software Foundation; either version 2 of the License, or
8644 + * (at your option) any later version.
8646 + * This program is distributed in the hope that it will be useful,
8647 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8648 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8649 + * GNU General Public License for more details.
8651 + * You should have received a copy of the GNU General Public License
8652 + * along with this program; if not, write to the Free Software
8653 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
8656 +#ifndef VCHIQ_UTIL_H
8657 +#define VCHIQ_UTIL_H
8659 +#include "vchiq_if.h"
8660 +#include "interface/vcos/vcos.h"
8668 + VCOS_EVENT_T push;
8670 + VCHIQ_HEADER_T **storage;
8673 +extern int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size);
8674 +extern void vchiu_queue_delete(VCHIU_QUEUE_T *queue);
8676 +extern int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue);
8678 +extern void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header);
8680 +extern VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue);
8681 +extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue);
8686 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_cmd.c
8688 +/*****************************************************************************
8689 +* Copyright 2009 - 2011 Broadcom Corporation. All rights reserved.
8691 +* Unless you and Broadcom execute a separate written software license
8692 +* agreement governing use of this software, this software is licensed to you
8693 +* under the terms of the GNU General Public License version 2, available at
8694 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
8696 +* Notwithstanding the above, under no circumstances may you combine this
8697 +* software in any way with any other Broadcom software provided under a
8698 +* license other than the GPL, without Broadcom's express prior written
8700 +*****************************************************************************/
8702 +/*****************************************************************************
8704 +* This file provides a generic command line interface which allows
8705 +* vcos internals to be manipulated and/or displayed.
8707 +*****************************************************************************/
8709 +/* ---- Include Files ---------------------------------------------------- */
8711 +#include "interface/vcos/vcos.h"
8713 +#ifdef HAVE_VCOS_VERSION
8714 +#include "interface/vcos/vcos_build_info.h"
8718 +#include vcfw/logging/logging.h
8721 +/* ---- Public Variables ------------------------------------------------- */
8723 +/* ---- Private Constants and Types -------------------------------------- */
8725 +#define VCOS_LOG_CATEGORY (&vcos_cmd_log_category)
8726 +VCOS_LOG_CAT_T vcos_cmd_log_category;
8728 +/* ---- Private Variables ------------------------------------------------ */
8730 +static struct VCOS_CMD_GLOBALS_T
8732 + VCOS_MUTEX_T lock;
8733 + VCOS_ONCE_T initialized;
8735 + unsigned num_cmd_entries;
8736 + unsigned num_cmd_alloc;
8737 + VCOS_CMD_T *cmd_entry;
8739 + VCOS_LOG_CAT_T *log_category;
8742 +/* ---- Private Function Prototypes -------------------------------------- */
8744 +static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param );
8746 +/* ---- Functions ------------------------------------------------------- */
8748 +/*****************************************************************************
8750 +* Walks through the commands looking for a particular command
8752 +*****************************************************************************/
8754 +static VCOS_CMD_T *find_cmd( VCOS_CMD_T *cmd_entry, const char *name )
8756 + VCOS_CMD_T *scan_entry = cmd_entry;
8758 + while ( scan_entry->name != NULL )
8760 + if ( vcos_strcmp( scan_entry->name, name ) == 0 )
8762 + return scan_entry;
8770 +/*****************************************************************************
8773 +* each line individually.
8775 +*****************************************************************************/
8777 +void vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category )
8779 + cmd_globals.log_category = log_category;
8782 +/*****************************************************************************
8784 +* Walks through a buffer containing newline separated lines, and logs
8785 +* each line individually.
8787 +*****************************************************************************/
8789 +static void cmd_log_results( VCOS_CMD_PARAM_T *param )
8794 + start = end = param->result_buf;
8796 + while ( *start != '\0' )
8798 + while (( *end != '\0' ) && ( *end != '\n' ))
8801 + if ( *end == '\n' )
8806 + if ( cmd_globals.log_category != NULL )
8808 + if ( vcos_is_log_enabled( cmd_globals.log_category, VCOS_LOG_INFO ))
8810 + vcos_log_impl( cmd_globals.log_category, VCOS_LOG_INFO, "%s", start );
8815 + vcos_log_info( "%s", start );
8821 + /* Since we logged the buffer, reset the pointer back to the beginning. */
8823 + param->result_ptr = param->result_buf;
8824 + param->result_buf[0] = '\0';
8827 +/*****************************************************************************
8829 +* Since we may have limited output space, we create a generic routine
8830 +* which tries to use the result space, but will switch over to using
8831 +* logging if the output is too large.
8833 +*****************************************************************************/
8835 +void vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args )
8837 + int bytes_written;
8838 + int bytes_remaining;
8840 + bytes_remaining = (int)(param->result_size - ( param->result_ptr - param->result_buf ));
8842 + bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
8844 + if ( cmd_globals.log_category != NULL )
8846 + /* We're going to log each line as we encounter it. If the buffer
8847 + * doesn't end in a newline, then we'll wait for one first.
8850 + if ( (( bytes_written + 1 ) >= bytes_remaining )
8851 + || ( param->result_ptr[ bytes_written - 1 ] == '\n' ))
8853 + cmd_log_results( param );
8857 + param->result_ptr += bytes_written;
8862 + if (( bytes_written + 1 ) >= bytes_remaining )
8864 + /* Output doesn't fit - switch over to logging */
8866 + param->use_log = 1;
8868 + *param->result_ptr = '\0'; /* Zap the partial line that didn't fit above. */
8870 + cmd_log_results( param ); /* resets result_ptr */
8872 + bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
8874 + param->result_ptr += bytes_written;
8878 +/*****************************************************************************
8880 +* Prints the output.
8882 +*****************************************************************************/
8884 +void vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
8888 + va_start( args, fmt );
8889 + vcos_cmd_vprintf( param, fmt, args );
8893 +/*****************************************************************************
8895 +* Prints the arguments which were on the command line prior to ours.
8897 +*****************************************************************************/
8899 +static void print_argument_prefix( VCOS_CMD_PARAM_T *param )
8903 + for ( arg_idx = 0; ¶m->argv_orig[arg_idx] != param->argv; arg_idx++ )
8905 + vcos_cmd_printf( param, "%s ", param->argv_orig[arg_idx] );
8909 +/*****************************************************************************
8911 +* Prints an error message, prefixed by the command chain required to get
8912 +* to where we're at.
8914 +*****************************************************************************/
8916 +void vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
8920 + print_argument_prefix( param );
8922 + va_start( args, fmt );
8923 + vcos_cmd_vprintf( param, fmt, args );
8925 + vcos_cmd_printf( param, "\n" );
8928 +/****************************************************************************
8930 +* usage - prints command usage for an array of commands.
8932 +***************************************************************************/
8934 +static void usage( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
8937 + int nameWidth = 0;
8938 + int argsWidth = 0;
8939 + VCOS_CMD_T *scan_entry;
8941 + vcos_cmd_printf( param, "Usage: " );
8942 + print_argument_prefix( param );
8943 + vcos_cmd_printf( param, "command [args ...]\n" );
8944 + vcos_cmd_printf( param, "\n" );
8945 + vcos_cmd_printf( param, "Where command is one of the following:\n" );
8947 + for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
8952 + scan_entry = &cmd_entry[cmd_idx];
8954 + nw = vcos_strlen( scan_entry->name );
8955 + aw = vcos_strlen( scan_entry->args );
8957 + if ( nw > nameWidth )
8961 + if ( aw > argsWidth )
8967 + for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
8969 + scan_entry = &cmd_entry[cmd_idx];
8971 + vcos_cmd_printf( param, " %-*s %-*s - %s\n",
8972 + nameWidth, scan_entry->name,
8973 + argsWidth, scan_entry->args,
8974 + scan_entry->descr );
8978 +/****************************************************************************
8980 +* Prints the usage for the current command.
8982 +***************************************************************************/
8984 +void vcos_cmd_usage( VCOS_CMD_PARAM_T *param )
8986 + VCOS_CMD_T *cmd_entry;
8988 + cmd_entry = param->cmd_entry;
8990 + if ( cmd_entry->sub_cmd_entry != NULL )
8992 + /* This command is command with sub-commands */
8994 + usage( param, param->cmd_entry->sub_cmd_entry );
8998 + vcos_cmd_printf( param, "Usage: " );
8999 + print_argument_prefix( param );
9000 + vcos_cmd_printf( param, "%s - %s\n",
9001 + param->cmd_entry->args,
9002 + param->cmd_entry->descr );
9006 +/*****************************************************************************
9008 +* Command to print out the help
9010 +* This help command is only called from the main menu.
9012 +*****************************************************************************/
9014 +static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param )
9016 + VCOS_CMD_T *found_entry;
9022 + vcos_log_trace( "%s: argc = %d", __func__, param->argc );
9023 + for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
9025 + vcos_log_trace( "%s: argv[%d] = '%s'", __func__, arg_idx, param->argv[arg_idx] );
9030 + /* If there is an argument after the word help, then we want to print
9031 + * help for that command.
9034 + if ( param->argc == 1 )
9036 + if ( param->cmd_parent_entry == cmd_globals.cmd_entry )
9038 + /* Bare help - print the command usage for the root */
9040 + usage( param, cmd_globals.cmd_entry );
9041 + return VCOS_SUCCESS;
9044 + /* For all other cases help requires an argument */
9046 + vcos_cmd_error( param, "%s requires an argument", param->argv[0] );
9047 + return VCOS_EINVAL;
9050 + /* We were given an argument. */
9052 + if (( found_entry = find_cmd( param->cmd_parent_entry, param->argv[1] )) != NULL )
9054 + /* Make it look like the command that was specified is the one that's
9055 + * currently running
9058 + param->cmd_entry = found_entry;
9059 + param->argv[0] = param->argv[1];
9063 + vcos_cmd_usage( param );
9064 + return VCOS_SUCCESS;
9067 + vcos_cmd_error( param, "- unrecognized command: '%s'", param->argv[1] );
9068 + return VCOS_ENOENT;
9071 +/*****************************************************************************
9073 +* Command to print out the version/build information.
9075 +*****************************************************************************/
9077 +#ifdef HAVE_VCOS_VERSION
9079 +static VCOS_STATUS_T version_cmd( VCOS_CMD_PARAM_T *param )
9081 + static const char* copyright = "Copyright (c) 2011 Broadcom";
9083 + vcos_cmd_printf( param, "%s %s\n%s\nversion %s\n",
9084 + vcos_get_build_date(),
9085 + vcos_get_build_time(),
9087 + vcos_get_build_version() );
9089 + return VCOS_SUCCESS;
9094 +/*****************************************************************************
9096 +* Internal commands
9098 +*****************************************************************************/
9100 +static VCOS_CMD_T cmd_help = { "help", "[command]", help_cmd, NULL, "Prints command help information" };
9102 +#ifdef HAVE_VCOS_VERSION
9103 +static VCOS_CMD_T cmd_version = { "version", "", version_cmd, NULL, "Prints build/version information" };
9106 +/*****************************************************************************
9108 +* Walks the command table and executes the commands
9110 +*****************************************************************************/
9112 +static VCOS_STATUS_T execute_cmd( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
9114 + const char *cmdStr;
9115 + VCOS_CMD_T *found_entry;
9121 + vcos_cmd_printf( param, "%s: argc = %d", __func__, param->argc );
9122 + for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
9124 + vcos_cmd_printf( param, " argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
9126 + vcos_cmd_printf( param, "\n" );
9130 + if ( param->argc <= 1 )
9132 + /* No command specified */
9134 + vcos_cmd_error( param, "%s - no command specified", param->argv[0] );
9135 + return VCOS_EINVAL;
9138 + /* argv[0] is the command/program that caused us to get invoked, so we strip
9144 + param->cmd_parent_entry = cmd_entry;
9146 + /* Not the help command, scan for the command and execute it. */
9148 + cmdStr = param->argv[0];
9150 + if (( found_entry = find_cmd( cmd_entry, cmdStr )) != NULL )
9152 + if ( found_entry->sub_cmd_entry != NULL )
9154 + return execute_cmd( param, found_entry->sub_cmd_entry );
9157 + param->cmd_entry = found_entry;
9158 + return found_entry->cmd_fn( param );
9161 + /* Unrecognized command - check to see if it was the help command */
9163 + if ( vcos_strcmp( cmdStr, cmd_help.name ) == 0 )
9165 + return help_cmd( param );
9168 + vcos_cmd_error( param, "- unrecognized command: '%s'", cmdStr );
9169 + return VCOS_ENOENT;
9172 +/*****************************************************************************
9174 +* Initializes the command line parser.
9176 +*****************************************************************************/
9178 +static void vcos_cmd_init( void )
9180 + vcos_mutex_create( &cmd_globals.lock, "vcos_cmd" );
9182 + cmd_globals.num_cmd_entries = 0;
9183 + cmd_globals.num_cmd_alloc = 0;
9184 + cmd_globals.cmd_entry = NULL;
9187 +/*****************************************************************************
9189 +* Command line processor.
9191 +*****************************************************************************/
9193 +VCOS_STATUS_T vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf )
9195 + VCOS_STATUS_T rc = VCOS_EINVAL;
9196 + VCOS_CMD_PARAM_T param;
9198 + vcos_once( &cmd_globals.initialized, vcos_cmd_init );
9200 + param.argc = argc;
9201 + param.argv = param.argv_orig = argv;
9203 + param.use_log = 0;
9204 + param.result_size = result_size;
9205 + param.result_ptr = result_buf;
9206 + param.result_buf = result_buf;
9208 + result_buf[0] = '\0';
9210 + vcos_mutex_lock( &cmd_globals.lock );
9212 + rc = execute_cmd( ¶m, cmd_globals.cmd_entry );
9214 + if ( param.use_log )
9216 + cmd_log_results( ¶m );
9217 + vcos_snprintf( result_buf, result_size, "results logged" );
9220 + if ( cmd_globals.log_category != NULL )
9222 + if ( result_buf[0] != '\0' )
9224 + /* There is a partial line still buffered. */
9226 + vcos_cmd_printf( ¶m, "\n" );
9230 + vcos_mutex_unlock( &cmd_globals.lock );
9235 +/*****************************************************************************
9237 +* Registers a command entry with the command line processor
9239 +*****************************************************************************/
9241 +VCOS_STATUS_T vcos_cmd_register( VCOS_CMD_T *cmd_entry )
9244 + VCOS_UNSIGNED new_num_cmd_alloc;
9245 + VCOS_CMD_T *new_cmd_entry;
9246 + VCOS_CMD_T *old_cmd_entry;
9247 + VCOS_CMD_T *scan_entry;
9249 + vcos_once( &cmd_globals.initialized, vcos_cmd_init );
9251 + vcos_assert( cmd_entry != NULL );
9252 + vcos_assert( cmd_entry->name != NULL );
9254 + vcos_log_trace( "%s: cmd '%s'", __FUNCTION__, cmd_entry->name );
9256 + vcos_assert( cmd_entry->args != NULL );
9257 + vcos_assert(( cmd_entry->cmd_fn != NULL ) || ( cmd_entry->sub_cmd_entry != NULL ));
9258 + vcos_assert( cmd_entry->descr != NULL );
9260 + /* We expect vcos_cmd_init to be called before vcos_logging_init, so we
9261 + * need to defer registering our logging category until someplace
9262 + * like right here.
9265 + if ( vcos_cmd_log_category.name == NULL )
9268 + * If you're using the command interface, you pretty much always want
9269 + * log messages from this file to show up. So we change the default
9270 + * from ERROR to be the more reasonable INFO level.
9273 + vcos_log_set_level(&vcos_cmd_log_category, VCOS_LOG_INFO);
9274 + vcos_log_register("vcos_cmd", &vcos_cmd_log_category);
9276 + /* We register a help command so that it shows up in the usage. */
9278 + vcos_cmd_register( &cmd_help );
9279 +#ifdef HAVE_VCOS_VERSION
9280 + vcos_cmd_register( &cmd_version );
9284 + vcos_mutex_lock( &cmd_globals.lock );
9286 + if ( cmd_globals.num_cmd_entries >= cmd_globals.num_cmd_alloc )
9288 + if ( cmd_globals.num_cmd_alloc == 0 )
9290 + /* We haven't allocated a table yet */
9293 + /* The number 8 is rather arbitrary. */
9295 + new_num_cmd_alloc = cmd_globals.num_cmd_alloc + 8;
9297 + /* The + 1 is to ensure that we always have a NULL entry at the end. */
9299 + new_cmd_entry = (VCOS_CMD_T *)vcos_calloc( new_num_cmd_alloc + 1, sizeof( *cmd_entry ), "vcos_cmd_entries" );
9300 + if ( new_cmd_entry == NULL )
9305 + memcpy( new_cmd_entry, cmd_globals.cmd_entry, cmd_globals.num_cmd_entries * sizeof( *cmd_entry ));
9306 + cmd_globals.num_cmd_alloc = new_num_cmd_alloc;
9307 + old_cmd_entry = cmd_globals.cmd_entry;
9308 + cmd_globals.cmd_entry = new_cmd_entry;
9309 + vcos_free( old_cmd_entry );
9312 + if ( cmd_globals.num_cmd_entries == 0 )
9314 + /* This is the first command being registered */
9316 + cmd_globals.cmd_entry[0] = *cmd_entry;
9320 + /* Keep the list in alphabetical order. We start at the end and work backwards
9321 + * shuffling entries up one until we find an insertion point.
9324 + for ( scan_entry = &cmd_globals.cmd_entry[cmd_globals.num_cmd_entries - 1];
9325 + scan_entry >= cmd_globals.cmd_entry; scan_entry-- )
9327 + if ( vcos_strcmp( cmd_entry->name, scan_entry->name ) > 0 )
9329 + /* We found an insertion point. */
9334 + scan_entry[1] = scan_entry[0];
9336 + scan_entry[1] = *cmd_entry;
9338 + cmd_globals.num_cmd_entries++;
9340 + rc = VCOS_SUCCESS;
9344 + vcos_mutex_unlock( &cmd_globals.lock );
9348 +/*****************************************************************************
9350 +* Registers multiple commands.
9352 +*****************************************************************************/
9354 +VCOS_STATUS_T vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry )
9356 + VCOS_STATUS_T status;
9358 + while ( cmd_entry->name != NULL )
9360 + if (( status = vcos_cmd_register( cmd_entry )) != VCOS_SUCCESS )
9366 + return VCOS_SUCCESS;
9370 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_common.h
9372 +/*=============================================================================
9373 +Copyright (c) 2009 Broadcom Europe Limited.
9374 +All rights reserved.
9377 +Module : chip driver
9380 +VideoCore OS Abstraction Layer - common postamble code
9381 +=============================================================================*/
9385 + * Postamble code included by the platform-specific header files
9388 +#define VCOS_THREAD_PRI_DEFAULT VCOS_THREAD_PRI_NORMAL
9390 +#if !defined(VCOS_THREAD_PRI_INCREASE)
9391 +#error Which way to thread priorities go?
9394 +#if VCOS_THREAD_PRI_INCREASE < 0
9395 +/* smaller numbers are higher priority */
9396 +#define VCOS_THREAD_PRI_LESS(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX)
9397 +#define VCOS_THREAD_PRI_MORE(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN)
9399 +/* bigger numbers are lower priority */
9400 +#define VCOS_THREAD_PRI_MORE(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX)
9401 +#define VCOS_THREAD_PRI_LESS(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN)
9404 +/* Convenience for Brits: */
9405 +#define VCOS_APPLICATION_INITIALISE VCOS_APPLICATION_INITIALIZE
9408 + * Check for constant definitions
9410 +#ifndef VCOS_TICKS_PER_SECOND
9411 +#error VCOS_TICKS_PER_SECOND not defined
9414 +#if !defined(VCOS_THREAD_PRI_MIN) || !defined(VCOS_THREAD_PRI_MAX)
9415 +#error Priority range not defined
9418 +#if !defined(VCOS_THREAD_PRI_HIGHEST) || !defined(VCOS_THREAD_PRI_LOWEST) || !defined(VCOS_THREAD_PRI_NORMAL)
9419 +#error Priority ordering not defined
9422 +#if !defined(VCOS_CAN_SET_STACK_ADDR)
9423 +#error Can stack addresses be set on this platform? Please set this macro to either 0 or 1.
9426 +#if (_VCOS_AFFINITY_CPU0|_VCOS_AFFINITY_CPU1) & (~_VCOS_AFFINITY_MASK)
9427 +#error _VCOS_AFFINITY_CPUxxx values are not consistent with _VCOS_AFFINITY_MASK
9430 +/** Append to the end of a singly-linked queue, O(1). Works with
9431 + * any structure where list has members 'head' and 'tail' and
9432 + * item has a 'next' pointer.
9434 +#define VCOS_QUEUE_APPEND_TAIL(list, item) {\
9435 + (item)->next = NULL;\
9436 + if (!(list)->head) {\
9437 + (list)->head = (list)->tail = (item); \
9439 + (list)->tail->next = (item); \
9440 + (list)->tail = (item); \
9444 +#ifndef VCOS_HAVE_TIMER
9445 +VCOSPRE_ void VCOSPOST_ vcos_timer_init(void);
9449 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_blockpool.h
9451 +/*=============================================================================
9452 +Copyright (c) 2011 Broadcom Europe Limited.
9453 +All rights reserved.
9456 +Module : chip driver
9459 +VideoCore OS Abstraction Layer - event flags implemented via a semaphore
9460 +=============================================================================*/
9462 +#ifndef VCOS_GENERIC_BLOCKPOOL_H
9463 +#define VCOS_GENERIC_BLOCKPOOL_H
9468 + * This provides a generic, thread safe implementation of a VCOS block pool
9469 + * fixed size memory allocator.
9476 +#include "interface/vcos/vcos_types.h"
9478 +/** Bits 0 to (VCOS_BLOCKPOOL_SUBPOOL_BITS - 1) are used to store the
9480 +#define VCOS_BLOCKPOOL_SUBPOOL_BITS 3
9481 +#define VCOS_BLOCKPOOL_MAX_SUBPOOLS (1 << VCOS_BLOCKPOOL_SUBPOOL_BITS)
9483 +/* Make zero an invalid handle at the cost of decreasing the maximum
9484 + * number of blocks (2^28) by 1. Alternatively, a spare bit could be
9485 + * used to indicated valid blocks but there are likely to be better
9486 + * uses for spare bits. e.g. allowing more subpools
9488 +#define INDEX_OFFSET 1
9490 +#define VCOS_BLOCKPOOL_HANDLE_GET_INDEX(h) \
9491 + (((h) >> VCOS_BLOCKPOOL_SUBPOOL_BITS) - INDEX_OFFSET)
9493 +#define VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(h) \
9494 + ((h) & ((1 << VCOS_BLOCKPOOL_SUBPOOL_BITS) - 1))
9496 +#define VCOS_BLOCKPOOL_HANDLE_CREATE(i,s) \
9497 + ((((i) + INDEX_OFFSET) << VCOS_BLOCKPOOL_SUBPOOL_BITS) | (s))
9499 +#define VCOS_BLOCKPOOL_INVALID_HANDLE 0
9501 +typedef struct VCOS_BLOCKPOOL_HEADER_TAG
9503 + /* Blocks either refer to to the pool if they are allocated
9504 + * or the free list if they are available.
9507 + struct VCOS_BLOCKPOOL_HEADER_TAG *next;
9508 + struct VCOS_BLOCKPOOL_SUBPOOL_TAG* subpool;
9510 +} VCOS_BLOCKPOOL_HEADER_T;
9512 +typedef struct VCOS_BLOCKPOOL_SUBPOOL_TAG
9514 + /** VCOS_BLOCKPOOL_SUBPOOL_MAGIC */
9516 + VCOS_BLOCKPOOL_HEADER_T* free_list;
9517 + /* The start of the pool memory */
9519 + /* Address of the first block header */
9521 + /** The number of blocks in this sub-pool */
9522 + VCOS_UNSIGNED num_blocks;
9523 + /** Current number of available blocks in this sub-pool */
9524 + VCOS_UNSIGNED available_blocks;
9525 + /** Pointers to the pool that owns this sub-pool */
9526 + struct VCOS_BLOCKPOOL_TAG* owner;
9527 + /** Define properties such as memory ownership */
9529 +} VCOS_BLOCKPOOL_SUBPOOL_T;
9531 +typedef struct VCOS_BLOCKPOOL_TAG
9533 + /** VCOS_BLOCKPOOL_MAGIC */
9535 + /** Thread safety for Alloc, Free, Delete, Stats */
9536 + VCOS_MUTEX_T mutex;
9537 + /** The size of the block data */
9538 + size_t block_data_size;
9539 + /** Block size inc overheads */
9540 + size_t block_size;
9541 + /** Name for debugging */
9543 + /* The number of subpools that may be used */
9544 + VCOS_UNSIGNED num_subpools;
9545 + /** Number of blocks in each dynamically allocated subpool */
9546 + VCOS_UNSIGNED num_extension_blocks;
9547 + /** Array of subpools. Subpool zero is is not deleted until the pool is
9548 + * destroed. If the index of the pool is < num_subpools and
9549 + * subpool[index.mem] is null then the subpool entry is valid but
9550 + * "not currently allocated" */
9551 + VCOS_BLOCKPOOL_SUBPOOL_T subpools[VCOS_BLOCKPOOL_MAX_SUBPOOLS];
9552 +} VCOS_BLOCKPOOL_T;
9554 +#define VCOS_BLOCKPOOL_ROUND_UP(x,s) (((x) + ((s) - 1)) & ~((s) - 1))
9556 + * Calculates the size in bytes required for a block pool containing
9557 + * num_blocks of size block_size plus any overheads.
9559 + * The block pool header (VCOS_BLOCKPOOL_T) is allocated separately
9562 + * block_size + header must be a multiple of sizeof(void*)
9563 + * The start of the first block may need to be up to wordsize - 1 bytes
9564 + * into the given buffer because statically allocated buffers within structures
9565 + * are not guaranteed to be word aligned.
9567 +#define VCOS_BLOCKPOOL_SIZE(num_blocks, block_size) \
9568 + ((VCOS_BLOCKPOOL_ROUND_UP((block_size) + sizeof(VCOS_BLOCKPOOL_HEADER_T), \
9569 + sizeof(void*)) * (num_blocks)) + sizeof(void*))
9572 + * Sanity check to verify whether a handle is potentially a blockpool handle
9573 + * when the pool pointer is not available.
9575 + * If the pool pointer is availabe use vcos_blockpool_elem_to_handle instead.
9577 + * @param handle the handle to verify
9578 + * @param max_blocks the expected maximum number of block in the pool
9579 + * that the handle belongs to.
9581 +#define VCOS_BLOCKPOOL_IS_VALID_HANDLE_FORMAT(handle, max_blocks) \
9582 + ((handle) != VCOS_BLOCKPOOL_INVALID_HANDLE \
9583 + && VCOS_BLOCKPOOL_HANDLE_GET_INDEX((handle)) < (max_blocks))
9586 + VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_init(VCOS_BLOCKPOOL_T *pool,
9587 + VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
9588 + void *start, VCOS_UNSIGNED pool_size, const char *name);
9591 + VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_create_on_heap(
9592 + VCOS_BLOCKPOOL_T *pool, VCOS_UNSIGNED num_blocks,
9593 + VCOS_UNSIGNED block_size, const char *name);
9596 + VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
9597 + VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks);
9599 +VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool);
9601 +VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool);
9603 +VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_free(void *block);
9606 + VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_available_count(
9607 + VCOS_BLOCKPOOL_T *pool);
9610 + VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_used_count(
9611 + VCOS_BLOCKPOOL_T *pool);
9613 +VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool);
9615 +VCOSPRE_ uint32_t VCOSPOST_ vcos_generic_blockpool_elem_to_handle(void *block);
9617 +VCOSPRE_ void VCOSPOST_
9618 + *vcos_generic_blockpool_elem_from_handle(
9619 + VCOS_BLOCKPOOL_T *pool, uint32_t handle);
9621 +VCOSPRE_ uint32_t VCOSPOST_
9622 + vcos_generic_blockpool_is_valid_elem(
9623 + VCOS_BLOCKPOOL_T *pool, const void *block);
9624 +#if defined(VCOS_INLINE_BODIES)
9627 +VCOS_STATUS_T vcos_blockpool_init(VCOS_BLOCKPOOL_T *pool,
9628 + VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
9629 + void *start, VCOS_UNSIGNED pool_size, const char *name)
9631 + return vcos_generic_blockpool_init(pool, num_blocks, block_size,
9632 + start, pool_size, name);
9636 +VCOS_STATUS_T vcos_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool,
9637 + VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, const char *name)
9639 + return vcos_generic_blockpool_create_on_heap(
9640 + pool, num_blocks, block_size, name);
9644 + VCOS_STATUS_T VCOSPOST_ vcos_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
9645 + VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks)
9647 + return vcos_generic_blockpool_extend(pool, num_extensions, num_blocks);
9651 +void *vcos_blockpool_alloc(VCOS_BLOCKPOOL_T *pool)
9653 + return vcos_generic_blockpool_alloc(pool);
9657 +void *vcos_blockpool_calloc(VCOS_BLOCKPOOL_T *pool)
9659 + return vcos_generic_blockpool_calloc(pool);
9663 +void vcos_blockpool_free(void *block)
9665 + vcos_generic_blockpool_free(block);
9669 +VCOS_UNSIGNED vcos_blockpool_available_count(VCOS_BLOCKPOOL_T *pool)
9671 + return vcos_generic_blockpool_available_count(pool);
9675 +VCOS_UNSIGNED vcos_blockpool_used_count(VCOS_BLOCKPOOL_T *pool)
9677 + return vcos_generic_blockpool_used_count(pool);
9681 +void vcos_blockpool_delete(VCOS_BLOCKPOOL_T *pool)
9683 + vcos_generic_blockpool_delete(pool);
9687 +uint32_t vcos_blockpool_elem_to_handle(void *block)
9689 + return vcos_generic_blockpool_elem_to_handle(block);
9693 +void *vcos_blockpool_elem_from_handle(VCOS_BLOCKPOOL_T *pool, uint32_t handle)
9695 + return vcos_generic_blockpool_elem_from_handle(pool, handle);
9699 +uint32_t vcos_blockpool_is_valid_elem(VCOS_BLOCKPOOL_T *pool, const void *block)
9701 + return vcos_generic_blockpool_is_valid_elem(pool, block);
9703 +#endif /* VCOS_INLINE_BODIES */
9709 +#endif /* VCOS_GENERIC_BLOCKPOOL_H */
9712 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.c
9714 +/*=============================================================================
9715 +Copyright (c) 2009 Broadcom Europe Limited.
9716 +All rights reserved.
9719 +VideoCore OS Abstraction Layer - event flags implemented via mutexes
9720 +=============================================================================*/
9722 +#include "interface/vcos/vcos.h"
9723 +#include "interface/vcos/generic/vcos_generic_event_flags.h"
9725 +#include <stddef.h>
9727 +/** A structure created by a thread that waits on the event flags
9728 + * for a particular combination of flags to arrive.
9730 +typedef struct VCOS_EVENT_WAITER_T
9732 + VCOS_UNSIGNED requested_events; /**< The events wanted */
9733 + VCOS_UNSIGNED actual_events; /**< Actual events found */
9734 + VCOS_UNSIGNED op; /**< The event operation to be used */
9735 + VCOS_STATUS_T return_status; /**< The return status the waiter should pass back */
9736 + VCOS_EVENT_FLAGS_T *flags; /**< Pointer to the original 'flags' structure */
9737 + VCOS_THREAD_T *thread; /**< Thread waiting */
9738 + struct VCOS_EVENT_WAITER_T *next;
9739 +} VCOS_EVENT_WAITER_T;
9742 +static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags);
9744 +static void event_flags_timer_expired(void *cxt);
9746 +VCOS_STATUS_T vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name)
9749 + if ((rc=vcos_mutex_create(&flags->lock, name)) != VCOS_SUCCESS)
9754 + flags->events = 0;
9755 + flags->waiters.head = flags->waiters.tail = 0;
9759 +void vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
9760 + VCOS_UNSIGNED bitmask,
9763 + vcos_assert(flags);
9764 + vcos_mutex_lock(&flags->lock);
9765 + if (op == VCOS_OR)
9767 + flags->events |= bitmask;
9769 + else if (op == VCOS_AND)
9771 + flags->events &= bitmask;
9778 + /* Now wake up any threads that have now become signalled. */
9779 + if (flags->waiters.head != NULL)
9781 + VCOS_UNSIGNED consumed_events = 0;
9782 + VCOS_EVENT_WAITER_T **pcurrent_waiter = &flags->waiters.head;
9783 + VCOS_EVENT_WAITER_T *prev_waiter = NULL;
9785 + /* Walk the chain of tasks suspend on this event flag group to determine
9786 + * if any of their requests can be satisfied.
9788 + while ((*pcurrent_waiter) != NULL)
9790 + VCOS_EVENT_WAITER_T *curr_waiter = *pcurrent_waiter;
9792 + /* Determine if this request has been satisfied */
9794 + /* First, find the event flags in common. */
9795 + VCOS_UNSIGNED waiter_satisfied = flags->events & curr_waiter->requested_events;
9797 + /* Second, determine if all the event flags must match */
9798 + if (curr_waiter->op & VCOS_AND)
9800 + /* All requested events must be present */
9801 + waiter_satisfied = (waiter_satisfied == curr_waiter->requested_events);
9804 + /* Wake this one up? */
9805 + if (waiter_satisfied)
9808 + if (curr_waiter->op & VCOS_CONSUME)
9810 + consumed_events |= curr_waiter->requested_events;
9813 + /* remove this block from the list, taking care at the end */
9814 + *pcurrent_waiter = curr_waiter->next;
9815 + if (curr_waiter->next == NULL)
9816 + flags->waiters.tail = prev_waiter;
9818 + vcos_assert(waiter_list_valid(flags));
9820 + curr_waiter->return_status = VCOS_SUCCESS;
9821 + curr_waiter->actual_events = flags->events;
9823 + _vcos_thread_sem_post(curr_waiter->thread);
9827 + /* move to next element in the list */
9828 + prev_waiter = *pcurrent_waiter;
9829 + pcurrent_waiter = &(curr_waiter->next);
9833 + flags->events &= ~consumed_events;
9837 + vcos_mutex_unlock(&flags->lock);
9840 +void vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *flags)
9842 + vcos_mutex_delete(&flags->lock);
9845 +extern VCOS_STATUS_T vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
9846 + VCOS_UNSIGNED bitmask,
9848 + VCOS_UNSIGNED suspend,
9849 + VCOS_UNSIGNED *retrieved_bits)
9851 + VCOS_EVENT_WAITER_T waitreq;
9852 + VCOS_STATUS_T rc = VCOS_EAGAIN;
9853 + int satisfied = 0;
9855 + vcos_assert(flags);
9857 + /* default retrieved bits to 0 */
9858 + *retrieved_bits = 0;
9860 + vcos_mutex_lock(&flags->lock);
9861 + switch (op & VCOS_EVENT_FLAG_OP_MASK)
9864 + if ((flags->events & bitmask) == bitmask)
9866 + *retrieved_bits = flags->events;
9867 + rc = VCOS_SUCCESS;
9869 + if (op & VCOS_CONSUME)
9870 + flags->events &= ~bitmask;
9875 + if (flags->events & bitmask)
9877 + *retrieved_bits = flags->events;
9878 + rc = VCOS_SUCCESS;
9880 + if (op & VCOS_CONSUME)
9881 + flags->events &= ~bitmask;
9891 + if (!satisfied && suspend)
9893 + /* Have to go to sleep.
9895 + * Append to tail so we get FIFO ordering.
9897 + waitreq.requested_events = bitmask;
9899 + waitreq.return_status = VCOS_EAGAIN;
9900 + waitreq.flags = flags;
9901 + waitreq.actual_events = 0;
9902 + waitreq.thread = vcos_thread_current();
9904 + vcos_assert(waitreq.thread != (VCOS_THREAD_T*)-1);
9905 + VCOS_QUEUE_APPEND_TAIL(&flags->waiters, &waitreq);
9907 + if (suspend != (VCOS_UNSIGNED)-1)
9908 + _vcos_task_timer_set(event_flags_timer_expired, &waitreq, suspend);
9910 + vcos_mutex_unlock(&flags->lock);
9911 + /* go to sleep and wait to be signalled or timeout */
9913 + _vcos_thread_sem_wait();
9915 + *retrieved_bits = waitreq.actual_events;
9916 + rc = waitreq.return_status;
9918 + /* cancel the timer - do not do this while holding the mutex as it
9919 + * might be waiting for the timeout function to complete, which will
9920 + * try to take the mutex.
9922 + if (suspend != (VCOS_UNSIGNED)-1)
9923 + _vcos_task_timer_cancel();
9927 + vcos_mutex_unlock(&flags->lock);
9934 +/** Called when a get call times out. Remove this thread's
9935 + * entry from the waiting queue, then resume the thread.
9937 +static void event_flags_timer_expired(void *cxt)
9939 + VCOS_EVENT_WAITER_T *waitreq = (VCOS_EVENT_WAITER_T *)cxt;
9940 + VCOS_EVENT_FLAGS_T *flags = waitreq->flags;
9941 + VCOS_EVENT_WAITER_T **plist;
9942 + VCOS_EVENT_WAITER_T *prev = NULL;
9943 + VCOS_THREAD_T *thread = 0;
9945 + vcos_assert(flags);
9947 + vcos_mutex_lock(&flags->lock);
9949 + /* walk the list of waiting threads on this event group, and remove
9950 + * the one that has expired.
9952 + * FIXME: could use doubly-linked list if lots of threads are found
9953 + * to be waiting on a single event flag instance.
9955 + plist = &flags->waiters.head;
9956 + while (*plist != NULL)
9958 + if (*plist == waitreq)
9962 + thread = (*plist)->thread;
9963 + at_end = ((*plist)->next == NULL);
9966 + *plist = (*plist)->next;
9968 + flags->waiters.tail = prev;
9973 + plist = &(*plist)->next;
9975 + vcos_assert(waiter_list_valid(flags));
9977 + vcos_mutex_unlock(&flags->lock);
9981 + _vcos_thread_sem_post(thread);
9987 +static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags)
9990 + /* Either both head and tail are NULL, or neither are NULL */
9991 + if (flags->waiters.head == NULL)
9993 + valid = (flags->waiters.tail == NULL);
9997 + valid = (flags->waiters.tail != NULL);
10000 + /* If head and tail point at the same non-NULL element, then there
10001 + * is only one element in the list.
10003 + if (flags->waiters.head && (flags->waiters.head == flags->waiters.tail))
10005 + valid = (flags->waiters.head->next == NULL);
10012 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.h
10014 +/*=============================================================================
10015 +Copyright (c) 2009 Broadcom Europe Limited.
10016 +All rights reserved.
10019 +VideoCore OS Abstraction Layer - event flags implemented via a semaphore
10020 +=============================================================================*/
10022 +#ifndef VCOS_GENERIC_EVENT_FLAGS_H
10023 +#define VCOS_GENERIC_EVENT_FLAGS_H
10025 +#ifdef __cplusplus
10029 +#include "interface/vcos/vcos_types.h"
10034 + * This provides event flags (as per Nucleus Event Groups) based on a
10035 + * mutex, a semaphore (per waiting thread) and a timer (per waiting
10038 + * The data structure is a 32 bit unsigned int (the current set of
10039 + * flags) and a linked list of clients waiting to be 'satisfied'.
10041 + * The mutex merely locks access to the data structure. If a client
10042 + * calls vcos_event_flags_get() and the requested bits are not already
10043 + * present, it then sleeps on its per-thread semaphore after adding
10044 + * this semaphore to the queue waiting. It also sets up a timer.
10046 + * The per-thread semaphore and timer are actually stored in the
10047 + * thread context (joinable thread). In future it may become necessary
10048 + * to support non-VCOS threads by using thread local storage to
10049 + * create these objects and associate them with the thread.
10052 +struct VCOS_EVENT_WAITER_T;
10054 +typedef struct VCOS_EVENT_FLAGS_T
10056 + VCOS_UNSIGNED events; /**< Events currently set */
10057 + VCOS_MUTEX_T lock; /**< Serialize access */
10060 + struct VCOS_EVENT_WAITER_T *head; /**< List of threads waiting */
10061 + struct VCOS_EVENT_WAITER_T *tail; /**< List of threads waiting */
10063 +} VCOS_EVENT_FLAGS_T;
10066 +#define VCOS_AND 2
10067 +#define VCOS_CONSUME 4
10068 +#define VCOS_OR_CONSUME (VCOS_OR | VCOS_CONSUME)
10069 +#define VCOS_AND_CONSUME (VCOS_AND | VCOS_CONSUME)
10070 +#define VCOS_EVENT_FLAG_OP_MASK (VCOS_OR|VCOS_AND)
10072 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name);
10073 +VCOSPRE_ void VCOSPOST_ vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
10074 + VCOS_UNSIGNED events,
10076 +VCOSPRE_ void VCOSPOST_ vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *);
10077 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
10078 + VCOS_UNSIGNED requested_events,
10080 + VCOS_UNSIGNED suspend,
10081 + VCOS_UNSIGNED *retrieved_events);
10083 +#ifdef VCOS_INLINE_BODIES
10086 +VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name) {
10087 + return vcos_generic_event_flags_create(flags, name);
10091 +void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
10092 + VCOS_UNSIGNED events,
10093 + VCOS_OPTION op) {
10094 + vcos_generic_event_flags_set(flags, events, op);
10098 +void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *f) {
10099 + vcos_generic_event_flags_delete(f);
10103 +VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
10104 + VCOS_UNSIGNED requested_events,
10106 + VCOS_UNSIGNED suspend,
10107 + VCOS_UNSIGNED *retrieved_events) {
10108 + return vcos_generic_event_flags_get(flags, requested_events, op, suspend, retrieved_events);
10111 +#endif /* VCOS_INLINE_BODIES */
10113 +#ifdef __cplusplus
10119 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_named_sem.h
10121 +/*=============================================================================
10122 +Copyright (c) 2009 Broadcom Europe Limited.
10123 +All rights reserved.
10126 +Module : chip driver
10129 +VideoCore OS Abstraction Layer - named semaphores
10130 +=============================================================================*/
10132 +#ifndef VCOS_GENERIC_NAMED_SEM_H
10133 +#define VCOS_GENERIC_NAMED_SEM_H
10135 +#ifdef __cplusplus
10139 +#include "interface/vcos/vcos_types.h"
10144 + * Generic support for named semaphores, using regular ones. This is only
10145 + * suitable for emulating them on an embedded MMUless system, since there is
10146 + * no support for opening semaphores across process boundaries.
10150 +#define VCOS_NAMED_SEMAPHORE_NAMELEN 64
10152 +/* In theory we could use the name facility provided within Nucleus. However, this
10153 + * is hard to do as semaphores are constantly being created and destroyed; we
10154 + * would need to stop everything while allocating the memory for the semaphore
10155 + * list and then walking it. So keep our own list.
10157 +typedef struct VCOS_NAMED_SEMAPHORE_T
10159 + struct VCOS_NAMED_SEMAPHORE_IMPL_T *actual; /**< There are 'n' named semaphores per 1 actual semaphore */
10160 + VCOS_SEMAPHORE_T *sem; /**< Pointer to actual underlying semaphore */
10161 +} VCOS_NAMED_SEMAPHORE_T;
10163 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_
10164 +vcos_generic_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
10166 +VCOSPRE_ void VCOSPOST_ vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem);
10168 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ _vcos_named_semaphore_init(void);
10169 +VCOSPRE_ void VCOSPOST_ _vcos_named_semaphore_deinit(void);
10171 +#if defined(VCOS_INLINE_BODIES)
10174 +VCOS_STATUS_T vcos_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count) {
10175 + return vcos_generic_named_semaphore_create(sem, name, count);
10179 +void vcos_named_semaphore_wait(VCOS_NAMED_SEMAPHORE_T *sem) {
10180 + vcos_semaphore_wait(sem->sem);
10184 +VCOS_STATUS_T vcos_named_semaphore_trywait(VCOS_NAMED_SEMAPHORE_T *sem) {
10185 + return vcos_semaphore_trywait(sem->sem);
10189 +void vcos_named_semaphore_post(VCOS_NAMED_SEMAPHORE_T *sem) {
10190 + vcos_semaphore_post(sem->sem);
10196 +#ifdef __cplusplus
10203 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_quickslow_mutex.h
10205 +/*=============================================================================
10206 +Copyright (c) 2009 Broadcom Europe Limited.
10207 +All rights reserved.
10210 +Module : chip driver
10213 +VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
10214 +=============================================================================*/
10216 +#ifndef VCOS_GENERIC_QUICKSLOW_MUTEX_H
10217 +#define VCOS_GENERIC_QUICKSLOW_MUTEX_H
10219 +#ifdef __cplusplus
10223 +#include "interface/vcos/vcos_types.h"
10228 + * Quickslow Mutexes implemented as regular ones (i.e. quick and slow modes are the same).
10232 +typedef VCOS_MUTEX_T VCOS_QUICKSLOW_MUTEX_T;
10234 +#if defined(VCOS_INLINE_BODIES)
10236 +VCOS_STATUS_T vcos_quickslow_mutex_create(VCOS_QUICKSLOW_MUTEX_T *m, const char *name)
10238 + return vcos_mutex_create(m, name);
10242 +void vcos_quickslow_mutex_delete(VCOS_QUICKSLOW_MUTEX_T *m)
10244 + vcos_mutex_delete(m);
10248 +void vcos_quickslow_mutex_lock(VCOS_QUICKSLOW_MUTEX_T *m)
10250 + while (vcos_mutex_lock(m) == VCOS_EAGAIN);
10254 +void vcos_quickslow_mutex_unlock(VCOS_QUICKSLOW_MUTEX_T *m)
10256 + vcos_mutex_unlock(m);
10260 +void vcos_quickslow_mutex_lock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
10262 + while (vcos_mutex_lock(m) == VCOS_EAGAIN);
10266 +void vcos_quickslow_mutex_unlock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
10268 + vcos_mutex_unlock(m);
10274 +#ifdef __cplusplus
10281 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_reentrant_mtx.h
10283 +/*=============================================================================
10284 +Copyright (c) 2009 Broadcom Europe Limited.
10285 +All rights reserved.
10288 +Module : chip driver
10291 +VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
10292 +=============================================================================*/
10294 +#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
10295 +#define VCOS_GENERIC_REENTRANT_MUTEX_H
10297 +#ifdef __cplusplus
10301 +#include "interface/vcos/vcos_types.h"
10306 + * Reentrant Mutexes from regular ones.
10310 +typedef struct VCOS_REENTRANT_MUTEX_T
10312 + VCOS_MUTEX_T mutex;
10313 + VCOS_THREAD_T *owner;
10315 +} VCOS_REENTRANT_MUTEX_T;
10317 +/* Extern definitions of functions that do the actual work */
10319 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name);
10321 +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m);
10323 +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m);
10325 +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m);
10327 +/* Inline forwarding functions */
10329 +#if defined(VCOS_INLINE_BODIES)
10332 +VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) {
10333 + return vcos_generic_reentrant_mutex_create(m,name);
10337 +void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
10338 + vcos_generic_reentrant_mutex_delete(m);
10342 +void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
10343 + vcos_generic_reentrant_mutex_lock(m);
10347 +void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
10348 + vcos_generic_reentrant_mutex_unlock(m);
10352 +#ifdef __cplusplus
10359 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_tls.h
10361 +/*=============================================================================
10362 +Copyright (c) 2009 Broadcom Europe Limited.
10363 +All rights reserved.
10366 +Module : chip driver
10369 +VideoCore OS Abstraction Layer - generic thread local storage
10370 +=============================================================================*/
10372 +#ifndef VCOS_GENERIC_TLS_H
10373 +#define VCOS_GENERIC_TLS_H
10375 +#ifdef __cplusplus
10379 +#include "interface/vcos/vcos_types.h"
10384 + * Do an emulation of Thread Local Storage. The platform needs to
10385 + * provide a way to set and get a per-thread pointer which is
10386 + * where the TLS data itself is stored.
10389 + * Each thread that wants to join in this scheme needs to call
10390 + * vcos_tls_thread_register().
10392 + * The platform needs to support the macros/functions
10393 + * _vcos_tls_thread_ptr_set() and _vcos_tls_thread_ptr_get().
10396 +#ifndef VCOS_WANT_TLS_EMULATION
10397 +#error Should not be included unless TLS emulation is defined
10400 +/** Number of slots to reserve per thread. This results in an overhead
10401 + * of this many words per thread.
10403 +#define VCOS_TLS_MAX_SLOTS 4
10405 +/** TLS key. Allocating one of these reserves the client one of the
10406 + * available slots.
10408 +typedef VCOS_UNSIGNED VCOS_TLS_KEY_T;
10410 +/** TLS per-thread structure. Each thread gets one of these
10411 + * if TLS emulation (rather than native TLS support) is
10414 +typedef struct VCOS_TLS_THREAD_T
10416 + void *slots[VCOS_TLS_MAX_SLOTS];
10417 +} VCOS_TLS_THREAD_T;
10423 +/** Register this thread's TLS storage area. */
10424 +VCOSPRE_ void VCOSPOST_ vcos_tls_thread_register(VCOS_TLS_THREAD_T *);
10426 +/** Create a new TLS key */
10427 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_tls_create(VCOS_TLS_KEY_T *key);
10429 +/** Delete a TLS key */
10430 +VCOSPRE_ void VCOSPOST_ vcos_generic_tls_delete(VCOS_TLS_KEY_T tls);
10432 +/** Initialise the TLS library */
10433 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_tls_init(void);
10435 +/** Deinitialise the TLS library */
10436 +VCOSPRE_ void VCOSPOST_ vcos_tls_deinit(void);
10438 +#if defined(VCOS_INLINE_BODIES)
10440 +#undef VCOS_ASSERT_LOGGING_DISABLE
10441 +#define VCOS_ASSERT_LOGGING_DISABLE 1
10444 + * Implementations of public API functions
10447 +/** Set the given value. Since everything is per-thread, there is no need
10448 + * for any locking.
10451 +VCOS_STATUS_T vcos_tls_set(VCOS_TLS_KEY_T tls, void *v) {
10452 + VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get();
10453 + vcos_assert(tlsdata); /* Fires if this thread has not been registered */
10454 + if (tls<VCOS_TLS_MAX_SLOTS)
10456 + tlsdata->slots[tls] = v;
10457 + return VCOS_SUCCESS;
10462 + return VCOS_EINVAL;
10466 +/** Get the given value. No locking required.
10469 +void *vcos_tls_get(VCOS_TLS_KEY_T tls) {
10470 + VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get();
10471 + vcos_assert(tlsdata); /* Fires if this thread has not been registered */
10472 + if (tls<VCOS_TLS_MAX_SLOTS)
10474 + return tlsdata->slots[tls];
10484 +VCOS_STATUS_T vcos_tls_create(VCOS_TLS_KEY_T *key) {
10485 + return vcos_generic_tls_create(key);
10489 +void vcos_tls_delete(VCOS_TLS_KEY_T tls) {
10490 + vcos_generic_tls_delete(tls);
10493 +#undef VCOS_ASSERT_LOGGING_DISABLE
10494 +#define VCOS_ASSERT_LOGGING_DISABLE 0
10496 +#endif /* VCOS_INLINE_BODIES */
10498 +#ifdef __cplusplus
10506 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_joinable_thread_from_plain.h
10508 +/*=============================================================================
10509 +Copyright (c) 2009 Broadcom Europe Limited.
10510 +All rights reserved.
10515 +VideoCore OS Abstraction Layer - implementation: joinable thread from plain
10516 +=============================================================================*/
10520 + * Header file for platforms creating the joinable thread from a lowlevel
10523 + * In addition to the actual thread, the following are also created:
10525 + * - a semaphore to wait on when joining the thread
10526 + * - a semaphore to support counted suspend/resume (used by event group)
10527 + * - a per-thread timer (used by event group, but could be removed)
10530 +#ifndef VCOS_JOINABLE_THREAD_FROM_PLAIN_H
10531 +#define VCOS_JOINABLE_THREAD_FROM_PLAIN_H
10533 +#ifdef __cplusplus
10537 +#include "interface/vcos/vcos_semaphore.h"
10538 +#include "interface/vcos/vcos_lowlevel_thread.h"
10539 +#include "interface/vcos/vcos_timer.h"
10541 +#ifdef VCOS_WANT_TLS_EMULATION
10542 +#include "interface/vcos/generic/vcos_generic_tls.h"
10545 +#define VCOS_THREAD_MAGIC 0x56436a74
10547 +#define VCOS_THREAD_VALID(t) (t->magic == VCOS_THREAD_MAGIC)
10548 +#define VCOS_HAVE_THREAD_AT_EXIT 1
10550 +/** Thread attribute structure. Clients should not manipulate this directly, but
10551 + * should instead use the provided functions.
10553 +typedef struct VCOS_THREAD_ATTR_T
10555 + void *ta_stackaddr;
10556 + VCOS_UNSIGNED ta_stacksz;
10557 + VCOS_UNSIGNED ta_priority;
10558 + VCOS_UNSIGNED ta_affinity;
10559 + VCOS_UNSIGNED ta_timeslice;
10560 + VCOS_UNSIGNED legacy;
10561 + VCOS_UNSIGNED ta_autostart;
10562 +} VCOS_THREAD_ATTR_T;
10564 +/** Each thread gets a timer, which is for internal VCOS use.
10566 +typedef struct _VCOS_THREAD_TIMER_T
10568 + VCOS_TIMER_T timer;
10569 + void (*pfn)(void *);
10571 +} _VCOS_THREAD_TIMER_T;
10573 +typedef void (*VCOS_THREAD_EXIT_HANDLER_T)(void *);
10574 +/** Called at thread exit.
10576 +typedef struct VCOS_THREAD_EXIT_T
10578 + VCOS_THREAD_EXIT_HANDLER_T pfn;
10580 +} VCOS_THREAD_EXIT_T;
10581 +#define VCOS_MAX_EXIT_HANDLERS 8
10583 +/* The name field isn't used for anything, so we can just copy the
10584 + * the pointer. Nucleus makes its own copy.
10586 +typedef const char * VCOS_LLTHREAD_T_NAME;
10587 +#define _VCOS_LLTHREAD_NAME(dst,src) (dst)=(src)
10590 + * Simulated TLS support
10594 +/** Thread structure.
10596 + * \warning Do not access the members of this structure directly!
10598 +typedef struct VCOS_THREAD_T
10600 + VCOS_LLTHREAD_T thread; /**< The underlying thread */
10601 + char name[16]; /**< The name */
10602 + unsigned int magic; /**< For debug */
10603 + void *exit_data; /**< Exit data passed out in vcos_joinable_thread_exit() */
10604 + void *stack; /**< Stack, if not supplied by caller */
10605 + VCOS_SEMAPHORE_T wait; /**< Semaphore to wait on at join */
10606 + VCOS_SEMAPHORE_T suspend; /**< Semaphore to wait on for counted suspend */
10607 + int16_t joined; /**< Joined yet? For debug. */
10608 + VCOS_UNSIGNED legacy; /**< Use (argc,argv) for entry point arguments */
10609 + void *(*entry)(void*); /**< Entry point */
10610 + void *arg; /**< Argument passed to entry point */
10611 + void *(*term)(void*); /**< Termination function, used by reaper */
10612 + void *term_arg; /**< Argument passed to termination function */
10613 + _VCOS_THREAD_TIMER_T _timer; /**< Internal timer, mainly for event groups */
10614 +#ifdef VCOS_WANT_TLS_EMULATION
10615 + VCOS_TLS_THREAD_T _tls; /**< TLS data when native TLS not available, or NULL */
10617 + /** Array of functions to call at thread exit */
10618 + VCOS_THREAD_EXIT_T at_exit[VCOS_MAX_EXIT_HANDLERS];
10620 + struct VCOS_THREAD_T *next; /**< For linked lists of threads */
10623 +#if defined(VCOS_INLINE_BODIES)
10626 +void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED stacksz) {
10627 + attrs->ta_stackaddr = addr;
10628 + attrs->ta_stacksz = stacksz;
10632 +void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED stacksz) {
10633 + attrs->ta_stacksz = stacksz;
10637 +void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri) {
10638 + attrs->ta_priority = pri;
10642 +void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED affinity) {
10643 + attrs->ta_affinity = affinity;
10647 +void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts) {
10648 + attrs->ta_timeslice = ts;
10652 +void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy) {
10653 + attrs->legacy = legacy;
10657 +void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart) {
10658 + attrs->ta_autostart = autostart;
10662 +VCOS_THREAD_T *vcos_thread_current(void) {
10663 + VCOS_THREAD_T *ret = (VCOS_THREAD_T*)vcos_llthread_current();
10664 + /*If we're called from a non-vcos thread, this assert will fail.
10665 + *XXX FIXME why is this commented out?
10666 + *vcos_assert(ret->magic == VCOS_THREAD_MAGIC);
10672 +int vcos_thread_running(VCOS_THREAD_T *thread) {
10673 + return vcos_llthread_running(&thread->thread);
10677 +void vcos_thread_resume(VCOS_THREAD_T *thread) {
10678 + vcos_llthread_resume(&thread->thread);
10681 +#endif /* VCOS_INLINE_BODIES */
10684 + * \brief Create a VCOS_THREAD_T for the current thread. This is so we can have
10685 + * VCOS_THREAD_Ts even for threads not originally created by VCOS (eg the
10686 + * thread that calls vcos_init)
10688 +extern VCOS_STATUS_T _vcos_thread_create_attach(VCOS_THREAD_T *thread,
10689 + const char *name);
10692 + * \brief Deletes the VCOS_THREAD_T, but does not wait for the underlying
10693 + * thread to exit. This will cleanup everything created by
10694 + * _vcos_thread_create_attach
10696 +extern void _vcos_thread_delete(VCOS_THREAD_T *thread);
10698 +/** Register a function to be called when the current thread exits.
10700 +extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt);
10702 +/** Deregister a previously registered at-exit function.
10704 +extern void vcos_thread_deregister_at_exit(void (*pfn)(void*), void *cxt);
10706 +#ifdef __cplusplus
10709 +#endif /* VCOS_JOINABLE_THREAD_FROM_PLAIN_H */
10711 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_latch_from_sem.h
10713 +/*=============================================================================
10714 +Copyright (c) 2009 Broadcom Europe Limited.
10715 +All rights reserved.
10721 +VideoCore OS Abstraction Layer - Construct a latch from a semaphore
10722 +=============================================================================*/
10724 +/** FIXME: rename to vcos_mutex_from_sem.c
10727 +typedef struct VCOS_MUTEX_T {
10728 + VCOS_SEMAPHORE_T sem;
10729 + struct VCOS_THREAD_T *owner;
10732 +extern VCOS_STATUS_T vcos_generic_mutex_create(VCOS_MUTEX_T *latch, const char *name);
10733 +extern void vcos_generic_mutex_delete(VCOS_MUTEX_T *latch);
10734 +extern VCOS_STATUS_T vcos_generic_mutex_lock(VCOS_MUTEX_T *latch);
10735 +extern void vcos_generic_mutex_unlock(VCOS_MUTEX_T *latch);
10737 +#if defined(VCOS_INLINE_BODIES)
10740 +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *latch, const char *name) {
10741 + return vcos_generic_mutex_create(latch,name);
10745 +void vcos_mutex_delete(VCOS_MUTEX_T *latch) {
10746 + vcos_generic_mutex_delete(latch);
10750 +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *latch) {
10751 + return vcos_generic_mutex_lock(latch);
10755 +void vcos_mutex_unlock(VCOS_MUTEX_T *latch) {
10756 + vcos_generic_mutex_unlock(latch);
10759 +#endif /* VCOS_INLINE_BODIES */
10762 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_logcat.c
10764 +/*=============================================================================
10765 +Copyright (c) 2010 Broadcom Europe Limited.
10766 +All rights reserved.
10772 +Categorized logging for VCOS - a generic implementation.
10773 +=============================================================================*/
10775 +#include "interface/vcos/vcos.h"
10776 +#include "interface/vcos/vcos_ctype.h"
10777 +#include "interface/vcos/vcos_string.h"
10779 +static VCOS_MUTEX_T lock;
10780 +static int warned_loglevel; /* only warn about invalid log level once */
10781 +static VCOS_VLOG_IMPL_FUNC_T vcos_vlog_impl_func = vcos_vlog_default_impl;
10783 +#define VCOS_LOG_CATEGORY (&dflt_log_category)
10784 +static VCOS_LOG_CAT_T dflt_log_category;
10785 +VCOS_LOG_CAT_T *vcos_logging_categories = NULL;
10786 +static int inited;
10791 + * For kernel or videocore purposes, we generally want the log command. For
10792 + * user-space apps, they might want to provide their own log command, so we
10793 + * don't include the built in on.
10795 + * So pthreads/vcos_platform.h defines VCOS_WANT_LOG_CMD to be 0. It is
10796 + * undefined elsewhere.
10799 +# if !defined( VCOS_WANT_LOG_CMD )
10800 +# define VCOS_WANT_LOG_CMD 1
10803 +# define VCOS_WANT_LOG_CMD 0
10806 +#if VCOS_WANT_LOG_CMD
10808 +/*****************************************************************************
10810 +* Does a vcos_assert(0), which is useful to test logging.
10812 +*****************************************************************************/
10814 +VCOS_STATUS_T vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param )
10818 +#if defined( NDEBUG ) && !defined( VCOS_RELEASE_ASSERTS )
10819 + vcos_log_error( "vcos_asserts have been compiled out" );
10820 + vcos_cmd_printf( param, "vcos_asserts have been compiled out - did a vcos_log_error instead\n" );
10823 + vcos_cmd_printf( param, "Executed vcos_assert(0)\n" );
10826 + return VCOS_SUCCESS;
10829 +/*****************************************************************************
10831 +* Sets a vcos logging level
10833 +*****************************************************************************/
10835 +VCOS_STATUS_T vcos_log_set_cmd( VCOS_CMD_PARAM_T *param )
10837 + VCOS_LOG_CAT_T *cat;
10840 + VCOS_LOG_LEVEL_T level;
10841 + VCOS_STATUS_T status;
10843 + if ( param->argc != 3 )
10845 + vcos_cmd_usage( param );
10846 + return VCOS_EINVAL;
10849 + name = param->argv[1];
10850 + levelStr = param->argv[2];
10852 + if ( vcos_string_to_log_level( levelStr, &level ) != VCOS_SUCCESS )
10854 + vcos_cmd_printf( param, "Unrecognized logging level: '%s'\n", levelStr );
10855 + return VCOS_EINVAL;
10858 + vcos_mutex_lock(&lock);
10860 + status = VCOS_SUCCESS;
10861 + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10863 + if ( vcos_strcmp( name, cat->name ) == 0 )
10865 + cat->level = level;
10866 + vcos_cmd_printf( param, "Category %s level set to %s\n", name, levelStr );
10870 + if ( cat == NULL )
10872 + vcos_cmd_printf( param, "Unrecognized category: '%s'\n", name );
10873 + status = VCOS_ENOENT;
10876 + vcos_mutex_unlock(&lock);
10881 +/*****************************************************************************
10883 +* Prints out the current settings for a given category (or all cvategories)
10885 +*****************************************************************************/
10887 +VCOS_STATUS_T vcos_log_status_cmd( VCOS_CMD_PARAM_T *param )
10889 + VCOS_LOG_CAT_T *cat;
10890 + VCOS_STATUS_T status;
10892 + vcos_mutex_lock(&lock);
10894 + if ( param->argc == 1)
10897 + int nameWidth = 0;
10899 + /* Print information about all of the categories. */
10901 + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10903 + nw = (int)strlen( cat->name );
10905 + if ( nw > nameWidth )
10911 + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10913 + vcos_cmd_printf( param, "%-*s - %s\n", nameWidth, cat->name, vcos_log_level_to_string( cat->level ));
10918 + /* Print information about a particular category */
10920 + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10922 + if ( vcos_strcmp( cat->name, param->argv[1] ) == 0 )
10924 + vcos_cmd_printf( param, "%s - %s\n", cat->name, vcos_log_level_to_string( cat->level ));
10928 + if ( cat == NULL )
10930 + vcos_cmd_printf( param, "Unrecognized logging category: '%s'\n", param->argv[1] );
10931 + status = VCOS_ENOENT;
10936 + status = VCOS_SUCCESS;
10938 + vcos_mutex_unlock(&lock);
10943 +/*****************************************************************************
10945 +* Prints out the current settings for a given category (or all cvategories)
10947 +*****************************************************************************/
10949 +VCOS_STATUS_T vcos_log_test_cmd( VCOS_CMD_PARAM_T *param )
10951 + if ( param->argc == 1 )
10953 + static int seq_num = 100;
10955 + /* No additional arguments - generate a message with an incrementing number */
10957 + vcos_log_error( "Test message %d", seq_num );
10960 + vcos_cmd_printf( param, "Logged 'Test message %d'\n", seq_num );
10966 + /* Arguments supplied - log these */
10968 + for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
10970 + vcos_log_error( "argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
10972 + vcos_cmd_printf( param, "Logged %d line(s) of test data\n", param->argc );
10974 + return VCOS_SUCCESS;
10977 +/*****************************************************************************
10979 +* Internal commands
10981 +*****************************************************************************/
10983 +static VCOS_CMD_T log_cmd_entry[] =
10985 + { "assert", "", vcos_log_assert_cmd, NULL, "Does a vcos_assert(0) to test logging" },
10986 + { "set", "category level", vcos_log_set_cmd, NULL, "Sets the vcos logging level for a category" },
10987 + { "status", "[category]", vcos_log_status_cmd, NULL, "Prints the vcos log status for a (or all) categories" },
10988 + { "test", "[arbitrary text]", vcos_log_test_cmd, NULL, "Does a vcos_log to test logging" },
10990 + { NULL, NULL, NULL, NULL, NULL }
10993 +static VCOS_CMD_T cmd_log =
10994 + { "log", "command [args]", NULL, log_cmd_entry, "Commands related to vcos logging" };
10998 +void vcos_logging_init(void)
11002 + /* FIXME: should print a warning or something here */
11005 + vcos_mutex_create(&lock, "vcos_log");
11007 + vcos_log_platform_init();
11009 + vcos_log_register("default", &dflt_log_category);
11011 +#if VCOS_WANT_LOG_CMD
11012 + vcos_cmd_register( &cmd_log );
11015 + vcos_assert(!inited);
11019 +/** Read an alphanumeric token, returning True if we succeeded.
11022 +static int read_tok(char *tok, size_t toklen, const char **pstr, char sep)
11024 + const char *str = *pstr;
11028 + /* skip past any whitespace */
11029 + while (str[0] && isspace((int)(str[0])))
11032 + while ((ch = *str) != '\0' &&
11034 + (isalnum((int)ch) || (ch == '_')) &&
11041 + /* did it work out? */
11042 + if (ch == '\0' || ch == sep)
11044 + if (ch) str++; /* move to next token if not at end */
11057 +const char *vcos_log_level_to_string( VCOS_LOG_LEVEL_T level )
11061 + case VCOS_LOG_UNINITIALIZED: return "uninit";
11062 + case VCOS_LOG_NEVER: return "never";
11063 + case VCOS_LOG_ERROR: return "error";
11064 + case VCOS_LOG_WARN: return "warn";
11065 + case VCOS_LOG_INFO: return "info";
11066 + case VCOS_LOG_TRACE: return "trace";
11071 +VCOS_STATUS_T vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level )
11073 + if (strcmp(str,"error") == 0)
11074 + *level = VCOS_LOG_ERROR;
11075 + else if (strcmp(str,"never") == 0)
11076 + *level = VCOS_LOG_NEVER;
11077 + else if (strcmp(str,"warn") == 0)
11078 + *level = VCOS_LOG_WARN;
11079 + else if (strcmp(str,"warning") == 0)
11080 + *level = VCOS_LOG_WARN;
11081 + else if (strcmp(str,"info") == 0)
11082 + *level = VCOS_LOG_INFO;
11083 + else if (strcmp(str,"trace") == 0)
11084 + *level = VCOS_LOG_TRACE;
11086 + return VCOS_EINVAL;
11088 + return VCOS_SUCCESS;
11091 +static int read_level(VCOS_LOG_LEVEL_T *level, const char **pstr, char sep)
11095 + if (read_tok(buf,sizeof(buf),pstr,sep))
11097 + if (vcos_string_to_log_level(buf,level) != VCOS_SUCCESS)
11099 + vcos_log("Invalid trace level '%s'\n", buf);
11110 +void vcos_log_register(const char *name, VCOS_LOG_CAT_T *category)
11113 + VCOS_LOG_CAT_T *i;
11115 + category->name = name;
11116 + if ( category->level == VCOS_LOG_UNINITIALIZED )
11118 + category->level = VCOS_LOG_ERROR;
11120 + category->flags.want_prefix = (category != &dflt_log_category );
11122 + vcos_mutex_lock(&lock);
11124 + /* is it already registered? */
11125 + for (i = vcos_logging_categories; i ; i = i->next )
11127 + if (i == category)
11136 + /* not yet registered */
11137 + category->next = vcos_logging_categories;
11138 + vcos_logging_categories = category;
11139 + category->refcount++;
11141 + vcos_log_platform_register(category);
11144 + vcos_mutex_unlock(&lock);
11146 + /* Check to see if this log level has been enabled. Look for
11147 + * (<category:level>,)*
11149 + * VC_LOGLEVEL=ilcs:info,vchiq:warn
11152 + env = _VCOS_LOG_LEVEL();
11157 + char env_name[64];
11158 + VCOS_LOG_LEVEL_T level;
11159 + if (read_tok(env_name, sizeof(env_name), &env, ':') &&
11160 + read_level(&level, &env, ','))
11162 + if (strcmp(env_name, name) == 0)
11164 + category->level = level;
11170 + if (!warned_loglevel)
11172 + vcos_log("VC_LOGLEVEL format invalid at %s\n", env);
11173 + warned_loglevel = 1;
11177 + } while (env[0] != '\0');
11180 + vcos_log_info( "Registered log category '%s' with level %s",
11182 + vcos_log_level_to_string( category->level ));
11185 +void vcos_log_unregister(VCOS_LOG_CAT_T *category)
11187 + VCOS_LOG_CAT_T **pcat;
11188 + vcos_mutex_lock(&lock);
11189 + category->refcount--;
11190 + if (category->refcount == 0)
11192 + pcat = &vcos_logging_categories;
11193 + while (*pcat != category)
11196 + break; /* possibly deregistered twice? */
11197 + if ((*pcat)->next == NULL)
11199 + vcos_assert(0); /* already removed! */
11200 + vcos_mutex_unlock(&lock);
11203 + pcat = &(*pcat)->next;
11206 + *pcat = category->next;
11208 + vcos_log_platform_unregister(category);
11210 + vcos_mutex_unlock(&lock);
11213 +VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void)
11215 + return &dflt_log_category;
11218 +void vcos_set_log_options(const char *opt)
11223 +void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
11224 + const char *label,
11226 + const void *voidMem,
11227 + size_t numBytes )
11229 + const uint8_t *mem = (const uint8_t *)voidMem;
11231 + char lineBuf[ 100 ];
11234 + while ( numBytes > 0 )
11238 + for ( offset = 0; offset < 16; offset++ )
11240 + if ( offset < numBytes )
11242 + s += vcos_snprintf( s, 4, "%02x ", mem[ offset ]);
11246 + s += vcos_snprintf( s, 4, " " );
11250 + for ( offset = 0; offset < 16; offset++ )
11252 + if ( offset < numBytes )
11254 + uint8_t ch = mem[ offset ];
11256 + if (( ch < ' ' ) || ( ch > '~' ))
11265 + if (( label != NULL ) && ( *label != '\0' ))
11267 + vcos_log_impl( cat, VCOS_LOG_INFO, "%s: %08x: %s", label, addr, lineBuf );
11271 + vcos_log_impl( cat, VCOS_LOG_INFO, "%08x: %s", addr, lineBuf );
11276 + if ( numBytes > 16 )
11288 +void vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...)
11291 + va_start(ap,fmt);
11292 + vcos_vlog_impl( cat, _level, fmt, ap );
11296 +void vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
11298 + vcos_vlog_impl_func( cat, _level, fmt, args );
11301 +void vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func )
11303 + if ( vlog_impl_func == NULL )
11305 + vcos_vlog_impl_func = vcos_vlog_default_impl;
11309 + vcos_vlog_impl_func = vlog_impl_func;
11314 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.c
11316 +/*=============================================================================
11317 +Copyright (c) 2009 Broadcom Europe Limited.
11318 +All rights reserved.
11324 +VideoCore OS Abstraction Layer - memory alloc implementation
11325 +=============================================================================*/
11327 +#include "interface/vcos/vcos.h"
11329 +#ifndef _vcos_platform_malloc
11330 +#include <stdlib.h>
11331 +#define _vcos_platform_malloc malloc
11332 +#define _vcos_platform_free free
11335 +typedef struct malloc_header_s {
11336 + uint32_t guardword;
11338 + const char *description;
11340 +} MALLOC_HEADER_T;
11343 +#define MIN_ALIGN sizeof(MALLOC_HEADER_T)
11345 +#define GUARDWORDHEAP 0xa55a5aa5
11347 +void *vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *desc)
11349 + int local_align = align == 0 ? 1 : align;
11350 + int required_size = size + local_align + sizeof(MALLOC_HEADER_T);
11351 + void *ptr = _vcos_platform_malloc(required_size);
11352 + void *ret = (void *)VCOS_ALIGN_UP(((char *)ptr)+sizeof(MALLOC_HEADER_T), local_align);
11353 + MALLOC_HEADER_T *h = ((MALLOC_HEADER_T *)ret)-1;
11356 + h->description = desc;
11357 + h->guardword = GUARDWORDHEAP;
11363 +void *vcos_generic_mem_alloc(VCOS_UNSIGNED size, const char *desc)
11365 + return vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
11368 +void *vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *desc)
11370 + uint32_t size = count*sz;
11371 + void *ptr = vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
11374 + memset(ptr, 0, size);
11379 +void vcos_generic_mem_free(void *ptr)
11381 + MALLOC_HEADER_T *h;
11382 + if (! ptr) return;
11384 + h = ((MALLOC_HEADER_T *)ptr)-1;
11385 + vcos_assert(h->guardword == GUARDWORDHEAP);
11386 + _vcos_platform_free(h->ptr);
11390 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.h
11392 +/*=============================================================================
11393 +Copyright (c) 2009 Broadcom Europe Limited.
11394 +All rights reserved.
11396 +Project : VMCS Host Apps
11397 +Module : Framework - VMCS
11400 +Create the vcos_malloc API from the regular system malloc/free
11401 +=============================================================================*/
11406 + * Create the vcos malloc API from a regular system malloc/free library.
11408 + * The API lets callers specify an alignment.
11410 + * Under VideoCore this is not needed, as we can simply use the rtos_malloc routines.
11411 + * But on host platforms that won't be the case.
11415 +VCOSPRE_ void * VCOSPOST_ vcos_generic_mem_alloc(VCOS_UNSIGNED sz, const char *desc);
11416 +VCOSPRE_ void * VCOSPOST_ vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *descr);
11417 +VCOSPRE_ void VCOSPOST_ vcos_generic_mem_free(void *ptr);
11418 +VCOSPRE_ void * VCOSPOST_ vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED sz, VCOS_UNSIGNED align, const char *desc);
11420 +#ifdef VCOS_INLINE_BODIES
11423 +void *vcos_malloc(VCOS_UNSIGNED size, const char *description) {
11424 + return vcos_generic_mem_alloc(size, description);
11428 +void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description) {
11429 + return vcos_generic_mem_calloc(num, size, description);
11433 +void vcos_free(void *ptr) {
11434 + vcos_generic_mem_free(ptr);
11438 +void * vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description) {
11439 + return vcos_generic_mem_alloc_aligned(size, align, description);
11443 +#endif /* VCOS_INLINE_BODIES */
11447 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mutexes_are_reentrant.h
11449 +/*=============================================================================
11450 +Copyright (c) 2009 Broadcom Europe Limited.
11451 +All rights reserved.
11454 +Module : chip driver
11457 +VideoCore OS Abstraction Layer - reentrant mutexes mapped directly to regular ones
11458 +=============================================================================*/
11460 +#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
11461 +#define VCOS_GENERIC_REENTRANT_MUTEX_H
11463 +#ifdef __cplusplus
11467 +#include "interface/vcos/vcos_types.h"
11468 +#include "interface/vcos/vcos_mutex.h"
11473 + * Reentrant Mutexes directly using the native re-entrant mutex.
11477 +typedef VCOS_MUTEX_T VCOS_REENTRANT_MUTEX_T;
11479 +/* Inline forwarding functions */
11481 +#if defined(VCOS_INLINE_BODIES)
11484 +VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) {
11485 + return vcos_mutex_create(m,name);
11489 +void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
11490 + vcos_mutex_delete(m);
11494 +void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
11495 + vcos_mutex_lock(m);
11499 +void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
11500 + vcos_mutex_unlock(m);
11504 +int vcos_reentrant_mutex_is_locked(VCOS_REENTRANT_MUTEX_T *m) {
11505 + return vcos_mutex_is_locked(m);
11510 +#ifdef __cplusplus
11518 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_thread_reaper.h
11520 +/*=============================================================================
11521 +Copyright (c) 2010 Broadcom Europe Limited.
11522 +All rights reserved.
11528 +VideoCore OS Abstraction Layer - thread reaping
11529 +=============================================================================*/
11531 +#ifndef VCOS_THREAD_REAPER_H
11532 +#define VCOS_THREAD_REAPER_H
11534 +#define VCOS_HAVE_THREAD_REAPER
11536 +/** Initialise the thread reaper.
11538 +VCOS_STATUS_T vcos_thread_reaper_init(void);
11540 +/** Reap a thread. Arranges for the thread to be automatically
11543 + * @sa vcos_thread_join().
11545 + * @param thread the thread to terminate
11546 + * @param on_terminated called after the thread has exited
11547 + * @param cxt pass back to the callback
11550 +void vcos_thread_reap(VCOS_THREAD_T *thread, void (*on_terminated)(void*), void *cxt);
11556 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/stdint.h
11558 +/*=============================================================================
11559 +Copyright (c) 2010 Broadcom Europe Limited.
11560 +All rights reserved.
11563 +VideoCore OS fAbstraction Layer - stdint.h C standard header
11564 +=============================================================================*/
11566 +#ifndef _VCOS_PLATFORM_LINUX_STDINT_H
11567 +#define _VCOS_PLATFORM_LINUX_STDINT_H
11569 +/* The Linux kernel does not have a <stdint.h> so we have to provide one of
11572 +#include <linux/types.h> /* includes integer types */
11574 +#endif /* _VCOS_PLATFORM_LINUX_STDINT_H */
11576 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel.c
11578 +/*=============================================================================
11579 +Copyright (c) 2009 Broadcom Europe Limited.
11580 +All rights reserved.
11586 +VideoCore OS Abstraction Layer - pthreads types
11587 +=============================================================================*/
11589 +#define VCOS_INLINE_BODIES
11590 +#include <linux/module.h>
11591 +#include <linux/kernel.h>
11592 +#include <linux/time.h>
11593 +#include <linux/pid.h>
11594 +#include <linux/mm.h>
11595 +#include <linux/version.h>
11597 +#if defined( CONFIG_BCM_KNLLOG_SUPPORT )
11598 +#include <linux/broadcom/knllog.h>
11600 +#include "interface/vcos/vcos.h"
11601 +#ifdef HAVE_VCOS_VERSION
11602 +#include "interface/vcos/vcos_build_info.h"
11605 +VCOS_CFG_ENTRY_T vcos_cfg_dir;
11606 +VCOS_CFG_ENTRY_T vcos_logging_cfg_dir;
11607 +VCOS_CFG_ENTRY_T vcos_version_cfg;
11609 +#ifndef VCOS_DEFAULT_STACK_SIZE
11610 +#define VCOS_DEFAULT_STACK_SIZE 4096
11613 +static VCOS_THREAD_ATTR_T default_attrs = {
11615 + VCOS_DEFAULT_STACK_SIZE,
11618 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
11619 +static DEFINE_SEMAPHORE(lock);
11621 +static DECLARE_MUTEX(lock);
11624 +typedef void (*LEGACY_ENTRY_FN_T)(int, void *);
11626 +/** Wrapper function around the real thread function. Posts the semaphore
11627 + * when completed.
11629 +static int vcos_thread_wrapper(void *arg)
11632 + VCOS_THREAD_T *thread = arg;
11634 + vcos_assert(thread->magic == VCOS_THREAD_MAGIC);
11636 + thread->thread.thread = current;
11638 + vcos_add_thread(thread);
11640 +#ifdef VCOS_WANT_TLS_EMULATION
11641 + vcos_tls_thread_register(&thread->_tls);
11644 + if (thread->legacy)
11646 + LEGACY_ENTRY_FN_T fn = (LEGACY_ENTRY_FN_T)thread->entry;
11647 + fn(0,thread->arg);
11652 + ret = thread->entry(thread->arg);
11655 + thread->exit_data = ret;
11657 + vcos_remove_thread(current);
11659 + /* For join and cleanup */
11660 + vcos_semaphore_post(&thread->wait);
11665 +VCOS_STATUS_T vcos_thread_create(VCOS_THREAD_T *thread,
11666 + const char *name,
11667 + VCOS_THREAD_ATTR_T *attrs,
11668 + VCOS_THREAD_ENTRY_FN_T entry,
11671 + VCOS_STATUS_T st;
11672 + struct task_struct *kthread;
11674 + memset(thread, 0, sizeof(*thread));
11675 + thread->magic = VCOS_THREAD_MAGIC;
11676 + strlcpy( thread->name, name, sizeof( thread->name ));
11677 + thread->legacy = attrs ? attrs->legacy : 0;
11678 + thread->entry = entry;
11679 + thread->arg = arg;
11684 + return VCOS_EINVAL;
11687 + st = vcos_semaphore_create(&thread->wait, NULL, 0);
11688 + if (st != VCOS_SUCCESS)
11693 + st = vcos_semaphore_create(&thread->suspend, NULL, 0);
11694 + if (st != VCOS_SUCCESS)
11699 + /*required for event groups */
11700 + vcos_timer_create(&thread->_timer.timer, thread->name, NULL, NULL);
11702 + kthread = kthread_create((int (*)(void *))vcos_thread_wrapper, (void*)thread, name);
11703 + vcos_assert(kthread != NULL);
11704 + set_user_nice(kthread, attrs->ta_priority);
11705 + thread->thread.thread = kthread;
11706 + wake_up_process(kthread);
11707 + return VCOS_SUCCESS;
11710 +void vcos_thread_join(VCOS_THREAD_T *thread,
11713 + vcos_assert(thread);
11714 + vcos_assert(thread->magic == VCOS_THREAD_MAGIC);
11716 + thread->joined = 1;
11718 + vcos_semaphore_wait(&thread->wait);
11722 + *pData = thread->exit_data;
11726 + if (thread->stack)
11727 + vcos_free(thread->stack);
11729 + vcos_semaphore_delete(&thread->wait);
11730 + vcos_semaphore_delete(&thread->suspend);
11734 +uint32_t vcos_getmicrosecs( void )
11736 + struct timeval tv;
11737 +/*XXX FIX ME! switch to ktime_get_ts to use MONOTONIC clock */
11738 + do_gettimeofday(&tv);
11739 + return (tv.tv_sec*1000000) + tv.tv_usec;
11742 +VCOS_STATUS_T vcos_timer_init(void)
11744 + return VCOS_SUCCESS;
11747 +static const char *log_prefix[] =
11749 + "", /* VCOS_LOG_UNINITIALIZED */
11750 + "", /* VCOS_LOG_NEVER */
11751 + KERN_ERR, /* VCOS_LOG_ERROR */
11752 + KERN_WARNING, /* VCOS_LOG_WARN */
11753 + KERN_INFO, /* VCOS_LOG_INFO */
11754 + KERN_INFO /* VCOS_LOG_TRACE */
11757 +void vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
11759 + char *newline = strchr( fmt, '\n' );
11760 + const char *prefix;
11761 + const char *real_fmt;
11763 + preempt_disable();
11765 + if ( *fmt == '<' )
11768 + real_fmt= &fmt[3];
11772 + prefix = log_prefix[_level];
11775 +#if defined( CONFIG_BCM_KNLLOG_SUPPORT )
11776 + knllog_ventry( "vcos", real_fmt, args );
11778 + printk( "%.3svcos: [%d]: ", prefix, current->pid );
11779 + vprintk( real_fmt, args );
11781 + if ( newline == NULL )
11786 + preempt_enable();
11790 +const char * _vcos_log_level(void)
11795 +/*****************************************************************************
11797 +* Displays the version information in /proc/vcos/version
11799 +*****************************************************************************/
11801 +#ifdef HAVE_VCOS_VERSION
11803 +static void show_version( VCOS_CFG_BUF_T buf, void *data )
11805 + static const char* copyright = "Copyright (c) 2011 Broadcom";
11807 + vcos_cfg_buf_printf( buf, "Built %s %s on %s\n%s\nversion %s\n",
11808 + vcos_get_build_date(),
11809 + vcos_get_build_time(),
11810 + vcos_get_build_hostname(),
11812 + vcos_get_build_version() );
11817 +/*****************************************************************************
11819 +* Initialises vcos
11821 +*****************************************************************************/
11823 +VCOS_STATUS_T vcos_init(void)
11825 + if ( vcos_cfg_mkdir( &vcos_cfg_dir, NULL, "vcos" ) != VCOS_SUCCESS )
11827 + printk( KERN_ERR "%s: Unable to create vcos cfg entry\n", __func__ );
11829 + vcos_logging_init();
11831 +#ifdef HAVE_VCOS_VERSION
11832 + if ( vcos_cfg_create_entry( &vcos_version_cfg, &vcos_cfg_dir, "version",
11833 + show_version, NULL, NULL ) != VCOS_SUCCESS )
11835 + printk( KERN_ERR "%s: Unable to create vcos cfg entry 'version'\n", __func__ );
11839 + return VCOS_SUCCESS;
11842 +/*****************************************************************************
11844 +* Deinitializes vcos
11846 +*****************************************************************************/
11848 +void vcos_deinit(void)
11850 +#ifdef HAVE_VCOS_VERSION
11851 + vcos_cfg_remove_entry( &vcos_version_cfg );
11853 + vcos_cfg_remove_entry( &vcos_cfg_dir );
11856 +void vcos_global_lock(void)
11861 +void vcos_global_unlock(void)
11866 +/* vcos_thread_exit() doesn't really stop this thread here
11868 + * At the moment, call to do_exit() will leak task_struct for
11869 + * current thread, so we let the vcos_thread_wrapper() do the
11870 + * cleanup and exit job, and we return w/o actually stopping the thread.
11872 + * ToDo: Kernel v2.6.31 onwards, it is considered safe to call do_exit()
11873 + * from kthread, the implementation of which is combined in 2 patches
11874 + * with commit-ids "63706172" and "cdd140bd" in oss Linux kernel tree
11877 +void vcos_thread_exit(void *arg)
11879 + VCOS_THREAD_T *thread = vcos_thread_current();
11881 + vcos_assert(thread);
11882 + vcos_assert(thread->magic == VCOS_THREAD_MAGIC);
11884 + thread->exit_data = arg;
11887 +void vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs)
11889 + *attrs = default_attrs;
11892 +void _vcos_task_timer_set(void (*pfn)(void *), void *cxt, VCOS_UNSIGNED ms)
11894 + VCOS_THREAD_T *self = vcos_thread_current();
11895 + vcos_assert(self);
11896 + vcos_assert(self->_timer.pfn == NULL);
11898 + vcos_timer_create( &self->_timer.timer, "TaskTimer", pfn, cxt );
11899 + vcos_timer_set(&self->_timer.timer, ms);
11902 +void _vcos_task_timer_cancel(void)
11904 + VCOS_THREAD_T *self = vcos_thread_current();
11905 + if (self->_timer.timer.linux_timer.function)
11907 + vcos_timer_cancel(&self->_timer.timer);
11908 + vcos_timer_delete(&self->_timer.timer);
11912 +int vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap )
11914 + return vsnprintf( buf, buflen, fmt, ap );
11917 +int vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...)
11921 + va_start(ap,fmt);
11922 + ret = vsnprintf(buf, buflen, fmt, ap);
11927 +int vcos_llthread_running(VCOS_LLTHREAD_T *t) {
11928 + vcos_assert(0); /* this function only exists as a nasty hack for the video codecs! */
11932 +static int vcos_verify_bkpts = 1;
11934 +int vcos_verify_bkpts_enabled(void)
11936 + return vcos_verify_bkpts;
11939 +/*****************************************************************************
11941 +* _vcos_log_platform_init is called from vcos_logging_init
11943 +*****************************************************************************/
11945 +void _vcos_log_platform_init(void)
11947 + if ( vcos_cfg_mkdir( &vcos_logging_cfg_dir, &vcos_cfg_dir, "logging" ) != VCOS_SUCCESS )
11949 + printk( KERN_ERR "%s: Unable to create logging cfg entry\n", __func__ );
11953 +/*****************************************************************************
11955 +* Called to display the contents of a logging category.
11957 +*****************************************************************************/
11959 +static void logging_show_category( VCOS_CFG_BUF_T buf, void *data )
11961 + VCOS_LOG_CAT_T *category = data;
11963 + vcos_cfg_buf_printf( buf, "%s\n", vcos_log_level_to_string( category->level ));
11966 +/*****************************************************************************
11968 +* Called to parse content for a logging category.
11970 +*****************************************************************************/
11972 +static void logging_parse_category( VCOS_CFG_BUF_T buf, void *data )
11974 + VCOS_LOG_CAT_T *category = data;
11975 + const char *str = vcos_cfg_buf_get_str( buf );
11976 + VCOS_LOG_LEVEL_T level;
11978 + if ( vcos_string_to_log_level( str, &level ) == VCOS_SUCCESS )
11980 + category->level = level;
11984 + printk( KERN_ERR "%s: Unrecognized logging level: '%s'\n",
11989 +/*****************************************************************************
11991 +* _vcos_log_platform_register is called from vcos_log_register whenever
11992 +* a new category is registered.
11994 +*****************************************************************************/
11996 +void _vcos_log_platform_register(VCOS_LOG_CAT_T *category)
11998 + VCOS_CFG_ENTRY_T entry;
12000 + if ( vcos_cfg_create_entry( &entry, &vcos_logging_cfg_dir, category->name,
12001 + logging_show_category, logging_parse_category,
12002 + category ) != VCOS_SUCCESS )
12004 + printk( KERN_ERR "%s: Unable to create cfg entry for logging category '%s'\n",
12005 + __func__, category->name );
12006 + category->platform_data = NULL;
12010 + category->platform_data = entry;
12014 +/*****************************************************************************
12016 +* _vcos_log_platform_unregister is called from vcos_log_unregister whenever
12017 +* a new category is unregistered.
12019 +*****************************************************************************/
12021 +void _vcos_log_platform_unregister(VCOS_LOG_CAT_T *category)
12023 + VCOS_CFG_ENTRY_T entry;
12025 + entry = category->platform_data;
12026 + if ( entry != NULL )
12028 + if ( vcos_cfg_remove_entry( &entry ) != VCOS_SUCCESS )
12030 + printk( KERN_ERR "%s: Unable to remove cfg entry for logging category '%s'\n",
12031 + __func__, category->name );
12036 +/*****************************************************************************
12038 +* Allocate memory.
12040 +*****************************************************************************/
12042 +void *vcos_platform_malloc( VCOS_UNSIGNED required_size )
12044 + if ( required_size >= ( 2 * PAGE_SIZE ))
12046 + /* For larger allocations, use vmalloc, whose underlying allocator
12050 + return vmalloc( required_size );
12053 + /* For smaller allocation, use kmalloc */
12055 + return kmalloc( required_size, GFP_KERNEL );
12058 +/*****************************************************************************
12060 +* Free previously allocated memory
12062 +*****************************************************************************/
12064 +void vcos_platform_free( void *ptr )
12066 + if (((unsigned long)ptr >= VMALLOC_START )
12067 + && ((unsigned long)ptr < VMALLOC_END ))
12077 +/*****************************************************************************
12079 +* Execute a routine exactly once.
12081 +*****************************************************************************/
12083 +VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
12084 + void (*init_routine)(void))
12086 + /* In order to be thread-safe we need to re-test *once_control
12087 + * inside the lock. The outer test is basically an optimization
12088 + * so that once it is initialized we don't need to waste time
12089 + * trying to acquire the lock.
12092 + if ( *once_control == 0 )
12094 + vcos_global_lock();
12095 + if ( *once_control == 0 )
12098 + *once_control = 1;
12100 + vcos_global_unlock();
12103 + return VCOS_SUCCESS;
12106 +/*****************************************************************************
12108 +* String duplication routine.
12110 +*****************************************************************************/
12112 +char *vcos_strdup(const char *str)
12114 + return kstrdup(str, GFP_KERNEL);
12118 +/* Export functions for modules to use */
12119 +EXPORT_SYMBOL( vcos_init );
12121 +EXPORT_SYMBOL( vcos_semaphore_trywait );
12122 +EXPORT_SYMBOL( vcos_semaphore_post );
12123 +EXPORT_SYMBOL( vcos_semaphore_create );
12124 +EXPORT_SYMBOL( vcos_semaphore_wait );
12125 +EXPORT_SYMBOL( vcos_semaphore_delete );
12127 +EXPORT_SYMBOL( vcos_log_impl );
12128 +EXPORT_SYMBOL( vcos_vlog_impl );
12129 +EXPORT_SYMBOL( vcos_vlog_default_impl );
12130 +EXPORT_SYMBOL( vcos_log_get_default_category );
12131 +EXPORT_SYMBOL( vcos_log_register );
12132 +EXPORT_SYMBOL( vcos_log_unregister );
12133 +EXPORT_SYMBOL( vcos_logging_init );
12134 +EXPORT_SYMBOL( vcos_log_level_to_string );
12135 +EXPORT_SYMBOL( vcos_string_to_log_level );
12136 +EXPORT_SYMBOL( vcos_log_dump_mem_impl );
12138 +EXPORT_SYMBOL( vcos_event_create );
12139 +EXPORT_SYMBOL( vcos_event_delete );
12140 +EXPORT_SYMBOL( vcos_event_flags_set );
12141 +EXPORT_SYMBOL( vcos_event_signal );
12142 +EXPORT_SYMBOL( vcos_event_wait );
12143 +EXPORT_SYMBOL( vcos_event_try );
12145 +EXPORT_SYMBOL( vcos_getmicrosecs );
12147 +EXPORT_SYMBOL( vcos_strcasecmp );
12148 +EXPORT_SYMBOL( vcos_snprintf );
12149 +EXPORT_SYMBOL( vcos_vsnprintf );
12151 +EXPORT_SYMBOL( vcos_thread_current );
12152 +EXPORT_SYMBOL( vcos_thread_join );
12153 +EXPORT_SYMBOL( vcos_thread_create );
12154 +EXPORT_SYMBOL( vcos_thread_set_priority );
12155 +EXPORT_SYMBOL( vcos_thread_exit );
12156 +EXPORT_SYMBOL( vcos_once );
12158 +EXPORT_SYMBOL( vcos_thread_attr_init );
12159 +EXPORT_SYMBOL( vcos_thread_attr_setpriority );
12160 +EXPORT_SYMBOL( vcos_thread_attr_settimeslice );
12161 +EXPORT_SYMBOL( vcos_thread_attr_setstacksize );
12162 +EXPORT_SYMBOL( _vcos_thread_attr_setlegacyapi );
12164 +EXPORT_SYMBOL( vcos_event_flags_create );
12165 +EXPORT_SYMBOL( vcos_event_flags_delete );
12166 +EXPORT_SYMBOL( vcos_event_flags_get );
12168 +EXPORT_SYMBOL( vcos_sleep );
12170 +EXPORT_SYMBOL( vcos_calloc );
12171 +EXPORT_SYMBOL( vcos_malloc );
12172 +EXPORT_SYMBOL( vcos_malloc_aligned );
12173 +EXPORT_SYMBOL( vcos_free );
12175 +EXPORT_SYMBOL( vcos_mutex_create );
12176 +EXPORT_SYMBOL( vcos_mutex_delete );
12177 +EXPORT_SYMBOL( vcos_mutex_lock );
12178 +EXPORT_SYMBOL( vcos_mutex_unlock );
12179 +EXPORT_SYMBOL( vcos_mutex_trylock );
12181 +EXPORT_SYMBOL( vcos_timer_cancel );
12182 +EXPORT_SYMBOL( vcos_timer_create );
12183 +EXPORT_SYMBOL( vcos_timer_delete );
12184 +EXPORT_SYMBOL( vcos_timer_set );
12186 +EXPORT_SYMBOL( vcos_atomic_flags_create );
12187 +EXPORT_SYMBOL( vcos_atomic_flags_delete );
12188 +EXPORT_SYMBOL( vcos_atomic_flags_or );
12189 +EXPORT_SYMBOL( vcos_atomic_flags_get_and_clear );
12191 +EXPORT_SYMBOL( vcos_verify_bkpts_enabled );
12193 +EXPORT_SYMBOL( vcos_strdup );
12195 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_cfg.c
12197 +/*****************************************************************************
12198 +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved.
12200 +* Unless you and Broadcom execute a separate written software license
12201 +* agreement governing use of this software, this software is licensed to you
12202 +* under the terms of the GNU General Public License version 2, available at
12203 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
12205 +* Notwithstanding the above, under no circumstances may you combine this
12206 +* software in any way with any other Broadcom software provided under a
12207 +* license other than the GPL, without Broadcom's express prior written
12209 +*****************************************************************************/
12211 +#include "interface/vcos/vcos.h"
12212 +#include <linux/module.h>
12213 +#include <linux/proc_fs.h>
12214 +#include <linux/seq_file.h>
12215 +#include <asm/uaccess.h>
12217 +struct opaque_vcos_cfg_buf_t
12219 + struct seq_file *seq;
12223 +struct opaque_vcos_cfg_entry_t
12225 + struct proc_dir_entry *pde;
12226 + struct proc_dir_entry *parent_pde;
12227 + VCOS_CFG_SHOW_FPTR showFunc;
12228 + VCOS_CFG_PARSE_FPTR parseFunc;
12230 + const char *name;
12233 +/*****************************************************************************
12237 +*****************************************************************************/
12239 +static int cfg_proc_show( struct seq_file *s, void *v )
12241 + VCOS_CFG_ENTRY_T entry;
12242 + struct opaque_vcos_cfg_buf_t buf;
12244 + entry = s->private;
12246 + if ( entry->showFunc )
12248 + memset( &buf, 0, sizeof( buf ));
12251 + entry->showFunc( &buf, entry->data );
12257 +/*****************************************************************************
12261 +*****************************************************************************/
12263 +static ssize_t cfg_proc_write( struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
12265 + VCOS_CFG_ENTRY_T entry = PDE(file->f_path.dentry->d_inode)->data;
12267 + struct opaque_vcos_cfg_buf_t buf;
12270 + if ( entry->parseFunc != NULL )
12272 + /* The number 4000 is rather arbitrary. It just needs to be bigger than any input
12273 + * string we expect to use.
12277 + if ( count > 4000 )
12282 + /* Allocate a kernel buffer to contain the string being written. */
12284 + charBuf = kmalloc( len + 1, GFP_KERNEL );
12285 + if ( copy_from_user( charBuf, buffer, len ))
12287 + kfree( charBuf );
12291 + /* echo puts a trailing newline in the buffer - strip it out. */
12293 + if (( len > 0 ) && ( charBuf[ len - 1 ] == '\n' ))
12297 + charBuf[len] = '\0';
12299 + memset( &buf, 0, sizeof( buf ));
12300 + buf.charBuf = charBuf;
12302 + entry->parseFunc( &buf, entry->data );
12303 + kfree( charBuf );
12308 +/*****************************************************************************
12312 +*****************************************************************************/
12314 +static int cfg_proc_open( struct inode *inode, struct file *file )
12316 + return single_open( file, cfg_proc_show, PDE(inode)->data );
12319 +static const struct file_operations cfg_proc_fops =
12321 + .open = cfg_proc_open,
12322 + .read = seq_read,
12323 + .llseek = seq_lseek,
12324 + .release = single_release,
12325 + .write = cfg_proc_write,
12328 +/*****************************************************************************
12332 +*****************************************************************************/
12334 +VCOS_STATUS_T vcos_cfg_mkdir( VCOS_CFG_ENTRY_T *entryp,
12335 + VCOS_CFG_ENTRY_T *parent,
12336 + const char *dirName )
12338 + VCOS_CFG_ENTRY_T entry;
12340 + if (( entry = kzalloc( sizeof( *entry ), GFP_KERNEL )) == NULL )
12342 + return VCOS_ENOMEM;
12345 + if ( parent == NULL )
12347 + entry->pde = proc_mkdir( dirName, NULL );
12351 + entry->pde = proc_mkdir( dirName, (*parent)->pde );
12352 + entry->parent_pde = (*parent)->pde;
12354 + if ( entry->pde == NULL )
12357 + return VCOS_ENOMEM;
12360 + entry->name = dirName;
12363 + return VCOS_SUCCESS;
12366 +/*****************************************************************************
12368 +* vcos_cfg_create_entry
12370 +*****************************************************************************/
12372 +VCOS_STATUS_T vcos_cfg_create_entry( VCOS_CFG_ENTRY_T *entryp,
12373 + VCOS_CFG_ENTRY_T *parent,
12374 + const char *entryName,
12375 + VCOS_CFG_SHOW_FPTR showFunc,
12376 + VCOS_CFG_PARSE_FPTR parseFunc,
12379 + VCOS_CFG_ENTRY_T entry;
12384 + if (( entry = kzalloc( sizeof( *entry ), GFP_KERNEL )) == NULL )
12386 + return VCOS_ENOMEM;
12390 + if ( showFunc != NULL )
12394 + if ( parseFunc != NULL )
12399 + if ( parent == NULL )
12401 + entry->pde = create_proc_entry( entryName, mode, NULL );
12405 + entry->pde = create_proc_entry( entryName, mode, (*parent)->pde );
12406 + entry->parent_pde = (*parent)->pde;
12408 + if ( entry->pde == NULL )
12413 + entry->showFunc = showFunc;
12414 + entry->parseFunc = parseFunc;
12415 + entry->data = data;
12416 + entry->name = entryName;
12418 + entry->pde->data = entry;
12419 + entry->pde->proc_fops = &cfg_proc_fops;
12422 + return VCOS_SUCCESS;
12425 +/*****************************************************************************
12427 +* vcos_cfg_remove_entry
12429 +*****************************************************************************/
12431 +VCOS_STATUS_T vcos_cfg_remove_entry( VCOS_CFG_ENTRY_T *entryp )
12433 + if (( entryp != NULL ) && ( *entryp != NULL ))
12435 + remove_proc_entry( (*entryp)->name, (*entryp)->parent_pde );
12437 + kfree( *entryp );
12441 + return VCOS_SUCCESS;
12444 +/*****************************************************************************
12446 +* vcos_cfg_is_entry_created
12448 +*****************************************************************************/
12450 +int vcos_cfg_is_entry_created( VCOS_CFG_ENTRY_T entry )
12452 + return ( entry != NULL ) && ( entry->pde != NULL );
12455 +/*****************************************************************************
12457 +* vcos_cfg_buf_printf
12459 +*****************************************************************************/
12461 +void vcos_cfg_buf_printf( VCOS_CFG_BUF_T buf, const char *fmt, ... )
12463 + struct seq_file *m = buf->seq;
12465 + /* Bah - there is no seq_vprintf */
12470 + if (m->count < m->size) {
12471 + va_start(args, fmt);
12472 + len = vsnprintf(m->buf + m->count, m->size - m->count, fmt, args);
12474 + if (m->count + len < m->size) {
12479 + m->count = m->size;
12482 +/*****************************************************************************
12484 +* vcos_cfg_buf_get_str
12486 +*****************************************************************************/
12488 +char *vcos_cfg_buf_get_str( VCOS_CFG_BUF_T buf )
12490 + return buf->charBuf;
12493 +/*****************************************************************************
12495 +* vcos_cfg_get_proc_entry
12497 +* This function is only created for a couple of backwards compatibility '
12498 +* issues and shouldn't normally be used.
12500 +*****************************************************************************/
12502 +void *vcos_cfg_get_proc_entry( VCOS_CFG_ENTRY_T entry )
12504 + return entry->pde;
12507 +/*****************************************************************************
12509 +* vcos_cfg_get_entry_name
12511 +*****************************************************************************/
12513 +const char *vcos_cfg_get_entry_name( VCOS_CFG_ENTRY_T entry )
12515 + return entry->pde->name;
12519 +EXPORT_SYMBOL( vcos_cfg_mkdir );
12520 +EXPORT_SYMBOL( vcos_cfg_create_entry );
12521 +EXPORT_SYMBOL( vcos_cfg_remove_entry );
12522 +EXPORT_SYMBOL( vcos_cfg_get_entry_name );
12523 +EXPORT_SYMBOL( vcos_cfg_is_entry_created );
12524 +EXPORT_SYMBOL( vcos_cfg_buf_printf );
12525 +EXPORT_SYMBOL( vcos_cfg_buf_get_str );
12527 +EXPORT_SYMBOL_GPL( vcos_cfg_get_proc_entry );
12530 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_misc.c
12532 +// #############################################################################
12533 +// START #######################################################################
12534 +/*****************************************************************************
12535 +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved.
12537 +* Unless you and Broadcom execute a separate written software license
12538 +* agreement governing use of this software, this software is licensed to you
12539 +* under the terms of the GNU General Public License version 2, available at
12540 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
12542 +* Notwithstanding the above, under no circumstances may you combine this
12543 +* software in any way with any other Broadcom software provided under a
12544 +* license other than the GPL, without Broadcom's express prior written
12546 +*****************************************************************************/
12548 +#include "interface/vcos/vcos.h"
12549 +#include <linux/sched.h>
12550 +#include <linux/module.h>
12551 +#include <linux/freezer.h>
12552 +#include <linux/string.h>
12553 +#include <linux/slab.h>
12555 +/*****************************************************************************
12557 +* vcos_semaphore_wait_freezable
12559 +*****************************************************************************/
12561 +VCOS_STATUS_T vcos_semaphore_wait_freezable(VCOS_SEMAPHORE_T *sem)
12563 + int rval, sig_pended = 0;
12564 + unsigned long flags;
12565 + struct task_struct *task = current;
12568 + rval = down_interruptible((struct semaphore *)sem);
12569 + if (rval == 0) { /* down now */
12572 + if (freezing(current)) {
12575 + spin_lock_irqsave(&task->sighand->siglock, flags);
12576 + if (test_tsk_thread_flag(task, TIF_SIGPENDING)) {
12577 + clear_tsk_thread_flag(task, TIF_SIGPENDING);
12580 + spin_unlock_irqrestore(&task->sighand->siglock, flags);
12585 + if (sig_pended) {
12586 + spin_lock_irqsave(&task->sighand->siglock, flags);
12587 + set_tsk_thread_flag(task, TIF_SIGPENDING);
12588 + spin_unlock_irqrestore(&task->sighand->siglock, flags);
12594 +EXPORT_SYMBOL( vcos_semaphore_wait_freezable );
12596 +/*****************************************************************************
12600 +* We really need to convert malloc to do kmalloc or vmalloc based on the
12601 +* size, but for now we'll add a separate function.
12603 +*****************************************************************************/
12605 +void *vcos_kmalloc(VCOS_UNSIGNED size, const char *description)
12607 + (void)description;
12609 + return kmalloc( size, GFP_KERNEL );
12612 +/*****************************************************************************
12616 +* We really need to convert malloc to do kmalloc or vmalloc based on the
12617 +* size, but for now we'll add a separate function.
12619 +*****************************************************************************/
12621 +void *vcos_kcalloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description)
12623 + (void)description;
12625 + return kzalloc( num * size, GFP_KERNEL );
12628 +/*****************************************************************************
12632 +*****************************************************************************/
12634 +void vcos_kfree(void *ptr)
12639 +EXPORT_SYMBOL( vcos_kmalloc );
12640 +EXPORT_SYMBOL( vcos_kcalloc );
12641 +EXPORT_SYMBOL( vcos_kfree );
12643 +// END #########################################################################
12644 +// #############################################################################
12646 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_mod_init.c
12648 +/*****************************************************************************
12649 +* Copyright 2006 - 2008 Broadcom Corporation. All rights reserved.
12651 +* Unless you and Broadcom execute a separate written software license
12652 +* agreement governing use of this software, this software is licensed to you
12653 +* under the terms of the GNU General Public License version 2, available at
12654 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
12656 +* Notwithstanding the above, under no circumstances may you combine this
12657 +* software in any way with any other Broadcom software provided under a
12658 +* license other than the GPL, without Broadcom's express prior written
12660 +****************************************************************************/
12662 +/* ---- Include Files ---------------------------------------------------- */
12664 +#include "interface/vcos/vcos.h"
12665 +#include <linux/module.h>
12667 +/* ---- Public Variables ------------------------------------------------- */
12669 +/* ---- Private Constants and Types -------------------------------------- */
12671 +/* ---- Private Variables ------------------------------------------------ */
12673 +/* ---- Private Function Prototypes -------------------------------------- */
12675 +/* ---- Functions -------------------------------------------------------- */
12677 +/****************************************************************************
12679 +* Called to perform module initialization when the module is loaded
12681 +***************************************************************************/
12683 +static int __init vcos_mod_init( void )
12685 + printk( KERN_INFO "VCOS Module\n" );
12691 +/****************************************************************************
12693 +* Called to perform module cleanup when the module is unloaded.
12695 +***************************************************************************/
12697 +static void __exit vcos_mod_exit( void )
12702 +/****************************************************************************/
12704 +module_init( vcos_mod_init );
12705 +module_exit( vcos_mod_exit );
12707 +MODULE_AUTHOR("Broadcom");
12708 +MODULE_DESCRIPTION( "VCOS Module Functions" );
12709 +MODULE_LICENSE( "GPL" );
12710 +MODULE_VERSION( "1.0" );
12713 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform.h
12715 +/*=============================================================================
12716 +Copyright (c) 2009 Broadcom Europe Limited.
12717 +All rights reserved.
12723 +VideoCore OS Abstraction Layer - Linux kernel (partial) implementation.
12724 +=============================================================================*/
12726 +/* Do not include this file directly - instead include it via vcos.h */
12730 + * Linux kernel (partial) implementation of VCOS.
12734 +#ifndef VCOS_PLATFORM_H
12735 +#define VCOS_PLATFORM_H
12737 +#include <linux/types.h>
12738 +#include <linux/semaphore.h>
12739 +#include <linux/mutex.h>
12740 +#include <asm/bitops.h>
12741 +#include <linux/kthread.h>
12742 +#include <linux/wait.h>
12743 +#include <linux/vmalloc.h>
12744 +#include <linux/jiffies.h>
12745 +#include <linux/delay.h>
12746 +#include <linux/string.h>
12747 +#include <linux/types.h>
12748 +#include <linux/interrupt.h>
12749 +#include <linux/random.h>
12750 +#include <linux/sched.h>
12751 +#include <linux/ctype.h>
12752 +#include <linux/uaccess.h>
12753 +#include <linux/time.h> /* for time_t */
12754 +#include <linux/slab.h>
12755 +#include <linux/vmalloc.h>
12757 +#define VCOS_HAVE_RTOS 1
12758 +#define VCOS_HAVE_SEMAPHORE 1
12759 +#define VCOS_HAVE_EVENT 1
12760 +#define VCOS_HAVE_QUEUE 0
12761 +#define VCOS_HAVE_LEGACY_ISR 0
12762 +#define VCOS_HAVE_TIMER 1
12763 +#define VCOS_HAVE_CANCELLATION_SAFE_TIMER 0
12764 +#define VCOS_HAVE_MEMPOOL 0
12765 +#define VCOS_HAVE_ISR 0
12766 +#define VCOS_HAVE_ATOMIC_FLAGS 1
12767 +#define VCOS_HAVE_BLOCK_POOL 0
12768 +#define VCOS_HAVE_ONCE 1
12769 +#define VCOS_HAVE_FILE 0
12770 +#define VCOS_HAVE_USER_BUF 0
12771 +#define VCOS_HAVE_CFG 1
12772 +#define VCOS_HAVE_SPINLOCK 0
12773 +#define VCOS_HAVE_CMD 1
12774 +#define VCOS_HAVE_EVENT_FLAGS 1
12776 +/* Exclude many VCOS classes which don't have predicates */
12777 +#define VCOS_TLS_H
12778 +#define VCOS_NAMED_MUTEX_H
12779 +#define VCOS_REENTRANT_MUTEX_H
12780 +#define VCOS_NAMED_SEMAPHORE_H
12781 +#define VCOS_QUICKSLOW_MUTEX_H
12782 +/*#define VCOS_INIT_H */
12783 +/*#define VCOS_MEM_H */
12784 +/*#define VCOS_STRING_H */
12786 +typedef struct semaphore VCOS_SEMAPHORE_T;
12787 +typedef struct semaphore VCOS_EVENT_T;
12788 +typedef struct mutex VCOS_MUTEX_T;
12789 +typedef volatile int VCOS_ONCE_T;
12791 +typedef unsigned int VCOS_UNSIGNED;
12792 +typedef unsigned int VCOS_OPTION;
12793 +typedef atomic_t VCOS_ATOMIC_FLAGS_T;
12797 + struct timer_list linux_timer;
12799 + void (*expiration_routine)(void *context);
12803 +typedef struct VCOS_LLTHREAD_T
12805 + struct task_struct *thread; /**< The thread itself */
12806 + VCOS_SEMAPHORE_T suspend; /**< For support event groups and similar - a per thread semaphore */
12807 +} VCOS_LLTHREAD_T;
12811 + VCOS_O_RDONLY = 00000000,
12812 + VCOS_O_WRONLY = 00000001,
12813 + VCOS_O_RDWR = 00000002,
12814 + VCOS_O_TRUNC = 00001000,
12815 +} VCOS_FILE_FLAGS_T;
12817 +typedef struct file *VCOS_FILE_T;
12819 +#define VCOS_SUSPEND -1
12820 +#define VCOS_NO_SUSPEND 0
12822 +#define VCOS_START 1
12823 +#define VCOS_NO_START 0
12825 +#define VCOS_THREAD_PRI_MIN -20
12826 +#define VCOS_THREAD_PRI_MAX 19
12828 +#define VCOS_THREAD_PRI_INCREASE -1
12829 +#define VCOS_THREAD_PRI_HIGHEST VCOS_THREAD_PRI_MIN
12830 +#define VCOS_THREAD_PRI_LOWEST VCOS_THREAD_PRI_MAX
12831 +#define VCOS_THREAD_PRI_NORMAL ((VCOS_THREAD_PRI_MAX+VCOS_THREAD_PRI_MIN)/2)
12832 +#define VCOS_THREAD_PRI_ABOVE_NORMAL (VCOS_THREAD_PRI_NORMAL + VCOS_THREAD_PRI_INCREASE)
12833 +#define VCOS_THREAD_PRI_REALTIME VCOS_THREAD_PRI_HIGHEST
12835 +#define _VCOS_AFFINITY_DEFAULT 0
12836 +#define _VCOS_AFFINITY_CPU0 0
12837 +#define _VCOS_AFFINITY_CPU1 0
12838 +#define _VCOS_AFFINITY_MASK 0
12839 +#define VCOS_CAN_SET_STACK_ADDR 0
12841 +#define VCOS_TICKS_PER_SECOND HZ
12843 +#include "interface/vcos/generic/vcos_generic_event_flags.h"
12844 +#include "interface/vcos/generic/vcos_mem_from_malloc.h"
12845 +#include "interface/vcos/generic/vcos_joinable_thread_from_plain.h"
12847 +/***********************************************************
12849 + * Memory allcoation
12851 + ***********************************************************/
12853 +#define _vcos_platform_malloc vcos_platform_malloc
12854 +#define _vcos_platform_free vcos_platform_free
12856 +void *vcos_platform_malloc( VCOS_UNSIGNED required_size );
12857 +void vcos_platform_free( void *ptr );
12859 +#if defined(VCOS_INLINE_BODIES)
12861 +#undef VCOS_ASSERT_LOGGING_DISABLE
12862 +#define VCOS_ASSERT_LOGGING_DISABLE 1
12864 +/***********************************************************
12866 + * Counted Semaphores
12868 + ***********************************************************/
12871 +VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem) {
12872 + int ret = down_interruptible(sem);
12875 + return VCOS_SUCCESS;
12876 + else if ( ret == -EINTR )
12877 + /* Interrupted */
12878 + return VCOS_EINTR;
12880 + /* Default (timeout) */
12881 + return VCOS_EAGAIN;
12885 +VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem) {
12886 + if (down_trylock(sem) != 0)
12887 + return VCOS_EAGAIN;
12888 + return VCOS_SUCCESS;
12892 +VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem,
12893 + const char *name,
12894 + VCOS_UNSIGNED initial_count) {
12895 + sema_init(sem, initial_count);
12896 + return VCOS_SUCCESS;
12900 +void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem) {
12904 +VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem) {
12906 + return VCOS_SUCCESS;
12909 +/***********************************************************
12913 + ***********************************************************/
12915 +#include "vcos_thread_map.h"
12918 +VCOS_LLTHREAD_T *vcos_llthread_current(void) {
12919 + return &vcos_kthread_current()->thread;
12923 +void vcos_llthread_resume(VCOS_LLTHREAD_T *thread) {
12928 +void vcos_sleep(uint32_t ms) {
12933 +void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED p) {
12934 + /* not implemented */
12937 +VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread) {
12938 + /* not implemented */
12942 +/***********************************************************
12946 + ***********************************************************/
12949 +int vcos_strcasecmp(const char *s1, const char *s2) {
12950 + return strcasecmp(s1,s2);
12954 +/***********************************************************
12958 + ***********************************************************/
12961 +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *m, const char *name) {
12963 + return VCOS_SUCCESS;
12967 +void vcos_mutex_delete(VCOS_MUTEX_T *m) {
12971 +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *m) {
12972 + int ret = mutex_lock_interruptible(m);
12975 + return VCOS_SUCCESS;
12976 + else if ( ret == -EINTR )
12977 + /* Interrupted */
12978 + return VCOS_EINTR;
12981 + return VCOS_EAGAIN;
12985 +void vcos_mutex_unlock(VCOS_MUTEX_T *m) {
12990 +int vcos_mutex_is_locked(VCOS_MUTEX_T *m) {
12991 + if (mutex_trylock(m) != 0)
12992 + return 1; /* it was locked */
12994 + /* it wasn't locked */
12999 +VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m) {
13000 + if (mutex_trylock(m) == 0)
13001 + return VCOS_SUCCESS;
13003 + return VCOS_EAGAIN;
13006 +/* For supporting event groups - per thread semaphore */
13008 +void _vcos_thread_sem_wait(void) {
13009 + VCOS_THREAD_T *t = vcos_thread_current();
13010 + vcos_semaphore_wait(&t->suspend);
13014 +void _vcos_thread_sem_post(VCOS_THREAD_T *target) {
13015 + vcos_semaphore_post(&target->suspend);
13018 +/***********************************************************
13022 + ***********************************************************/
13025 +VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *debug_name)
13027 + sema_init(event, 0);
13028 + return VCOS_SUCCESS;
13032 +void vcos_event_signal(VCOS_EVENT_T *event)
13038 +VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event)
13040 + int ret = down_interruptible(event);
13041 + if ( ret == -EINTR )
13042 + /* Interrupted */
13043 + return VCOS_EINTR;
13044 + else if (ret != 0)
13045 + /* Default (timeout) */
13046 + return VCOS_EAGAIN;
13047 + /* Emulate a maximum count of 1 by removing any extra upness */
13048 + while (down_trylock(event) == 0) continue;
13049 + return VCOS_SUCCESS;
13053 +VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event)
13055 + return (down_trylock(event) == 0) ? VCOS_SUCCESS : VCOS_EAGAIN;
13059 +void vcos_event_delete(VCOS_EVENT_T *event)
13063 +/***********************************************************
13067 + ***********************************************************/
13070 +void vcos_timer_linux_func(unsigned long data)
13072 + VCOS_TIMER_T *vcos_timer = (VCOS_TIMER_T *)data;
13074 + vcos_timer->expiration_routine( vcos_timer->context );
13078 +VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
13079 + const char *name,
13080 + void (*expiration_routine)(void *context),
13082 + init_timer(&timer->linux_timer);
13083 + timer->linux_timer.data = (unsigned long)timer;
13084 + timer->linux_timer.function = vcos_timer_linux_func;
13086 + timer->context = context;
13087 + timer->expiration_routine = expiration_routine;
13089 + return VCOS_SUCCESS;
13093 +void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms) {
13094 + timer->linux_timer.expires = jiffies + msecs_to_jiffies(delay_ms);
13095 + add_timer(&timer->linux_timer);
13099 +void vcos_timer_cancel(VCOS_TIMER_T *timer) {
13100 + del_timer(&timer->linux_timer);
13104 +void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms) {
13105 + del_timer_sync(&timer->linux_timer);
13106 + timer->linux_timer.expires = jiffies + msecs_to_jiffies(delay_ms);
13107 + add_timer(&timer->linux_timer);
13111 +void vcos_timer_delete(VCOS_TIMER_T *timer) {
13112 + timer->context = NULL;
13113 + timer->expiration_routine = NULL;
13114 + timer->linux_timer.function = NULL;
13115 + timer->linux_timer.data = 0;
13120 +VCOS_UNSIGNED vcos_process_id_current(void) {
13121 + return (VCOS_UNSIGNED)current->pid;
13126 +int vcos_in_interrupt(void) {
13127 + return in_interrupt();
13130 +/***********************************************************
13134 + ***********************************************************/
13137 +VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags)
13139 + atomic_set(atomic_flags, 0);
13140 + return VCOS_SUCCESS;
13144 +void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags)
13148 + value = atomic_read(atomic_flags);
13149 + } while (atomic_cmpxchg(atomic_flags, value, value | flags) != value);
13153 +uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags)
13155 + return atomic_xchg(atomic_flags, 0);
13159 +void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags)
13163 +#undef VCOS_ASSERT_LOGGING_DISABLE
13164 +#define VCOS_ASSERT_LOGGING_DISABLE 0
13166 +#endif /* VCOS_INLINE_BODIES */
13168 +VCOS_INLINE_DECL void _vcos_thread_sem_wait(void);
13169 +VCOS_INLINE_DECL void _vcos_thread_sem_post(VCOS_THREAD_T *);
13171 +/***********************************************************
13175 + ***********************************************************/
13176 +VCOS_INLINE_DECL char *vcos_strdup(const char *str);
13178 +/***********************************************************
13182 + ***********************************************************/
13184 +VCOSPRE_ const char * VCOSPOST_ _vcos_log_level(void);
13185 +#define _VCOS_LOG_LEVEL() _vcos_log_level()
13187 +#define vcos_log_platform_init() _vcos_log_platform_init()
13188 +#define vcos_log_platform_register(category) _vcos_log_platform_register(category)
13189 +#define vcos_log_platform_unregister(category) _vcos_log_platform_unregister(category)
13191 +struct VCOS_LOG_CAT_T; /* Forward declaration since vcos_logging.h hasn't been included yet */
13193 +void _vcos_log_platform_init(void);
13194 +void _vcos_log_platform_register(struct VCOS_LOG_CAT_T *category);
13195 +void _vcos_log_platform_unregister(struct VCOS_LOG_CAT_T *category);
13197 +/***********************************************************
13199 + * Memory barriers
13201 + ***********************************************************/
13203 +#define vcos_wmb(x) wmb()
13204 +#define vcos_rmb() rmb()
13206 +#include "interface/vcos/generic/vcos_common.h"
13207 +/*#include "interface/vcos/generic/vcos_generic_quickslow_mutex.h" */
13209 +#endif /* VCOS_PLATFORM_H */
13212 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform_types.h
13214 +/*=============================================================================
13215 +Copyright (c) 2009 Broadcom Europe Limited.
13216 +All rights reserved.
13222 +VideoCore OS Abstraction Layer - platform-specific types and defines
13223 +=============================================================================*/
13225 +#ifndef VCOS_PLATFORM_TYPES_H
13226 +#define VCOS_PLATFORM_TYPES_H
13228 +#include <stddef.h>
13229 +#include <linux/types.h>
13230 +#include <linux/bug.h>
13232 +#define VCOSPRE_ extern
13235 +#if defined(__GNUC__) && (( __GNUC__ > 2 ) || (( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 3 )))
13236 +#define VCOS_FORMAT_ATTR_(ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK) __attribute__ ((format (ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK)))
13238 +#define VCOS_FORMAT_ATTR_(ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK)
13241 +#if !defined( __STDC_VERSION__ )
13242 +#define __STDC_VERSION__ 199901L
13245 +#if !defined( __STDC_VERSION )
13246 +#define __STDC_VERSION __STDC_VERSION__
13249 +static inline void __vcos_bkpt( void ) { BUG(); }
13250 +#define VCOS_BKPT __vcos_bkpt()
13252 +#define VCOS_ASSERT_MSG(...) printk( KERN_ERR "vcos_assert: " __VA_ARGS__ )
13254 +#define PRId64 "lld"
13255 +#define PRIi64 "lli"
13256 +#define PRIo64 "llo"
13257 +#define PRIu64 "llu"
13258 +#define PRIx64 "llx"
13262 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.c
13264 +/*****************************************************************************
13265 +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved.
13267 +* Unless you and Broadcom execute a separate written software license
13268 +* agreement governing use of this software, this software is licensed to you
13269 +* under the terms of the GNU General Public License version 2, available at
13270 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
13272 +* Notwithstanding the above, under no circumstances may you combine this
13273 +* software in any way with any other Broadcom software provided under a
13274 +* license other than the GPL, without Broadcom's express prior written
13276 +*****************************************************************************/
13278 +/** Support to allow VCOS thread-related functions to be called from
13279 + * threads that were not created by VCOS.
13282 +#include <linux/semaphore.h>
13283 +#include <linux/vmalloc.h>
13284 +#include <linux/list.h>
13285 +#include <linux/sched.h>
13287 +#include "vcos_thread_map.h"
13288 +#include "interface/vcos/vcos_logging.h"
13291 + * Store the vcos_thread pointer at the end of
13292 + * current kthread stack, right after the thread_info
13295 + * I belive we should be safe here to steal these 4 bytes
13296 + * from the stack, as long as the vcos thread does not use up
13297 + * all the stack available
13299 + * NOTE: This scheme will not work on architectures with stack growing up
13302 +/* Shout, if we are not being compiled for ARM kernel */
13304 +#ifndef CONFIG_ARM
13305 +#error " **** The vcos kthread implementation may not work for non-ARM kernel ****"
13308 +static inline void *to_current_vcos_thread(void)
13310 + unsigned long *vcos_data;
13312 + vcos_data = (unsigned long *)((char *)current_thread_info() + sizeof(struct thread_info));
13314 + return (void *)vcos_data;
13318 +static inline void *to_vcos_thread(struct task_struct *tsk)
13320 + unsigned long *vcos_data;
13322 + vcos_data = (unsigned long *)((char *)tsk->stack + sizeof(struct thread_info));
13324 + return (void *)vcos_data;
13328 + @fn uint32_t vcos_add_thread(THREAD_MAP_T *vcos_thread);
13330 +uint32_t vcos_add_thread(VCOS_THREAD_T *vcos_thread)
13332 + VCOS_THREAD_T **vcos_thread_storage = (VCOS_THREAD_T **)to_current_vcos_thread();
13334 + *vcos_thread_storage = vcos_thread;
13341 + @fn uint32_t vcos_remove_thread(struct task_struct * thread_id);
13343 +uint32_t vcos_remove_thread(struct task_struct *thread_id)
13345 + /* Remove thread_id -> VCOS_THREAD_T relationship */
13346 + VCOS_THREAD_T **vcos_thread_storage;
13349 + * We want to be able to build vcos as a loadable module, which
13350 + * means that we can't call get_task_struct. So we assert if we're
13351 + * ever called with thread_id != current.
13354 + BUG_ON( thread_id != current );
13356 + vcos_thread_storage = (VCOS_THREAD_T **)to_vcos_thread(thread_id);
13358 + *(unsigned long *)vcos_thread_storage = 0xCAFEBABE;
13364 +VCOS_THREAD_T *vcos_kthread_current(void)
13366 + VCOS_THREAD_T **vcos_thread_storage = (VCOS_THREAD_T **)to_current_vcos_thread();
13368 + /* If we find this, either the thread is already dead or stack pages of a
13369 + * dead vcos thread are re-allocated to this one.
13371 + * Since there's no way to differentiate between these 2 cases, we just dump
13372 + * the current task name to the log.
13374 + * If the current thread is created using VCOS API, you should *never* see this
13377 + * If its a non-VCOS thread, just let it go ...
13379 + * To debug VCOS, uncomment printk's under the "if" condition below
13382 + if (*vcos_thread_storage == (void *)0xCAFEBABE)
13385 + printk(KERN_DEBUG"****************************************************\n");
13386 + printk(KERN_DEBUG"%s : You have a problem, if \"%s\" is a VCOS thread\n",__func__, current->comm);
13387 + printk(KERN_DEBUG"****************************************************\n");
13391 + return *vcos_thread_storage;
13394 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.h
13396 +/*****************************************************************************
13397 +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved.
13399 +* Unless you and Broadcom execute a separate written software license
13400 +* agreement governing use of this software, this software is licensed to you
13401 +* under the terms of the GNU General Public License version 2, available at
13402 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
13404 +* Notwithstanding the above, under no circumstances may you combine this
13405 +* software in any way with any other Broadcom software provided under a
13406 +* license other than the GPL, without Broadcom's express prior written
13408 +*****************************************************************************/
13411 +#ifndef VCOS_THREAD_MAP_H
13412 +#define VCOS_THREAD_MAP_H
13414 +#include <linux/string.h>
13416 +#include "vcos_platform.h"
13418 +static inline void vcos_thread_map_init(void)
13423 +static inline void vcos_thread_map_cleanup(void)
13428 +uint32_t vcos_add_thread(VCOS_THREAD_T *vcos_thread);
13430 +uint32_t vcos_remove_thread(struct task_struct *thread_id);
13432 +VCOS_THREAD_T *vcos_kthread_current(void);
13434 +#endif /*VCOS_THREAD_MAP_H */
13436 +++ b/drivers/misc/vc04_services/interface/vcos/vcos.h
13438 +/*=============================================================================
13439 +Copyright (c) 2009 Broadcom Europe Limited.
13440 +All rights reserved.
13443 +Module : chip driver
13446 +VideoCore OS Abstraction Layer - public header file
13447 +=============================================================================*/
13450 + * \mainpage OS Abstraction Layer
13452 + * \section intro Introduction
13454 + * This abstraction layer is here to allow the underlying OS to be easily changed (e.g. from
13455 + * Nucleus to ThreadX) and to aid in porting host applications to new targets.
13457 + * \subsection error Error handling
13459 + * Wherever possible, VCOS functions assert internally and return void. The only exceptions
13460 + * are creation functions (which might fail due to lack of resources) and functions that
13461 + * might timeout or fail due to lack of space. Errors that might be reported by the underlying
13462 + * OS API (e.g. invalid mutex) are treated as a programming error, and are merely asserted on.
13464 + * \section thread_synch Threads and synchronisation
13466 + * \subsection thread Threads
13468 + * The thread API is somewhat different to that found in Nucleus. In particular, threads
13469 + * cannot just be destroyed at arbitrary times and nor can they merely exit. This is so
13470 + * that the same API can be implemented across all interesting platforms without too much
13471 + * difficulty. See vcos_thread.h for details. Thread attributes are configured via
13472 + * the VCOS_THREAD_ATTR_T structure, found in vcos_thread_attr.h.
13474 + * \subsection sema Semaphores
13476 + * Counted semaphores (c.f. Nucleus NU_SEMAPHORE) are created with VCOS_SEMAPHORE_T.
13477 + * Under ThreadX on VideoCore, semaphores are implemented using VideoCore spinlocks, and
13478 + * so are quite a lot faster than ordinary ThreadX semaphores. See vcos_semaphore.h.
13480 + * \subsection mtx Mutexes
13482 + * Mutexes are used for locking. Attempts to take a mutex twice, or to unlock it
13483 + * in a different thread to the one in which it was locked should be expected to fail.
13484 + * Mutexes are not re-entrant (see vcos_reentrant_mutex.h for a slightly slower
13485 + * re-entrant mutex).
13487 + * \subsection evflags Event flags
13489 + * Event flags (the ThreadX name - also known as event groups under Nucleus) provide
13490 + * 32 flags which can be waited on by multiple clients, and signalled by multiple clients.
13491 + * A timeout can be specified. See vcos_event_flags.h. An alternative to this is the
13492 + * VCOS_EVENT_T (see vcos_event.h) which is akin to the Win32 auto-reset event, or a
13493 + * saturating counted semaphore.
13495 + * \subsection event Events
13497 + * A VCOS_EVENT_T is a bit like a saturating semaphore. No matter how many times it
13498 + * is signalled, the waiter will only wake up once. See vcos_event.h. You might think this
13499 + * is useful if you suspect that the cost of reading the semaphore count (perhaps via a
13500 + * system call) is expensive on your platform.
13502 + * \subsection tls Thread local storage
13504 + * Thread local storage is supported using vcos_tls.h. This is emulated on Nucleus
13507 + * \section int Interrupts
13509 + * The legacy LISR/HISR scheme found in Nucleus is supported via the legacy ISR API,
13510 + * which is also supported on ThreadX. New code should avoid this, and old code should
13511 + * be migrated away from it, since it is slow. See vcos_legacy_isr.h.
13513 + * Registering an interrupt handler, and disabling/restoring interrupts, is handled
13514 + * using the functions in vcos_isr.h.
13521 + * This is the top level header file. Clients include this. It pulls in the platform-specific
13522 + * header file (vcos_platform.h) together with header files defining the expected APIs, such
13523 + * as vcos_mutex.h, vcos_semaphore.h, etc. It is also possible to include these header files
13531 +#include "interface/vcos/vcos_assert.h"
13532 +#include "vcos_types.h"
13533 +#include "vcos_platform.h"
13535 +#ifndef VCOS_INIT_H
13536 +#include "interface/vcos/vcos_init.h"
13539 +#ifndef VCOS_SEMAPHORE_H
13540 +#include "interface/vcos/vcos_semaphore.h"
13543 +#ifndef VCOS_THREAD_H
13544 +#include "interface/vcos/vcos_thread.h"
13547 +#ifndef VCOS_MUTEX_H
13548 +#include "interface/vcos/vcos_mutex.h"
13551 +#ifndef VCOS_MEM_H
13552 +#include "interface/vcos/vcos_mem.h"
13555 +#ifndef VCOS_LOGGING_H
13556 +#include "interface/vcos/vcos_logging.h"
13559 +#ifndef VCOS_STRING_H
13560 +#include "interface/vcos/vcos_string.h"
13563 +#ifndef VCOS_EVENT_H
13564 +#include "interface/vcos/vcos_event.h"
13567 +#ifndef VCOS_THREAD_ATTR_H
13568 +#include "interface/vcos/vcos_thread_attr.h"
13571 +#ifndef VCOS_TLS_H
13572 +#include "interface/vcos/vcos_tls.h"
13575 +#ifndef VCOS_REENTRANT_MUTEX_H
13576 +#include "interface/vcos/vcos_reentrant_mutex.h"
13579 +#ifndef VCOS_NAMED_SEMAPHORE_H
13580 +#include "interface/vcos/vcos_named_semaphore.h"
13583 +#ifndef VCOS_QUICKSLOW_MUTEX_H
13584 +#include "interface/vcos/vcos_quickslow_mutex.h"
13587 +/* Headers with predicates */
13589 +#if VCOS_HAVE_EVENT_FLAGS
13590 +#include "interface/vcos/vcos_event_flags.h"
13593 +#if VCOS_HAVE_QUEUE
13594 +#include "interface/vcos/vcos_queue.h"
13597 +#if VCOS_HAVE_LEGACY_ISR
13598 +#include "interface/vcos/vcos_legacy_isr.h"
13601 +#if VCOS_HAVE_TIMER
13602 +#include "interface/vcos/vcos_timer.h"
13605 +#if VCOS_HAVE_MEMPOOL
13606 +#include "interface/vcos/vcos_mempool.h"
13610 +#include "interface/vcos/vcos_isr.h"
13613 +#if VCOS_HAVE_ATOMIC_FLAGS
13614 +#include "interface/vcos/vcos_atomic_flags.h"
13617 +#if VCOS_HAVE_ONCE
13618 +#include "interface/vcos/vcos_once.h"
13621 +#if VCOS_HAVE_BLOCK_POOL
13622 +#include "interface/vcos/vcos_blockpool.h"
13625 +#if VCOS_HAVE_FILE
13626 +#include "interface/vcos/vcos_file.h"
13630 +#include "interface/vcos/vcos_cfg.h"
13634 +#include "interface/vcos/vcos_cmd.h"
13637 +#endif /* VCOS_H */
13640 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_assert.h
13642 +/*=============================================================================
13643 +Copyright (c) 2009 Broadcom Europe Limited.
13644 +All rights reserved.
13650 +VideoCore OS Abstraction Layer - Assertion and error-handling macros.
13651 +=============================================================================*/
13654 +#ifndef VCOS_ASSERT_H
13655 +#define VCOS_ASSERT_H
13659 + * vcos_assert(cond)
13660 + * vcos_assert_msg(cond, fmt, ...)
13662 + * Detecting programming errors by ensuring that assumptions are correct.
13664 + * Performs a platform-dependent "breakpoint", usually with an assert-style
13665 + * message. The '_msg' variant expects a printf-style format string and
13667 + * If a failure is detected, the code should be fixed and rebuilt.
13668 + * In release builds:
13669 + * Generates no code, i.e. does not evaluate 'cond'.
13674 + * vcos_demand(cond)
13675 + * vcos_demand_msg(cond, fmt, ...)
13677 + * Detecting fatal system errors that require a reboot.
13679 + * Performs a platform-dependent "breakpoint", usually with an assert-style
13680 + * message, then calls vcos_abort (see below).
13681 + * In release builds:
13682 + * Calls vcos_abort() if 'cond' is false.
13684 + * Nothing (never, on failure).
13687 + * vcos_verify(cond)
13688 + * vcos_verify_msg(cond, fmt, ...)
13690 + * Detecting run-time errors and interesting conditions, normally within an
13691 + * 'if' statement to catch the failures, i.e.
13692 + * if (!vcos_verify(cond)) handle_error();
13694 + * Generates a message and optionally stops at a platform-dependent
13695 + * "breakpoint" (usually disabled). See vcos_verify_bkpts_enable below.
13696 + * In release builds:
13697 + * Just evaluates and returns 'cond'.
13699 + * Non-zero if 'cond' is true, otherwise zero.
13702 + * vcos_static_assert(cond)
13704 + * Detecting compile-time errors.
13706 + * Generates a compiler error.
13707 + * In release builds:
13708 + * Generates a compiler error.
13711 + * void vcos_abort(void)
13713 + * Invokes the fatal error handling mechanism, alerting the host where
13719 + * VCOS_VERIFY_BKPTS
13721 + * Define in a module (before including vcos.h) to specify an alternative
13722 + * flag to control breakpoints on vcos_verify() failures.
13724 + * Non-zero values enable breakpoints.
13727 + * int vcos_verify_bkpts_enable(int enable);
13729 + * Sets the global flag controlling breakpoints on vcos_verify failures,
13730 + * enabling the breakpoints iff 'enable' is non-zero.
13732 + * The previous state of the flag.
13735 + * int vcos_verify_bkpts_enabled(void);
13737 + * Queries the state of the global flag enabling breakpoints on vcos_verify
13740 + * The current state of the flag.
13744 + * int my_breakpoint_enable_flag = 1;
13746 + * #define VCOS_VERIFY_BKPTS my_breakpoint_enable_flag
13748 + * #include "interface/vcos/vcos.h"
13750 + * vcos_static_assert((sizeof(object) % 32) == 0);
13754 + * vcos_assert_msg(postcondition_is_true, "Coding error");
13756 + * if (!vcos_verify_msg(buf, "Buffer allocation failed (%d bytes)", size))
13760 + * return OUT_OF_MEMORY;
13763 + * vcos_demand(*p++==GUARDWORDHEAP);
13766 +#ifdef __cplusplus
13770 +#include "interface/vcos/vcos_types.h"
13772 +#ifdef __COVERITY__
13773 +#undef VCOS_ASSERT_BKPT
13774 +#define VCOS_ASSERT_BKPT __coverity_panic__()
13777 +#ifndef VCOS_VERIFY_BKPTS
13778 +#define VCOS_VERIFY_BKPTS vcos_verify_bkpts_enabled()
13782 +#if defined(__VIDEOCORE__) && !defined(VCOS_ASSERT_NO_BKPTS)
13783 +#define VCOS_BKPT _bkpt()
13785 +#define VCOS_BKPT (void )0
13789 +#ifndef VCOS_ASSERT_BKPT
13790 +#define VCOS_ASSERT_BKPT VCOS_BKPT
13793 +#ifndef VCOS_VERIFY_BKPT
13794 +#define VCOS_VERIFY_BKPT (VCOS_VERIFY_BKPTS ? VCOS_BKPT : (void)0)
13797 +VCOSPRE_ int VCOSPOST_ vcos_verify_bkpts_enabled(void);
13798 +VCOSPRE_ int VCOSPOST_ vcos_verify_bkpts_enable(int enable);
13799 +VCOSPRE_ void VCOSPOST_ vcos_abort(void);
13801 +#ifndef VCOS_ASSERT_MSG
13803 +extern void logging_assert(const char *file, const char *func, int line, const char *format, ...);
13804 +#define VCOS_ASSERT_MSG(...) ((VCOS_ASSERT_LOGGING && !VCOS_ASSERT_LOGGING_DISABLE) ? logging_assert(__FILE__, __func__, __LINE__, __VA_ARGS__) : (void)0)
13806 +#define VCOS_ASSERT_MSG(...) ((void)0)
13810 +#ifndef VCOS_VERIFY_MSG
13811 +#define VCOS_VERIFY_MSG(...) VCOS_ASSERT_MSG(__VA_ARGS__)
13814 +#ifndef VCOS_ASSERT_LOGGING
13815 +#define VCOS_ASSERT_LOGGING 0
13818 +#ifndef VCOS_ASSERT_LOGGING_DISABLE
13819 +#define VCOS_ASSERT_LOGGING_DISABLE 0
13822 +#if !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS)
13824 +#ifndef vcos_assert
13825 +#define vcos_assert(cond) \
13826 + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG("%s", #cond), VCOS_ASSERT_BKPT) )
13829 +#ifndef vcos_assert_msg
13830 +#define vcos_assert_msg(cond, ...) \
13831 + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT) )
13834 +#else /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */
13836 +#ifndef vcos_assert
13837 +#define vcos_assert(cond) (void)0
13840 +#ifndef vcos_assert_msg
13841 +#define vcos_assert_msg(cond, ...) (void)0
13844 +#endif /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */
13846 +#if !defined(NDEBUG)
13848 +#ifndef vcos_demand
13849 +#define vcos_demand(cond) \
13850 + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG("%s", #cond), VCOS_ASSERT_BKPT, vcos_abort()) )
13853 +#ifndef vcos_demand_msg
13854 +#define vcos_demand_msg(cond, ...) \
13855 + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT, vcos_abort()) )
13858 +#ifndef vcos_verify
13859 +#define vcos_verify(cond) \
13860 + ( (cond) ? 1 : (VCOS_VERIFY_MSG("%s", #cond), VCOS_VERIFY_BKPT, 0) )
13863 +#ifndef vcos_verify_msg
13864 +#define vcos_verify_msg(cond, ...) \
13865 + ( (cond) ? 1 : (VCOS_VERIFY_MSG(__VA_ARGS__), VCOS_VERIFY_BKPT, 0) )
13868 +#else /* !defined(NDEBUG) */
13870 +#ifndef vcos_demand
13871 +#define vcos_demand(cond) \
13872 + ( (cond) ? (void)0 : vcos_abort() )
13875 +#ifndef vcos_demand_msg
13876 +#define vcos_demand_msg(cond, ...) \
13877 + ( (cond) ? (void)0 : vcos_abort() )
13880 +#ifndef vcos_verify
13881 +#define vcos_verify(cond) (cond)
13884 +#ifndef vcos_verify_msg
13885 +#define vcos_verify_msg(cond, ...) (cond)
13888 +#endif /* !defined(NDEBUG) */
13890 +#ifndef vcos_static_assert
13891 +#if defined(__GNUC__)
13892 +#define vcos_static_assert(cond) __attribute__((unused)) extern int vcos_static_assert[(cond)?1:-1]
13894 +#define vcos_static_assert(cond) extern int vcos_static_assert[(cond)?1:-1]
13899 +#define vc_assert(cond) vcos_assert(cond)
13902 +/** Print out a backtrace, on supported platforms.
13904 +extern void vcos_backtrace_self(void);
13906 +#ifdef __cplusplus
13910 +#endif /* VCOS_ASSERT_H */
13912 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_atomic_flags.h
13914 +/*=============================================================================
13915 +Copyright (c) 2009 Broadcom Europe Limited.
13916 +All rights reserved.
13919 +Module : chip driver (just for consistency with the rest of vcos ;)
13922 +VideoCore OS Abstraction Layer - public header file
13923 +=============================================================================*/
13925 +#ifndef VCOS_ATOMIC_FLAGS_H
13926 +#define VCOS_ATOMIC_FLAGS_H
13928 +#ifdef __cplusplus
13932 +#include "interface/vcos/vcos_types.h"
13933 +#include "vcos_platform.h"
13936 + * \file vcos_atomic_flags.h
13938 + * Defines atomic flags API.
13940 + * 32 flags. Atomic "or" and "get and clear" operations
13944 + * Create an atomic flags instance.
13946 + * @param atomic_flags Pointer to atomic flags instance, filled in on return
13948 + * @return VCOS_SUCCESS if succeeded.
13951 +VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags);
13954 + * Atomically set the specified flags.
13956 + * @param atomic_flags Instance to set flags on
13957 + * @param flags Mask of flags to set
13960 +void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags);
13963 + * Retrieve the current flags and then clear them. The entire operation is
13966 + * @param atomic_flags Instance to get/clear flags from/on
13968 + * @return Mask of flags which were set (and we cleared)
13971 +uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags);
13974 + * Delete an atomic flags instance.
13976 + * @param atomic_flags Instance to delete
13979 +void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags);
13981 +#ifdef __cplusplus
13987 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_build_info.h
13989 +const char *vcos_get_build_hostname( void );
13990 +const char *vcos_get_build_version( void );
13991 +const char *vcos_get_build_time( void );
13992 +const char *vcos_get_build_date( void );
13995 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_cfg.h
13997 +/*****************************************************************************
13998 +* Copyright 2009 - 2011 Broadcom Corporation. All rights reserved.
14000 +* Unless you and Broadcom execute a separate written software license
14001 +* agreement governing use of this software, this software is licensed to you
14002 +* under the terms of the GNU General Public License version 2, available at
14003 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
14005 +* Notwithstanding the above, under no circumstances may you combine this
14006 +* software in any way with any other Broadcom software provided under a
14007 +* license other than the GPL, without Broadcom's express prior written
14009 +*****************************************************************************/
14011 +#if !defined( VCOS_CFG_H )
14012 +#define VCOS_CFG_H
14014 +#ifdef __cplusplus
14018 +#include "interface/vcos/vcos_types.h"
14019 +#include "vcos_platform.h"
14021 +typedef struct opaque_vcos_cfg_buf_t *VCOS_CFG_BUF_T;
14022 +typedef struct opaque_vcos_cfg_entry_t *VCOS_CFG_ENTRY_T;
14024 +/** \file vcos_file.h
14026 + * API for accessing configuration/statistics information. This
14027 + * is loosely modelled on the linux proc entries.
14030 +typedef void (*VCOS_CFG_SHOW_FPTR)( VCOS_CFG_BUF_T buf, void *data );
14031 +typedef void (*VCOS_CFG_PARSE_FPTR)( VCOS_CFG_BUF_T buf, void *data );
14033 +/** Create a configuration directory.
14035 + * @param entry Place to store the created config entry.
14036 + * @param parent Parent entry (for directory like config
14038 + * @param entryName Name of the directory.
14041 +VCOS_STATUS_T vcos_cfg_mkdir( VCOS_CFG_ENTRY_T *entry,
14042 + VCOS_CFG_ENTRY_T *parent,
14043 + const char *dirName );
14045 +/** Create a configuration entry.
14047 + * @param entry Place to store the created config entry.
14048 + * @param parent Parent entry (for directory like config
14050 + * @param entryName Name of the configuration entry.
14051 + * @param showFunc Function pointer to show configuration
14053 + * @param parseFunc Function pointer to parse new data.
14056 +VCOS_STATUS_T vcos_cfg_create_entry( VCOS_CFG_ENTRY_T *entry,
14057 + VCOS_CFG_ENTRY_T *parent,
14058 + const char *entryName,
14059 + VCOS_CFG_SHOW_FPTR showFunc,
14060 + VCOS_CFG_PARSE_FPTR parseFunc,
14063 +/** Determines if a configuration entry has been created or not.
14065 + * @param entry Configuration entry to query.
14068 +int vcos_cfg_is_entry_created( VCOS_CFG_ENTRY_T entry );
14070 +/** Returns the name of a configuration entry.
14072 + * @param entry Configuration entry to query.
14075 +const char *vcos_cfg_get_entry_name( VCOS_CFG_ENTRY_T entry );
14077 +/** Removes a configuration entry.
14079 + * @param entry Configuration entry to remove.
14082 +VCOS_STATUS_T vcos_cfg_remove_entry( VCOS_CFG_ENTRY_T *entry );
14085 +/** Writes data into a configuration buffer. Only valid inside
14086 + * the show function.
14088 + * @param buf Buffer to write data into.
14089 + * @param fmt printf style format string.
14092 +void vcos_cfg_buf_printf( VCOS_CFG_BUF_T buf, const char *fmt, ... );
14094 +/** Retrieves a null terminated string of the data associated
14095 + * with the buffer. Only valid inside the parse function.
14097 + * @param buf Buffer to get data from.
14098 + * @param fmt printf style format string.
14101 +char *vcos_cfg_buf_get_str( VCOS_CFG_BUF_T buf );
14103 +void *vcos_cfg_get_proc_entry( VCOS_CFG_ENTRY_T entry );
14105 +#ifdef __cplusplus
14111 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_cmd.h
14113 +/*****************************************************************************
14114 +* Copyright 2009 - 2011 Broadcom Corporation. All rights reserved.
14116 +* Unless you and Broadcom execute a separate written software license
14117 +* agreement governing use of this software, this software is licensed to you
14118 +* under the terms of the GNU General Public License version 2, available at
14119 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
14121 +* Notwithstanding the above, under no circumstances may you combine this
14122 +* software in any way with any other Broadcom software provided under a
14123 +* license other than the GPL, without Broadcom's express prior written
14125 +*****************************************************************************/
14127 +#if !defined( VCOS_CMD_H )
14128 +#define VCOS_CMD_H
14130 +/* ---- Include Files ----------------------------------------------------- */
14132 +#include "interface/vcos/vcos.h"
14133 +#include "interface/vcos/vcos_stdint.h"
14136 +/* ---- Constants and Types ---------------------------------------------- */
14138 +struct VCOS_CMD_S;
14139 +typedef struct VCOS_CMD_S VCOS_CMD_T;
14143 + int argc; /* Number of arguments (includes the command/sub-command) */
14144 + char **argv; /* Array of arguments */
14145 + char **argv_orig; /* Original array of arguments */
14147 + VCOS_CMD_T *cmd_entry;
14148 + VCOS_CMD_T *cmd_parent_entry;
14150 + int use_log; /* Output being logged? */
14151 + size_t result_size; /* Size of result buffer. */
14152 + char *result_ptr; /* Next place to put output. */
14153 + char *result_buf; /* Start of the buffer. */
14155 +} VCOS_CMD_PARAM_T;
14157 +typedef VCOS_STATUS_T (*VCOS_CMD_FUNC_T)( VCOS_CMD_PARAM_T *param );
14161 + const char *name;
14162 + const char *args;
14163 + VCOS_CMD_FUNC_T cmd_fn;
14164 + VCOS_CMD_T *sub_cmd_entry;
14165 + const char *descr;
14169 +/* ---- Variable Externs ------------------------------------------------- */
14171 +/* ---- Function Prototypes ---------------------------------------------- */
14174 + * Common printing routine for generating command output.
14176 +VCOSPRE_ void VCOSPOST_ vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) VCOS_FORMAT_ATTR_(printf, 2, 3);
14177 +VCOSPRE_ void VCOSPOST_ vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) VCOS_FORMAT_ATTR_(printf, 2, 3);
14178 +VCOSPRE_ void VCOSPOST_ vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args ) VCOS_FORMAT_ATTR_(printf, 2, 0);
14181 + * Cause vcos_cmd_error, printf and vprintf to always log to the provided
14182 + * category. When this call is made, the results buffer passed into
14183 + * vcos_cmd_execute is used as a line buffer and does not need to be
14184 + * output by the caller.
14186 +VCOSPRE_ void VCOSPOST_ vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category );
14189 + * Prints command usage for the current command.
14191 +VCOSPRE_ void VCOSPOST_ vcos_cmd_usage( VCOS_CMD_PARAM_T *param );
14194 + * Register commands to be processed
14196 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register( VCOS_CMD_T *cmd_entry );
14199 + * Registers multiple commands to be processed. The array should
14200 + * be terminated by an entry with all zeros.
14202 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry );
14205 + * Executes a command based on a command line.
14207 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf );
14209 +#endif /* VCOS_CMD_H */
14212 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_ctype.h
14214 +/*=============================================================================
14215 +Copyright (c) 2009 Broadcom Europe Limited.
14216 +All rights reserved.
14219 +Module : chip driver
14222 +VideoCore OS Abstraction Layer - public header file
14223 +=============================================================================*/
14225 +#ifndef VCOS_CTYPE_H
14226 +#define VCOS_CTYPE_H
14231 + * ctype functions.
14236 +#include <linux/ctype.h>
14238 +#include <ctype.h>
14244 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_dlfcn.h
14246 +/*=============================================================================
14247 +Copyright (c) 2010 Broadcom Europe Limited.
14248 +All rights reserved.
14251 +Module : chip driver
14254 +VCOS - abstraction over dynamic library opening
14255 +=============================================================================*/
14257 +#ifndef VCOS_DLFCN_H
14258 +#define VCOS_DLFCN_H
14260 +#include "interface/vcos/vcos_types.h"
14261 +#include "vcos_platform.h"
14263 +#ifdef __cplusplus
14267 +#define VCOS_DL_LAZY 1
14268 +#define VCOS_DL_NOW 2
14273 + * Loading dynamic libraries. See also dlfcn.h.
14276 +/** Open a dynamic library.
14278 + * @param name name of the library
14279 + * @param mode Load lazily or immediately (VCOS_DL_LAZY, VCOS_DL_NOW).
14281 + * @return A handle for use in subsequent calls.
14283 +VCOSPRE_ void * VCOSPOST_ vcos_dlopen(const char *name, int mode);
14285 +/** Look up a symbol.
14287 + * @param handle Handle to open
14288 + * @param name Name of function
14290 + * @return Function pointer, or NULL.
14292 +VCOSPRE_ void VCOSPOST_ (*vcos_dlsym(void *handle, const char *name))(void);
14294 +/** Close a library
14296 + * @param handle Handle to close
14298 +VCOSPRE_ int VCOSPOST_ vcos_dlclose (void *handle);
14300 +/** Return error message from library.
14302 + * @param err On return, set to non-zero if an error has occurred
14303 + * @param buf Buffer to write error to
14304 + * @param len Size of buffer (including terminating NUL).
14306 +VCOSPRE_ int VCOSPOST_ vcos_dlerror(int *err, char *buf, size_t buflen);
14309 +#ifdef __cplusplus
14316 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_event.h
14318 +/*=============================================================================
14319 +Copyright (c) 2009 Broadcom Europe Limited.
14320 +All rights reserved.
14323 +Module : chip driver
14326 +VideoCore OS Abstraction Layer - public header file for events
14327 +=============================================================================*/
14329 +#ifndef VCOS_EVENT_H
14330 +#define VCOS_EVENT_H
14332 +#ifdef __cplusplus
14336 +#include "interface/vcos/vcos_types.h"
14337 +#include "vcos_platform.h"
14342 + * An event is akin to the Win32 auto-reset event.
14345 + * Signalling an event will wake up one waiting thread only. Once one
14346 + * thread has been woken the event atomically returns to the unsignalled
14349 + * If no threads are waiting on the event when it is signalled it remains
14352 + * This is almost, but not quite, completely unlike the "event flags"
14353 + * object based on Nucleus event groups and ThreadX event flags.
14355 + * In particular, it should be similar in speed to a semaphore, unlike
14356 + * the event flags.
14360 + * Create an event instance.
14362 + * @param event Filled in with constructed event.
14363 + * @param name Name of the event (for debugging)
14365 + * @return VCOS_SUCCESS on success, or error code.
14368 +VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *name);
14370 +#ifndef vcos_event_signal
14373 + * Signal the event. The event will return to being unsignalled
14374 + * after exactly one waiting thread has been woken up. If no
14375 + * threads are waiting it remains signalled.
14377 + * @param event The event to signal
14380 +void vcos_event_signal(VCOS_EVENT_T *event);
14383 + * Wait for the event.
14385 + * @param event The event to wait for
14386 + * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the wait was interrupted.
14389 +VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event);
14392 + * Try event, but don't block.
14394 + * @param event The event to try
14395 + * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the event is not currently signalled
14398 +VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event);
14403 + * Destroy an event.
14406 +void vcos_event_delete(VCOS_EVENT_T *event);
14408 +#ifdef __cplusplus
14416 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_event_flags.h
14418 +/*=============================================================================
14419 +Copyright (c) 2009 Broadcom Europe Limited.
14420 +All rights reserved.
14423 +Module : chip driver
14426 +VideoCore OS Abstraction Layer - public header file
14427 +=============================================================================*/
14429 +#ifndef VCOS_EVENT_FLAGS_H
14430 +#define VCOS_EVENT_FLAGS_H
14433 +#ifdef __cplusplus
14437 +#include "interface/vcos/vcos_types.h"
14438 +#include "vcos_platform.h"
14440 +#define VCOS_EVENT_FLAGS_SUSPEND VCOS_SUSPEND
14441 +#define VCOS_EVENT_FLAGS_NO_SUSPEND VCOS_NO_SUSPEND
14442 +typedef VCOS_OPTION VCOS_EVENTGROUP_OPERATION_T;
14445 + * \file vcos_event_flags.h
14447 + * Defines event flags API.
14449 + * Similar to Nucleus event groups.
14451 + * These have the same semantics as Nucleus event groups and ThreadX event
14452 + * flags. As such, they are quite complex internally; if speed is important
14453 + * they might not be your best choice.
14458 + * Create an event flags instance.
14460 + * @param flags Pointer to event flags instance, filled in on return.
14461 + * @param name Name for the event flags, used for debug.
14463 + * @return VCOS_SUCCESS if succeeded.
14467 +VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name);
14470 + * Set some events.
14472 + * @param flags Instance to set flags on
14473 + * @param events Bitmask of the flags to actually set
14474 + * @param op How the flags should be set. VCOS_OR will OR in the flags; VCOS_AND
14475 + * will AND them in, possibly clearing existing flags.
14478 +void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
14479 + VCOS_UNSIGNED events,
14483 + * Retrieve some events.
14485 + * Waits until the specified events have been set.
14487 + * @param flags Instance to wait on
14488 + * @param requested_events The bitmask to wait for
14489 + * @param op VCOS_OR - get any; VCOS_AND - get all.
14490 + * @param ms_suspend How long to wait, in milliseconds
14491 + * @param retrieved_events the events actually retrieved.
14493 + * @return VCOS_SUCCESS if events were retrieved. VCOS_EAGAIN if the
14494 + * timeout expired.
14497 +VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
14498 + VCOS_UNSIGNED requested_events,
14500 + VCOS_UNSIGNED ms_suspend,
14501 + VCOS_UNSIGNED *retrieved_events);
14505 + * Delete an event flags instance.
14508 +void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *);
14510 +#ifdef __cplusplus
14517 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_init.h
14519 +/*=============================================================================
14520 +Copyright (c) 2009 Broadcom Europe Limited.
14521 +All rights reserved.
14524 +Module : chip driver
14527 +VideoCore OS Abstraction Layer - initialization routines
14528 +=============================================================================*/
14531 +#include "interface/vcos/vcos_types.h"
14532 +#include "vcos_platform.h"
14534 +#ifdef __cplusplus
14540 + * Some OS support libraries need some initialization. To support this, call this
14541 + * function at the start of day.
14544 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_init(void);
14545 +VCOSPRE_ void VCOSPOST_ vcos_deinit(void);
14546 +VCOSPRE_ void VCOSPOST_ vcos_global_lock(void);
14547 +VCOSPRE_ void VCOSPOST_ vcos_global_unlock(void);
14549 +/** Pass in the argv/argc arguments passed to main() */
14550 +VCOSPRE_ void VCOSPOST_ vcos_set_args(int argc, const char **argv);
14552 +/** Return argc. */
14553 +VCOSPRE_ int VCOSPOST_ vcos_get_argc(void);
14555 +/** Return argv. */
14556 +VCOSPRE_ const char ** VCOSPOST_ vcos_get_argv(void);
14558 +#ifdef __cplusplus
14563 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_logging.h
14565 +/*=============================================================================
14566 +Copyright (c) 2009-2011 Broadcom Europe Limited.
14567 +All rights reserved.
14570 +Module : chip driver
14573 +VideoCore OS Abstraction Layer - logging support
14574 +=============================================================================*/
14576 +#ifndef VCOS_LOGGING_H
14577 +#define VCOS_LOGGING_H
14579 +#ifdef __cplusplus
14583 +#include <stdarg.h>
14585 +#include "interface/vcos/vcos_types.h"
14586 +#include "vcos_platform.h"
14591 + * Logging support
14593 + * This provides categorised logging. Clients register
14594 + * a category, and then get a number of logging levels for
14597 + * The logging level flag is tested using a flag *before* the
14598 + * function call, which makes logging very fast when disabled - there
14599 + * is no function call overhead just to find out that this log
14600 + * message is disabled.
14602 + * \section VCOS_LOG_CATEGORY
14604 + * As a convenience, clients define VCOS_LOG_CATEGORY to point to
14605 + * their category; the various vcos_log_xxx() macros then expand to
14610 + * #define VCOS_LOG_CATEGORY (&my_category)
14612 + * #include <interface/vcos/vcos.h>
14614 + * VCOS_LOG_CAT_T my_category;
14618 + * vcos_log_trace("Stuff happened: %d", n_stuff);
14622 +/** Logging levels */
14623 +typedef enum VCOS_LOG_LEVEL_T
14625 + VCOS_LOG_UNINITIALIZED = 0,
14631 +} VCOS_LOG_LEVEL_T;
14634 +/** Initialize a logging category without going through vcos_log_register().
14636 + * This is useful for the case where there is no obvious point to do the
14637 + * registration (no initialization function for the module). However, it
14638 + * means that your logging category is not registered, so cannot be easily
14639 + * changed at run-time.
14641 +#define VCOS_LOG_INIT(n,l) { l, n, 0, {0}, 0, 0 }
14643 +/** A registered logging category.
14645 +typedef struct VCOS_LOG_CAT_T
14647 + VCOS_LOG_LEVEL_T level; /** Which levels are enabled for this category */
14648 + const char *name; /** Name for this category. */
14649 + struct VCOS_LOG_CAT_T *next;
14651 + unsigned int want_prefix:1;
14653 + unsigned int refcount;
14654 + void *platform_data; /** platform specific data */
14657 +typedef void (*VCOS_VLOG_IMPL_FUNC_T)(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args);
14659 +/** Convert a VCOS_LOG_LEVEL_T into a printable string.
14660 + * The platform needs to implement this function.
14662 +VCOSPRE_ const char * VCOSPOST_ vcos_log_level_to_string( VCOS_LOG_LEVEL_T level );
14664 +/** Convert a string into a VCOS_LOG_LEVEL_T
14665 + * The platform needs to implement this function.
14667 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level );
14669 +/** Log a message. Basic API. Normal code should not use this.
14670 + * The platform needs to implement this function.
14672 +VCOSPRE_ void VCOSPOST_ vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...) VCOS_FORMAT_ATTR_(printf, 3, 4);
14674 +/** Log a message using a varargs parameter list. Normal code should
14677 +VCOSPRE_ void VCOSPOST_ vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) VCOS_FORMAT_ATTR_(printf, 3, 0);
14679 +/** Set the function which does the actual logging output.
14680 + * Passing in NULL causes the default logging function to be
14683 +VCOSPRE_ void VCOSPOST_ vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func );
14685 +/** The default logging function, which is provided by each
14689 +VCOSPRE_ void VCOSPOST_ vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) VCOS_FORMAT_ATTR_(printf, 3, 0);
14692 + * Initialise the logging subsystem. This is called from
14693 + * vcos_init() so you don't normally need to call it.
14695 +VCOSPRE_ void VCOSPOST_ vcos_logging_init(void);
14697 +/** Register a logging category.
14699 + * @param name the name of this category.
14700 + * @param category the category to register.
14702 +VCOSPRE_ void VCOSPOST_ vcos_log_register(const char *name, VCOS_LOG_CAT_T *category);
14704 +/** Unregister a logging category.
14706 +VCOSPRE_ void VCOSPOST_ vcos_log_unregister(VCOS_LOG_CAT_T *category);
14708 +/** Return a default logging category, for people too lazy to create their own.
14710 + * Using the default category will be slow (there's an extra function
14711 + * call overhead). Don't do this in normal code.
14713 +VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void);
14715 +VCOSPRE_ void VCOSPOST_ vcos_set_log_options(const char *opt);
14717 +/** Set the logging level for a category at run time. Without this, the level
14718 + * will be that set by vcos_log_register from a platform-specific source.
14720 + * @param category the category to modify.
14721 + * @param level the new logging level for this category.
14723 +VCOS_STATIC_INLINE void vcos_log_set_level(VCOS_LOG_CAT_T *category, VCOS_LOG_LEVEL_T level)
14725 + category->level = level;
14728 +#define vcos_log_dump_mem(cat,label,addr,voidMem,numBytes) do { if (vcos_is_log_enabled(cat,VCOS_LOG_TRACE)) vcos_log_dump_mem_impl(cat,label,addr,voidMem,numBytes); } while (0)
14730 +void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
14731 + const char *label,
14733 + const void *voidMem,
14734 + size_t numBytes );
14737 + * Platform specific hooks (optional).
14739 +#ifndef vcos_log_platform_init
14740 +#define vcos_log_platform_init() (void)0
14743 +#ifndef vcos_log_platform_register
14744 +#define vcos_log_platform_register(category) (void)0
14747 +#ifndef vcos_log_platform_unregister
14748 +#define vcos_log_platform_unregister(category) (void)0
14751 +/* VCOS_TRACE() - deprecated macro which just outputs in a debug build and
14752 + * is a no-op in a release build.
14754 + * _VCOS_LOG_X() - internal macro which outputs if the current level for the
14755 + * particular category is higher than the supplied message level.
14758 +#define VCOS_LOG_DFLT_CATEGORY vcos_log_get_default_category()
14760 +#define _VCOS_LEVEL(x) (x)
14762 +#define vcos_is_log_enabled(cat,_level) (_VCOS_LEVEL((cat)->level) >= _VCOS_LEVEL(_level))
14764 +#if defined(_VCOS_METAWARE) || defined(__GNUC__)
14766 +# if !defined(NDEBUG) || defined(VCOS_ALWAYS_WANT_LOGGING)
14767 +# define VCOS_LOGGING_ENABLED
14768 +# define _VCOS_LOG_X(cat, _level, fmt...) do { if (vcos_is_log_enabled(cat,_level)) vcos_log_impl(cat,_level,fmt); } while (0)
14769 +# define _VCOS_VLOG_X(cat, _level, fmt, ap) do { if (vcos_is_log_enabled(cat,_level)) vcos_vlog_impl(cat,_level,fmt,ap); } while (0)
14771 +# define _VCOS_LOG_X(cat, _level, fmt...) (void)0
14772 +# define _VCOS_VLOG_X(cat, _level, fmt, ap) (void)0
14777 +# define vcos_log_error(...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, __VA_ARGS__)
14778 +# define vcos_log_warn(...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, __VA_ARGS__)
14779 +# define vcos_log_info(...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
14780 +# define vcos_log_trace(...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, __VA_ARGS__)
14782 +# define vcos_vlog_error(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, fmt, ap)
14783 +# define vcos_vlog_warn(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, fmt, ap)
14784 +# define vcos_vlog_info(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, fmt, ap)
14785 +# define vcos_vlog_trace(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, fmt, ap)
14787 +# define vcos_log(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
14788 +# define vcos_vlog(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt, ap)
14789 +# define VCOS_ALERT(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_ERROR, __VA_ARGS__)
14790 +# define VCOS_TRACE(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
14793 + * MS Visual Studio - pre 2005 does not grok variadic macros
14795 +#elif defined(_MSC_VER)
14797 +# if _MSC_VER >= 1400
14799 +# if !defined(NDEBUG) || defined(VCOS_ALWAYS_WANT_LOGGING)
14800 +# define VCOS_LOGGING_ENABLED
14801 +# define _VCOS_LOG_X(cat, _level, fmt,...) do { if (vcos_is_log_enabled(cat,_level)) vcos_log_impl(cat, _level, fmt, __VA_ARGS__); } while (0)
14803 +# define _VCOS_LOG_X(cat, _level, fmt,...) (void)0
14806 +# define vcos_log_error(fmt,...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, fmt, __VA_ARGS__)
14807 +# define vcos_log_warn(fmt,...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, fmt, __VA_ARGS__)
14808 +# define vcos_log_info(fmt,...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, fmt, __VA_ARGS__)
14809 +# define vcos_log_trace(fmt,...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, fmt, __VA_ARGS__)
14811 +# define vcos_log(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt)
14812 +# define VCOS_ALERT(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_ERROR, fmt)
14813 +# define VCOS_TRACE(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt)
14815 +# else /* _MSC_VER >= 1400 */
14817 +/* do not define these */
14819 +# endif /* _MSC_VER >= 1400 */
14825 +#include "interface/vcos/vcos_cmd.h"
14828 + * These are the log sub-commands. They're exported here for user-mode apps which
14829 + * may want to call these, since the "log" command isn't registered for user-mode
14830 + * apps (vcdbg for example, has its own log command).
14832 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param );
14833 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_set_cmd( VCOS_CMD_PARAM_T *param );
14834 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_status_cmd( VCOS_CMD_PARAM_T *param );
14835 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_test_cmd( VCOS_CMD_PARAM_T *param );
14838 +#ifdef __cplusplus
14841 +#endif /* VCOS_LOGGING_H */
14845 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_lowlevel_thread.h
14847 +/*=============================================================================
14848 +Copyright (c) 2009 Broadcom Europe Limited.
14849 +All rights reserved.
14852 +Module : chip driver
14855 +VideoCore OS Abstraction Layer - low level thread support
14856 +=============================================================================*/
14858 +#ifndef VCOS_LOWLEVEL_THREAD_H
14859 +#define VCOS_LOWLEVEL_THREAD_H
14861 +#ifdef __cplusplus
14865 +#include "interface/vcos/vcos_types.h"
14866 +#include "vcos_platform.h"
14871 + * This defines a low level thread API that is supported by *some* operating systems
14872 + * and can be used to construct the regular "joinable thread" API on those operating
14875 + * Most clients will not need to use this code.
14877 + * \sa vcos_joinable_thread.h
14881 + * \brief Create a thread.
14883 + * This creates a thread which can be stopped either by returning from the
14884 + * entry point function or by calling vcos_llthread_exit from within the entry
14885 + * point function. The thread must be cleaned up by calling
14886 + * vcos_llthread_delete. vcos_llthread_delete may or may not terminate the
14889 + * The preemptible parameter familiar from Nucleus is removed, as it is unused in
14890 + * VideoCore code. Affinity is added, since we do use this.
14892 + * @param thread Filled in with thread instance
14893 + * @param name An optional name for the thread. "" may be used (but
14894 + * a name will aid in debugging).
14895 + * @param entry Entry point
14896 + * @param arg A single argument passed to the entry point function
14897 + * @param stack Pointer to stack address
14898 + * @param stacksz Size of stack in bytes
14899 + * @param priority Priority of task, between VCOS_PRI_LOW and VCOS_PRI_HIGH
14900 + * @param affinity CPU affinity
14902 + * @sa vcos_llthread_terminate vcos_llthread_delete
14904 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_llthread_create(VCOS_LLTHREAD_T *thread,
14905 + const char *name,
14906 + VCOS_LLTHREAD_ENTRY_FN_T entry,
14909 + VCOS_UNSIGNED stacksz,
14910 + VCOS_UNSIGNED priority,
14911 + VCOS_UNSIGNED affinity,
14912 + VCOS_UNSIGNED timeslice,
14913 + VCOS_UNSIGNED autostart);
14916 + * \brief Exits the current thread.
14918 +VCOSPRE_ void VCOSPOST_ vcos_llthread_exit(void);
14921 + * \brief Delete a thread. This must be called to cleanup after
14922 + * vcos_llthread_create. This may or may not terminate the thread.
14923 + * It does not clean up any resources that may have been
14924 + * allocated by the thread.
14926 +VCOSPRE_ void VCOSPOST_ vcos_llthread_delete(VCOS_LLTHREAD_T *thread);
14929 + * \brief Return current lowlevel thread pointer.
14932 +VCOS_LLTHREAD_T *vcos_llthread_current(void);
14935 + * Resume a thread.
14938 +void vcos_llthread_resume(VCOS_LLTHREAD_T *thread);
14940 +VCOSPRE_ int VCOSPOST_ vcos_llthread_running(VCOS_LLTHREAD_T *thread);
14943 + * \brief Create a VCOS_LLTHREAD_T for the current thread. This is so we can
14944 + * have VCOS_LLTHREAD_Ts even for threads not originally created by VCOS (eg
14945 + * the thread that calls vcos_init).
14947 +extern VCOS_STATUS_T _vcos_llthread_create_attach(VCOS_LLTHREAD_T *thread);
14949 +#ifdef __cplusplus
14955 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_mem.h
14957 +/*=============================================================================
14958 +Copyright (c) 2009 Broadcom Europe Limited.
14959 +All rights reserved.
14962 +Module : chip driver
14965 +VideoCore OS Abstraction Layer - memory support
14966 +=============================================================================*/
14968 +#ifndef VCOS_MEM_H
14969 +#define VCOS_MEM_H
14971 +#ifdef __cplusplus
14975 +#include "interface/vcos/vcos_types.h"
14976 +#include "vcos_platform.h"
14980 + * Memory allocation api (malloc/free equivalents) is for benefit of host
14981 + * applications. VideoCore code should use rtos_XXX functions.
14986 +/** Allocate memory
14988 + * @param size Size of memory to allocate
14989 + * @param description Description, to aid in debugging. May be ignored internally on some platforms.
14992 +void *vcos_malloc(VCOS_UNSIGNED size, const char *description);
14994 +void *vcos_kmalloc(VCOS_UNSIGNED size, const char *description);
14995 +void *vcos_kcalloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description);
14997 +/** Allocate cleared memory
14999 + * @param num Number of items to allocate.
15000 + * @param size Size of each item in bytes.
15001 + * @param description Description, to aid in debugging. May be ignored internally on some platforms.
15004 +void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description);
15008 + * Free memory that has been allocated.
15011 +void vcos_free(void *ptr);
15013 +void vcos_kfree(void *ptr);
15015 +/** Allocate aligned memory
15017 + * Allocate memory aligned on the specified boundary.
15019 + * @param size Size of memory to allocate
15020 + * @param description Description, to aid in debugging. May be ignored internally on some platforms.
15023 +void *vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description);
15025 +/** Return the amount of free heap memory
15029 +unsigned long vcos_get_free_mem(void);
15031 +#ifdef __cplusplus
15039 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_msgqueue.h
15041 +/*=============================================================================
15042 +Copyright (c) 2009 Broadcom Europe Limited.
15043 +All rights reserved.
15046 +Module : chip driver
15049 +VCOS - packet-like messages, based loosely on those found in TRIPOS.
15050 +=============================================================================*/
15052 +#ifndef VCOS_MSGQUEUE_H
15053 +#define VCOS_MSGQUEUE_H
15055 +#ifdef __cplusplus
15059 +#include "interface/vcos/vcos_types.h"
15060 +#include "vcos_platform.h"
15065 + * Packet-like messages, based loosely on those found in TRIPOS and
15066 + * derivatives thereof.
15068 + * A task can send a message *pointer* to another task, where it is
15069 + * queued on a linked list and the task woken up. The receiving task
15070 + * consumes all of the messages on its input queue, and optionally
15071 + * sends back replies using the original message memory.
15073 + * A caller can wait for the reply to a specific message - any other
15074 + * messages that arrive in the meantime are queued separately.
15077 + * All messages have a standard common layout, but the payload area can
15078 + * be used freely to extend this.
15081 +/** Map the payload portion of a message to a structure pointer.
15083 +#define VCOS_MSG_DATA(_msg) (void*)((_msg)->data)
15085 +/** Standard message ids - FIXME - these need to be done properly! */
15086 +#define VCOS_MSG_N_QUIT 1
15087 +#define VCOS_MSG_N_OPEN 2
15088 +#define VCOS_MSG_N_CLOSE 3
15089 +#define VCOS_MSG_N_PRIVATE (1<<20)
15091 +#define VCOS_MSG_REPLY_BIT (1<<31)
15093 +/** Make gnuc compiler be happy about pointer punning */
15095 +#define __VCOS_MAY_ALIAS __attribute__((__may_alias__))
15097 +#define __VCOS_MAY_ALIAS
15100 +/** A single message queue.
15102 +typedef struct VCOS_MSGQUEUE_T
15104 + struct VCOS_MSG_T *head; /**< head of linked list of messages waiting on this queue */
15105 + struct VCOS_MSG_T *tail; /**< tail of message queue */
15106 + VCOS_SEMAPHORE_T sem; /**< thread waits on this for new messages */
15107 + VCOS_MUTEX_T lock; /**< locks the messages list */
15108 +} VCOS_MSGQUEUE_T;
15110 +/** A single message
15112 +typedef struct VCOS_MSG_T
15114 + uint32_t code; /**< message code */
15115 + int error; /**< error status signalled back to caller */
15116 + VCOS_MSGQUEUE_T *dst; /**< destination queue */
15117 + VCOS_MSGQUEUE_T *src; /**< source; replies go back to here */
15118 + struct VCOS_MSG_T *next; /**< next in queue */
15119 + VCOS_THREAD_T *src_thread; /**< for debug */
15120 + uint32_t data[25]; /**< payload area */
15125 +typedef struct VCOS_MSG_ENDPOINT_T
15127 + VCOS_MSGQUEUE_T primary; /**< incoming messages */
15128 + VCOS_MSGQUEUE_T secondary; /**< this is used for waitspecific */
15129 + char name[32]; /**< name of this endpoint, for find() */
15130 + struct VCOS_MSG_ENDPOINT_T *next; /**< next in global list of endpoints */
15131 +} VCOS_MSG_ENDPOINT_T;
15132 +#define MSG_REPLY_BIT (1<<31)
15134 +/** Initalise the library. Normally called from vcos_init().
15136 +extern VCOS_STATUS_T vcos_msgq_init(void);
15138 +/** Find a message queue by name and get a handle to it.
15140 + * @param name the name of the queue to find
15142 + * @return The message queue, or NULL if not found.
15144 +VCOSPRE_ VCOS_MSGQUEUE_T VCOSPOST_ *vcos_msgq_find(const char *name);
15146 +/** Wait for a message queue to come into existence. If it already exists,
15147 + * return immediately, otherwise block.
15149 + * On the whole, if you find yourself using this, it is probably a sign
15150 + * of poor design, since you should create all the server threads first,
15151 + * and then the client threads. But it is sometimes useful.
15153 + * @param name the name of the queue to find
15154 + * @return The message queue
15156 +VCOSPRE_ VCOS_MSGQUEUE_T VCOSPOST_ *vcos_msgq_wait(const char *name);
15158 +/** Send a message.
15160 +VCOSPRE_ void VCOSPOST_ vcos_msg_send(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg);
15162 +/** Send a message and wait for a reply.
15164 +VCOSPRE_ void VCOSPOST_ vcos_msg_sendwait(VCOS_MSGQUEUE_T *queue, uint32_t code, VCOS_MSG_T *msg);
15166 +/** Wait for a message on this thread's endpoint.
15168 +VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_wait(void);
15170 +/** Wait for a specific message.
15172 +VCOS_MSG_T * vcos_msg_wait_specific(VCOS_MSGQUEUE_T *queue, VCOS_MSG_T *msg);
15174 +/** Peek for a message on this thread's endpoint, if a message is not available, NULL is
15175 + returned. If a message is available it will be removed from the endpoint and returned.
15177 +VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_peek(void);
15179 +/** Send a reply to a message
15181 +VCOSPRE_ void VCOSPOST_ vcos_msg_reply(VCOS_MSG_T *msg);
15183 +/** Create an endpoint. Each thread should need no more than one of these - if you
15184 + * find yourself needing a second one, you've done something wrong.
15186 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_endpoint_create(VCOS_MSG_ENDPOINT_T *ep, const char *name);
15188 +/** Destroy an endpoint.
15190 +VCOSPRE_ void VCOSPOST_ vcos_msgq_endpoint_delete(VCOS_MSG_ENDPOINT_T *ep);
15192 +#ifdef __cplusplus
15199 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_mutex.h
15201 +/*=============================================================================
15202 +Copyright (c) 2009 Broadcom Europe Limited.
15203 +All rights reserved.
15206 +Module : chip driver
15209 +VideoCore OS Abstraction Layer - mutex public header file
15210 +=============================================================================*/
15212 +#ifndef VCOS_MUTEX_H
15213 +#define VCOS_MUTEX_H
15215 +#ifdef __cplusplus
15219 +#include "interface/vcos/vcos_types.h"
15220 +#include "vcos_platform.h"
15223 + * \file vcos_mutex.h
15225 + * Mutex API. Mutexes are not re-entrant, as supporting this adds extra code
15226 + * that slows down clients which have been written sensibly.
15228 + * \sa vcos_reentrant_mutex.h
15232 +/** Create a mutex.
15234 + * @param m Filled in with mutex on return
15235 + * @param name A non-null name for the mutex, used for diagnostics.
15237 + * @return VCOS_SUCCESS if mutex was created, or error code.
15240 +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *m, const char *name);
15242 +/** Delete the mutex.
15245 +void vcos_mutex_delete(VCOS_MUTEX_T *m);
15248 + * \brief Wait to claim the mutex.
15250 + * On most platforms this always returns VCOS_SUCCESS, and so would ideally be
15251 + * a void function, however some platforms allow a wait to be interrupted so
15252 + * it remains non-void.
15254 + * Try to obtain the mutex.
15255 + * @param m Mutex to wait on
15256 + * @return VCOS_SUCCESS - mutex was taken.
15257 + * VCOS_EAGAIN - could not take mutex.
15259 +#ifndef vcos_mutex_lock
15261 +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *m);
15263 +/** Release the mutex.
15266 +void vcos_mutex_unlock(VCOS_MUTEX_T *m);
15269 +/** Test if the mutex is already locked.
15271 + * @return 1 if mutex is locked, 0 if it is unlocked.
15274 +int vcos_mutex_is_locked(VCOS_MUTEX_T *m);
15276 +/** Obtain the mutex if possible.
15278 + * @param m the mutex to try to obtain
15280 + * @return VCOS_SUCCESS if mutex is succesfully obtained, or VCOS_EAGAIN
15281 + * if it is already in use by another thread.
15283 +#ifndef vcos_mutex_trylock
15285 +VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m);
15289 +#ifdef __cplusplus
15294 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_once.h
15296 +/*=============================================================================
15297 +Copyright (c) 2011 Broadcom Europe Limited.
15298 +All rights reserved.
15301 +Module : chip driver
15304 +VideoCore OS Abstraction Layer - 'once'
15305 +=============================================================================*/
15307 +#ifndef VCOS_ONCE_H
15308 +#define VCOS_ONCE_H
15310 +#ifdef __cplusplus
15314 +#include "interface/vcos/vcos_types.h"
15315 +#include "vcos_platform.h"
15318 + * \file vcos_once.h
15320 + * Ensure something is called only once.
15322 + * Initialize once_control to VCOS_ONCE_INIT. The first
15323 + * time this is called, the init_routine will be called. Thereafter
15326 + * \sa pthread_once()
15330 +VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
15331 + void (*init_routine)(void));
15333 +#ifdef __cplusplus
15339 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_semaphore.h
15341 +/*=============================================================================
15342 +Copyright (c) 2009 Broadcom Europe Limited.
15343 +All rights reserved.
15346 +Module : chip driver
15349 +VideoCore OS Abstraction Layer - public header file
15350 +=============================================================================*/
15352 +#ifndef VCOS_SEMAPHORE_H
15353 +#define VCOS_SEMAPHORE_H
15355 +#ifdef __cplusplus
15359 +#include "interface/vcos/vcos_types.h"
15360 +#include "vcos_platform.h"
15363 + * \file vcos_semaphore.h
15365 + * \section sem Semaphores
15367 + * This provides counting semaphores. Semaphores are not re-entrant. On sensible
15368 + * operating systems a semaphore can always be posted but can only be taken in
15369 + * thread (not interrupt) context. Under Nucleus, a LISR cannot post a semaphore,
15370 + * although it would not be hard to lift this restriction.
15372 + * \subsection timeout Timeout
15374 + * On both Nucleus and ThreadX a semaphore can be taken with a timeout. This is
15375 + * not supported by VCOS because it makes the non-timeout code considerably more
15376 + * complicated (and hence slower). In the unlikely event that you need a timeout
15377 + * with a semaphore, and you cannot simply redesign your code to avoid it, use
15378 + * an event flag (vcos_event_flags.h).
15380 + * \subsection sem_nucleus Changes from Nucleus:
15382 + * Semaphores are always "FIFO" - i.e. sleeping threads are woken in FIFO order. That's
15384 + * \arg there's no support for NU_PRIORITY in threadx (though it can be emulated, slowly)
15385 + * \arg we don't appear to actually consciously use it - for example, Dispmanx uses
15386 + * it, but all threads waiting are the same priority.
15391 + * \brief Create a semaphore.
15393 + * Create a semaphore.
15395 + * @param sem Pointer to memory to be initialized
15396 + * @param name A name for this semaphore. The name may be truncated internally.
15397 + * @param count The initial count for the semaphore.
15399 + * @return VCOS_SUCCESS if the semaphore was created.
15403 +VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
15406 + * \brief Wait on a semaphore.
15408 + * There is no timeout option on a semaphore, as adding this will slow down
15409 + * implementations on some platforms. If you need that kind of behaviour, use
15410 + * an event group.
15412 + * On most platforms this always returns VCOS_SUCCESS, and so would ideally be
15413 + * a void function, however some platforms allow a wait to be interrupted so
15414 + * it remains non-void.
15416 + * @param sem Semaphore to wait on
15417 + * @return VCOS_SUCCESS - semaphore was taken.
15418 + * VCOS_EAGAIN - could not take semaphore
15422 +VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem);
15425 + * \brief Try to wait for a semaphore.
15427 + * Try to obtain the semaphore. If it is already taken, return VCOS_TIMEOUT.
15428 + * @param sem Semaphore to wait on
15429 + * @return VCOS_SUCCESS - semaphore was taken.
15430 + * VCOS_EAGAIN - could not take semaphore
15433 +VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem);
15436 + * \brief Post a semaphore.
15438 + * @param sem Semaphore to wait on
15441 +VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem);
15444 + * \brief Delete a semaphore, releasing any resources consumed by it.
15446 + * @param sem Semaphore to wait on
15449 +void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem);
15451 +#ifdef __cplusplus
15457 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_stdbool.h
15459 +#ifndef VCOS_STDBOOL_H
15460 +#define VCOS_STDBOOL_H
15462 +#ifndef __cplusplus
15464 +#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
15465 +#include <stdbool.h>
15473 +#endif /* __cplusplus */
15477 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_stdint.h
15479 +/*=============================================================================
15480 +Copyright (c) 2011 Broadcom Europe Limited.
15481 +All rights reserved.
15485 +=============================================================================*/
15487 +#ifndef VCOS_STDINT_H
15488 +#define VCOS_STDINT_H
15490 +/* Attempt to provide the types defined in stdint.h.
15492 + * Ideally this would either call out to a platform-specific
15493 + * header file (e.g. stdint.h) or define the types on a
15494 + * per-architecture/compiler basis. But for now we just
15498 +#ifdef __cplusplus
15502 +#ifdef __SYMBIAN32__
15504 +typedef signed char int8_t;
15505 +typedef unsigned char uint8_t;
15507 +typedef signed short int16_t;
15508 +typedef unsigned short uint16_t;
15510 +typedef int16_t int_least16_t;
15512 +typedef signed long int32_t;
15513 +typedef unsigned long uint32_t;
15515 +typedef signed long long int64_t;
15516 +typedef unsigned long long uint64_t;
15518 +typedef int32_t intptr_t;
15519 +typedef uint32_t uintptr_t;
15521 +typedef int64_t intmax_t;
15522 +typedef uint64_t uintmax_t;
15524 +#define INT8_MIN SCHAR_MIN
15525 +#define INT8_MAX SCHAR_MAX
15526 +#define UINT8_MAX UCHAR_MAX
15527 +#define INT16_MIN SHRT_MIN
15528 +#define INT16_MAX SHRT_MAX
15529 +#define UINT16_MAX USHRT_MAX
15530 +#define INT32_MIN LONG_MIN
15531 +#define INT32_MAX LONG_MAX
15532 +#define UINT32_MAX ULONG_MAX
15533 +#define INT64_MIN LLONG_MIN
15534 +#define INT64_MAX LLONG_MAX
15535 +#define UINT64_MAX ULLONG_MAX
15537 +#define INTPTR_MIN INT32_MIN
15538 +#define INTPTR_MAX INT32_MAX
15539 +#define UINTPTR_MAX UINT32_MAX
15540 +#define INTMAX_MIN INT64_MIN
15541 +#define INTMAX_MAX INT64_MAX
15542 +#define INT_LEAST16_MAX INT16_MAX
15543 +#define INT_LEAST16_MAX INT16_MAX
15545 +/*{{{ C99 types - THIS WHOLE SECTION IS INCOMPATIBLE WITH C99. IT SHOULD RESIDE IN A STDINT.H SINCE THIS FILE GETS USED ON HOST SIDE */
15547 +#elif defined( __STDC__ ) && __STDC_VERSION__ >= 199901L
15549 +#include <stdint.h>
15551 +#elif defined( __GNUC__ )
15553 +#include <stdint.h>
15555 +#elif defined(_MSC_VER) /* Visual C define equivalent types */
15557 +#include <stddef.h> /* Avoids intptr_t being defined in vadefs.h */
15559 +typedef __int8 int8_t;
15560 +typedef unsigned __int8 uint8_t;
15562 +typedef __int16 int16_t;
15563 +typedef unsigned __int16 uint16_t;
15565 +typedef __int32 int32_t;
15566 +typedef unsigned __int32 uint32_t;
15568 +typedef __int64 int64_t;
15569 +typedef unsigned __int64 uint64_t;
15570 +typedef uint32_t uintptr_t;
15571 +typedef int64_t intmax_t;
15572 +typedef uint64_t uintmax_t;
15573 +typedef int16_t int_least16_t;
15575 +#elif defined (VCMODS_LCC)
15576 +#include <limits.h>
15578 +typedef signed char int8_t;
15579 +typedef unsigned char uint8_t;
15581 +typedef signed short int16_t;
15582 +typedef unsigned short uint16_t;
15584 +typedef signed long int32_t;
15585 +typedef unsigned long uint32_t;
15587 +typedef signed long int64_t; /*!!!! PFCD, this means code using 64bit numbers will be broken on the VCE */
15588 +typedef unsigned long uint64_t; /* !!!! PFCD */
15590 +typedef int32_t intptr_t;
15591 +typedef uint32_t uintptr_t;
15592 +typedef int64_t intmax_t;
15593 +typedef uint64_t uintmax_t;
15594 +typedef int16_t int_least16_t;
15596 +#define INT8_MIN SCHAR_MIN
15597 +#define INT8_MAX SCHAR_MAX
15598 +#define UINT8_MAX UCHAR_MAX
15599 +#define INT16_MIN SHRT_MIN
15600 +#define INT16_MAX SHRT_MAX
15601 +#define UINT16_MAX USHRT_MAX
15602 +#define INT32_MIN LONG_MIN
15603 +#define INT32_MAX LONG_MAX
15604 +#define UINT32_MAX ULONG_MAX
15605 +#define INT64_MIN LONG_MIN /* !!!! PFCD */
15606 +#define INT64_MAX LONG_MAX /* !!!! PFCD */
15607 +#define UINT64_MAX ULONG_MAX /* !!!! PFCD */
15609 +#define INTPTR_MIN INT32_MIN
15610 +#define INTPTR_MAX INT32_MAX
15611 +#define UINTPTR_MAX UINT32_MAX
15612 +#define INTMAX_MIN INT64_MIN
15613 +#define INTMAX_MIN INT64_MIN
15614 +#define INT_LEAST16_MAX INT16_MAX
15615 +#define INT_LEAST16_MAX INT16_MAX
15617 +#elif defined(__VIDEOCORE__)
15619 +typedef signed char int8_t;
15620 +typedef unsigned char uint8_t;
15622 +typedef signed short int16_t;
15623 +typedef unsigned short uint16_t;
15625 +typedef signed long int32_t;
15626 +typedef unsigned long uint32_t;
15628 +typedef signed long long int64_t;
15629 +typedef unsigned long long uint64_t;
15631 +typedef int32_t intptr_t;
15632 +typedef uint32_t uintptr_t;
15633 +typedef int64_t intmax_t;
15634 +typedef uint64_t uintmax_t;
15635 +typedef int16_t int_least16_t;
15637 +#define INT8_MIN SCHAR_MIN
15638 +#define INT8_MAX SCHAR_MAX
15639 +#define UINT8_MAX UCHAR_MAX
15640 +#define INT16_MIN SHRT_MIN
15641 +#define INT16_MAX SHRT_MAX
15642 +#define UINT16_MAX USHRT_MAX
15643 +#define INT32_MIN LONG_MIN
15644 +#define INT32_MAX LONG_MAX
15645 +#define UINT32_MAX ULONG_MAX
15646 +#define INT64_MIN LLONG_MIN
15647 +#define INT64_MAX LLONG_MAX
15648 +#define UINT64_MAX ULLONG_MAX
15650 +#define INTPTR_MIN INT32_MIN
15651 +#define INTPTR_MAX INT32_MAX
15652 +#define UINTPTR_MAX UINT32_MAX
15653 +#define INTMAX_MIN INT64_MIN
15654 +#define INTMAX_MAX INT64_MAX
15655 +#define INT_LEAST16_MAX INT16_MAX
15656 +#define INT_LEAST16_MAX INT16_MAX
15658 +#elif defined (__HIGHC__) && defined(_I386)
15660 +#include <stdint.h>
15663 +#error Unknown platform
15666 +#ifdef __cplusplus
15669 +#endif /* VCOS_STDINT_H */
15673 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_string.h
15675 +/*=============================================================================
15676 +Copyright (c) 2009 Broadcom Europe Limited.
15677 +All rights reserved.
15680 +Module : chip driver
15683 +VideoCore OS Abstraction Layer - public header file
15684 +=============================================================================*/
15686 +#ifndef VCOS_STRING_H
15687 +#define VCOS_STRING_H
15692 + * String functions.
15696 +#ifdef __cplusplus
15700 +#include "interface/vcos/vcos_types.h"
15701 +#include "vcos_platform.h"
15704 +#include <linux/string.h>
15706 +#include <string.h>
15709 +/** Case insensitive string comparison.
15714 +int vcos_strcasecmp(const char *s1, const char *s2);
15717 +int vcos_strncasecmp(const char *s1, const char *s2, size_t n);
15719 +VCOSPRE_ int VCOSPOST_ vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap );
15721 +VCOSPRE_ int VCOSPOST_ vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...);
15723 +VCOS_STATIC_INLINE
15724 +int vcos_strlen(const char *s) { return (int)strlen(s); }
15726 +VCOS_STATIC_INLINE
15727 +int vcos_strcmp(const char *s1, const char *s2) { return strcmp(s1,s2); }
15729 +VCOS_STATIC_INLINE
15730 +int vcos_strncmp(const char *cs, const char *ct, size_t count) { return strncmp(cs, ct, count); }
15732 +VCOS_STATIC_INLINE
15733 +char *vcos_strcpy(char *dst, const char *src) { return strcpy(dst, src); }
15735 +VCOS_STATIC_INLINE
15736 +char *vcos_strncpy(char *dst, const char *src, size_t count) { return strncpy(dst, src, count); }
15738 +VCOS_STATIC_INLINE
15739 +void *vcos_memcpy(void *dst, const void *src, size_t n) { memcpy(dst, src, n); return dst; }
15741 +VCOS_STATIC_INLINE
15742 +void *vcos_memset(void *p, int c, size_t n) { return memset(p, c, n); }
15744 +#ifdef __cplusplus
15749 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_thread.h
15751 +/*=============================================================================
15752 +Copyright (c) 2009 Broadcom Europe Limited.
15753 +All rights reserved.
15756 +Module : chip driver
15759 +VideoCore OS Abstraction Layer - public header file
15760 +=============================================================================*/
15762 +#ifndef VCOS_THREAD_H
15763 +#define VCOS_THREAD_H
15765 +#ifdef __cplusplus
15769 +#include "interface/vcos/vcos_types.h"
15770 +#include "vcos_platform.h"
15773 + * \file vcos_thread.h
15775 + * \section thread Threads
15777 + * Under Nucleus, a thread is created by NU_Create_Task, passing in the stack
15778 + * and various other parameters. To stop the thread, NU_Terminate_Thread() and
15779 + * NU_Delete_Thread() are called.
15781 + * Unfortunately it's not possible to emulate this API under some fairly common
15782 + * operating systems. Under Windows you can't pass in the stack, and you can't
15783 + * safely terminate a thread.
15785 + * Therefore, an API which is similar to the pthreads API is used instead. This
15786 + * API can (mostly) be emulated under all interesting operating systems.
15788 + * Obviously this makes the code somewhat more complicated on VideoCore than it
15789 + * would otherwise be - we end up with an extra mutex per thread, and some code
15790 + * that waits for it. The benefit is that we have a single way of creating
15791 + * threads that works consistently on all platforms (apart from stack supplying).
15793 + * \subsection stack Stack
15795 + * It's still not possible to pass in the stack address, but this can be made
15796 + * much more obvious in the API: the relevant function is missing and the
15797 + * CPP symbol VCOS_CAN_SET_STACK_ADDR is zero rather than one.
15799 + * \subsection thr_create Creating a thread
15801 + * The simplest way to create a thread is with vcos_thread_create() passing in a
15802 + * NULL thread parameter argument. To wait for the thread to exit, call
15803 + * vcos_thread_join().
15805 + * \subsection back Backward compatibility
15807 + * To ease migration, a "classic" thread creation API is provided for code
15808 + * that used to make use of Nucleus, vcos_thread_create_classic(). The
15809 + * arguments are not exactly the same, as the PREEMPT parameter is dropped.
15813 +#define VCOS_AFFINITY_CPU0 _VCOS_AFFINITY_CPU0
15814 +#define VCOS_AFFINITY_CPU1 _VCOS_AFFINITY_CPU1
15815 +#define VCOS_AFFINITY_MASK _VCOS_AFFINITY_MASK
15816 +#define VCOS_AFFINITY_DEFAULT _VCOS_AFFINITY_DEFAULT
15817 +#define VCOS_AFFINITY_THISCPU _VCOS_AFFINITY_THISCPU
15819 +/** Report whether or not we have an RTOS at all, and hence the ability to
15820 + * create threads.
15822 +VCOSPRE_ int VCOSPOST_ vcos_have_rtos(void);
15824 +/** Create a thread. It must be cleaned up by calling vcos_thread_join().
15826 + * @param thread Filled in on return with thread
15827 + * @param name A name for the thread. May be the empty string.
15828 + * @param attrs Attributes; default attributes will be used if this is NULL.
15829 + * @param entry Entry point.
15830 + * @param arg Argument passed to the entry point.
15832 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create(VCOS_THREAD_T *thread,
15833 + const char *name,
15834 + VCOS_THREAD_ATTR_T *attrs,
15835 + VCOS_THREAD_ENTRY_FN_T entry,
15838 +/** Exit the thread from within the thread function itself.
15839 + * Resources must still be cleaned up via a call to thread_join().
15841 + * The thread can also be terminated by simply exiting the thread function.
15843 + * @param data Data passed to thread_join. May be NULL.
15845 +VCOSPRE_ void VCOSPOST_ vcos_thread_exit(void *data);
15847 +/** Wait for a thread to terminate and then clean up its resources.
15849 + * @param thread Thread to wait for
15850 + * @param pData Updated to point at data provided in vcos_thread_exit or exit
15851 + * code of thread function.
15853 +VCOSPRE_ void VCOSPOST_ vcos_thread_join(VCOS_THREAD_T *thread,
15858 + * \brief Create a thread using an API similar to the one "traditionally"
15859 + * used under Nucleus.
15861 + * This creates a thread which must be cleaned up by calling vcos_thread_join().
15862 + * The thread cannot be simply terminated (as in Nucleus and ThreadX) as thread
15863 + * termination is not universally supported.
15865 + * @param thread Filled in with thread instance
15866 + * @param name An optional name for the thread. NULL or "" may be used (but
15867 + * a name will aid in debugging).
15868 + * @param entry Entry point
15869 + * @param arg A single argument passed to the entry point function
15870 + * @param stack Pointer to stack address
15871 + * @param stacksz Size of stack in bytes
15872 + * @param priaff Priority of task, between VCOS_PRI_LOW and VCOS_PRI_HIGH, ORed with the CPU affinity
15873 + * @param autostart If non-zero the thread will start immediately.
15874 + * @param timeslice Timeslice (system ticks) for this thread.
15876 + * @sa vcos_thread_terminate vcos_thread_delete
15878 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create_classic(VCOS_THREAD_T *thread,
15879 + const char *name,
15880 + void *(*entry)(void *arg),
15883 + VCOS_UNSIGNED stacksz,
15884 + VCOS_UNSIGNED priaff,
15885 + VCOS_UNSIGNED timeslice,
15886 + VCOS_UNSIGNED autostart);
15889 + * \brief Set a thread's priority
15891 + * Set the priority for a thread.
15893 + * @param thread The thread
15894 + * @param pri Thread priority in VCOS_PRI_MASK bits; affinity in VCOS_AFFINITY_MASK bits.
15897 +void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED pri);
15900 + * \brief Return the currently executing thread.
15904 +VCOS_THREAD_T *vcos_thread_current(void);
15907 + * \brief Return the thread's priority.
15910 +VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread);
15913 + * \brief Return the thread's cpu affinity.
15916 +VCOS_UNSIGNED vcos_thread_get_affinity(VCOS_THREAD_T *thread);
15919 + * \brief Set the thread's cpu affinity.
15923 +void vcos_thread_set_affinity(VCOS_THREAD_T *thread, VCOS_UNSIGNED affinity);
15926 + * \brief Query whether we are in an interrupt.
15928 + * @return 1 if in interrupt context.
15931 +int vcos_in_interrupt(void);
15934 + * \brief Sleep a while.
15936 + * @param ms Number of milliseconds to sleep for
15938 + * This may actually sleep a whole number of ticks.
15941 +void vcos_sleep(uint32_t ms);
15944 + * \brief Return the value of the hardware microsecond counter.
15948 +uint32_t vcos_getmicrosecs(void);
15950 +#define vcos_get_ms() (vcos_getmicrosecs()/1000)
15953 + * \brief Return a unique identifier for the current process
15957 +VCOS_UNSIGNED vcos_process_id_current(void);
15959 +/** Relinquish this time slice. */
15961 +void vcos_thread_relinquish(void);
15963 +/** Return the name of the given thread.
15965 +VCOSPRE_ const char * VCOSPOST_ vcos_thread_get_name(const VCOS_THREAD_T *thread);
15967 +/** Change preemption. This is almost certainly not what you want, as it won't
15968 + * work reliably in a multicore system: although you can affect the preemption
15969 + * on *this* core, you won't affect what's happening on the other core(s).
15971 + * It's mainly here to ease migration. If you're using it in new code, you
15972 + * probably need to think again.
15974 + * @param pe New preemption, VCOS_PREEMPT or VCOS_NO_PREEMPT
15975 + * @return Old value of preemption.
15978 +VCOS_UNSIGNED vcos_change_preemption(VCOS_UNSIGNED pe);
15980 +/** Is a thread still running, or has it exited?
15982 + * Note: this exists for some fairly scary code in the video codec tests. Don't
15983 + * try to use it for anything else, as it may well not do what you expect.
15985 + * @param thread thread to query
15986 + * @return non-zero if thread is running, or zero if it has exited.
15989 +int vcos_thread_running(VCOS_THREAD_T *thread);
15991 +/** Resume a thread.
15993 + * @param thread thread to resume
15996 +void vcos_thread_resume(VCOS_THREAD_T *thread);
15999 + * Internal APIs - may not always be present and should not be used in
16003 +extern void _vcos_task_timer_set(void (*pfn)(void*), void *, VCOS_UNSIGNED ms);
16004 +extern void _vcos_task_timer_cancel(void);
16006 +#ifdef __cplusplus
16011 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_thread_attr.h
16013 +/*=============================================================================
16014 +Copyright (c) 2009 Broadcom Europe Limited.
16015 +All rights reserved.
16018 +VideoCore OS Abstraction Layer - thread attributes
16019 +=============================================================================*/
16021 +#ifndef VCOS_THREAD_ATTR_H
16022 +#define VCOS_THREAD_ATTR_H
16024 +#ifdef __cplusplus
16031 + * Attributes for thread creation.
16035 +/** Initialize thread attribute struct. This call does not allocate memory,
16036 + * and so cannot fail.
16039 +VCOSPRE_ void VCOSPOST_ vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs);
16041 +/** Set the stack address and size. If not set, a stack will be allocated automatically.
16043 + * This can only be set on some platforms. It will always be possible to set the stack
16044 + * address on VideoCore, but on host platforms, support may well not be available.
16046 +#if VCOS_CAN_SET_STACK_ADDR
16048 +void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED sz);
16051 +/** Set the stack size. If not set, a default size will be used. Attempting to call this after having
16052 + * set the stack location with vcos_thread_attr_setstack() will result in undefined behaviour.
16055 +void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED sz);
16057 +/** Set the task priority. If not set, a default value will be used.
16060 +void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri);
16062 +/** Set the task cpu affinity. If not set, the default will be used.
16065 +void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED aff);
16067 +/** Set the timeslice. If not set the default will be used.
16070 +void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts);
16072 +/** The thread entry function takes (argc,argv), as per Nucleus, with
16073 + * argc being 0. This may be withdrawn in a future release and should not
16074 + * be used in new code.
16077 +void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy);
16080 +void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart);
16082 +#ifdef __cplusplus
16087 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_timer.h
16089 +/*=============================================================================
16090 +Copyright (c) 2009 Broadcom Europe Limited.
16091 +All rights reserved.
16094 +Module : chip driver
16097 +VideoCore OS Abstraction Layer - timer support
16098 +=============================================================================*/
16100 +#ifndef VCOS_TIMER_H
16101 +#define VCOS_TIMER_H
16103 +#ifdef __cplusplus
16107 +#include "interface/vcos/vcos_types.h"
16108 +#include "vcos_platform.h"
16110 +/** \file vcos_timer.h
16112 + * Timers are single shot.
16114 + * Timer times are in milliseconds.
16116 + * \note that timer callback functions are called from an arbitrary thread
16117 + * context. The expiration function should do its work as quickly as possible;
16118 + * blocking should be avoided.
16120 + * \note On Windows, the separate function vcos_timer_init() must be called
16121 + * as timer initialization from DllMain is not possible.
16124 +/** Perform timer subsystem initialization. This function is not needed
16125 + * on non-Windows platforms but is still present so that it can be
16126 + * called. On Windows it is needed because vcos_init() gets called
16127 + * from DLL initialization where it is not possible to create a
16128 + * time queue (deadlock occurs if you try).
16130 + * @return VCOS_SUCCESS on success. VCOS_EEXIST if this has already been called
16131 + * once. VCOS_ENOMEM if resource allocation failed.
16133 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_timer_init(void);
16135 +/** Create a timer in a disabled state.
16137 + * The timer is initially disabled.
16139 + * @param timer timer handle
16140 + * @param name name for timer
16141 + * @param expiration_routine function to call when timer expires
16142 + * @param context context passed to expiration routine
16146 +VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
16147 + const char *name,
16148 + void (*expiration_routine)(void *context),
16153 +/** Start a timer running.
16155 + * Timer must be stopped.
16157 + * @param timer timer handle
16158 + * @param delay Delay to wait for, in ms
16161 +void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay);
16163 +/** Stop an already running timer.
16165 + * @param timer timer handle
16168 +void vcos_timer_cancel(VCOS_TIMER_T *timer);
16170 +/** Stop a timer and restart it.
16171 + * @param timer timer handle
16172 + * @param delay delay in ms
16175 +void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay);
16178 +void vcos_timer_delete(VCOS_TIMER_T *timer);
16180 +#ifdef __cplusplus
16185 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_types.h
16187 +/*=============================================================================
16188 +Copyright (c) 2009 Broadcom Europe Limited.
16189 +All rights reserved.
16192 +VideoCore OS Abstraction Layer - basic types
16193 +=============================================================================*/
16195 +#ifndef VCOS_TYPES_H
16196 +#define VCOS_TYPES_H
16198 +#define VCOS_VERSION 1
16200 +#include "vcos_platform_types.h"
16202 +#if !defined(VCOSPRE_) || !defined(VCOSPOST_)
16203 +#error VCOSPRE_ and VCOSPOST_ not defined!
16206 +/* Redefine these here; this means that existing header files can carry on
16207 + * using the VCHPOST/VCHPRE macros rather than having huge changes, which
16208 + * could cause nasty merge problems.
16211 +#define VCHPOST_ VCOSPOST_
16214 +#define VCHPRE_ VCOSPRE_
16217 +/** Entry function for a lowlevel thread.
16219 + * Returns void for consistency with Nucleus/ThreadX.
16221 +typedef void (*VCOS_LLTHREAD_ENTRY_FN_T)(void *);
16223 +/** Thread entry point. Returns a void* for consistency
16226 +typedef void *(*VCOS_THREAD_ENTRY_FN_T)(void*);
16229 +/* Error return codes - chosen to be similar to errno values */
16245 +/* Some compilers (MetaWare) won't inline with -g turned on, which then results
16246 + * in a lot of code bloat. To overcome this, inline functions are forward declared
16247 + * with the prefix VCOS_INLINE_DECL, and implemented with the prefix VCOS_INLINE_IMPL.
16249 + * That then means that in a release build, "static inline" can be used in the obvious
16250 + * way, but in a debug build the implementations can be skipped in all but one file,
16251 + * by using VCOS_INLINE_BODIES.
16253 + * VCOS_INLINE_DECL - put this at the start of an inline forward declaration of a VCOS
16256 + * VCOS_INLINE_IMPL - put this at the start of an inlined implementation of a VCOS
16261 +/* VCOS_EXPORT - it turns out that in some circumstances we need the implementation of
16262 + * a function even if it is usually inlined.
16264 + * In particular, if we have a codec that is usually provided in object form, if it
16265 + * was built for a debug build it will be full of calls to vcos_XXX(). If this is used
16266 + * in a *release* build, then there won't be any of these calls around in the main image
16267 + * as they will all have been inlined. The problem also exists for vcos functions called
16268 + * from assembler.
16270 + * VCOS_EXPORT ensures that the named function will be emitted as a regular (not static-inline)
16271 + * function inside vcos_<platform>.c so that it can be linked against. Doing this for every
16272 + * VCOS function would be a bit code-bloat-tastic, so it is only done for those that need it.
16276 +#ifdef __cplusplus
16277 +#define _VCOS_INLINE inline
16279 +#define _VCOS_INLINE __inline
16282 +#if defined(NDEBUG)
16285 +# define VCOS_INLINE_DECL extern __inline__
16286 +# define VCOS_INLINE_IMPL static __inline__
16288 +# define VCOS_INLINE_DECL static _VCOS_INLINE /* declare a func */
16289 +# define VCOS_INLINE_IMPL static _VCOS_INLINE /* implement a func inline */
16292 +# if defined(VCOS_WANT_IMPL)
16293 +# define VCOS_EXPORT
16295 +# define VCOS_EXPORT VCOS_INLINE_IMPL
16296 +# endif /* VCOS_WANT_IMPL */
16298 +#define VCOS_INLINE_BODIES
16300 +#else /* NDEBUG */
16302 +#if !defined(VCOS_INLINE_DECL)
16303 + #define VCOS_INLINE_DECL extern
16305 +#if !defined(VCOS_INLINE_IMPL)
16306 + #define VCOS_INLINE_IMPL
16308 +#define VCOS_EXPORT VCOS_INLINE_IMPL
16311 +#define VCOS_STATIC_INLINE static _VCOS_INLINE
16313 +#if defined(__HIGHC__) || defined(__HIGHC_ANSI__)
16314 +#define _VCOS_METAWARE
16317 +/** It seems that __FUNCTION__ isn't standard!
16319 +#if __STDC_VERSION__ < 199901L
16320 +# if __GNUC__ >= 2 || defined(__VIDEOCORE__)
16321 +# define VCOS_FUNCTION __FUNCTION__
16323 +# define VCOS_FUNCTION "<unknown>"
16326 +# define VCOS_FUNCTION __func__
16329 +#define _VCOS_MS_PER_TICK (1000/VCOS_TICKS_PER_SECOND)
16331 +/* Convert a number of milliseconds to a tick count. Internal use only - fails to
16332 + * convert VCOS_SUSPEND correctly.
16334 +#define _VCOS_MS_TO_TICKS(ms) (((ms)+_VCOS_MS_PER_TICK-1)/_VCOS_MS_PER_TICK)
16336 +#define VCOS_TICKS_TO_MS(ticks) ((ticks) * _VCOS_MS_PER_TICK)
16338 +/** VCOS version of DATESTR, from pcdisk.h. Used by the hostreq service.
16340 +typedef struct vcos_datestr
16342 + uint8_t cmsec; /**< Centesimal mili second */
16343 + uint16_t date; /**< Date */
16344 + uint16_t time; /**< Time */
16348 +/* Compile-time assert - declares invalid array length if condition
16349 + * not met, or array of length one if OK.
16351 +#define VCOS_CASSERT(e) extern char vcos_compile_time_check[1/(e)]
16353 +#define vcos_min(x,y) ((x) < (y) ? (x) : (y))
16354 +#define vcos_max(x,y) ((x) > (y) ? (x) : (y))
16356 +/** Return the count of an array. FIXME: under gcc we could make
16357 + * this report an error for pointers using __builtin_types_compatible().
16359 +#define vcos_countof(x) (sizeof((x)) / sizeof((x)[0]))
16361 +/* for backward compatibility */
16362 +#define countof(x) (sizeof((x)) / sizeof((x)[0]))
16364 +#define VCOS_ALIGN_DOWN(p,n) (((ptrdiff_t)(p)) & ~((n)-1))
16365 +#define VCOS_ALIGN_UP(p,n) VCOS_ALIGN_DOWN((ptrdiff_t)(p)+(n)-1,(n))
16367 +/** bool_t is not a POSIX type so cannot rely on it. Define it here.
16368 + * It's not even defined in stdbool.h.
16370 +typedef int32_t vcos_bool_t;
16371 +typedef int32_t vcos_fourcc_t;
16373 +#define VCOS_FALSE 0
16374 +#define VCOS_TRUE (!VCOS_FALSE)
16376 +/** Mark unused arguments to keep compilers quiet */
16377 +#define vcos_unused(x) (void)(x)
16379 +/** For backward compatibility */
16380 +typedef vcos_fourcc_t fourcc_t;
16381 +typedef vcos_fourcc_t FOURCC_T;