bee41d712ed0e7c4587777225ff56fd3bbb99a4f
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.3 / 0005-bcm2708-vchiq-driver.patch
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
5
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
7 ---
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
155
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"
163 endmenu
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/
171 +
172 --- /dev/null
173 +++ b/drivers/misc/vc04_services/Kconfig
174 @@ -0,0 +1,7 @@
175 +config BCM2708_VCHIQ
176 + tristate "Videocore VCHIQ"
177 + depends on MACH_BCM2708
178 + default y
179 + help
180 + Helper for communication for VideoCore.
181 +
182 --- /dev/null
183 +++ b/drivers/misc/vc04_services/Makefile
184 @@ -0,0 +1,19 @@
185 +obj-$(CONFIG_BCM2708_VCHIQ) += vchiq.o
186 +
187 +vchiq-objs := \
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
199 +
200 +EXTRA_CFLAGS += -DVCOS_VERIFY_BKPTS=1 -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel
201 +
202 +
203 +
204 --- /dev/null
205 +++ b/drivers/misc/vc04_services/interface/vchi/vchi_mh.h
206 @@ -0,0 +1,19 @@
207 +/*=============================================================================
208 +Copyright (c) 2010 Broadcom Europe Limited. All rights reserved.
209 +
210 +Project : vchi
211 +Module : vchi
212 +
213 +FILE DESCRIPTION:
214 +Definitions for memory handle types.
215 +=============================================================================*/
216 +
217 +#ifndef VCHI_MH_H_
218 +#define VCHI_MH_H_
219 +
220 +#include <interface/vcos/vcos.h>
221 +
222 +typedef int32_t VCHI_MEM_HANDLE_T;
223 +#define VCHI_MEM_HANDLE_INVALID 0
224 +
225 +#endif
226 --- /dev/null
227 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
228 @@ -0,0 +1,27 @@
229 +/*
230 + * Copyright (c) 2010-2011 Broadcom. All rights reserved.
231 + *
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.
236 + *
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.
241 + *
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
245 + */
246 +
247 +#ifndef VCHIQ_VCHIQ_H
248 +#define VCHIQ_VCHIQ_H
249 +
250 +#include "vchiq_if.h"
251 +#include "vchiq_util.h"
252 +#include "interface/vcos/vcos.h"
253 +
254 +#endif
255 +
256 --- /dev/null
257 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
258 @@ -0,0 +1,27 @@
259 +/*
260 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
261 + *
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.
266 + *
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.
271 + *
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
275 + */
276 +
277 +#ifndef VCHIQ_2835_H
278 +#define VCHIQ_2835_H
279 +
280 +#include "vchiq_pagelist.h"
281 +
282 +#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0
283 +#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1
284 +
285 +#endif /* VCHIQ_2835_H */
286 --- /dev/null
287 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
288 @@ -0,0 +1,487 @@
289 +/*
290 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
291 + *
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.
296 + *
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.
301 + *
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
305 + */
306 +
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>
316 +#include <asm/io.h>
317 +#include <asm/uaccess.h>
318 +
319 +#include <mach/irqs.h>
320 +
321 +#include <mach/platform.h>
322 +#include <mach/vcio.h>
323 +
324 +#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
325 +
326 +#define VCHIQ_DOORBELL_IRQ IRQ_ARM_DOORBELL_0
327 +#define VCHIQ_ARM_ADDRESS(x) __virt_to_bus(x)
328 +
329 +#include "vchiq_arm.h"
330 +#include "vchiq_2835.h"
331 +
332 +#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
333 +
334 +#define VCOS_LOG_CATEGORY (&vchiq_arm_log_category)
335 +
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;
342 +
343 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
344 +static DEFINE_SEMAPHORE(g_free_fragments_mutex);
345 +#else
346 +static DECLARE_MUTEX(g_free_fragments_mutex);
347 +#endif
348 +
349 +static irqreturn_t
350 +vchiq_doorbell_irq(int irq, void *dev_id);
351 +
352 +static int
353 +create_pagelist(char __user *buf, size_t count, unsigned short type,
354 + struct task_struct *task, PAGELIST_T ** ppagelist);
355 +
356 +static void
357 +free_pagelist(PAGELIST_T *pagelist, int actual);
358 +
359 +int __init
360 +vchiq_platform_vcos_init(void)
361 +{
362 + return (vcos_init() == VCOS_SUCCESS) ? 0 : -EINVAL;
363 +}
364 +
365 +int __init
366 +vchiq_platform_init(VCHIQ_STATE_T *state)
367 +{
368 + VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
369 + int frag_mem_size;
370 + int err;
371 + int i;
372 +
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);
376 +
377 + g_slot_mem = dma_alloc_coherent(NULL, g_slot_mem_size + frag_mem_size,
378 + &g_slot_phys, GFP_ATOMIC);
379 +
380 + if (!g_slot_mem) {
381 + vcos_log_error("Unable to allocate channel memory");
382 + err = -ENOMEM;
383 + goto failed_alloc;
384 + }
385 +
386 + vcos_assert(((int)g_slot_mem & (PAGE_SIZE - 1)) == 0);
387 +
388 + vchiq_slot_zero = vchiq_init_slots(g_slot_mem, g_slot_mem_size);
389 + if (!vchiq_slot_zero)
390 + {
391 + err = -EINVAL;
392 + goto failed_init_slots;
393 + }
394 +
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;
397 +
398 + g_fragments_base = (FRAGMENTS_T *)(g_slot_mem + g_slot_mem_size);
399 + g_slot_mem_size += frag_mem_size;
400 +
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];
405 + }
406 + *(FRAGMENTS_T **) & g_fragments_base[i] = NULL;
407 + sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
408 +
409 + if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) !=
410 + VCHIQ_SUCCESS)
411 + {
412 + err = -EINVAL;
413 + goto failed_vchiq_init;
414 + }
415 +
416 + err = request_irq(VCHIQ_DOORBELL_IRQ, vchiq_doorbell_irq,
417 + IRQF_SAMPLE_RANDOM | IRQF_IRQPOLL, "VCHIQ doorbell",
418 + state);
419 + if (err < 0)
420 + {
421 + printk( KERN_ERR "%s: failed to register irq=%d err=%d\n", __func__,
422 + VCHIQ_DOORBELL_IRQ, err );
423 + goto failed_request_irq;
424 + }
425 +
426 + /* Send the base address of the slots to VideoCore */
427 +
428 + dsb(); /* Ensure all writes have completed */
429 +
430 + bcm_mailbox_write(MBOX_CHAN_VCHIQ, (unsigned int)g_slot_phys);
431 +
432 + vcos_log_info("vchiq_init - done (slots %x, phys %x)",
433 + (unsigned int)vchiq_slot_zero, g_slot_phys);
434 +
435 + return 0;
436 +
437 +failed_request_irq:
438 +failed_vchiq_init:
439 +failed_init_slots:
440 + dma_free_coherent(NULL, g_slot_mem_size, g_slot_mem, g_slot_phys);
441 +
442 +failed_alloc:
443 + return err;
444 +}
445 +
446 +void __exit
447 +vchiq_platform_exit(VCHIQ_STATE_T *state)
448 +{
449 + free_irq(VCHIQ_DOORBELL_IRQ, state);
450 + dma_free_coherent(NULL, g_slot_mem_size,
451 + g_slot_mem, g_slot_phys);
452 +}
453 +
454 +void
455 +remote_event_signal(REMOTE_EVENT_T *event)
456 +{
457 + event->fired = 1;
458 +
459 + /* The test on the next line also ensures the write on the previous line
460 + has completed */
461 +
462 + if (event->armed) {
463 + /* trigger vc interrupt */
464 + dsb(); /* data barrier operation */
465 +
466 + writel(0, __io_address(ARM_0_BELL2));
467 + }
468 +}
469 +
470 +int
471 +vchiq_copy_from_user(void *dst, const void *src, int size)
472 +{
473 + return copy_from_user(dst, src, size);
474 +}
475 +
476 +VCHIQ_STATUS_T
477 +vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
478 + void *offset, int size, int dir)
479 +{
480 + PAGELIST_T *pagelist;
481 + int ret;
482 +
483 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
484 +
485 + ret = create_pagelist((char __user *)offset, size,
486 + (dir == VCHIQ_BULK_RECEIVE)
487 + ? PAGELIST_READ
488 + : PAGELIST_WRITE,
489 + current,
490 + &pagelist);
491 + if (ret != 0)
492 + return VCHIQ_ERROR;
493 +
494 + bulk->handle = memhandle;
495 + bulk->data = VCHIQ_ARM_ADDRESS(pagelist);
496 +
497 + /* Store the pagelist address in remote_data, which isn't used by the
498 + slave. */
499 + bulk->remote_data = pagelist;
500 +
501 + return VCHIQ_SUCCESS;
502 +}
503 +
504 +void
505 +vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
506 +{
507 + free_pagelist((PAGELIST_T *)bulk->remote_data, bulk->actual);
508 +}
509 +
510 +void
511 +vchiq_transfer_bulk(VCHIQ_BULK_T *bulk)
512 +{
513 + /*
514 + * This should only be called on the master (VideoCore) side, but
515 + * provide an implementation to avoid the need for ifdefery.
516 + */
517 + vcos_assert(!"This code should not be called by the ARM on BCM2835");
518 +}
519 +
520 +void
521 +vchiq_dump_platform_state(void *dump_context)
522 +{
523 + char buf[80];
524 + int len;
525 + len = vcos_snprintf(buf, sizeof(buf),
526 + " Platform: 2835 (VC master)");
527 + vchiq_dump(dump_context, buf, len + 1);
528 +}
529 +
530 +void
531 +vchiq_platform_paused(VCHIQ_STATE_T *state)
532 +{
533 + vcos_unused(state);
534 + vcos_assert_msg(0, "Suspend/resume not supported");
535 +}
536 +
537 +void
538 +vchiq_platform_resumed(VCHIQ_STATE_T *state)
539 +{
540 + vcos_unused(state);
541 + vcos_assert_msg(0, "Suspend/resume not supported");
542 +}
543 +
544 +VCHIQ_STATUS_T
545 +vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle)
546 +{
547 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
548 + if (!service)
549 + return VCHIQ_ERROR;
550 + return VCHIQ_SUCCESS;
551 +}
552 +
553 +VCHIQ_STATUS_T
554 +vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle)
555 +{
556 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
557 + if (!service)
558 + return VCHIQ_ERROR;
559 + return VCHIQ_SUCCESS;
560 +}
561 +
562 +VCHIQ_STATUS_T
563 +vchiq_check_service(VCHIQ_SERVICE_HANDLE_T handle)
564 +{
565 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
566 + if (!service)
567 + return VCHIQ_ERROR;
568 + return VCHIQ_SUCCESS;
569 +}
570 +
571 +/*
572 + * Local functions
573 + */
574 +
575 +static irqreturn_t
576 +vchiq_doorbell_irq(int irq, void *dev_id)
577 +{
578 + VCHIQ_STATE_T *state = dev_id;
579 + irqreturn_t ret = IRQ_NONE;
580 + unsigned int status;
581 +
582 + /* Read (and clear) the doorbell */
583 + status = readl(__io_address(ARM_0_BELL0));
584 +
585 + if (status & 0x4) { /* Was the doorbell rung? */
586 + remote_event_pollall(state);
587 + ret = IRQ_HANDLED;
588 + }
589 +
590 + return ret;
591 +}
592 +
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
598 + cached area.
599 +
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.
604 + */
605 +
606 +static int
607 +create_pagelist(char __user *buf, size_t count, unsigned short type,
608 + struct task_struct *task, PAGELIST_T ** ppagelist)
609 +{
610 + PAGELIST_T *pagelist;
611 + struct page **pages;
612 + struct page *page;
613 + unsigned long *addrs;
614 + unsigned int num_pages, offset, i;
615 + char *addr, *base_addr, *next_addr;
616 + int run, addridx, actual_pages;
617 +
618 + offset = (unsigned int)buf & (PAGE_SIZE - 1);
619 + num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE;
620 +
621 + *ppagelist = NULL;
622 +
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])),
627 + GFP_KERNEL);
628 +
629 + vcos_log_trace("create_pagelist - %x", (unsigned int)pagelist);
630 + if (!pagelist)
631 + return -ENOMEM;
632 +
633 + addrs = pagelist->addrs;
634 + pages = (struct page **)(addrs + num_pages);
635 +
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);
642 +
643 + if (actual_pages != num_pages)
644 + {
645 + for (i = 0; i < actual_pages; i++) {
646 + page_cache_release(pages[i]);
647 + }
648 + kfree(pagelist);
649 + return -EINVAL;
650 + }
651 +
652 + pagelist->length = count;
653 + pagelist->type = type;
654 + pagelist->offset = offset;
655 +
656 + /* Group the pages into runs of contiguous pages */
657 +
658 + base_addr = VCHIQ_ARM_ADDRESS(page_address(pages[0]));
659 + next_addr = base_addr + PAGE_SIZE;
660 + addridx = 0;
661 + run = 0;
662 +
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;
667 + run++;
668 + } else {
669 + addrs[addridx] = (unsigned long)base_addr + run;
670 + addridx++;
671 + base_addr = addr;
672 + next_addr = addr + PAGE_SIZE;
673 + run = 0;
674 + }
675 + }
676 +
677 + addrs[addridx] = (unsigned long)base_addr + run;
678 + addridx++;
679 +
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;
685 +
686 + if (down_interruptible(&g_free_fragments_sema) != 0) {
687 + kfree(pagelist);
688 + return -EINTR;
689 + }
690 +
691 + vcos_assert(g_free_fragments != NULL);
692 +
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);
698 + pagelist->type =
699 + PAGELIST_READ_WITH_FRAGMENTS + (fragments -
700 + g_fragments_base);
701 + }
702 +
703 + for (page = virt_to_page(pagelist);
704 + page <= virt_to_page(addrs + num_pages - 1); page++) {
705 + flush_dcache_page(page);
706 + }
707 +
708 + *ppagelist = pagelist;
709 +
710 + return 0;
711 +}
712 +
713 +static void
714 +free_pagelist(PAGELIST_T *pagelist, int actual)
715 +{
716 + struct page **pages;
717 + unsigned int num_pages, i;
718 +
719 + vcos_log_trace("free_pagelist - %x, %d", (unsigned int)pagelist, actual);
720 +
721 + num_pages =
722 + (pagelist->length + pagelist->offset + PAGE_SIZE - 1) / PAGE_SIZE;
723 +
724 + pages = (struct page **)(pagelist->addrs + num_pages);
725 +
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;
732 +
733 + if (actual >= 0)
734 + {
735 + if ((head_bytes = (CACHE_LINE_SIZE - pagelist->offset) & (CACHE_LINE_SIZE - 1)) != 0) {
736 + if (head_bytes > actual)
737 + head_bytes = actual;
738 +
739 + memcpy((char *)page_address(pages[0]) +
740 + pagelist->offset, fragments->headbuf,
741 + head_bytes);
742 + }
743 + if ((head_bytes < actual) &&
744 + (tail_bytes =
745 + (pagelist->offset + actual) & (CACHE_LINE_SIZE -
746 + 1)) != 0) {
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);
751 + }
752 + }
753 +
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);
759 + }
760 +
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]);
765 + }
766 +
767 + kfree(pagelist);
768 +}
769 +
770 +VCHIQ_STATUS_T
771 +vchiq_platform_suspend(VCHIQ_STATE_T *state)
772 +{
773 + vcos_unused(state);
774 + return VCHIQ_ERROR;
775 +}
776 --- /dev/null
777 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
778 @@ -0,0 +1,1293 @@
779 +/*
780 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
781 + *
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.
786 + *
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.
791 + *
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
795 + */
796 +
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>
804 +
805 +#include "vchiq_core.h"
806 +#include "vchiq_ioctl.h"
807 +#include "vchiq_arm.h"
808 +
809 +#define DEVICE_NAME "vchiq"
810 +
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 "."
814 +
815 +#define VCHIQ_MINOR 0
816 +
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
822 +
823 +#define VCOS_LOG_CATEGORY (&vchiq_arm_log_category)
824 +
825 +typedef struct client_service_struct {
826 + VCHIQ_SERVICE_T *service;
827 + void *userdata;
828 + VCHIQ_INSTANCE_T instance;
829 + int handle;
830 + int is_vchi;
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];
838 +} USER_SERVICE_T;
839 +
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;
847 +
848 + USER_SERVICE_T services[MAX_SERVICES];
849 +
850 + int connected;
851 + int closing;
852 + int pid;
853 + int mark;
854 +};
855 +
856 +typedef struct dump_context_struct
857 +{
858 + char __user *buf;
859 + size_t actual;
860 + size_t space;
861 + loff_t offset;
862 +} DUMP_CONTEXT_T;
863 +
864 +VCOS_LOG_CAT_T vchiq_arm_log_category;
865 +
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;
871 +
872 +static const char *ioctl_names[] =
873 +{
874 + "CONNECT",
875 + "SHUTDOWN",
876 + "CREATE_SERVICE",
877 + "REMOVE_SERVICE",
878 + "QUEUE_MESSAGE",
879 + "QUEUE_BULK_TRANSMIT",
880 + "QUEUE_BULK_RECEIVE",
881 + "AWAIT_COMPLETION",
882 + "DEQUEUE_MESSAGE",
883 + "GET_CLIENT_ID",
884 + "GET_CONFIG",
885 + "CLOSE_SERVICE",
886 + "USE_SERVICE",
887 + "RELEASE_SERIVCE"
888 +};
889 +
890 +VCOS_LOG_LEVEL_T vchiq_default_arm_log_level = VCOS_LOG_WARN;
891 +
892 +/****************************************************************************
893 +*
894 +* find_service_by_handle
895 +*
896 +***************************************************************************/
897 +
898 +static inline USER_SERVICE_T *find_service_by_handle(
899 + VCHIQ_INSTANCE_T instance, int handle )
900 +{
901 + USER_SERVICE_T *user_service;
902 +
903 + if (( handle >= 0 )
904 + && ( handle < MAX_SERVICES ))
905 + {
906 + user_service = &instance->services[ handle ];
907 +
908 + if ( user_service->service != NULL )
909 + {
910 + return user_service;
911 + }
912 + }
913 +
914 + return NULL;
915 +}
916 +
917 +/****************************************************************************
918 +*
919 +* find_avail_service_handle
920 +*
921 +***************************************************************************/
922 +
923 +static inline USER_SERVICE_T *find_avail_service_handle(
924 + VCHIQ_INSTANCE_T instance)
925 +{
926 + int handle;
927 +
928 + for ( handle = 0; handle < MAX_SERVICES; handle++ )
929 + {
930 + if ( instance->services[handle].service == NULL )
931 + {
932 + instance->services[handle].instance = instance;
933 + instance->services[handle].handle = handle;
934 +
935 + return &instance->services[handle];
936 + }
937 + }
938 + return NULL;
939 +}
940 +
941 +/****************************************************************************
942 +*
943 +* add_completion
944 +*
945 +***************************************************************************/
946 +
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)
950 +{
951 + VCHIQ_COMPLETION_DATA_T *completion;
952 + DEBUG_INITIALISE(g_state.local)
953 +
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;
966 + }
967 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
968 + }
969 +
970 + completion =
971 + &instance->
972 + completions[instance->completion_insert & (MAX_COMPLETIONS - 1)];
973 +
974 + completion->header = header;
975 + completion->reason = reason;
976 + completion->service_userdata = service;
977 + completion->bulk_userdata = bulk_userdata;
978 +
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);
982 +
983 + if (reason == VCHIQ_MESSAGE_AVAILABLE)
984 + service->message_available_pos = instance->completion_insert;
985 + instance->completion_insert++;
986 +
987 + vcos_event_signal(&instance->insert_event);
988 +
989 + return VCHIQ_SUCCESS;
990 +}
991 +
992 +/****************************************************************************
993 +*
994 +* service_callback
995 +*
996 +***************************************************************************/
997 +
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)
1001 +{
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.
1006 + */
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)
1011 +
1012 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1013 + vcos_log_trace
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);
1019 +
1020 + if (!instance || instance->closing) {
1021 + return VCHIQ_SUCCESS;
1022 + }
1023 +
1024 + if (header && service->is_vchi)
1025 + {
1026 + while (service->msg_insert == (service->msg_remove + MSG_QUEUE_SIZE))
1027 + {
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)
1033 + {
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)
1039 + {
1040 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1041 + return status;
1042 + }
1043 + }
1044 +
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;
1054 + }
1055 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1056 + }
1057 +
1058 + service->msg_queue[service->msg_insert & (MSG_QUEUE_SIZE - 1)] =
1059 + header;
1060 +
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)]);
1064 +
1065 + service->msg_insert++;
1066 + vcos_event_signal(&service->insert_event);
1067 +
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)
1073 + {
1074 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1075 + service->dequeue_pending = 0;
1076 + return VCHIQ_SUCCESS;
1077 + }
1078 +
1079 + header = NULL;
1080 + }
1081 + DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1082 +
1083 + return add_completion(instance, reason, header, service, bulk_userdata);
1084 +}
1085 +
1086 +/****************************************************************************
1087 +*
1088 +* vchiq_ioctl
1089 +*
1090 +***************************************************************************/
1091 +
1092 +static long
1093 +vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1094 +{
1095 + VCHIQ_INSTANCE_T instance = file->private_data;
1096 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
1097 + long ret = 0;
1098 + int i, rc;
1099 + DEBUG_INITIALISE(g_state.local)
1100 +
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);
1105 +
1106 + switch (cmd) {
1107 + case VCHIQ_IOC_SHUTDOWN:
1108 + if (!instance->connected)
1109 + break;
1110 +
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)
1117 + break;
1118 + service->service = NULL;
1119 + }
1120 + }
1121 +
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);
1126 + }
1127 +
1128 + break;
1129 +
1130 + case VCHIQ_IOC_CONNECT:
1131 + if (instance->connected) {
1132 + ret = -EINVAL;
1133 + break;
1134 + }
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);
1138 + ret = -EINTR;
1139 + break;
1140 + }
1141 + status = vchiq_connect_internal(instance->state, instance);
1142 + vcos_mutex_unlock(&instance->state->mutex);
1143 +
1144 + if (status == VCHIQ_SUCCESS)
1145 + instance->connected = 1;
1146 + else
1147 + vcos_log_error("vchiq: could not connect: %d", status);
1148 + break;
1149 +
1150 + case VCHIQ_IOC_CREATE_SERVICE:
1151 + {
1152 + VCHIQ_CREATE_SERVICE_T args;
1153 + VCHIQ_SERVICE_T *service = NULL;
1154 + USER_SERVICE_T *user_service = NULL;
1155 + void *userdata;
1156 + int srvstate;
1157 +
1158 + if (copy_from_user
1159 + (&args, (const void __user *)arg,
1160 + sizeof(args)) != 0) {
1161 + ret = -EFAULT;
1162 + break;
1163 + }
1164 +
1165 + for (i = 0; i < MAX_SERVICES; i++) {
1166 + if (instance->services[i].service == NULL) {
1167 + user_service = &instance->services[i];
1168 + break;
1169 + }
1170 + }
1171 +
1172 + if (!user_service) {
1173 + ret = -EMFILE;
1174 + break;
1175 + }
1176 +
1177 + if (args.is_open) {
1178 + if (instance->connected)
1179 + srvstate = VCHIQ_SRVSTATE_OPENING;
1180 + else {
1181 + ret = -ENOTCONN;
1182 + break;
1183 + }
1184 + } else {
1185 + srvstate =
1186 + instance->connected ?
1187 + VCHIQ_SRVSTATE_LISTENING :
1188 + VCHIQ_SRVSTATE_HIDDEN;
1189 + }
1190 +
1191 + vcos_mutex_lock(&instance->state->mutex);
1192 +
1193 + userdata = args.params.userdata;
1194 + args.params.callback = service_callback;
1195 + args.params.userdata = user_service;
1196 + service =
1197 + vchiq_add_service_internal(instance->state,
1198 + &args.params, srvstate,
1199 + instance);
1200 +
1201 + vcos_mutex_unlock(&instance->state->mutex);
1202 +
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");
1215 +
1216 + if (args.is_open) {
1217 + status =
1218 + vchiq_open_service_internal
1219 + (service, instance->pid);
1220 + if (status != VCHIQ_SUCCESS) {
1221 + vchiq_remove_service
1222 + (&service->base);
1223 + ret =
1224 + (status ==
1225 + VCHIQ_RETRY) ? -EINTR :
1226 + -EIO;
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);
1231 + break;
1232 + }
1233 + }
1234 +
1235 + if (copy_to_user((void __user *)
1236 + &(((VCHIQ_CREATE_SERVICE_T __user
1237 + *) arg)->handle),
1238 + (const void *)&user_service->
1239 + handle,
1240 + sizeof(user_service->
1241 + handle)) != 0)
1242 + ret = -EFAULT;
1243 + } else {
1244 + ret = -EEXIST;
1245 + }
1246 + }
1247 + break;
1248 +
1249 + case VCHIQ_IOC_CLOSE_SERVICE:
1250 + {
1251 + USER_SERVICE_T *user_service;
1252 + int handle = (int)arg;
1253 +
1254 + user_service = find_service_by_handle(instance, handle);
1255 + if (user_service != NULL)
1256 + {
1257 + int is_server = (user_service->service->public_fourcc != VCHIQ_FOURCC_INVALID);
1258 +
1259 + status =
1260 + vchiq_close_service(&user_service->service->base);
1261 + if ((status == VCHIQ_SUCCESS) && !is_server)
1262 + {
1263 + vcos_event_delete(&user_service->insert_event);
1264 + vcos_event_delete(&user_service->remove_event);
1265 + user_service->service = NULL;
1266 + }
1267 + } else
1268 + ret = -EINVAL;
1269 + }
1270 + break;
1271 +
1272 + case VCHIQ_IOC_REMOVE_SERVICE:
1273 + {
1274 + USER_SERVICE_T *user_service;
1275 + int handle = (int)arg;
1276 +
1277 + user_service = find_service_by_handle(instance, handle);
1278 + if (user_service != NULL)
1279 + {
1280 + status =
1281 + vchiq_remove_service(&user_service->service->base);
1282 + if (status == VCHIQ_SUCCESS)
1283 + {
1284 + vcos_event_delete(&user_service->insert_event);
1285 + vcos_event_delete(&user_service->remove_event);
1286 + user_service->service = NULL;
1287 + }
1288 + } else
1289 + ret = -EINVAL;
1290 + }
1291 + break;
1292 +
1293 + case VCHIQ_IOC_USE_SERVICE:
1294 + case VCHIQ_IOC_RELEASE_SERVICE:
1295 + {
1296 + USER_SERVICE_T *user_service;
1297 + int handle = (int)arg;
1298 +
1299 + user_service = find_service_by_handle(instance, handle);
1300 + if (user_service != NULL)
1301 + {
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)
1304 + {
1305 + ret = -EINVAL; // ???
1306 + }
1307 + }
1308 + }
1309 + break;
1310 +
1311 + case VCHIQ_IOC_QUEUE_MESSAGE:
1312 + {
1313 + VCHIQ_QUEUE_MESSAGE_T args;
1314 + USER_SERVICE_T *user_service;
1315 +
1316 + if (copy_from_user
1317 + (&args, (const void __user *)arg,
1318 + sizeof(args)) != 0) {
1319 + ret = -EFAULT;
1320 + break;
1321 + }
1322 + user_service = find_service_by_handle(instance, args.handle);
1323 + if ((user_service != NULL) && (args.count <= MAX_ELEMENTS))
1324 + {
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)
1330 + status =
1331 + vchiq_queue_message
1332 + (&user_service->service->base,
1333 + elements, args.count);
1334 + else
1335 + ret = -EFAULT;
1336 + } else {
1337 + ret = -EINVAL;
1338 + }
1339 + }
1340 + break;
1341 +
1342 + case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
1343 + case VCHIQ_IOC_QUEUE_BULK_RECEIVE:
1344 + {
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;
1350 +
1351 + if (copy_from_user
1352 + (&args, (const void __user *)arg,
1353 + sizeof(args)) != 0) {
1354 + ret = -EFAULT;
1355 + break;
1356 + }
1357 + user_service = find_service_by_handle(instance, args.handle);
1358 + if (user_service != NULL)
1359 + {
1360 + status =
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,
1366 + dir);
1367 + } else {
1368 + ret = -EINVAL;
1369 + }
1370 + }
1371 + break;
1372 +
1373 + case VCHIQ_IOC_AWAIT_COMPLETION:
1374 + {
1375 + VCHIQ_AWAIT_COMPLETION_T args;
1376 +
1377 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1378 + if (!instance->connected) {
1379 + ret = -ENOTCONN;
1380 + break;
1381 + }
1382 +
1383 + if (copy_from_user
1384 + (&args, (const void __user *)arg,
1385 + sizeof(args)) != 0) {
1386 + ret = -EFAULT;
1387 + break;
1388 + }
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) !=
1395 + VCOS_SUCCESS) {
1396 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1397 + vcos_log_info
1398 + ("AWAIT_COMPLETION interrupted");
1399 + ret = -EINTR;
1400 + break;
1401 + }
1402 + }
1403 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1404 +
1405 + /* A read memory barrier is needed to stop prefetch of a stale
1406 + completion record */
1407 + vcos_rmb();
1408 +
1409 + if (ret == 0) {
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)
1417 + break;
1418 + completion =
1419 + &instance->
1420 + completions
1421 + [instance->completion_remove &
1422 + (MAX_COMPLETIONS - 1)];
1423 +
1424 + service = (USER_SERVICE_T *)completion->service_userdata;
1425 + completion->service_userdata = service->userdata;
1426 +
1427 + header = completion->header;
1428 + if (header)
1429 + {
1430 + void __user *msgbuf;
1431 + int msglen;
1432 +
1433 + msglen = header->size + sizeof(VCHIQ_HEADER_T);
1434 + /* This must be a VCHIQ-style service */
1435 + if (args.msgbufsize < msglen)
1436 + {
1437 + vcos_log_error("header %x: msgbufsize %x < msglen %x",
1438 + (unsigned int)header, args.msgbufsize, msglen);
1439 + vcos_assert(0);
1440 + if (ret == 0)
1441 + ret = -EMSGSIZE;
1442 + break;
1443 + }
1444 + if (msgbufcount <= 0)
1445 + {
1446 + /* Stall here for lack of a buffer for the message */
1447 + break;
1448 + }
1449 + /* Get the pointer from user space */
1450 + msgbufcount--;
1451 + if (copy_from_user(&msgbuf,
1452 + (const void __user *)&args.msgbufs[msgbufcount],
1453 + sizeof(msgbuf)) != 0)
1454 + {
1455 + if (ret == 0)
1456 + ret = -EFAULT;
1457 + break;
1458 + }
1459 +
1460 + /* Copy the message to user space */
1461 + if (copy_to_user(msgbuf, header, msglen) != 0)
1462 + {
1463 + if (ret == 0)
1464 + ret = -EFAULT;
1465 + break;
1466 + }
1467 +
1468 + /* Now it has been copied, the message can be released. */
1469 + vchiq_release_message(&service->service->base, header);
1470 +
1471 + /* The completion must point to the msgbuf */
1472 + completion->header = msgbuf;
1473 + }
1474 +
1475 + if (copy_to_user
1476 + ((void __user *)((size_t) args.buf +
1477 + ret *
1478 + sizeof
1479 + (VCHIQ_COMPLETION_DATA_T)),
1480 + completion,
1481 + sizeof(VCHIQ_COMPLETION_DATA_T)) !=
1482 + 0) {
1483 + if (ret == 0)
1484 + ret = -EFAULT;
1485 + break;
1486 + }
1487 + instance->completion_remove++;
1488 + }
1489 +
1490 + if (msgbufcount != args.msgbufcount)
1491 + {
1492 + if (copy_to_user((void __user *)
1493 + &((VCHIQ_AWAIT_COMPLETION_T *)arg)->msgbufcount,
1494 + &msgbufcount, sizeof(msgbufcount)) != 0)
1495 + {
1496 + ret = -EFAULT;
1497 + break;
1498 + }
1499 + }
1500 + }
1501 +
1502 + if (ret != 0)
1503 + vcos_event_signal(&instance->remove_event);
1504 + DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1505 + }
1506 + break;
1507 +
1508 + case VCHIQ_IOC_DEQUEUE_MESSAGE:
1509 + {
1510 + VCHIQ_DEQUEUE_MESSAGE_T args;
1511 + USER_SERVICE_T *user_service;
1512 + VCHIQ_HEADER_T *header;
1513 +
1514 + DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1515 + if (copy_from_user
1516 + (&args, (const void __user *)arg,
1517 + sizeof(args)) != 0) {
1518 + ret = -EFAULT;
1519 + break;
1520 + }
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)) {
1525 + ret = -EINVAL;
1526 + break;
1527 + }
1528 + if (user_service->msg_remove == user_service->msg_insert)
1529 + {
1530 + if (!args.blocking)
1531 + {
1532 + DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1533 + ret = -EWOULDBLOCK;
1534 + break;
1535 + }
1536 + user_service->dequeue_pending = 1;
1537 + do {
1538 + DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1539 + if (vcos_event_wait(&user_service->insert_event) !=
1540 + VCOS_SUCCESS) {
1541 + vcos_log_info("DEQUEUE_MESSAGE interrupted");
1542 + ret = -EINTR;
1543 + break;
1544 + }
1545 + }
1546 + while (user_service->msg_remove == user_service->msg_insert);
1547 + }
1548 +
1549 + /* A read memory barrier is needed to stop prefetch of a stale
1550 + header value */
1551 + vcos_rmb();
1552 +
1553 + header = user_service->msg_queue[user_service->msg_remove &
1554 + (MSG_QUEUE_SIZE - 1)];
1555 + if (header == NULL)
1556 + ret = -ENOTCONN;
1557 + else if (header->size <= args.bufsize)
1558 + {
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))
1563 + {
1564 + ret = header->size;
1565 + vchiq_release_message(&user_service->service->base,
1566 + header);
1567 + user_service->msg_remove++;
1568 + vcos_event_signal(&user_service->remove_event);
1569 + }
1570 + else
1571 + ret = -EFAULT;
1572 + }
1573 + else
1574 + {
1575 + vcos_log_error("header %x: bufsize %x < size %x",
1576 + (unsigned int)header, args.bufsize, header->size);
1577 + vcos_assert(0);
1578 + ret = -EMSGSIZE;
1579 + }
1580 + DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1581 + }
1582 + break;
1583 +
1584 + case VCHIQ_IOC_GET_CLIENT_ID:
1585 + {
1586 + USER_SERVICE_T *user_service;
1587 + int handle = (int)arg;
1588 +
1589 + user_service = find_service_by_handle(instance, handle);
1590 + if (user_service != NULL)
1591 + ret = vchiq_get_client_id(&user_service->service->base);
1592 + else
1593 + ret = 0;
1594 + }
1595 + break;
1596 +
1597 + case VCHIQ_IOC_GET_CONFIG:
1598 + {
1599 + VCHIQ_GET_CONFIG_T args;
1600 + VCHIQ_CONFIG_T config;
1601 +
1602 + if (copy_from_user
1603 + (&args, (const void __user *)arg,
1604 + sizeof(args)) != 0) {
1605 + ret = -EFAULT;
1606 + break;
1607 + }
1608 + if (args.config_size > sizeof(config))
1609 + {
1610 + ret = -EINVAL;
1611 + break;
1612 + }
1613 + status = vchiq_get_config(instance, args.config_size, &config);
1614 + if (status == VCHIQ_SUCCESS)
1615 + {
1616 + if (copy_to_user((void __user *)args.pconfig,
1617 + &config, args.config_size) != 0)
1618 + {
1619 + ret = -EFAULT;
1620 + break;
1621 + }
1622 + }
1623 + }
1624 + break;
1625 +
1626 + case VCHIQ_IOC_SET_SERVICE_OPTION:
1627 + {
1628 + VCHIQ_SET_SERVICE_OPTION_T args;
1629 + USER_SERVICE_T *user_service;
1630 +
1631 + if (copy_from_user(
1632 + &args, (const void __user *)arg,
1633 + sizeof(args)) != 0)
1634 + {
1635 + ret = -EFAULT;
1636 + break;
1637 + }
1638 +
1639 + user_service = find_service_by_handle(instance, args.handle);
1640 + if (user_service != NULL)
1641 + {
1642 + status = vchiq_set_service_option(
1643 + &user_service->service->base,
1644 + args.option, args.value);
1645 + }
1646 + else
1647 + {
1648 + ret = -EINVAL;
1649 + }
1650 + }
1651 + break;
1652 +
1653 + default:
1654 + ret = -ENOTTY;
1655 + break;
1656 + }
1657 +
1658 + if (ret == 0) {
1659 + if (status == VCHIQ_ERROR)
1660 + ret = -EIO;
1661 + else if (status == VCHIQ_RETRY)
1662 + ret = -EINTR;
1663 + }
1664 +
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);
1670 + else
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);
1675 +
1676 + return ret;
1677 +}
1678 +
1679 +/****************************************************************************
1680 +*
1681 +* vchiq_open
1682 +*
1683 +***************************************************************************/
1684 +
1685 +static int
1686 +vchiq_open(struct inode *inode, struct file *file)
1687 +{
1688 + int dev = iminor(inode) & 0x0f;
1689 + vcos_log_info("vchiq_open");
1690 + switch (dev) {
1691 + case VCHIQ_MINOR:
1692 + {
1693 + VCHIQ_STATE_T *state = vchiq_get_state();
1694 + VCHIQ_INSTANCE_T instance;
1695 +
1696 + if (!state)
1697 + {
1698 + vcos_log_error( "vchiq has no connection to VideoCore");
1699 + return -ENOTCONN;
1700 + }
1701 +
1702 + instance = kzalloc(sizeof(*instance), GFP_KERNEL);
1703 + if (!instance)
1704 + return -ENOMEM;
1705 +
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);
1710 +
1711 + file->private_data = instance;
1712 + }
1713 + break;
1714 +
1715 + default:
1716 + vcos_log_error("Unknown minor device: %d", dev);
1717 + return -ENXIO;
1718 + }
1719 +
1720 + return 0;
1721 +}
1722 +
1723 +/****************************************************************************
1724 +*
1725 +* vchiq_release
1726 +*
1727 +***************************************************************************/
1728 +
1729 +static int
1730 +vchiq_release(struct inode *inode, struct file *file)
1731 +{
1732 + int dev = iminor(inode) & 0x0f;
1733 + int ret = 0;
1734 + switch (dev) {
1735 + case VCHIQ_MINOR:
1736 + {
1737 + VCHIQ_INSTANCE_T instance = file->private_data;
1738 + int i;
1739 +
1740 + vcos_log_info("vchiq_release: instance=%lx",
1741 + (unsigned long)instance);
1742 +
1743 + instance->closing = 1;
1744 +
1745 + /* Wake the slot handler if the completion queue is full */
1746 + vcos_event_signal(&instance->remove_event);
1747 +
1748 + /* Mark all services for termination... */
1749 +
1750 + for (i = 0; i < MAX_SERVICES; i++) {
1751 + USER_SERVICE_T *user_service =
1752 + &instance->services[i];
1753 + if (user_service->service != NULL)
1754 + {
1755 + /* Wake the slot handler if the msg queue is full */
1756 + vcos_event_signal(&user_service->remove_event);
1757 +
1758 + if ((user_service->service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) &&
1759 + (user_service->service->srvstate != VCHIQ_SRVSTATE_LISTENING))
1760 + {
1761 + vchiq_terminate_service_internal(user_service->service);
1762 + }
1763 + }
1764 + }
1765 +
1766 + /* ...and wait for them to die */
1767 +
1768 + for (i = 0; i < MAX_SERVICES; i++) {
1769 + USER_SERVICE_T *user_service =
1770 + &instance->services[i];
1771 + if (user_service->service != NULL)
1772 + {
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))
1777 + {
1778 + down(&user_service->service->remove_event);
1779 + }
1780 +
1781 + vchiq_free_service_internal
1782 + (user_service->service);
1783 + }
1784 + }
1785 +
1786 + vcos_event_delete(&instance->insert_event);
1787 + vcos_event_delete(&instance->remove_event);
1788 +
1789 + kfree(instance);
1790 + file->private_data = NULL;
1791 + }
1792 + break;
1793 +
1794 + default:
1795 + vcos_log_error("Unknown minor device: %d", dev);
1796 + ret = -ENXIO;
1797 + }
1798 +
1799 + return ret;
1800 +}
1801 +
1802 +/****************************************************************************
1803 +*
1804 +* vchiq_dump
1805 +*
1806 +***************************************************************************/
1807 +
1808 +void
1809 +vchiq_dump(void *dump_context, const char *str, int len)
1810 +{
1811 + DUMP_CONTEXT_T *context = (DUMP_CONTEXT_T *)dump_context;
1812 +
1813 + if ((context->actual >= 0) && (context->actual < context->space))
1814 + {
1815 + int copy_bytes;
1816 + if (context->offset > 0)
1817 + {
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)
1823 + return;
1824 + }
1825 + copy_bytes = vcos_min(len, context->space - context->actual);
1826 + if (copy_bytes == 0)
1827 + return;
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;
1832 +
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.
1835 + */
1836 + if ((len == 0) && (str[copy_bytes - 1] == '\0'))
1837 + {
1838 + char cr = '\n';
1839 + if (copy_to_user(context->buf + context->actual - 1, &cr, 1))
1840 + {
1841 + context->actual = -EFAULT;
1842 + }
1843 + }
1844 + }
1845 +}
1846 +
1847 +/****************************************************************************
1848 +*
1849 +* vchiq_dump_platform_instance_state
1850 +*
1851 +***************************************************************************/
1852 +
1853 +void
1854 +vchiq_dump_platform_instances(void *dump_context)
1855 +{
1856 + VCHIQ_STATE_T *state = vchiq_get_state();
1857 + char buf[80];
1858 + int len;
1859 + int i;
1860 +
1861 + /* There is no list of instances, so instead scan all services,
1862 + marking those that have been dumped. */
1863 +
1864 + for (i = 0; i < state->unused_service; i++)
1865 + {
1866 + VCHIQ_SERVICE_T *service = state->services[i];
1867 + VCHIQ_INSTANCE_T instance;
1868 +
1869 + if (service
1870 + && ((instance = service->instance) != NULL)
1871 + && (service->base.callback == service_callback))
1872 + instance->mark = 0;
1873 + }
1874 +
1875 + for (i = 0; i < state->unused_service; i++)
1876 + {
1877 + VCHIQ_SERVICE_T *service = state->services[i];
1878 + VCHIQ_INSTANCE_T instance;
1879 +
1880 + if (service
1881 + && ((instance = service->instance) != NULL)
1882 + && (service->base.callback == service_callback))
1883 + {
1884 + if (!instance->mark)
1885 + {
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,
1891 + MAX_COMPLETIONS);
1892 +
1893 + vchiq_dump(dump_context, buf, len + 1);
1894 +
1895 + instance->mark = 1;
1896 + }
1897 + }
1898 + }
1899 +}
1900 +
1901 +/****************************************************************************
1902 +*
1903 +* vchiq_dump_platform_service_state
1904 +*
1905 +***************************************************************************/
1906 +
1907 +void
1908 +vchiq_dump_platform_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
1909 +{
1910 + USER_SERVICE_T *user_service = (USER_SERVICE_T *)service->base.userdata;
1911 + char buf[80];
1912 + int len;
1913 +
1914 + len = vcos_snprintf(buf, sizeof(buf), " instance %x",
1915 + service->instance);
1916 +
1917 + if ((service->base.callback == service_callback) && user_service->is_vchi)
1918 + {
1919 + len += vcos_snprintf(buf + len, sizeof(buf) - len,
1920 + ", %d/%d messages",
1921 + user_service->msg_insert - user_service->msg_remove,
1922 + MSG_QUEUE_SIZE);
1923 +
1924 + if (user_service->dequeue_pending)
1925 + len += vcos_snprintf(buf + len, sizeof(buf) - len,
1926 + " (dequeue pending)");
1927 + }
1928 +
1929 + vchiq_dump(dump_context, buf, len + 1);
1930 +}
1931 +
1932 +/****************************************************************************
1933 +*
1934 +* vchiq_read
1935 +*
1936 +***************************************************************************/
1937 +
1938 +static ssize_t
1939 +vchiq_read(struct file * file, char __user * buf,
1940 + size_t count, loff_t *ppos)
1941 +{
1942 + DUMP_CONTEXT_T context;
1943 + context.buf = buf;
1944 + context.actual = 0;
1945 + context.space = count;
1946 + context.offset = *ppos;
1947 +
1948 + vchiq_dump_state(&context, &g_state);
1949 +
1950 + if (context.actual >= 0)
1951 + *ppos += context.actual;
1952 +
1953 + return context.actual;
1954 +}
1955 +
1956 +VCHIQ_STATE_T *
1957 +vchiq_get_state(void)
1958 +{
1959 +
1960 + if (g_state.remote == NULL)
1961 + {
1962 + printk( "%s: g_state.remote == NULL\n", __func__ );
1963 + }
1964 + else
1965 + {
1966 + if ( g_state.remote->initialised != 1)
1967 + {
1968 + printk( "%s: g_state.remote->initialised != 1 (%d)\n", __func__, g_state.remote->initialised );
1969 + }
1970 + }
1971 +
1972 + return ((g_state.remote != NULL) &&
1973 + (g_state.remote->initialised == 1)) ? &g_state : NULL;
1974 +}
1975 +
1976 +static const struct file_operations
1977 +vchiq_fops = {
1978 + .owner = THIS_MODULE,
1979 + .unlocked_ioctl = vchiq_ioctl,
1980 + .open = vchiq_open,
1981 + .release = vchiq_release,
1982 + .read = vchiq_read
1983 +};
1984 +
1985 +/****************************************************************************
1986 +*
1987 +* vchiq_init - called when the module is loaded.
1988 +*
1989 +***************************************************************************/
1990 +
1991 +static int __init
1992 +vchiq_init(void)
1993 +{
1994 + int err;
1995 + void *ptr_err;
1996 +
1997 + err = vchiq_platform_vcos_init();
1998 + if (err != 0)
1999 + goto failed_platform_vcos_init;
2000 +
2001 + vcos_log_set_level(VCOS_LOG_CATEGORY, vchiq_default_arm_log_level);
2002 + vcos_log_register("vchiq_arm", VCOS_LOG_CATEGORY);
2003 +
2004 + if ((err =
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;
2009 + }
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;
2015 + }
2016 +
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;
2021 +
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;
2026 +
2027 + err = vchiq_platform_init(&g_state);
2028 + if (err != 0)
2029 + goto failed_platform_init;
2030 +
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));
2034 +
2035 + return 0;
2036 +
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);
2044 +failed_cdev_add:
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");
2049 + return err;
2050 +}
2051 +/****************************************************************************
2052 +*
2053 +* vchiq_exit - called when the module is unloaded.
2054 +*
2055 +***************************************************************************/
2056 +
2057 +static void __exit
2058 +vchiq_exit(void)
2059 +{
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);
2066 +}
2067 +
2068 +module_init(vchiq_init);
2069 +module_exit(vchiq_exit);
2070 +MODULE_LICENSE("GPL");
2071 +MODULE_AUTHOR("Broadcom Corporation");
2072 --- /dev/null
2073 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
2074 @@ -0,0 +1,38 @@
2075 +/*
2076 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
2077 + *
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.
2082 + *
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.
2087 + *
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
2091 + */
2092 +
2093 +#ifndef VCHIQ_ARM_H
2094 +#define VCHIQ_ARM_H
2095 +
2096 +#include "vchiq_core.h"
2097 +
2098 +extern VCOS_LOG_CAT_T vchiq_arm_log_category;
2099 +
2100 +extern int __init
2101 +vchiq_platform_vcos_init(void);
2102 +
2103 +extern int __init
2104 +vchiq_platform_init(VCHIQ_STATE_T *state);
2105 +
2106 +extern void __exit
2107 +vchiq_platform_exit(VCHIQ_STATE_T *state);
2108 +
2109 +extern VCHIQ_STATE_T *
2110 +vchiq_get_state(void);
2111 +
2112 +#endif /* VCHIQ_ARM_H */
2113 --- /dev/null
2114 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
2115 @@ -0,0 +1,43 @@
2116 +/*
2117 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
2118 + *
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.
2123 + *
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.
2128 + *
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
2132 + */
2133 +
2134 +#ifndef VCHIQ_CFG_H
2135 +#define VCHIQ_CFG_H
2136 +
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
2142 +
2143 +#define VCHIQ_MAX_SERVICES 4096
2144 +#define VCHIQ_MAX_SLOTS 128
2145 +#define VCHIQ_MAX_SLOTS_PER_SIDE 64
2146 +
2147 +#define VCHIQ_NUM_CURRENT_BULKS 32
2148 +#define VCHIQ_NUM_SERVICE_BULKS 4
2149 +
2150 +#ifndef VCHIQ_ENABLE_DEBUG
2151 +#define VCHIQ_ENABLE_DEBUG 1
2152 +#endif
2153 +
2154 +#ifndef VCHIQ_ENABLE_STATS
2155 +#define VCHIQ_ENABLE_STATS 1
2156 +#endif
2157 +
2158 +#endif /* VCHIQ_CFG_H */
2159 --- /dev/null
2160 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
2161 @@ -0,0 +1,101 @@
2162 +/*****************************************************************************
2163 +* Copyright 2001 - 2010 Broadcom Corporation. All rights reserved.
2164 +*
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").
2169 +*
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
2173 +* consent.
2174 +*****************************************************************************/
2175 +
2176 +#include "vcos.h"
2177 +#include "vchiq_connected.h"
2178 +#include <linux/module.h>
2179 +
2180 +#define MAX_CALLBACKS 10
2181 +
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;
2187 +
2188 +extern VCOS_LOG_CAT_T vchiq_core_log_category;
2189 +#define VCOS_LOG_CATEGORY (&vchiq_core_log_category)
2190 +
2191 +/****************************************************************************
2192 +*
2193 +* Function to initialize our lock.
2194 +*
2195 +***************************************************************************/
2196 +
2197 +static void connected_init( void )
2198 +{
2199 + vcos_mutex_create( &g_connected_mutex, "connected_mutex");
2200 +}
2201 +
2202 +/****************************************************************************
2203 +*
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.
2208 +*
2209 +***************************************************************************/
2210 +
2211 +void vchiq_add_connected_callback( VCHIQ_CONNECTED_CALLBACK_T callback )
2212 +{
2213 + vcos_once( &g_once_init, connected_init );
2214 +
2215 + vcos_mutex_lock( &g_connected_mutex );
2216 +
2217 + if ( g_connected )
2218 + {
2219 + // We're already connected. Call the callback immediately.
2220 +
2221 + callback();
2222 + }
2223 + else
2224 + {
2225 + if ( g_num_deferred_callbacks >= MAX_CALLBACKS )
2226 + {
2227 + vcos_log_error( "There already %d callback registered - please increase MAX_CALLBACKS",
2228 + g_num_deferred_callbacks );
2229 + }
2230 + else
2231 + {
2232 + g_deferred_callback[ g_num_deferred_callbacks ] = callback;
2233 + g_num_deferred_callbacks++;
2234 + }
2235 + }
2236 + vcos_mutex_unlock( &g_connected_mutex );
2237 +}
2238 +
2239 +/****************************************************************************
2240 +*
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.
2243 +*
2244 +***************************************************************************/
2245 +
2246 +void vchiq_call_connected_callbacks( void )
2247 +{
2248 + int i;
2249 +
2250 + vcos_once( &g_once_init, connected_init );
2251 +
2252 + vcos_mutex_lock( &g_connected_mutex );
2253 + for ( i = 0; i < g_num_deferred_callbacks; i++ )\
2254 + {
2255 + g_deferred_callback[i]();
2256 + }
2257 + g_num_deferred_callbacks = 0;
2258 + g_connected = 1;
2259 + vcos_mutex_unlock( &g_connected_mutex );
2260 +}
2261 +
2262 +EXPORT_SYMBOL( vchiq_add_connected_callback );
2263 --- /dev/null
2264 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
2265 @@ -0,0 +1,32 @@
2266 +/*****************************************************************************
2267 +* Copyright 2001 - 2010 Broadcom Corporation. All rights reserved.
2268 +*
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").
2273 +*
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
2277 +* consent.
2278 +*****************************************************************************/
2279 +
2280 +#ifndef VCHIQ_CONNECTED_H
2281 +#define VCHIQ_CONNECTED_H
2282 +
2283 +/* ---- Include Files ----------------------------------------------------- */
2284 +
2285 +/* ---- Constants and Types ---------------------------------------------- */
2286 +
2287 +typedef void (*VCHIQ_CONNECTED_CALLBACK_T)( void );
2288 +
2289 +/* ---- Variable Externs ------------------------------------------------- */
2290 +
2291 +/* ---- Function Prototypes ---------------------------------------------- */
2292 +
2293 +void vchiq_add_connected_callback( VCHIQ_CONNECTED_CALLBACK_T callback );
2294 +void vchiq_call_connected_callbacks( void );
2295 +
2296 +#endif /* VCHIQ_CONNECTED_H */
2297 +
2298 --- /dev/null
2299 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
2300 @@ -0,0 +1,2604 @@
2301 +/*
2302 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
2303 + *
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.
2308 + *
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.
2313 + *
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
2317 + */
2318 +
2319 +#include "vchiq_core.h"
2320 +
2321 +#define VCHIQ_SLOT_HANDLER_STACK 8192
2322 +
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))
2328 +
2329 +#define VCOS_LOG_CATEGORY (&vchiq_core_log_category)
2330 +
2331 +#define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1))
2332 +
2333 +typedef struct bulk_waiter_struct
2334 +{
2335 + VCOS_EVENT_T event;
2336 + int actual;
2337 +} BULK_WAITER_T;
2338 +
2339 +typedef struct vchiq_open_payload_struct{
2340 + int fourcc;
2341 + int client_id;
2342 + short version;
2343 + short version_min;
2344 +} VCHIQ_OPEN_PAYLOAD_T;
2345 +
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));
2350 +
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;
2355 +
2356 +static const char *const srvstate_names[] =
2357 +{
2358 + "FREE",
2359 + "HIDDEN",
2360 + "LISTENING",
2361 + "OPENING",
2362 + "OPEN",
2363 + "CLOSESENT",
2364 + "CLOSING",
2365 + "CLOSEWAIT"
2366 +};
2367 +
2368 +static const char *const reason_names[] =
2369 +{
2370 + "SERVICE_OPENED",
2371 + "SERVICE_CLOSED",
2372 + "MESSAGE_AVAILABLE",
2373 + "BULK_TRANSMIT_DONE",
2374 + "BULK_RECEIVE_DONE",
2375 + "BULK_TRANSMIT_ABORTED",
2376 + "BULK_RECEIVE_ABORTED"
2377 +};
2378 +
2379 +static const char *const conn_state_names[] =
2380 +{
2381 + "DISCONNECTED",
2382 + "CONNECTED",
2383 + "PAUSING",
2384 + "PAUSE_SENT",
2385 + "PAUSED",
2386 + "RESUMING"
2387 +};
2388 +
2389 +static const char *msg_type_str( unsigned int msg_type )
2390 +{
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";
2404 + }
2405 + return "???";
2406 +}
2407 +
2408 +static inline void
2409 +vchiq_set_service_state(VCHIQ_SERVICE_T *service, int newstate)
2410 +{
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;
2415 +}
2416 +
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)
2420 +{
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);
2425 +}
2426 +
2427 +static inline void
2428 +vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate)
2429 +{
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;
2434 +}
2435 +
2436 +static inline void
2437 +remote_event_create(REMOTE_EVENT_T *event)
2438 +{
2439 + event->armed = 0;
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");
2442 +}
2443 +
2444 +static inline void
2445 +remote_event_destroy(REMOTE_EVENT_T *event)
2446 +{
2447 + vcos_event_delete(event->event);
2448 +}
2449 +
2450 +static inline int
2451 +remote_event_wait(REMOTE_EVENT_T *event)
2452 +{
2453 + if (!event->fired)
2454 + {
2455 + event->armed = 1;
2456 + if (event->fired) /* Also ensures the write has completed */
2457 + event->armed = 0;
2458 + else if (vcos_event_wait(event->event) != VCOS_SUCCESS)
2459 + return 0;
2460 + }
2461 +
2462 + event->fired = 0;
2463 + return 1;
2464 +}
2465 +
2466 +static inline void
2467 +remote_event_signal_local(REMOTE_EVENT_T *event)
2468 +{
2469 + event->armed = 0;
2470 + vcos_event_signal(event->event);
2471 +}
2472 +
2473 +static inline void
2474 +remote_event_poll(REMOTE_EVENT_T *event)
2475 +{
2476 + if (event->armed)
2477 + remote_event_signal_local(event);
2478 +}
2479 +
2480 +void
2481 +remote_event_pollall(VCHIQ_STATE_T *state)
2482 +{
2483 + remote_event_poll(&state->local->trigger);
2484 + remote_event_poll(&state->local->recycle);
2485 +}
2486 +
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. */
2490 +
2491 +static inline unsigned int
2492 +calc_stride(unsigned int size)
2493 +{
2494 + /* Allow room for the header */
2495 + size += sizeof(VCHIQ_HEADER_T);
2496 +
2497 + /* Round up */
2498 + return (size + sizeof(VCHIQ_HEADER_T) - 1) & ~(sizeof(VCHIQ_HEADER_T) - 1);
2499 +}
2500 +
2501 +static VCHIQ_SERVICE_T *
2502 +get_listening_service(VCHIQ_STATE_T *state, int fourcc)
2503 +{
2504 + int i;
2505 +
2506 + vcos_assert(fourcc != VCHIQ_FOURCC_INVALID);
2507 +
2508 + for (i = 0; i < state->unused_service; i++)
2509 + {
2510 + VCHIQ_SERVICE_T *service = state->services[i];
2511 + if (service &&
2512 + (service->public_fourcc == fourcc) &&
2513 + ((service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
2514 + ((service->srvstate == VCHIQ_SRVSTATE_OPEN) &&
2515 + (service->remoteport == VCHIQ_PORT_FREE))))
2516 + return service;
2517 + }
2518 +
2519 + return NULL;
2520 +}
2521 +
2522 +static VCHIQ_SERVICE_T *
2523 +get_connected_service(VCHIQ_STATE_T *state, unsigned int port)
2524 +{
2525 + int i;
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)) {
2530 + return service;
2531 + }
2532 + }
2533 + return NULL;
2534 +}
2535 +
2536 +static inline void
2537 +request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type)
2538 +{
2539 + if (service)
2540 + {
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)));
2544 + }
2545 +
2546 + state->poll_needed = 1;
2547 + vcos_wmb(&state->poll_needed);
2548 +
2549 + /* ... and ensure the slot handler runs. */
2550 + remote_event_signal_local(&state->local->trigger);
2551 +}
2552 +
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)
2557 +{
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);
2561 +
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);
2569 +
2570 + tx_pos += slot_space;
2571 + }
2572 +
2573 + /* If necessary, get the next slot. */
2574 + if ((tx_pos & VCHIQ_SLOT_MASK) == 0)
2575 + {
2576 + int slot_index;
2577 +
2578 + /* If there is no free slot... */
2579 + if (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE))
2580 + {
2581 + /* ...wait for one. */
2582 + VCHIQ_STATS_INC(state, slot_stalls);
2583 +
2584 + /* But first, flush through the last slot. */
2585 + local->tx_pos = tx_pos;
2586 + remote_event_signal(&state->remote->trigger);
2587 +
2588 + do {
2589 + if (!is_blocking ||
2590 + (vcos_event_wait(&state->slot_available_event) != VCOS_SUCCESS))
2591 + {
2592 + return NULL; /* No space available now */
2593 + }
2594 + }
2595 + while (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE));
2596 + }
2597 +
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);
2600 + }
2601 +
2602 + state->local_tx_pos = tx_pos + space;
2603 +
2604 + return (VCHIQ_HEADER_T *)(state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
2605 +}
2606 +
2607 +/* Called with slot_mutex held */
2608 +static void
2609 +process_free_queue(VCHIQ_STATE_T *state)
2610 +{
2611 + VCHIQ_SHARED_STATE_T *local = state->local;
2612 + BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
2613 + int slot_queue_available;
2614 +
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
2617 + values. */
2618 + vcos_rmb();
2619 +
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;
2623 +
2624 + while (slot_queue_available != local->slot_queue_recycle)
2625 + {
2626 + int pos;
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);
2629 +
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);
2633 +
2634 + /* Initialise the bitmask for services which have used this slot */
2635 + BITSET_ZERO(service_found);
2636 +
2637 + pos = 0;
2638 +
2639 + while (pos < VCHIQ_SLOT_SIZE)
2640 + {
2641 + VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)(data + pos);
2642 + int msgid = header->msgid;
2643 + if (VCHIQ_MSG_TYPE(msgid) == VCHIQ_MSG_DATA)
2644 + {
2645 + int port = VCHIQ_MSG_SRCPORT(msgid);
2646 + if (!BITSET_IS_SET(service_found, port))
2647 + {
2648 + VCHIQ_SERVICE_QUOTA_T *service_quota =
2649 + &state->service_quotas[port];
2650 +
2651 + /* Set the found bit for this service */
2652 + BITSET_SET(service_found, port);
2653 +
2654 + if (service_quota->slot_use_count > 0)
2655 + {
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",
2660 + state->id, port,
2661 + header->size, (unsigned int)header,
2662 + service_quota->slot_use_count);
2663 + }
2664 + else
2665 + {
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,
2670 + header->size);
2671 + vcos_assert(0);
2672 + }
2673 + }
2674 + }
2675 +
2676 + pos += calc_stride(header->size);
2677 + if (pos > VCHIQ_SLOT_SIZE)
2678 + {
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);
2681 + vcos_assert(0);
2682 + }
2683 + }
2684 + }
2685 +
2686 + if (slot_queue_available != state->slot_queue_available)
2687 + {
2688 + state->slot_queue_available = slot_queue_available;
2689 + vcos_wmb(&state->slot_queue_available);
2690 + vcos_event_signal(&state->slot_available_event);
2691 + }
2692 +}
2693 +
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)
2699 +{
2700 + VCHIQ_SHARED_STATE_T *local;
2701 + VCHIQ_SERVICE_QUOTA_T *service_quota = NULL;
2702 + VCHIQ_HEADER_T *header;
2703 +
2704 + unsigned int stride;
2705 +
2706 + local = state->local;
2707 +
2708 + stride = calc_stride(size);
2709 +
2710 + vcos_assert(stride <= VCHIQ_SLOT_SIZE);
2711 +
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.
2715 + */
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;
2720 +
2721 + if (service)
2722 + {
2723 + int tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1);
2724 +
2725 + if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
2726 + {
2727 + /* The service has been closed, probably while waiting for the mutex */
2728 + vcos_mutex_unlock(&state->slot_mutex);
2729 + return VCHIQ_ERROR;
2730 + }
2731 +
2732 + service_quota = &state->service_quotas[service->localport];
2733 +
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))
2737 + {
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);
2749 + }
2750 + }
2751 +
2752 + header = reserve_space(state, stride, is_blocking);
2753 +
2754 + if (!header) {
2755 + if (service)
2756 + VCHIQ_SERVICE_STATS_INC(service, slot_stalls);
2757 + vcos_mutex_unlock(&state->slot_mutex);
2758 + return VCHIQ_RETRY;
2759 + }
2760 +
2761 + if (service) {
2762 + int i, pos;
2763 + int tx_end_index;
2764 +
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));
2770 +
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) !=
2777 + VCHIQ_SUCCESS) {
2778 + vcos_mutex_unlock(&state->slot_mutex);
2779 + VCHIQ_SERVICE_STATS_INC(service, error_count);
2780 + return VCHIQ_ERROR;
2781 + }
2782 + if (i == 0) {
2783 + vcos_log_dump_mem( &vchiq_core_msg_log_category,
2784 + "Sent", 0, header->data + pos,
2785 + vcos_min( 64, elements[0].size ));
2786 + }
2787 + }
2788 +
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)
2792 + {
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);
2798 + }
2799 +
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);
2803 + } else {
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));
2809 + if (size != 0)
2810 + {
2811 + vcos_assert((count == 1) && (size == elements[0].size));
2812 + memcpy(header->data, elements[0].data, elements[0].size);
2813 + }
2814 + VCHIQ_STATS_INC(state, ctrl_tx_count);
2815 + }
2816 +
2817 + header->msgid = msgid;
2818 + header->size = size;
2819 +
2820 + if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
2821 + {
2822 + int svc_fourcc;
2823 +
2824 + svc_fourcc = service
2825 + ? service->base.fourcc
2826 + : VCHIQ_MAKE_FOURCC('?','?','?','?');
2827 +
2828 + vcos_log_impl( &vchiq_core_msg_log_category,
2829 + VCOS_LOG_INFO,
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),
2836 + size );
2837 + }
2838 +
2839 + /* Make the new tx_pos visible to the peer. */
2840 + local->tx_pos = state->local_tx_pos;
2841 + vcos_wmb(&local->tx_pos);
2842 +
2843 + if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
2844 + vcos_mutex_unlock(&state->slot_mutex);
2845 +
2846 + remote_event_signal(&state->remote->trigger);
2847 +
2848 + return VCHIQ_SUCCESS;
2849 +}
2850 +
2851 +static inline void
2852 +claim_slot(VCHIQ_SLOT_INFO_T *slot)
2853 +{
2854 + slot->use_count++;
2855 +}
2856 +
2857 +static void
2858 +release_slot(VCHIQ_STATE_T *state, VCHIQ_SLOT_INFO_T *slot_info)
2859 +{
2860 + int release_count;
2861 + vcos_mutex_lock(&state->recycle_mutex);
2862 +
2863 + release_count = slot_info->release_count;
2864 + slot_info->release_count = ++release_count;
2865 +
2866 + if (release_count == slot_info->use_count)
2867 + {
2868 + int slot_queue_recycle;
2869 + /* Add to the freed queue */
2870 +
2871 + /* A read barrier is necessary here to prevent speculative fetches of
2872 + remote->slot_queue_recycle from overtaking the mutex. */
2873 + vcos_rmb();
2874 +
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);
2882 +
2883 + /* A write barrier is necessary, but remote_event_signal contains one. */
2884 + remote_event_signal(&state->remote->recycle);
2885 + }
2886 +
2887 + vcos_mutex_unlock(&state->recycle_mutex);
2888 +}
2889 +
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)
2893 +{
2894 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
2895 +
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);
2900 +
2901 + if (service->state->is_master)
2902 + {
2903 + while (queue->remote_notify != queue->process)
2904 + {
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)
2912 + {
2913 + status = queue_message(service->state, NULL, msgid, &element, 1, 4, 0);
2914 + if (status != VCHIQ_SUCCESS)
2915 + break;
2916 + }
2917 + queue->remote_notify++;
2918 + }
2919 + }
2920 + else
2921 + {
2922 + queue->remote_notify = queue->process;
2923 + }
2924 +
2925 + if (status == VCHIQ_SUCCESS)
2926 + {
2927 + while (queue->remove != queue->remote_notify)
2928 + {
2929 + VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->remove)];
2930 +
2931 + /* Only generate callbacks for non-dummy bulk requests */
2932 + if (bulk->data)
2933 + {
2934 + if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED)
2935 + {
2936 + if (bulk->dir == VCHIQ_BULK_TRANSMIT)
2937 + {
2938 + VCHIQ_SERVICE_STATS_INC(service, bulk_tx_count);
2939 + VCHIQ_SERVICE_STATS_ADD(service, bulk_tx_bytes, bulk->actual);
2940 + }
2941 + else
2942 + {
2943 + VCHIQ_SERVICE_STATS_INC(service, bulk_rx_count);
2944 + VCHIQ_SERVICE_STATS_ADD(service, bulk_rx_bytes, bulk->actual);
2945 + }
2946 + }
2947 + else
2948 + {
2949 + VCHIQ_SERVICE_STATS_INC(service, bulk_aborted_count);
2950 + }
2951 + if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING)
2952 + {
2953 + BULK_WAITER_T *waiter = (BULK_WAITER_T *)bulk->userdata;
2954 + if (waiter)
2955 + {
2956 + waiter->actual = bulk->actual;
2957 + vcos_event_signal(&waiter->event);
2958 + }
2959 + }
2960 + else if (bulk->mode == VCHIQ_BULK_MODE_CALLBACK)
2961 + {
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)
2970 + break;
2971 + }
2972 + }
2973 +
2974 + queue->remove++;
2975 + vcos_event_signal(&service->bulk_remove_event);
2976 + }
2977 + }
2978 +
2979 + if (status != VCHIQ_SUCCESS)
2980 + request_poll(service->state, service, (queue == &service->bulk_tx) ?
2981 + VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
2982 +
2983 + return status;
2984 +}
2985 +
2986 +/* Called by the slot handler thread */
2987 +static void
2988 +poll_services(VCHIQ_STATE_T *state)
2989 +{
2990 + int group, i;
2991 +
2992 + for (group = 0; group < BITSET_SIZE(state->unused_service); group++)
2993 + {
2994 + uint32_t flags;
2995 + flags = vcos_atomic_flags_get_and_clear(&state->poll_services[group]);
2996 + for (i = 0; flags; i++)
2997 + {
2998 + if (flags & (1 << i))
2999 + {
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))
3004 + {
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);
3008 + }
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);
3014 + }
3015 + }
3016 + }
3017 +}
3018 +
3019 +/* Called by the slot handler or application threads, holding the bulk mutex. */
3020 +static int
3021 +resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
3022 +{
3023 + VCHIQ_STATE_T *state = service->state;
3024 + int resolved = 0;
3025 +
3026 + while ((queue->process != queue->local_insert) &&
3027 + (queue->process != queue->remote_insert))
3028 + {
3029 + VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
3030 +
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,
3035 + queue->process);
3036 +
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);
3040 +
3041 + if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3042 + {
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,
3047 + VCOS_LOG_INFO,
3048 + "%s %c%c%c%c d:%d len:%d %x<->%x",
3049 + header,
3050 + VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3051 + service->remoteport,
3052 + bulk->size,
3053 + (unsigned int)bulk->data,
3054 + (unsigned int)bulk->remote_data );
3055 + else
3056 + vcos_log_impl( &vchiq_core_msg_log_category,
3057 + VCOS_LOG_INFO,
3058 + "%s %c%c%c%c d:%d ABORTED - tx len:%d, rx len:%d %x<->%x",
3059 + header,
3060 + VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3061 + service->remoteport,
3062 + bulk->size,
3063 + bulk->remote_size,
3064 + (unsigned int)bulk->data,
3065 + (unsigned int)bulk->remote_data );
3066 + }
3067 +
3068 + vchiq_complete_bulk(bulk);
3069 + queue->process++;
3070 + resolved++;
3071 + }
3072 + return resolved;
3073 +}
3074 +
3075 +/* Called with the bulk_mutex held */
3076 +static void
3077 +abort_outstanding_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
3078 +{
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);
3083 +
3084 + vcos_assert((int)(queue->local_insert - queue->process) >= 0);
3085 + vcos_assert((int)(queue->remote_insert - queue->process) >= 0);
3086 +
3087 + while ((queue->process != queue->local_insert) ||
3088 + (queue->process != queue->remote_insert))
3089 + {
3090 + VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
3091 +
3092 + if (queue->process == queue->remote_insert)
3093 + {
3094 + /* fabricate a matching dummy bulk */
3095 + bulk->remote_data = NULL;
3096 + bulk->remote_size = 0;
3097 + queue->remote_insert++;
3098 + }
3099 +
3100 + if (queue->process != queue->local_insert)
3101 + {
3102 + vchiq_complete_bulk(bulk);
3103 +
3104 + if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3105 + {
3106 + vcos_log_impl( &vchiq_core_msg_log_category,
3107 + VCOS_LOG_INFO,
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,
3112 + bulk->size,
3113 + bulk->remote_size );
3114 + }
3115 + }
3116 + else
3117 + {
3118 + /* fabricate a matching dummy bulk */
3119 + bulk->data = NULL;
3120 + bulk->size = 0;
3121 + bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
3122 + bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
3123 + queue->local_insert++;
3124 + }
3125 +
3126 + queue->process++;
3127 + }
3128 +}
3129 +
3130 +static void
3131 +pause_bulks(VCHIQ_STATE_T *state)
3132 +{
3133 + int i;
3134 +
3135 + /* Block bulk transfers from all services */
3136 + for (i = 0; i < state->unused_service; i++)
3137 + {
3138 + VCHIQ_SERVICE_T *service = state->services[i];
3139 + if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN))
3140 + continue;
3141 +
3142 + vcos_log_trace("locking bulk_mutex for service %d", i);
3143 + vcos_mutex_lock(&service->bulk_mutex);
3144 + }
3145 +}
3146 +
3147 +static void
3148 +resume_bulks(VCHIQ_STATE_T *state)
3149 +{
3150 + int i;
3151 +
3152 + /* Poll all services in case any bulk transfers have been
3153 + deferred */
3154 + for (i = 0; i < state->unused_service; i++)
3155 + {
3156 + VCHIQ_SERVICE_T *service = state->services[i];
3157 + if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN))
3158 + continue;
3159 +
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);
3166 + }
3167 +}
3168 +
3169 +/* Called by the slot handler thread */
3170 +static void
3171 +parse_rx_slots(VCHIQ_STATE_T *state)
3172 +{
3173 + VCHIQ_SHARED_STATE_T *remote = state->remote;
3174 + int tx_pos;
3175 + DEBUG_INITIALISE(state->local)
3176 +
3177 + tx_pos = remote->tx_pos;
3178 +
3179 + while (state->rx_pos != tx_pos) {
3180 + VCHIQ_SERVICE_T *service = NULL;
3181 + VCHIQ_HEADER_T *header;
3182 + int msgid, size;
3183 + int type;
3184 + unsigned int localport, remoteport;
3185 +
3186 + DEBUG_TRACE(PARSE_LINE);
3187 + if (!state->rx_data)
3188 + {
3189 + int rx_index;
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);
3194 +
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;
3199 + }
3200 +
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);
3209 +
3210 + if (type != VCHIQ_MSG_DATA)
3211 + {
3212 + VCHIQ_STATS_INC(state, ctrl_rx_count);
3213 + }
3214 +
3215 + switch (type)
3216 + {
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)
3225 + {
3226 + service = state->services[localport];
3227 + if (service && (service->srvstate == VCHIQ_SRVSTATE_FREE))
3228 + service = NULL;
3229 + }
3230 + if (!service)
3231 + {
3232 + vcos_log_error(
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;
3237 + }
3238 + default:
3239 + break;
3240 + }
3241 +
3242 + if ( vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3243 + {
3244 + int svc_fourcc;
3245 +
3246 + svc_fourcc = service
3247 + ? service->base.fourcc
3248 + : VCHIQ_MAKE_FOURCC('?','?','?','?');
3249 + vcos_log_impl( &vchiq_core_msg_log_category,
3250 + VCOS_LOG_INFO,
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 );
3255 + if (size > 0) {
3256 + vcos_log_dump_mem( &vchiq_core_msg_log_category,
3257 + "Rcvd", 0, header->data,
3258 + vcos_min( 64, size ));
3259 + }
3260 + }
3261 +
3262 + if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size) > VCHIQ_SLOT_SIZE)
3263 + {
3264 + vcos_log_error("header %x (msgid %x) - size %x too big for slot",
3265 + (unsigned int)header, (unsigned int)msgid, (unsigned int)size);
3266 + vcos_assert(0);
3267 + }
3268 +
3269 + switch (type) {
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;
3275 +
3276 + fourcc = payload->fourcc;
3277 + vcos_log_info("%d: prs OPEN@%x (%d->'%c%c%c%c')",
3278 + state->id, (unsigned int)header,
3279 + localport,
3280 + VCHIQ_FOURCC_AS_4CHARS(fourcc));
3281 +
3282 + service = get_listening_service(state, fourcc);
3283 +
3284 + if (service)
3285 + {
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))
3291 + {
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);
3299 + goto fail_open;
3300 + }
3301 + if (service->srvstate == VCHIQ_SRVSTATE_LISTENING)
3302 + {
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 */
3308 +
3309 + /* The service is now open */
3310 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_OPEN);
3311 + }
3312 +
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)
3317 + {
3318 + /* Bail out if not ready */
3319 + service->remoteport = VCHIQ_PORT_FREE;
3320 + return;
3321 + }
3322 +
3323 + /* Break out, and skip the failure handling */
3324 + break;
3325 + }
3326 + }
3327 + fail_open:
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 */
3333 + break;
3334 + case VCHIQ_MSG_OPENACK:
3335 + {
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);
3344 + }
3345 + }
3346 + break;
3347 + case VCHIQ_MSG_CLOSE:
3348 + {
3349 + vcos_assert(size == 0); /* There should be no data */
3350 +
3351 + vcos_log_info("%d: prs CLOSE@%x (%d->%d)",
3352 + state->id, (unsigned int)header,
3353 + remoteport, localport);
3354 +
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);
3360 + if (!service)
3361 + break;
3362 + }
3363 +
3364 + if (vchiq_close_service_internal(service,
3365 + 1/*close_recvd*/) == VCHIQ_RETRY)
3366 + return; /* Bail out if not ready */
3367 +
3368 + if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3369 + {
3370 + vcos_log_impl( &vchiq_core_msg_log_category,
3371 + VCOS_LOG_INFO,
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 );
3376 + }
3377 + }
3378 + break;
3379 + case VCHIQ_MSG_DATA:
3380 + {
3381 + vcos_log_trace("%d: prs DATA@%x,%x (%d->%d)",
3382 + state->id, (unsigned int)header, size,
3383 + remoteport, localport);
3384 +
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)
3394 + {
3395 + DEBUG_TRACE(PARSE_LINE);
3396 + return; /* Bail out if not ready */
3397 + }
3398 + VCHIQ_SERVICE_STATS_INC(service, ctrl_rx_count);
3399 + VCHIQ_SERVICE_STATS_ADD(service, ctrl_rx_bytes, size);
3400 + }
3401 + else
3402 + {
3403 + VCHIQ_STATS_INC(state, error_count);
3404 + }
3405 + }
3406 + break;
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);
3411 + break;
3412 + case VCHIQ_MSG_BULK_RX:
3413 + case VCHIQ_MSG_BULK_TX:
3414 + {
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))
3422 + {
3423 + VCHIQ_BULK_T *bulk;
3424 + int resolved;
3425 +
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];
3431 +
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);
3438 +
3439 + queue->remote_insert++;
3440 +
3441 + if (state->conn_state != VCHIQ_CONNSTATE_CONNECTED)
3442 + break;
3443 +
3444 + DEBUG_TRACE(PARSE_LINE);
3445 + if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
3446 + {
3447 + DEBUG_TRACE(PARSE_LINE);
3448 + return;
3449 + }
3450 + DEBUG_TRACE(PARSE_LINE);
3451 + resolved = resolve_bulks(service, queue);
3452 + vcos_mutex_unlock(&service->bulk_mutex);
3453 + if (resolved)
3454 + notify_bulks(service, queue);
3455 + }
3456 + }
3457 + break;
3458 + case VCHIQ_MSG_BULK_RX_DONE:
3459 + case VCHIQ_MSG_BULK_TX_DONE:
3460 + {
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;
3467 +
3468 + queue = (type == VCHIQ_MSG_BULK_RX_DONE) ?
3469 + &service->bulk_rx : &service->bulk_tx;
3470 +
3471 + bulk = &queue->bulks[BULK_INDEX(queue->process)];
3472 + bulk->actual = *(int *)header->data;
3473 +
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);
3479 +
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);
3485 +
3486 + DEBUG_TRACE(PARSE_LINE);
3487 + if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
3488 + {
3489 + DEBUG_TRACE(PARSE_LINE);
3490 + return;
3491 + }
3492 + DEBUG_TRACE(PARSE_LINE);
3493 + vcos_assert(queue->process != queue->local_insert);
3494 + vchiq_complete_bulk(bulk);
3495 + queue->process++;
3496 + vcos_mutex_unlock(&service->bulk_mutex);
3497 + DEBUG_TRACE(PARSE_LINE);
3498 + notify_bulks(service, queue);
3499 + DEBUG_TRACE(PARSE_LINE);
3500 + }
3501 + }
3502 + break;
3503 + case VCHIQ_MSG_PADDING:
3504 + vcos_log_trace("%d: prs PADDING@%x,%x",
3505 + state->id, (unsigned int)header, size);
3506 + break;
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)
3512 + {
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);
3520 + }
3521 + /* At this point slot_mutex is held */
3522 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
3523 + vchiq_platform_paused(state);
3524 + break;
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);
3534 + break;
3535 + default:
3536 + vcos_log_error("%d: prs invalid msgid %x@%x,%x",
3537 + state->id, msgid, (unsigned int)header, size);
3538 + vcos_assert(0);
3539 + break;
3540 + }
3541 +
3542 + skip_message:
3543 + state->rx_pos += calc_stride(size);
3544 +
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)
3548 + {
3549 + /* Remove the extra reference count. */
3550 + release_slot(state, state->rx_info);
3551 + state->rx_data = NULL;
3552 + }
3553 + }
3554 +}
3555 +
3556 +/* Called by the slot handler thread */
3557 +static void *
3558 +slot_handler_func(void *v)
3559 +{
3560 + VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
3561 + VCHIQ_SHARED_STATE_T *local = state->local;
3562 + DEBUG_INITIALISE(local)
3563 +
3564 + while (1) {
3565 + DEBUG_COUNT(SLOT_HANDLER_COUNT);
3566 + DEBUG_TRACE(SLOT_HANDLER_LINE);
3567 + remote_event_wait(&local->trigger);
3568 +
3569 + vcos_rmb();
3570 +
3571 + DEBUG_TRACE(SLOT_HANDLER_LINE);
3572 + if (state->poll_needed)
3573 + {
3574 + state->poll_needed = 0;
3575 +
3576 + /* Handle service polling and other rare conditions here out
3577 + of the mainline code */
3578 + switch (state->conn_state)
3579 + {
3580 + case VCHIQ_CONNSTATE_CONNECTED:
3581 + /* Poll the services as requested */
3582 + poll_services(state);
3583 + break;
3584 +
3585 + case VCHIQ_CONNSTATE_PAUSING:
3586 + if (queue_message(state, NULL,
3587 + VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), NULL, 0, 0, 0)
3588 + != VCHIQ_RETRY)
3589 + {
3590 + if (state->is_master)
3591 + pause_bulks(state);
3592 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSE_SENT);
3593 + }
3594 + else
3595 + {
3596 + state->poll_needed = 1; /* Retry later */
3597 + }
3598 + break;
3599 +
3600 + case VCHIQ_CONNSTATE_RESUMING:
3601 + if (queue_message(state, NULL,
3602 + VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0), NULL, 0, 0, 0)
3603 + != VCHIQ_RETRY)
3604 + {
3605 + if (state->is_master)
3606 + resume_bulks(state);
3607 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
3608 + vchiq_platform_resumed(state);
3609 + }
3610 + else
3611 + {
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");
3615 + vcos_demand(0);
3616 + }
3617 + break;
3618 + default:
3619 + break;
3620 + }
3621 + }
3622 +
3623 + DEBUG_TRACE(SLOT_HANDLER_LINE);
3624 + parse_rx_slots(state);
3625 + }
3626 + return NULL;
3627 +}
3628 +
3629 +extern VCHIQ_STATUS_T
3630 +vchiq_platform_suspend(VCHIQ_STATE_T *state);
3631 +
3632 +/* Called by the recycle thread */
3633 +static void *
3634 +recycle_func(void *v)
3635 +{
3636 + VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
3637 + VCHIQ_SHARED_STATE_T *local = state->local;
3638 +
3639 + while (1) {
3640 + remote_event_wait(&local->recycle);
3641 +
3642 + vcos_mutex_lock(&state->slot_mutex);
3643 +
3644 + process_free_queue(state);
3645 +
3646 + vcos_mutex_unlock(&state->slot_mutex);
3647 + }
3648 + return NULL;
3649 +}
3650 +
3651 +/* Called by the lp thread */
3652 +static void *
3653 +lp_func(void *v)
3654 +{
3655 + VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
3656 +
3657 + while (1) {
3658 + vcos_event_wait(&state->lp_evt);
3659 + vcos_mutex_lock(&state->use_count_mutex);
3660 + if (state->videocore_use_count == 0)
3661 + {
3662 + vchiq_platform_suspend(state);
3663 + }
3664 + vcos_mutex_unlock(&state->use_count_mutex);
3665 + }
3666 + return NULL;
3667 +}
3668 +
3669 +static void
3670 +init_bulk_queue(VCHIQ_BULK_QUEUE_T *queue)
3671 +{
3672 + queue->local_insert = 0;
3673 + queue->remote_insert = 0;
3674 + queue->process = 0;
3675 + queue->remote_notify = 0;
3676 + queue->remove = 0;
3677 +}
3678 +
3679 +VCHIQ_SLOT_ZERO_T *
3680 +vchiq_init_slots(void *mem_base, int mem_size)
3681 +{
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;
3686 +
3687 + /* Ensure there is enough memory to run an absolutely minimum system */
3688 + num_slots -= first_data_slot;
3689 +
3690 + if (num_slots < 4)
3691 + {
3692 + vcos_log_error("vchiq_init_slots - insufficient memory %x bytes", mem_size);
3693 + return NULL;
3694 + }
3695 +
3696 + memset(slot_zero, 0, sizeof(VCHIQ_SLOT_ZERO_T));
3697 +
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;
3705 +
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;
3710 +
3711 + return slot_zero;
3712 +}
3713 +
3714 +VCHIQ_STATUS_T
3715 +vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, int is_master)
3716 +{
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;
3722 + int i;
3723 +
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);
3728 +
3729 + vcos_log_warn( "%s: slot_zero = 0x%08lx, is_master = %d\n", __func__, (unsigned long)slot_zero, is_master );
3730 +
3731 + /* Check the input configuration */
3732 +
3733 + if (slot_zero->magic != VCHIQ_MAGIC)
3734 + {
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;
3738 + }
3739 +
3740 + if (slot_zero->version < VCHIQ_VERSION_MIN)
3741 + {
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;
3745 + }
3746 +
3747 + if (VCHIQ_VERSION < slot_zero->version_min)
3748 + {
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;
3752 + }
3753 +
3754 + if (slot_zero->slot_zero_size != sizeof(VCHIQ_SLOT_ZERO_T))
3755 + {
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;
3759 + }
3760 +
3761 + if (slot_zero->slot_size != VCHIQ_SLOT_SIZE)
3762 + {
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;
3766 + }
3767 +
3768 + if (slot_zero->max_slots != VCHIQ_MAX_SLOTS)
3769 + {
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;
3773 + }
3774 +
3775 + if (slot_zero->max_slots_per_side != VCHIQ_MAX_SLOTS_PER_SIDE)
3776 + {
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;
3781 + }
3782 +
3783 + if (is_master)
3784 + {
3785 + local = &slot_zero->master;
3786 + remote = &slot_zero->slave;
3787 + }
3788 + else
3789 + {
3790 + local = &slot_zero->slave;
3791 + remote = &slot_zero->master;
3792 + }
3793 +
3794 + if (local->initialised)
3795 + {
3796 + if (remote->initialised)
3797 + vcos_log_error("vchiq: FATAL: local state has already been initialised");
3798 + else
3799 + vcos_log_error("vchiq: FATAL: master/slave mismatch - two %ss", is_master ? "master" : "slave");
3800 + return VCHIQ_ERROR;
3801 + }
3802 +
3803 + memset(state, 0, sizeof(VCHIQ_STATE_T));
3804 + state->id = id++;
3805 + state->is_master = is_master;
3806 +
3807 + /*
3808 + initialize shared state pointers
3809 + */
3810 +
3811 + state->local = local;
3812 + state->remote = remote;
3813 + state->slot_data = (VCHIQ_SLOT_T *)slot_zero;
3814 +
3815 + /*
3816 + initialize events and mutexes
3817 + */
3818 +
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");
3823 +
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");
3828 +
3829 + vcos_event_create(&state->slot_available_event, "v.slot_available_event");
3830 + vcos_event_create(&state->slot_remove_event, "v.slot_remove_event");
3831 +
3832 + state->slot_queue_available = 0;
3833 +
3834 + for (i = 0; i < VCHIQ_MAX_SERVICES; i++)
3835 + {
3836 + VCHIQ_SERVICE_QUOTA_T *service_quota = &state->service_quotas[i];
3837 + vcos_event_create(&service_quota->quota_event, "v.quota_event");
3838 + }
3839 +
3840 + for (i = local->slot_first; i <= local->slot_last; i++)
3841 + {
3842 + local->slot_queue[state->slot_queue_available++] = i;
3843 + }
3844 +
3845 + state->default_slot_quota = state->slot_queue_available/2;
3846 +
3847 + local->trigger.event = &state->trigger_event;
3848 + remote_event_create(&local->trigger);
3849 + local->tx_pos = 0;
3850 +
3851 + local->recycle.event = &state->recycle_event;
3852 + remote_event_create(&local->recycle);
3853 + local->slot_queue_recycle = state->slot_queue_available;
3854 +
3855 + vcos_event_create(&state->lp_evt, "LP_EVT");
3856 +
3857 + local->debug[DEBUG_ENTRIES] = DEBUG_MAX;
3858 +
3859 + /*
3860 + bring up slot handler thread
3861 + */
3862 +
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;
3870 +
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;
3878 +
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;
3886 +
3887 + /* Indicate readiness to the other side */
3888 + local->initialised = 1;
3889 +
3890 + return VCHIQ_SUCCESS;
3891 +}
3892 +
3893 +/* Called from application thread when a client or server service is created. */
3894 +VCHIQ_SERVICE_T *
3895 +vchiq_add_service_internal(VCHIQ_STATE_T *state,
3896 + const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
3897 + VCHIQ_INSTANCE_T instance)
3898 +{
3899 + VCHIQ_SERVICE_T **pservice = NULL;
3900 + VCHIQ_SERVICE_T *service = NULL;
3901 + int i;
3902 +
3903 + /* Prepare to use a previously unused service */
3904 + if (state->unused_service < VCHIQ_MAX_SERVICES)
3905 + {
3906 + pservice = &state->services[state->unused_service];
3907 + }
3908 +
3909 + if (srvstate == VCHIQ_SRVSTATE_OPENING) {
3910 + for (i = 0; i < state->unused_service; i++) {
3911 + VCHIQ_SERVICE_T *srv = state->services[i];
3912 + if (!srv)
3913 + {
3914 + pservice = &state->services[i];
3915 + break;
3916 + }
3917 + if (srv->srvstate == VCHIQ_SRVSTATE_FREE) {
3918 + service = srv;
3919 + break;
3920 + }
3921 + }
3922 + } else {
3923 + for (i = (state->unused_service - 1); i >= 0; i--) {
3924 + VCHIQ_SERVICE_T *srv = state->services[i];
3925 + if (!srv)
3926 + pservice = &state->services[i];
3927 + else if (srv->srvstate == VCHIQ_SRVSTATE_FREE) {
3928 + service = srv;
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 */
3933 + pservice = NULL;
3934 + service = NULL;
3935 + }
3936 + }
3937 + }
3938 +
3939 + if (pservice && !service)
3940 + {
3941 + service = vcos_malloc(sizeof(VCHIQ_SERVICE_T), "VCHIQ service");
3942 + if (service)
3943 + {
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;
3950 + }
3951 + else
3952 + {
3953 + vcos_log_error("vchiq: Out of memory");
3954 + }
3955 + }
3956 +
3957 + if (service) {
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,
3962 + VCOS_LOG_INFO,
3963 + "%s Service %c%c%c%c SrcPort:%d",
3964 + ( srvstate == VCHIQ_SRVSTATE_OPENING )
3965 + ? "Open" : "Add",
3966 + VCHIQ_FOURCC_AS_4CHARS(params->fourcc),
3967 + service->localport );
3968 + }
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 =
3977 + (srvstate ==
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);
3992 +
3993 + /* Ensure the events are unsignalled */
3994 + while (vcos_event_try(&service->remove_event) == VCOS_SUCCESS)
3995 + continue;
3996 + while (vcos_event_try(&service_quota->quota_event) == VCOS_SUCCESS)
3997 + continue;
3998 +
3999 + if (pservice == &state->services[state->unused_service])
4000 + state->unused_service++;
4001 + }
4002 +
4003 + return service;
4004 +}
4005 +
4006 +VCHIQ_STATUS_T
4007 +vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id)
4008 +{
4009 + VCHIQ_OPEN_PAYLOAD_T payload = {
4010 + service->base.fourcc,
4011 + client_id,
4012 + service->version,
4013 + service->version_min
4014 + };
4015 + VCHIQ_ELEMENT_T body = { &payload, sizeof(payload) };
4016 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4017 +
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);
4033 + }
4034 + }
4035 + return status;
4036 +}
4037 +
4038 +/* Called by the slot handler */
4039 +VCHIQ_STATUS_T
4040 +vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd)
4041 +{
4042 + VCHIQ_STATE_T *state = service->state;
4043 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4044 +
4045 + vcos_log_trace("%d: csi:%d (%s)",
4046 + service->state->id, service->localport,
4047 + srvstate_names[service->srvstate]);
4048 +
4049 + switch (service->srvstate)
4050 + {
4051 + case VCHIQ_SRVSTATE_OPENING:
4052 + if (close_recvd)
4053 + {
4054 + /* The open was rejected - tell the user */
4055 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSEWAIT);
4056 + vcos_event_signal(&service->remove_event);
4057 + }
4058 + else
4059 + {
4060 + /* Shutdown mid-open - let the other side know */
4061 + status = queue_message(state, NULL,
4062 + VCHIQ_MAKE_MSG
4063 + (VCHIQ_MSG_CLOSE,
4064 + service->localport,
4065 + VCHIQ_MSG_DSTPORT(service->remoteport)),
4066 + NULL, 0, 0, 0);
4067 +
4068 + if (status == VCHIQ_SUCCESS)
4069 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
4070 + }
4071 + break;
4072 +
4073 + case VCHIQ_SRVSTATE_OPEN:
4074 + if (state->is_master)
4075 + {
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);
4084 + }
4085 +
4086 + if (status == VCHIQ_SUCCESS)
4087 + status = queue_message(state, NULL,
4088 + VCHIQ_MAKE_MSG
4089 + (VCHIQ_MSG_CLOSE,
4090 + service->localport,
4091 + VCHIQ_MSG_DSTPORT(service->remoteport)),
4092 + NULL, 0, 0, 0);
4093 +
4094 + if (status == VCHIQ_SUCCESS)
4095 + {
4096 + if (close_recvd)
4097 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSING);
4098 + else
4099 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
4100 + }
4101 + break;
4102 +
4103 + case VCHIQ_SRVSTATE_CLOSESENT:
4104 + vcos_assert(close_recvd);
4105 +
4106 + if (!state->is_master)
4107 + {
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);
4116 + }
4117 +
4118 + if (status == VCHIQ_SUCCESS)
4119 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSING);
4120 + break;
4121 +
4122 + case VCHIQ_SRVSTATE_CLOSING:
4123 + /* We may come here after a retry */
4124 + vcos_assert(!close_recvd);
4125 + break;
4126 +
4127 + default:
4128 + vcos_log_error("vchiq_close_service_internal(%d) called in state %s",
4129 + close_recvd, srvstate_names[service->srvstate]);
4130 + vcos_assert(0);
4131 + break;
4132 + }
4133 +
4134 + if (service->srvstate == VCHIQ_SRVSTATE_CLOSING)
4135 + {
4136 + /* Complete the close process */
4137 + vchiq_release_service(&service->base);
4138 +
4139 + service->client_id = 0;
4140 +
4141 + /* Now tell the client that the services is closed */
4142 + if (service->instance)
4143 + {
4144 + int oldstate = service->srvstate;
4145 +
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);
4152 +
4153 + status = make_service_callback(service, VCHIQ_SERVICE_CLOSED, NULL, NULL);
4154 +
4155 + if (status == VCHIQ_RETRY)
4156 + {
4157 + /* Restore the old state, to be retried later */
4158 + vchiq_set_service_state(service, oldstate);
4159 + }
4160 + else
4161 + {
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);
4165 + }
4166 + }
4167 + }
4168 +
4169 + if (status != VCHIQ_RETRY)
4170 + {
4171 + if (service->srvstate == VCHIQ_SRVSTATE_CLOSING)
4172 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSEWAIT);
4173 + vcos_event_signal(&service->remove_event);
4174 + }
4175 + }
4176 +
4177 + return status;
4178 +}
4179 +
4180 +/* Called from the application process upon process death */
4181 +void
4182 +vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service)
4183 +{
4184 + VCHIQ_STATE_T *state = service->state;
4185 +
4186 + vcos_log_info("%d: tsi - (%d<->%d)", state->id, service->localport, service->remoteport);
4187 +
4188 + /* Disconnect from the instance, to prevent any callbacks */
4189 + service->instance = NULL;
4190 +
4191 + /* Mark the service for termination by the slot handler */
4192 + request_poll(state, service, VCHIQ_POLL_TERMINATE);
4193 +}
4194 +
4195 +/* Called from the application process upon process death, and from
4196 + vchiq_remove_service */
4197 +void
4198 +vchiq_free_service_internal(VCHIQ_SERVICE_T *service)
4199 +{
4200 + VCHIQ_STATE_T *state = service->state;
4201 + int slot_last = state->remote->slot_last;
4202 + int i;
4203 +
4204 + vcos_log_info("%d: fsi - (%d)", state->id, service->localport);
4205 +
4206 + vcos_mutex_lock(&state->mutex);
4207 +
4208 + /* Release any claimed messages */
4209 + for (i = state->remote->slot_first; i <= slot_last; i++)
4210 + {
4211 + VCHIQ_SLOT_INFO_T *slot_info = SLOT_INFO_FROM_INDEX(state, i);
4212 + if (slot_info->release_count != slot_info->use_count)
4213 + {
4214 + char *data = (char *)SLOT_DATA_FROM_INDEX(state, i);
4215 + int pos, end;
4216 +
4217 + end = VCHIQ_SLOT_SIZE;
4218 + if (data == state->rx_data)
4219 + {
4220 + /* This buffer is still being read from - stop at the current read position */
4221 + end = state->rx_pos & VCHIQ_SLOT_MASK;
4222 + }
4223 +
4224 + pos = 0;
4225 +
4226 + while (pos < end)
4227 + {
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)
4232 + {
4233 + if (msgid & VCHIQ_MSGID_CLAIMED)
4234 + {
4235 + header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
4236 + vcos_log_info(" fsi - hdr %x", (unsigned int)header);
4237 + release_slot(state, slot_info);
4238 + }
4239 + }
4240 + pos += calc_stride(header->size);
4241 + }
4242 + }
4243 + }
4244 +
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);
4250 +}
4251 +
4252 +VCHIQ_STATUS_T
4253 +vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
4254 +{
4255 + int i;
4256 +
4257 + /* Find all services registered to this client and enable them. */
4258 + for (i = 0; i < state->unused_service; i++)
4259 + {
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);
4265 + }
4266 + }
4267 +
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);
4274 +
4275 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
4276 + }
4277 +
4278 + return VCHIQ_SUCCESS;
4279 +}
4280 +
4281 +VCHIQ_STATUS_T
4282 +vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
4283 +{
4284 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4285 + int i;
4286 +
4287 + /* Find all services registered to this client and close them. */
4288 + for (i = 0; i < state->unused_service; i++)
4289 + {
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)))
4294 + {
4295 + status = vchiq_remove_service(&service->base);
4296 + if (status != VCHIQ_SUCCESS)
4297 + break;
4298 + }
4299 + }
4300 +
4301 + return status;
4302 +}
4303 +
4304 +VCHIQ_STATUS_T
4305 +vchiq_pause_internal(VCHIQ_STATE_T *state)
4306 +{
4307 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4308 +
4309 + switch (state->conn_state)
4310 + {
4311 + case VCHIQ_CONNSTATE_CONNECTED:
4312 + /* Request a pause */
4313 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSING);
4314 + request_poll(state, NULL, 0);
4315 + break;
4316 + case VCHIQ_CONNSTATE_PAUSED:
4317 + break;
4318 + default:
4319 + status = VCHIQ_ERROR;
4320 + VCHIQ_STATS_INC(state, error_count);
4321 + break;
4322 + }
4323 +
4324 + return status;
4325 +}
4326 +
4327 +VCHIQ_STATUS_T
4328 +vchiq_resume_internal(VCHIQ_STATE_T *state)
4329 +{
4330 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4331 +
4332 + if (state->conn_state == VCHIQ_CONNSTATE_PAUSED)
4333 + {
4334 + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_RESUMING);
4335 + request_poll(state, NULL, 0);
4336 + }
4337 + else
4338 + {
4339 + status = VCHIQ_ERROR;
4340 + VCHIQ_STATS_INC(state, error_count);
4341 + }
4342 +
4343 + return status;
4344 +}
4345 +
4346 +VCHIQ_STATUS_T
4347 +vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
4348 +{
4349 + /* Unregister the service */
4350 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *) handle;
4351 + VCHIQ_STATUS_T status = VCHIQ_ERROR;
4352 +
4353 + if (service == NULL)
4354 + return VCHIQ_ERROR;
4355 +
4356 + vcos_log_info("%d: close_service:%d", service->state->id, service->localport);
4357 +
4358 + if (service->public_fourcc != VCHIQ_FOURCC_INVALID)
4359 + {
4360 + if (service->srvstate == VCHIQ_SRVSTATE_CLOSEWAIT)
4361 + {
4362 + /* This is a non-auto-close server */
4363 + vchiq_set_service_state(service, VCHIQ_SRVSTATE_LISTENING);
4364 + status = VCHIQ_SUCCESS;
4365 + }
4366 + }
4367 + else
4368 + {
4369 + /* For clients, make it an alias of vchiq_remove_service */
4370 + status = vchiq_remove_service(handle);
4371 + }
4372 +
4373 + return status;
4374 +}
4375 +
4376 +VCHIQ_STATUS_T
4377 +vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
4378 +{
4379 + /* Unregister the service */
4380 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *) handle;
4381 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4382 +
4383 + if (service == NULL)
4384 + return VCHIQ_ERROR;
4385 +
4386 + vcos_log_info("%d: remove_service:%d", service->state->id, service->localport);
4387 +
4388 + switch (service->srvstate)
4389 + {
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);
4394 +
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))
4400 + {
4401 + if (vcos_event_wait(&service->remove_event) != VCOS_SUCCESS) {
4402 + status = VCHIQ_RETRY;
4403 + break;
4404 + }
4405 + }
4406 + break;
4407 +
4408 + default:
4409 + break;
4410 + }
4411 +
4412 + if (status == VCHIQ_SUCCESS) {
4413 + if (service->srvstate == VCHIQ_SRVSTATE_OPEN)
4414 + status = VCHIQ_ERROR;
4415 + else
4416 + {
4417 + service->instance = NULL;
4418 + vchiq_free_service_internal(service);
4419 + }
4420 + }
4421 +
4422 + return status;
4423 +}
4424 +
4425 +
4426 +VCHIQ_STATUS_T
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)
4430 +{
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;
4439 +
4440 + if ((service == NULL) ||
4441 + ((memhandle == VCHI_MEM_HANDLE_INVALID) && (offset == NULL)))
4442 + return VCHIQ_ERROR;
4443 +
4444 + state = service->state;
4445 +
4446 + if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
4447 + return VCHIQ_ERROR; /* Must be connected */
4448 +
4449 + if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
4450 + return VCHIQ_RETRY;
4451 +
4452 + if (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS)
4453 + {
4454 + VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
4455 + do {
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);
4462 + }
4463 +
4464 + bulk = &queue->bulks[BULK_INDEX(queue->local_insert)];
4465 +
4466 + if (mode == VCHIQ_BULK_MODE_BLOCKING)
4467 + {
4468 + vcos_event_create(&bulk_waiter.event, "bulk_waiter");
4469 + bulk_waiter.actual = 0;
4470 + userdata = &bulk_waiter;
4471 + }
4472 +
4473 + bulk->mode = mode;
4474 + bulk->dir = dir;
4475 + bulk->userdata = userdata;
4476 + bulk->size = size;
4477 + bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
4478 +
4479 + if (vchiq_prepare_bulk_data(bulk, memhandle, offset, size, dir) != VCHIQ_SUCCESS)
4480 + {
4481 + goto error_exit;
4482 + }
4483 +
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);
4487 +
4488 + if (state->is_master)
4489 + {
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);
4494 + }
4495 + else
4496 + {
4497 + int payload[2] = { (int)bulk->data, bulk->size };
4498 + VCHIQ_ELEMENT_T element = { payload, sizeof(payload) };
4499 +
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)
4504 + {
4505 + vchiq_complete_bulk(bulk);
4506 + goto error_exit;
4507 + }
4508 + queue->local_insert++;
4509 + queue->remote_insert++;
4510 + }
4511 +
4512 + vcos_mutex_unlock(&service->bulk_mutex);
4513 +
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);
4517 +
4518 + status = VCHIQ_SUCCESS;
4519 +
4520 + if (mode == VCHIQ_BULK_MODE_BLOCKING)
4521 + {
4522 + if (vcos_event_wait(&bulk_waiter.event) != VCOS_SUCCESS)
4523 + {
4524 + vcos_log_info("bulk wait interrupted");
4525 + /* Stop notify_bulks signalling a non-existent waiter */
4526 + bulk->userdata = NULL;
4527 + status = VCHIQ_ERROR;
4528 + }
4529 + else if (bulk_waiter.actual == VCHIQ_BULK_ACTUAL_ABORTED)
4530 + status = VCHIQ_ERROR;
4531 +
4532 + vcos_event_delete(&bulk_waiter.event);
4533 + }
4534 +
4535 + return status;
4536 +
4537 +error_exit:
4538 + if (mode == VCHIQ_BULK_MODE_BLOCKING)
4539 + vcos_event_delete(&bulk_waiter.event);
4540 + vcos_mutex_unlock(&service->bulk_mutex);
4541 +
4542 + return status;
4543 +}
4544 +
4545 +VCHIQ_STATUS_T
4546 +vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
4547 + const void *data, int size, void *userdata)
4548 +{
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);
4552 +}
4553 +
4554 +VCHIQ_STATUS_T
4555 +vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, int size,
4556 + void *userdata)
4557 +{
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);
4561 +}
4562 +
4563 +VCHIQ_STATUS_T
4564 +vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
4565 + VCHI_MEM_HANDLE_T memhandle, const void *offset, int size, void *userdata)
4566 +{
4567 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4568 + memhandle, (void *)offset, size, userdata,
4569 + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
4570 +}
4571 +
4572 +VCHIQ_STATUS_T
4573 +vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
4574 + VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata)
4575 +{
4576 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4577 + memhandle, offset, size, userdata,
4578 + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
4579 +}
4580 +
4581 +VCHIQ_STATUS_T
4582 +vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, int size,
4583 + void *userdata, VCHIQ_BULK_MODE_T mode)
4584 +{
4585 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4586 + VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
4587 + mode, VCHIQ_BULK_TRANSMIT);
4588 +}
4589 +
4590 +VCHIQ_STATUS_T
4591 +vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, int size,
4592 + void *userdata, VCHIQ_BULK_MODE_T mode)
4593 +{
4594 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4595 + VCHI_MEM_HANDLE_INVALID, data, size, userdata,
4596 + mode, VCHIQ_BULK_RECEIVE);
4597 +}
4598 +
4599 +VCHIQ_STATUS_T
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)
4603 +{
4604 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4605 + memhandle, (void *)offset, size, userdata,
4606 + mode, VCHIQ_BULK_TRANSMIT);
4607 +}
4608 +
4609 +VCHIQ_STATUS_T
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)
4613 +{
4614 + return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4615 + memhandle, offset, size, userdata,
4616 + mode, VCHIQ_BULK_RECEIVE);
4617 +}
4618 +
4619 +VCHIQ_STATUS_T
4620 +vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
4621 + const VCHIQ_ELEMENT_T *elements, int count)
4622 +{
4623 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *) handle;
4624 +
4625 + unsigned int size = 0;
4626 + unsigned int i;
4627 +
4628 + if ((service == NULL) ||
4629 + (service->srvstate != VCHIQ_SRVSTATE_OPEN))
4630 + return VCHIQ_ERROR;
4631 +
4632 + for (i = 0; i < (unsigned int)count; i++)
4633 + {
4634 + if (elements[i].size)
4635 + {
4636 + if (elements[i].data == NULL)
4637 + {
4638 + VCHIQ_SERVICE_STATS_INC(service, error_count);
4639 + return VCHIQ_ERROR;
4640 + }
4641 + size += elements[i].size;
4642 + }
4643 + }
4644 +
4645 + if (size > VCHIQ_MAX_MSG_SIZE)
4646 + {
4647 + VCHIQ_SERVICE_STATS_INC(service, error_count);
4648 + return VCHIQ_ERROR;
4649 + }
4650 +
4651 + return queue_message(service->state, service,
4652 + VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA, service->localport,
4653 + service->remoteport), elements, count, size, 1);
4654 +}
4655 +
4656 +void
4657 +vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle, VCHIQ_HEADER_T *header)
4658 +{
4659 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
4660 + VCHIQ_STATE_T *state;
4661 + int slot_index;
4662 + int msgid;
4663 +
4664 + if (service == NULL)
4665 + return;
4666 +
4667 + state = service->state;
4668 +
4669 + slot_index = SLOT_INDEX_FROM_DATA(state, (void *)header);
4670 +
4671 + if ((slot_index >= state->remote->slot_first) &&
4672 + (slot_index <= state->remote->slot_last) &&
4673 + ((msgid = header->msgid) & VCHIQ_MSGID_CLAIMED))
4674 + {
4675 + VCHIQ_SLOT_INFO_T *slot_info = SLOT_INFO_FROM_INDEX(state, slot_index);
4676 +
4677 + /* Rewrite the message header to prevent a double release */
4678 + header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
4679 +
4680 + release_slot(state, slot_info);
4681 + }
4682 +}
4683 +
4684 +int
4685 +vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
4686 +{
4687 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
4688 + return service ? service->client_id : 0;
4689 +}
4690 +
4691 +VCHIQ_STATUS_T
4692 +vchiq_get_config(VCHIQ_INSTANCE_T instance,
4693 + int config_size, VCHIQ_CONFIG_T *pconfig)
4694 +{
4695 + VCHIQ_CONFIG_T config;
4696 +
4697 + vcos_unused(instance);
4698 +
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;
4705 +
4706 + if (config_size > sizeof(VCHIQ_CONFIG_T))
4707 + return VCHIQ_ERROR;
4708 +
4709 + memcpy(pconfig, &config, vcos_min(config_size, sizeof(VCHIQ_CONFIG_T)));
4710 +
4711 + return VCHIQ_SUCCESS;
4712 +}
4713 +
4714 +VCHIQ_STATUS_T
4715 +vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
4716 + VCHIQ_SERVICE_OPTION_T option, int value)
4717 +{
4718 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
4719 + VCHIQ_STATUS_T status = VCHIQ_ERROR;
4720 +
4721 + if (service)
4722 + {
4723 + switch (option)
4724 + {
4725 + case VCHIQ_SERVICE_OPTION_AUTOCLOSE:
4726 + service->auto_close = value;
4727 + status = VCHIQ_SUCCESS;
4728 + break;
4729 +
4730 + default:
4731 + break;
4732 + }
4733 + }
4734 +
4735 + return status;
4736 +}
4737 +
4738 +void
4739 +vchiq_dump_shared_state(void *dump_context, VCHIQ_STATE_T *state,
4740 + VCHIQ_SHARED_STATE_T *shared, const char *label)
4741 +{
4742 + static const char *const debug_names[] =
4743 + {
4744 + "<entries>",
4745 + "SLOT_HANDLER_COUNT",
4746 + "SLOT_HANDLER_LINE",
4747 + "PARSE_LINE",
4748 + "PARSE_HEADER",
4749 + "PARSE_MSGID",
4750 + "AWAIT_COMPLETION_LINE",
4751 + "DEQUEUE_MESSAGE_LINE",
4752 + "SERVICE_CALLBACK_LINE",
4753 + "MSG_QUEUE_FULL_COUNT",
4754 + "COMPLETION_QUEUE_FULL_COUNT"
4755 + };
4756 + int i;
4757 +
4758 + char buf[80];
4759 + int len;
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);
4765 +
4766 + len = vcos_snprintf(buf, sizeof(buf),
4767 + " Slots claimed:");
4768 + vchiq_dump(dump_context, buf, len + 1);
4769 +
4770 + for (i = shared->slot_first; i <= shared->slot_last; i++)
4771 + {
4772 + VCHIQ_SLOT_INFO_T slot_info = *SLOT_INFO_FROM_INDEX(state, i);
4773 + if (slot_info.use_count != slot_info.release_count)
4774 + {
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);
4778 + }
4779 + }
4780 +
4781 + for (i = 1; i < shared->debug[DEBUG_ENTRIES]; i++)
4782 + {
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);
4786 + }
4787 +}
4788 +
4789 +void
4790 +vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state)
4791 +{
4792 + char buf[80];
4793 + int len;
4794 + int i;
4795 +
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);
4799 +
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),
4804 + state->rx_pos,
4805 + (uint32_t)state->rx_data + (state->rx_pos & VCHIQ_SLOT_MASK));
4806 + vchiq_dump(dump_context, buf, len + 1);
4807 +
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);
4812 +
4813 + if (VCHIQ_ENABLE_STATS)
4814 + {
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);
4820 + }
4821 +
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);
4828 +
4829 + vchiq_dump_platform_state(dump_context);
4830 +
4831 + vchiq_dump_shared_state(dump_context, state, state->local, "Local");
4832 + vchiq_dump_shared_state(dump_context, state, state->remote, "Remote");
4833 +
4834 + vchiq_dump_platform_instances(dump_context);
4835 +
4836 + for (i = 0; i < state->unused_service; i++) {
4837 + VCHIQ_SERVICE_T *service = state->services[i];
4838 +
4839 + if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE))
4840 + vchiq_dump_service_state(dump_context, service);
4841 + }
4842 +}
4843 +
4844 +void
4845 +vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
4846 +{
4847 + char buf[80];
4848 + int len;
4849 +
4850 + len = vcos_snprintf(buf, sizeof(buf), "Service %d: %s",
4851 + service->localport, srvstate_names[service->srvstate]);
4852 +
4853 + if (service->srvstate != VCHIQ_SRVSTATE_FREE)
4854 + {
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)
4860 + {
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);
4866 + }
4867 + else
4868 + vcos_strcpy(remoteport, "n/a");
4869 +
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),
4873 + remoteport,
4874 + service_quota->slot_use_count,
4875 + service_quota->slot_quota);
4876 +
4877 + if (VCHIQ_ENABLE_STATS)
4878 + {
4879 + vchiq_dump(dump_context, buf, len + 1);
4880 +
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);
4886 +
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);
4892 +
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);
4898 + }
4899 + }
4900 +
4901 + vchiq_dump(dump_context, buf, len + 1);
4902 +
4903 + vchiq_dump_platform_service_state(dump_context, service);
4904 +}
4905 --- /dev/null
4906 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
4907 @@ -0,0 +1,480 @@
4908 +/*
4909 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
4910 + *
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.
4915 + *
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.
4920 + *
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
4924 + */
4925 +
4926 +#ifndef VCHIQ_CORE_H
4927 +#define VCHIQ_CORE_H
4928 +
4929 +#include "vchiq_cfg.h"
4930 +
4931 +#include "vchiq.h"
4932 +
4933 +#define IS_POW2(x) (x && ((x & (x - 1)) == 0))
4934 +
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));
4939 +
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)
4944 +
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 // -
4957 +
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)
4965 +
4966 +#define VCHIQ_FOURCC_AS_4CHARS(fourcc) \
4967 + ((fourcc) >> 24) & 0xff, \
4968 + ((fourcc) >> 16) & 0xff, \
4969 + ((fourcc) >> 8) & 0xff, \
4970 + ((fourcc) ) & 0xff
4971 +
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);
4976 +
4977 +#define VCHIQ_MSGID_PADDING VCHIQ_MAKE_MSG(VCHIQ_MSG_PADDING,0,0)
4978 +#define VCHIQ_MSGID_CLAIMED 0x40000000
4979 +
4980 +#define VCHIQ_FOURCC_INVALID 0x00000000
4981 +#define VCHIQ_FOURCC_IS_LEGAL(fourcc) (fourcc != VCHIQ_FOURCC_INVALID)
4982 +
4983 +#define VCHIQ_BULK_ACTUAL_ABORTED -1
4984 +
4985 +typedef uint32_t BITSET_T;
4986 +
4987 +vcos_static_assert((sizeof(BITSET_T) * 8) == 32);
4988 +
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))
4996 +
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)
5001 +#else
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)
5005 +#endif
5006 +
5007 +enum
5008 +{
5009 + DEBUG_ENTRIES,
5010 +#if VCHIQ_ENABLE_DEBUG
5011 + DEBUG_SLOT_HANDLER_COUNT,
5012 + DEBUG_SLOT_HANDLER_LINE,
5013 + DEBUG_PARSE_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,
5021 +#endif
5022 + DEBUG_MAX
5023 +};
5024 +
5025 +#if VCHIQ_ENABLE_DEBUG
5026 +
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]++
5031 +
5032 +#else /* VCHIQ_ENABLE_DEBUG */
5033 +
5034 +#define DEBUG_INITIALISE(local)
5035 +#define DEBUG_TRACE(d)
5036 +#define DEBUG_VALUE(d,v)
5037 +#define DEBUG_COUNT(d)
5038 +
5039 +#endif /* VCHIQ_ENABLE_DEBUG */
5040 +
5041 +typedef enum
5042 +{
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;
5050 +
5051 +enum
5052 +{
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
5061 +};
5062 +
5063 +enum
5064 +{
5065 + VCHIQ_POLL_TERMINATE,
5066 + VCHIQ_POLL_TXNOTIFY,
5067 + VCHIQ_POLL_RXNOTIFY,
5068 + VCHIQ_POLL_COUNT
5069 +};
5070 +
5071 +typedef enum
5072 +{
5073 + VCHIQ_BULK_TRANSMIT,
5074 + VCHIQ_BULK_RECEIVE
5075 +} VCHIQ_BULK_DIR_T;
5076 +
5077 +typedef struct vchiq_bulk_struct {
5078 + short mode;
5079 + short dir;
5080 + void *userdata;
5081 + VCHI_MEM_HANDLE_T handle;
5082 + void *data;
5083 + int size;
5084 + void *remote_data;
5085 + int remote_size;
5086 + int actual;
5087 +} VCHIQ_BULK_T;
5088 +
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;
5097 +
5098 +typedef struct remote_event_struct {
5099 + volatile int armed;
5100 + volatile int fired;
5101 + VCOS_EVENT_T * event;
5102 +} REMOTE_EVENT_T;
5103 +
5104 +typedef struct vchiq_state_struct VCHIQ_STATE_T;
5105 +
5106 +typedef struct vchiq_slot_struct {
5107 + char data[VCHIQ_SLOT_SIZE];
5108 +} VCHIQ_SLOT_T;
5109 +
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;
5115 +
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;
5122 + int client_id;
5123 + int auto_close;
5124 + VCOS_ATOMIC_FLAGS_T poll_flags;
5125 + short version;
5126 + short version_min;
5127 +
5128 + VCHIQ_STATE_T *state;
5129 + VCHIQ_INSTANCE_T instance;
5130 +
5131 + int service_use_count;
5132 +
5133 + VCHIQ_BULK_QUEUE_T bulk_tx;
5134 + VCHIQ_BULK_QUEUE_T bulk_rx;
5135 +
5136 + VCOS_EVENT_T remove_event;
5137 + VCOS_EVENT_T bulk_remove_event;
5138 + VCOS_MUTEX_T bulk_mutex;
5139 +
5140 + struct service_stats_struct
5141 + {
5142 + int quota_stalls;
5143 + int slot_stalls;
5144 + int bulk_stalls;
5145 + int error_count;
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;
5155 + } stats;
5156 +} VCHIQ_SERVICE_T;
5157 +
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.
5161 + */
5162 +typedef struct vchiq_service_quota_struct {
5163 + int slot_quota;
5164 + int slot_use_count;
5165 + VCOS_EVENT_T quota_event;
5166 + int previous_tx_index;
5167 +} VCHIQ_SERVICE_QUOTA_T;
5168 +
5169 +typedef struct vchiq_shared_state_struct {
5170 +
5171 + /* A non-zero value here indicates that the content is valid. */
5172 + int initialised;
5173 +
5174 + /* The first and last (inclusive) slots allocated to the owner. */
5175 + int slot_first;
5176 + int slot_last;
5177 +
5178 + /* Signalling this event indicates that owner's slot handler thread should
5179 + run. */
5180 + REMOTE_EVENT_T trigger;
5181 +
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;
5186 +
5187 + /* This event should be signalled when a slot is recycled. */
5188 + REMOTE_EVENT_T recycle;
5189 +
5190 + /* The slot_queue index where the next recycled slot will be written. */
5191 + volatile int slot_queue_recycle;
5192 +
5193 + /* A circular buffer of slot indexes. */
5194 + int slot_queue[VCHIQ_MAX_SLOTS_PER_SIDE];
5195 +
5196 + /* Debugging state */
5197 + volatile int debug[DEBUG_MAX];
5198 +} VCHIQ_SHARED_STATE_T;
5199 +
5200 +typedef struct vchiq_slot_zero_struct {
5201 + int magic;
5202 + short version;
5203 + short version_min;
5204 + int slot_zero_size;
5205 + int slot_size;
5206 + int max_slots;
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;
5213 +
5214 +struct vchiq_state_struct {
5215 + int id;
5216 + int initialised;
5217 + VCHIQ_CONNSTATE_T conn_state;
5218 + int is_master;
5219 +
5220 + VCHIQ_SHARED_STATE_T *local;
5221 + VCHIQ_SHARED_STATE_T *remote;
5222 + VCHIQ_SLOT_T *slot_data;
5223 +
5224 + int default_slot_quota;
5225 +
5226 + VCOS_EVENT_T connect; // event indicating connect message received
5227 + VCOS_MUTEX_T mutex; // mutex protecting services
5228 + VCHIQ_INSTANCE_T *instance;
5229 +
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)
5233 +
5234 + /* Local implementation of the trigger remote event */
5235 + VCOS_EVENT_T trigger_event;
5236 +
5237 + /* Local implementation of the recycle remote event */
5238 + VCOS_EVENT_T recycle_event;
5239 +
5240 + VCOS_EVENT_T lp_evt;
5241 +
5242 + char *tx_data;
5243 + char *rx_data;
5244 + VCHIQ_SLOT_INFO_T *rx_info;
5245 +
5246 + VCOS_MUTEX_T slot_mutex;
5247 +
5248 + VCOS_MUTEX_T recycle_mutex;
5249 +
5250 + VCOS_MUTEX_T suspend_resume_mutex;
5251 + VCOS_MUTEX_T use_count_mutex;
5252 +
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;
5257 +
5258 + /* Flag to indicate whether videocore is currently suspended */
5259 + int videocore_suspended;
5260 +
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. */
5264 + int rx_pos;
5265 +
5266 + /* A cached copy of local->tx_pos. Only write to local->tx_pos, and read
5267 + from remote->tx_pos. */
5268 + int local_tx_pos;
5269 +
5270 + /* The slot_queue index of the slot to become available next. */
5271 + int slot_queue_available;
5272 +
5273 + /* A flag to indicate if any poll has been requested */
5274 + int poll_needed;
5275 +
5276 + /* An array of bit sets indicating which services must be polled. */
5277 + VCOS_ATOMIC_FLAGS_T poll_services[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
5278 +
5279 + /* The number of the first unused service */
5280 + int unused_service;
5281 +
5282 + /* Signalled when a free slot becomes available. */
5283 + VCOS_EVENT_T slot_available_event;
5284 +
5285 + VCOS_EVENT_T slot_remove_event;
5286 +
5287 + struct state_stats_struct
5288 + {
5289 + int slot_stalls;
5290 + int ctrl_tx_count;
5291 + int ctrl_rx_count;
5292 + int error_count;
5293 + } stats;
5294 +
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];
5298 +};
5299 +
5300 +extern VCHIQ_SLOT_ZERO_T *
5301 +vchiq_init_slots(void *mem_base, int mem_size);
5302 +
5303 +extern VCHIQ_STATUS_T
5304 +vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, int is_master);
5305 +
5306 +extern VCHIQ_STATUS_T
5307 +vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
5308 +
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);
5313 +
5314 +extern VCHIQ_STATUS_T
5315 +vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id);
5316 +
5317 +extern VCHIQ_STATUS_T
5318 +vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd);
5319 +
5320 +extern void
5321 +vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service);
5322 +
5323 +extern void
5324 +vchiq_free_service_internal(VCHIQ_SERVICE_T *service);
5325 +
5326 +extern VCHIQ_STATUS_T
5327 +vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
5328 +
5329 +extern VCHIQ_STATUS_T
5330 +vchiq_pause_internal(VCHIQ_STATE_T *state);
5331 +
5332 +extern VCHIQ_STATUS_T
5333 +vchiq_resume_internal(VCHIQ_STATE_T *state);
5334 +
5335 +extern void
5336 +remote_event_pollall(VCHIQ_STATE_T *state);
5337 +
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);
5342 +
5343 +extern void
5344 +vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state);
5345 +
5346 +extern void
5347 +vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service);
5348 +
5349 +/* The following functions are called from vchiq_core, and external
5350 + implementations must be provided. */
5351 +
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);
5355 +
5356 +extern void
5357 +vchiq_transfer_bulk(VCHIQ_BULK_T *bulk);
5358 +
5359 +extern void
5360 +vchiq_complete_bulk(VCHIQ_BULK_T *bulk);
5361 +
5362 +extern VCHIQ_STATUS_T
5363 +vchiq_copy_from_user(void *dst, const void *src, int size);
5364 +
5365 +extern void
5366 +remote_event_signal(REMOTE_EVENT_T *event);
5367 +
5368 +extern void
5369 +vchiq_platform_paused(VCHIQ_STATE_T *state);
5370 +
5371 +extern void
5372 +vchiq_platform_resumed(VCHIQ_STATE_T *state);
5373 +
5374 +extern void
5375 +vchiq_dump(void *dump_context, const char *str, int len);
5376 +
5377 +extern void
5378 +vchiq_dump_platform_state(void *dump_context);
5379 +
5380 +extern void
5381 +vchiq_dump_platform_instances(void *dump_context);
5382 +
5383 +extern void
5384 +vchiq_dump_platform_service_state(void *dump_context,
5385 + VCHIQ_SERVICE_T *service);
5386 +
5387 +#endif
5388 --- /dev/null
5389 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
5390 @@ -0,0 +1,148 @@
5391 +/*
5392 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
5393 + *
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.
5398 + *
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.
5403 + *
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
5407 + */
5408 +
5409 +#ifndef VCHIQ_IF_H
5410 +#define VCHIQ_IF_H
5411 +
5412 +#include "interface/vchi/vchi_mh.h"
5413 +
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 */
5417 +
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)
5421 +
5422 +typedef enum {
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
5430 +} VCHIQ_REASON_T;
5431 +
5432 +typedef enum
5433 +{
5434 + VCHIQ_ERROR = -1,
5435 + VCHIQ_SUCCESS = 0,
5436 + VCHIQ_RETRY = 1
5437 +} VCHIQ_STATUS_T;
5438 +
5439 +typedef enum
5440 +{
5441 + VCHIQ_BULK_MODE_CALLBACK,
5442 + VCHIQ_BULK_MODE_BLOCKING,
5443 + VCHIQ_BULK_MODE_NOCALLBACK
5444 +} VCHIQ_BULK_MODE_T;
5445 +
5446 +typedef enum
5447 +{
5448 + VCHIQ_SERVICE_OPTION_AUTOCLOSE
5449 +} VCHIQ_SERVICE_OPTION_T;
5450 +
5451 +#ifdef __HIGHC__
5452 +/* Allow zero-sized arrays without warnings */
5453 +#pragma warning (push)
5454 +#pragma warning (disable : 4200)
5455 +#endif
5456 +
5457 +typedef struct vchiq_header_struct {
5458 + /* The message identifier - opaque to applications. */
5459 + int msgid;
5460 +
5461 + /* Size of message data. */
5462 + unsigned int size;
5463 +
5464 + char data[0]; /* message */
5465 +} VCHIQ_HEADER_T;
5466 +
5467 +#ifdef __HIGHC__
5468 +#pragma warning (pop)
5469 +#endif
5470 +
5471 +typedef struct {
5472 + const void *data;
5473 + int size;
5474 +} VCHIQ_ELEMENT_T;
5475 +
5476 +typedef const struct vchiq_service_base_struct *VCHIQ_SERVICE_HANDLE_T;
5477 +
5478 +typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, VCHIQ_HEADER_T *, VCHIQ_SERVICE_HANDLE_T, void *);
5479 +
5480 +typedef struct vchiq_service_base_struct {
5481 + int fourcc;
5482 + VCHIQ_CALLBACK_T callback;
5483 + void *userdata;
5484 +} VCHIQ_SERVICE_BASE_T;
5485 +
5486 +typedef struct vchiq_service_params_struct {
5487 + int fourcc;
5488 + VCHIQ_CALLBACK_T callback;
5489 + void *userdata;
5490 + short version; /* Increment for non-trivial changes */
5491 + short version_min; /* Update for incompatible changes */
5492 +} VCHIQ_SERVICE_PARAMS_T;
5493 +
5494 +typedef struct vchiq_config_struct {
5495 + int max_msg_size;
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;
5499 + int max_services;
5500 + short version; /* The version of VCHIQ */
5501 + short version_min; /* The minimum compatible version of VCHIQ */
5502 +} VCHIQ_CONFIG_T;
5503 +
5504 +typedef struct vchiq_instance_struct *VCHIQ_INSTANCE_T;
5505 +
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);
5521 +
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);
5535 +
5536 +extern VCHIQ_STATUS_T vchiq_dump_phys_mem( VCHIQ_SERVICE_HANDLE_T service, void *ptr, size_t num_bytes );
5537 +
5538 +#endif /* VCHIQ_IF_H */
5539 --- /dev/null
5540 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
5541 @@ -0,0 +1,105 @@
5542 +/*
5543 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
5544 + *
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.
5549 + *
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.
5554 + *
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
5558 + */
5559 +
5560 +#ifndef VCHIQ_IOCTLS_H
5561 +#define VCHIQ_IOCTLS_H
5562 +
5563 +#include <linux/ioctl.h>
5564 +#include "vchiq_if.h"
5565 +
5566 +#define VCHIQ_IOC_MAGIC 0xc4
5567 +#define VCHIQ_INVALID_HANDLE -1
5568 +
5569 +typedef struct {
5570 + VCHIQ_SERVICE_PARAMS_T params;
5571 + int is_open;
5572 + int is_vchi;
5573 + int handle; /* OUT */
5574 +} VCHIQ_CREATE_SERVICE_T;
5575 +
5576 +typedef struct {
5577 + int handle;
5578 + int count;
5579 + const VCHIQ_ELEMENT_T *elements;
5580 +} VCHIQ_QUEUE_MESSAGE_T;
5581 +
5582 +typedef struct {
5583 + int handle;
5584 + void *data;
5585 + int size;
5586 + void *userdata;
5587 + VCHIQ_BULK_MODE_T mode;
5588 +} VCHIQ_QUEUE_BULK_TRANSFER_T;
5589 +
5590 +typedef struct {
5591 + VCHIQ_REASON_T reason;
5592 + VCHIQ_HEADER_T *header;
5593 + void *service_userdata;
5594 + void *bulk_userdata;
5595 +} VCHIQ_COMPLETION_DATA_T;
5596 +
5597 +typedef struct {
5598 + int count;
5599 + VCHIQ_COMPLETION_DATA_T *buf;
5600 + int msgbufsize;
5601 + int msgbufcount; /* IN/OUT */
5602 + void **msgbufs;
5603 +} VCHIQ_AWAIT_COMPLETION_T;
5604 +
5605 +typedef struct {
5606 + int handle;
5607 + int blocking;
5608 + int bufsize;
5609 + void *buf;
5610 +} VCHIQ_DEQUEUE_MESSAGE_T;
5611 +
5612 +typedef struct {
5613 + int config_size;
5614 + VCHIQ_CONFIG_T *pconfig;
5615 +} VCHIQ_GET_CONFIG_T;
5616 +
5617 +typedef struct {
5618 + int handle;
5619 + VCHIQ_SERVICE_OPTION_T option;
5620 + int value;
5621 +} VCHIQ_SET_SERVICE_OPTION_T;
5622 +
5623 +typedef struct {
5624 + void *virt_addr;
5625 + size_t num_bytes;
5626 +} VCHIQ_DUMP_MEM_T;
5627 +
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
5645 +
5646 +#endif
5647 --- /dev/null
5648 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
5649 @@ -0,0 +1,297 @@
5650 +/*****************************************************************************
5651 +* Copyright 2001 - 2011 Broadcom Corporation. All rights reserved.
5652 +*
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").
5657 +*
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
5661 +* consent.
5662 +*****************************************************************************/
5663 +
5664 +/* ---- Include Files ---------------------------------------------------- */
5665 +
5666 +#include <linux/kernel.h>
5667 +#include <linux/module.h>
5668 +
5669 +#include "vchiq_core.h"
5670 +#include "vchiq_arm.h"
5671 +#include "interface/vcos/vcos_logging.h"
5672 +
5673 +/* ---- Public Variables ------------------------------------------------- */
5674 +
5675 +extern VCOS_LOG_CAT_T vchiq_core_log_category;
5676 +#define VCOS_LOG_CATEGORY (&vchiq_core_log_category)
5677 +
5678 +/* ---- Private Constants and Types -------------------------------------- */
5679 +
5680 +struct vchiq_instance_struct {
5681 + VCHIQ_STATE_T *state;
5682 +
5683 + int connected;
5684 +};
5685 +
5686 +/****************************************************************************
5687 +*
5688 +* vchiq_initialise
5689 +*
5690 +***************************************************************************/
5691 +
5692 +VCHIQ_STATUS_T vchiq_initialise( VCHIQ_INSTANCE_T *instanceOut )
5693 +{
5694 + VCHIQ_STATUS_T status = VCHIQ_ERROR;
5695 + VCHIQ_STATE_T *state;
5696 + VCHIQ_INSTANCE_T instance = NULL;
5697 +
5698 + vcos_log_trace( "%s called", __func__ );
5699 +
5700 + state = vchiq_get_state();
5701 + if (!state)
5702 + {
5703 + printk( KERN_ERR "%s: videocore not initialized\n", __func__ );
5704 + goto failed;
5705 + }
5706 +
5707 + instance = kzalloc( sizeof(*instance), GFP_KERNEL );
5708 + if( !instance )
5709 + {
5710 + printk( KERN_ERR "%s: error allocating vchiq instance\n", __func__ );
5711 + goto failed;
5712 + }
5713 +
5714 + instance->connected = 0;
5715 + instance->state = state;
5716 +
5717 + *instanceOut = instance;
5718 +
5719 + status = VCHIQ_SUCCESS;
5720 +
5721 +failed:
5722 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5723 +
5724 + return status;
5725 +}
5726 +
5727 +/****************************************************************************
5728 +*
5729 +* vchiq_shutdown
5730 +*
5731 +***************************************************************************/
5732 +
5733 +VCHIQ_STATUS_T vchiq_shutdown( VCHIQ_INSTANCE_T instance )
5734 +{
5735 + VCHIQ_STATUS_T status;
5736 + VCHIQ_STATE_T *state = instance->state;
5737 +
5738 + vcos_log_trace( "%s(%p) called", __func__, instance );
5739 +
5740 + vcos_mutex_lock(&state->mutex);
5741 +
5742 + /* Remove all services */
5743 + status = vchiq_shutdown_internal(state, instance);
5744 +
5745 + vcos_mutex_unlock(&state->mutex);
5746 +
5747 + if (status == VCHIQ_SUCCESS)
5748 + kfree(instance);
5749 +
5750 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5751 +
5752 + return status;
5753 +}
5754 +
5755 +/****************************************************************************
5756 +*
5757 +* vchiq_is_connected
5758 +*
5759 +***************************************************************************/
5760 +
5761 +int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
5762 +{
5763 + return instance->connected;
5764 +}
5765 +
5766 +/****************************************************************************
5767 +*
5768 +* vchiq_connect
5769 +*
5770 +***************************************************************************/
5771 +
5772 +VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
5773 +{
5774 + VCHIQ_STATUS_T status;
5775 + VCHIQ_STATE_T *state = instance->state;
5776 +
5777 + vcos_log_trace( "%s(%p) called", __func__, instance );
5778 +
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;
5782 + goto failed;
5783 + }
5784 + status = vchiq_connect_internal(state, instance);
5785 +
5786 + if (status == VCHIQ_SUCCESS)
5787 + instance->connected = 1;
5788 +
5789 + vcos_mutex_unlock(&state->mutex);
5790 +
5791 +failed:
5792 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5793 +
5794 + return status;
5795 +}
5796 +
5797 +/****************************************************************************
5798 +*
5799 +* vchiq_add_service
5800 +*
5801 +***************************************************************************/
5802 +
5803 +VCHIQ_STATUS_T vchiq_add_service(
5804 + VCHIQ_INSTANCE_T instance,
5805 + int fourcc,
5806 + VCHIQ_CALLBACK_T callback,
5807 + void *userdata,
5808 + VCHIQ_SERVICE_HANDLE_T *pservice)
5809 +{
5810 + VCHIQ_SERVICE_PARAMS_T params;
5811 +
5812 + params.fourcc = fourcc;
5813 + params.callback = callback;
5814 + params.userdata = userdata;
5815 + params.version = 0;
5816 + params.version_min = 0;
5817 +
5818 + return vchiq_add_service_params(instance, &params, pservice);
5819 +}
5820 +
5821 +/****************************************************************************
5822 +*
5823 +* vchiq_open_service
5824 +*
5825 +***************************************************************************/
5826 +
5827 +VCHIQ_STATUS_T vchiq_open_service(
5828 + VCHIQ_INSTANCE_T instance,
5829 + int fourcc,
5830 + VCHIQ_CALLBACK_T callback,
5831 + void *userdata,
5832 + VCHIQ_SERVICE_HANDLE_T *pservice)
5833 +{
5834 + VCHIQ_SERVICE_PARAMS_T params;
5835 +
5836 + params.fourcc = fourcc;
5837 + params.callback = callback;
5838 + params.userdata = userdata;
5839 + params.version = 0;
5840 + params.version_min = 0;
5841 +
5842 + return vchiq_open_service_params(instance, &params, pservice);
5843 +}
5844 +
5845 +/****************************************************************************
5846 +*
5847 +* vchiq_add_service_params
5848 +*
5849 +***************************************************************************/
5850 +
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)
5855 +{
5856 + VCHIQ_STATUS_T status;
5857 + VCHIQ_STATE_T *state = instance->state;
5858 + VCHIQ_SERVICE_T *service;
5859 + int srvstate;
5860 +
5861 + vcos_log_trace( "%s(%p) called", __func__, instance );
5862 +
5863 + *pservice = NULL;
5864 +
5865 + srvstate = vchiq_is_connected( instance )
5866 + ? VCHIQ_SRVSTATE_LISTENING
5867 + : VCHIQ_SRVSTATE_HIDDEN;
5868 +
5869 + vcos_mutex_lock(&state->mutex);
5870 +
5871 + service = vchiq_add_service_internal(
5872 + state,
5873 + params,
5874 + srvstate,
5875 + instance);
5876 +
5877 + vcos_mutex_unlock(&state->mutex);
5878 +
5879 + if ( service )
5880 + {
5881 + *pservice = &service->base;
5882 + status = VCHIQ_SUCCESS;
5883 + }
5884 + else
5885 + {
5886 + status = VCHIQ_ERROR;
5887 + }
5888 +
5889 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5890 +
5891 + return status;
5892 +}
5893 +
5894 +/****************************************************************************
5895 +*
5896 +* vchiq_open_service_params
5897 +*
5898 +***************************************************************************/
5899 +
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)
5904 +{
5905 + VCHIQ_STATUS_T status = VCHIQ_ERROR;
5906 + VCHIQ_STATE_T *state = instance->state;
5907 + VCHIQ_SERVICE_T *service;
5908 +
5909 + vcos_log_trace( "%s(%p) called", __func__, instance );
5910 +
5911 + *pservice = NULL;
5912 +
5913 + if (!vchiq_is_connected(instance))
5914 + goto failed;
5915 +
5916 + vcos_mutex_lock(&state->mutex);
5917 +
5918 + service = vchiq_add_service_internal(state,
5919 + params,
5920 + VCHIQ_SRVSTATE_OPENING,
5921 + instance);
5922 +
5923 + vcos_mutex_unlock(&state->mutex);
5924 +
5925 + if ( service )
5926 + {
5927 + status = vchiq_open_service_internal(service, current->pid);
5928 + if ( status == VCHIQ_SUCCESS )
5929 + *pservice = &service->base;
5930 + else
5931 + vchiq_remove_service(&service->base);
5932 + }
5933 +
5934 +failed:
5935 + vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5936 +
5937 + return status;
5938 +}
5939 +
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);
5947 --- /dev/null
5948 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_lib.c
5949 @@ -0,0 +1,1518 @@
5950 +/*
5951 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
5952 + *
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.
5957 + *
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.
5962 + *
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
5966 + */
5967 +
5968 +#include <unistd.h>
5969 +#include <fcntl.h>
5970 +#include <sys/ioctl.h>
5971 +#include <stdio.h>
5972 +
5973 +#include "vchiq.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"
5979 +
5980 +#define VCHIQ_MAX_INSTANCE_SERVICES 32
5981 +#define MSGBUF_SIZE (VCHIQ_MAX_MSG_SIZE + sizeof(VCHIQ_HEADER_T))
5982 +
5983 +#define RETRY(r,x) do { r = x; } while ((r == -1) && (errno == EINTR))
5984 +
5985 +#define VCOS_LOG_CATEGORY (&vchiq_lib_log_category)
5986 +
5987 +typedef struct vchiq_service_struct
5988 +{
5989 + VCHIQ_SERVICE_BASE_T base;
5990 + int handle;
5991 + int fd;
5992 + VCHI_CALLBACK_T vchi_callback;
5993 + void *peek_buf;
5994 + int peek_size;
5995 + int client_id;
5996 +} VCHIQ_SERVICE_T;
5997 +
5998 +typedef struct vchiq_service_struct VCHI_SERVICE_T;
5999 +
6000 +struct vchiq_instance_struct
6001 +{
6002 + int fd;
6003 + int initialised;
6004 + int connected;
6005 + VCOS_THREAD_T completion_thread;
6006 + VCOS_MUTEX_T mutex;
6007 + int used_services;
6008 + VCHIQ_SERVICE_T services[VCHIQ_MAX_INSTANCE_SERVICES];
6009 +} vchiq_instance;
6010 +
6011 +typedef struct vchiq_instance_struct VCHI_STATE_T;
6012 +
6013 +/* Local data */
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;
6018 +
6019 +
6020 +/* Local utility functions */
6021 +static VCHIQ_INSTANCE_T
6022 +vchiq_lib_init(void);
6023 +
6024 +static void *completion_thread(void *);
6025 +
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,
6030 + int is_open,
6031 + VCHIQ_SERVICE_HANDLE_T *pservice);
6032 +
6033 +static int
6034 +fill_peek_buf(VCHI_SERVICE_T *service,
6035 + VCHI_FLAGS_T flags);
6036 +
6037 +static void *
6038 +alloc_msgbuf(void);
6039 +
6040 +static void
6041 +free_msgbuf(void *buf);
6042 +
6043 +static __inline int
6044 +is_valid_instance(VCHIQ_INSTANCE_T instance)
6045 +{
6046 + return (instance == &vchiq_instance) && (instance->initialised > 0);
6047 +}
6048 +
6049 +/*
6050 + * VCHIQ API
6051 + */
6052 +
6053 +VCHIQ_STATUS_T
6054 +vchiq_initialise(VCHIQ_INSTANCE_T *pinstance)
6055 +{
6056 + VCHIQ_INSTANCE_T instance;
6057 +
6058 + instance = vchiq_lib_init();
6059 +
6060 + vcos_log_trace( "%s: returning instance handle %p", __func__, instance );
6061 +
6062 + *pinstance = instance;
6063 +
6064 + return (instance != NULL) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6065 +}
6066 +
6067 +VCHIQ_STATUS_T
6068 +vchiq_shutdown(VCHIQ_INSTANCE_T instance)
6069 +{
6070 + vcos_log_trace( "%s called", __func__ );
6071 +
6072 + if (!is_valid_instance(instance))
6073 + return VCHIQ_ERROR;
6074 +
6075 + vcos_mutex_lock(&instance->mutex);
6076 +
6077 + if (instance->initialised == 1)
6078 + {
6079 + int i;
6080 +
6081 + instance->initialised = -1; /* Enter limbo */
6082 +
6083 + /* Remove all services */
6084 +
6085 + for (i = 0; i < instance->used_services; i++)
6086 + {
6087 + if (instance->services[i].handle != VCHIQ_INVALID_HANDLE)
6088 + {
6089 + vchiq_remove_service(&instance->services[i].base);
6090 + instance->services[i].handle = VCHIQ_INVALID_HANDLE;
6091 + }
6092 + }
6093 +
6094 + if (instance->connected)
6095 + {
6096 + int ret;
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;
6101 + }
6102 +
6103 + close(instance->fd);
6104 + instance->fd = -1;
6105 + }
6106 + else if (instance->initialised > 1)
6107 + {
6108 + instance->initialised--;
6109 + }
6110 +
6111 + vcos_mutex_unlock(&instance->mutex);
6112 +
6113 + vcos_global_lock();
6114 +
6115 + if (instance->initialised == -1)
6116 + {
6117 + vcos_mutex_delete(&instance->mutex);
6118 + instance->initialised = 0;
6119 + }
6120 +
6121 + vcos_global_unlock();
6122 +
6123 + vcos_log_trace( "%s returning", __func__ );
6124 +
6125 + return VCHIQ_SUCCESS;
6126 +}
6127 +
6128 +VCHIQ_STATUS_T
6129 +vchiq_connect(VCHIQ_INSTANCE_T instance)
6130 +{
6131 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
6132 +
6133 + vcos_log_trace( "%s called", __func__ );
6134 +
6135 + if (!is_valid_instance(instance))
6136 + return VCHIQ_ERROR;
6137 +
6138 + vcos_mutex_lock(&instance->mutex);
6139 +
6140 + if (!instance->connected)
6141 + {
6142 + int ret = ioctl(instance->fd, VCHIQ_IOC_CONNECT, 0);
6143 + if (ret == 0)
6144 + {
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);
6150 + }
6151 + else
6152 + {
6153 + status = VCHIQ_ERROR;
6154 + }
6155 + }
6156 +
6157 + vcos_mutex_unlock(&instance->mutex);
6158 +
6159 + return status;
6160 +}
6161 +
6162 +VCHIQ_STATUS_T
6163 +vchiq_add_service(VCHIQ_INSTANCE_T instance,
6164 + int fourcc,
6165 + VCHIQ_CALLBACK_T callback,
6166 + void *userdata,
6167 + VCHIQ_SERVICE_HANDLE_T *pservice)
6168 +{
6169 + VCHIQ_SERVICE_PARAMS_T params;
6170 +
6171 + params.fourcc = fourcc;
6172 + params.callback = callback;
6173 + params.userdata = userdata;
6174 + params.version = 0;
6175 + params.version_min = 0;
6176 +
6177 + return vchiq_add_service_params(instance, &params, pservice);
6178 +}
6179 +
6180 +VCHIQ_STATUS_T
6181 +vchiq_open_service(VCHIQ_INSTANCE_T instance,
6182 + int fourcc,
6183 + VCHIQ_CALLBACK_T callback,
6184 + void *userdata,
6185 + VCHIQ_SERVICE_HANDLE_T *pservice)
6186 +{
6187 + VCHIQ_SERVICE_PARAMS_T params;
6188 +
6189 + params.fourcc = fourcc;
6190 + params.callback = callback;
6191 + params.userdata = userdata;
6192 + params.version = 0;
6193 + params.version_min = 0;
6194 +
6195 + return vchiq_open_service_params(instance, &params, pservice);
6196 +}
6197 +
6198 +VCHIQ_STATUS_T
6199 +vchiq_add_service_params(VCHIQ_INSTANCE_T instance,
6200 + const VCHIQ_SERVICE_PARAMS_T *params,
6201 + VCHIQ_SERVICE_HANDLE_T *pservice)
6202 +{
6203 + VCHIQ_STATUS_T status;
6204 +
6205 + vcos_log_trace( "%s called fourcc = 0x%08x (%c%c%c%c)",
6206 + __func__,
6207 + params->fourcc,
6208 + (params->fourcc >> 24) & 0xff,
6209 + (params->fourcc >> 16) & 0xff,
6210 + (params->fourcc >> 8) & 0xff,
6211 + (params->fourcc ) & 0xff );
6212 +
6213 + if (!params->callback)
6214 + return VCHIQ_ERROR;
6215 +
6216 + if (!is_valid_instance(instance))
6217 + return VCHIQ_ERROR;
6218 +
6219 + status = create_service(instance,
6220 + params,
6221 + NULL/*vchi_callback*/,
6222 + 0/*!open*/,
6223 + pservice);
6224 +
6225 + vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*pservice );
6226 +
6227 + return status;
6228 +}
6229 +
6230 +VCHIQ_STATUS_T
6231 +vchiq_open_service_params(VCHIQ_INSTANCE_T instance,
6232 + const VCHIQ_SERVICE_PARAMS_T *params,
6233 + VCHIQ_SERVICE_HANDLE_T *pservice)
6234 +{
6235 + VCHIQ_STATUS_T status;
6236 +
6237 + vcos_log_trace( "%s called fourcc = 0x%08x (%c%c%c%c)",
6238 + __func__,
6239 + params->fourcc,
6240 + (params->fourcc >> 24) & 0xff,
6241 + (params->fourcc >> 16) & 0xff,
6242 + (params->fourcc >> 8) & 0xff,
6243 + (params->fourcc ) & 0xff );
6244 +
6245 + if (!params->callback)
6246 + return VCHIQ_ERROR;
6247 +
6248 + if (!is_valid_instance(instance))
6249 + return VCHIQ_ERROR;
6250 +
6251 + status = create_service(instance,
6252 + params,
6253 + NULL/*vchi_callback*/,
6254 + 1/*open*/,
6255 + pservice);
6256 +
6257 + vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*pservice );
6258 +
6259 + return status;
6260 +}
6261 +
6262 +VCHIQ_STATUS_T
6263 +vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
6264 +{
6265 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6266 + int ret;
6267 +
6268 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6269 +
6270 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_CLOSE_SERVICE, service->handle));
6271 +
6272 + if (ret != 0)
6273 + return VCHIQ_ERROR;
6274 +
6275 + service->handle = VCHIQ_INVALID_HANDLE;
6276 + return VCHIQ_SUCCESS;
6277 +}
6278 +
6279 +VCHIQ_STATUS_T
6280 +vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
6281 +{
6282 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6283 + int ret;
6284 +
6285 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6286 +
6287 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
6288 +
6289 + if (ret != 0)
6290 + return VCHIQ_ERROR;
6291 +
6292 + service->handle = VCHIQ_INVALID_HANDLE;
6293 + return VCHIQ_SUCCESS;
6294 +}
6295 +
6296 +VCHIQ_STATUS_T
6297 +vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
6298 + const VCHIQ_ELEMENT_T *elements,
6299 + int count)
6300 +{
6301 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6302 + VCHIQ_QUEUE_MESSAGE_T args;
6303 + int ret;
6304 +
6305 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6306 +
6307 + args.handle = service->handle;
6308 + args.elements = elements;
6309 + args.count = count;
6310 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
6311 +
6312 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6313 +}
6314 +
6315 +void
6316 +vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle,
6317 + VCHIQ_HEADER_T *header)
6318 +{
6319 + vcos_log_trace( "%s handle=%08x, header=%x", __func__, (uint32_t)handle, (uint32_t)header );
6320 +
6321 + free_msgbuf(header);
6322 +}
6323 +
6324 +VCHIQ_STATUS_T
6325 +vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
6326 + const void *data,
6327 + int size,
6328 + void *userdata)
6329 +{
6330 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6331 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6332 + int ret;
6333 +
6334 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6335 +
6336 + args.handle = service->handle;
6337 + args.data = (void *)data;
6338 + args.size = size;
6339 + args.userdata = userdata;
6340 + args.mode = VCHIQ_BULK_MODE_CALLBACK;
6341 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
6342 +
6343 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6344 +}
6345 +
6346 +VCHIQ_STATUS_T
6347 +vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
6348 + void *data,
6349 + int size,
6350 + void *userdata)
6351 +{
6352 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6353 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6354 + int ret;
6355 +
6356 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6357 +
6358 + args.handle = service->handle;
6359 + args.data = data;
6360 + args.size = size;
6361 + args.userdata = userdata;
6362 + args.mode = VCHIQ_BULK_MODE_CALLBACK;
6363 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
6364 +
6365 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6366 +}
6367 +
6368 +VCHIQ_STATUS_T
6369 +vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
6370 + VCHI_MEM_HANDLE_T memhandle,
6371 + const void *offset,
6372 + int size,
6373 + void *userdata)
6374 +{
6375 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6376 +
6377 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6378 +
6379 + return vchiq_queue_bulk_transmit(handle, offset, size, userdata);
6380 +}
6381 +
6382 +VCHIQ_STATUS_T
6383 +vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
6384 + VCHI_MEM_HANDLE_T memhandle,
6385 + void *offset,
6386 + int size,
6387 + void *userdata)
6388 +{
6389 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6390 +
6391 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6392 +
6393 + return vchiq_queue_bulk_receive(handle, offset, size, userdata);
6394 +}
6395 +
6396 +VCHIQ_STATUS_T
6397 +vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
6398 + const void *data,
6399 + int size,
6400 + void *userdata,
6401 + VCHIQ_BULK_MODE_T mode)
6402 +{
6403 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6404 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6405 + int ret;
6406 +
6407 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6408 +
6409 + args.handle = service->handle;
6410 + args.data = (void *)data;
6411 + args.size = size;
6412 + args.userdata = userdata;
6413 + args.mode = mode;
6414 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
6415 +
6416 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6417 +}
6418 +
6419 +VCHIQ_STATUS_T
6420 +vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
6421 + void *data,
6422 + int size,
6423 + void *userdata,
6424 + VCHIQ_BULK_MODE_T mode)
6425 +{
6426 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6427 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6428 + int ret;
6429 +
6430 + vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6431 +
6432 + args.handle = service->handle;
6433 + args.data = data;
6434 + args.size = size;
6435 + args.userdata = userdata;
6436 + args.mode = mode;
6437 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
6438 +
6439 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6440 +}
6441 +
6442 +VCHIQ_STATUS_T
6443 +vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
6444 + VCHI_MEM_HANDLE_T memhandle,
6445 + const void *offset,
6446 + int size,
6447 + void *userdata,
6448 + VCHIQ_BULK_MODE_T mode)
6449 +{
6450 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6451 +
6452 + return vchiq_bulk_transmit(handle, offset, size, userdata, mode);
6453 +}
6454 +
6455 +VCHIQ_STATUS_T
6456 +vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
6457 + VCHI_MEM_HANDLE_T memhandle,
6458 + void *offset,
6459 + int size,
6460 + void *userdata,
6461 + VCHIQ_BULK_MODE_T mode)
6462 +{
6463 + vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6464 +
6465 + return vchiq_bulk_receive(handle, offset, size, userdata, mode);
6466 +}
6467 +
6468 +int
6469 +vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
6470 +{
6471 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6472 +
6473 + return ioctl(service->fd, VCHIQ_IOC_GET_CLIENT_ID, service->handle);
6474 +}
6475 +
6476 +VCHIQ_STATUS_T
6477 +vchiq_get_config(VCHIQ_INSTANCE_T instance,
6478 + int config_size,
6479 + VCHIQ_CONFIG_T *pconfig)
6480 +{
6481 + VCHIQ_GET_CONFIG_T args;
6482 + int ret;
6483 +
6484 + if (!is_valid_instance(instance))
6485 + return VCHIQ_ERROR;
6486 +
6487 + args.config_size = config_size;
6488 + args.pconfig = pconfig;
6489 +
6490 + RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_GET_CONFIG, &args));
6491 +
6492 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6493 +}
6494 +
6495 +int32_t
6496 +vchiq_use_service( const VCHIQ_SERVICE_HANDLE_T handle )
6497 +{
6498 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6499 + int ret;
6500 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
6501 + return ret;
6502 +}
6503 +
6504 +int32_t
6505 +vchiq_release_service( const VCHIQ_SERVICE_HANDLE_T handle )
6506 +{
6507 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6508 + int ret;
6509 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
6510 + return ret;
6511 +}
6512 +
6513 +VCHIQ_STATUS_T
6514 +vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
6515 + VCHIQ_SERVICE_OPTION_T option, int value)
6516 +{
6517 + VCHIQ_SET_SERVICE_OPTION_T args;
6518 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6519 + int ret;
6520 +
6521 + args.handle = service->handle;
6522 + args.option = option;
6523 + args.value = value;
6524 +
6525 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_SET_SERVICE_OPTION, &args));
6526 +
6527 + return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6528 +}
6529 +
6530 +/*
6531 + * VCHI API
6532 + */
6533 +
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 )
6539 +{
6540 + return NULL;
6541 +}
6542 +
6543 +/* ----------------------------------------------------------------------
6544 + * return a pointer to the 'single' connection driver fops
6545 + * -------------------------------------------------------------------- */
6546 +const VCHI_CONNECTION_API_T *
6547 +single_get_func_table( void )
6548 +{
6549 + return NULL;
6550 +}
6551 +
6552 +VCHI_CONNECTION_T *
6553 +vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
6554 + const VCHI_MESSAGE_DRIVER_T * low_level )
6555 +{
6556 + vcos_unused(function_table);
6557 + vcos_unused(low_level);
6558 +
6559 + return NULL;
6560 +}
6561 +
6562 +/***********************************************************
6563 + * Name: vchi_msg_peek
6564 + *
6565 + * Arguments: const VCHI_SERVICE_HANDLE_T handle,
6566 + * void **data,
6567 + * uint32_t *msg_size,
6568 + * VCHI_FLAGS_T flags
6569 + *
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
6572 + *
6573 + * Returns: int32_t - success == 0
6574 + *
6575 + ***********************************************************/
6576 +int32_t
6577 +vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
6578 + void **data,
6579 + uint32_t *msg_size,
6580 + VCHI_FLAGS_T flags )
6581 +{
6582 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6583 + int ret;
6584 +
6585 + ret = fill_peek_buf(service, flags);
6586 +
6587 + if (ret == 0)
6588 + {
6589 + *data = service->peek_buf;
6590 + *msg_size = service->peek_size;
6591 + }
6592 +
6593 + return ret;
6594 +}
6595 +
6596 +/***********************************************************
6597 + * Name: vchi_msg_remove
6598 + *
6599 + * Arguments: const VCHI_SERVICE_HANDLE_T handle,
6600 + *
6601 + * Description: Routine to remove a message (after it has been read with vchi_msg_peek)
6602 + *
6603 + * Returns: int32_t - success == 0
6604 + *
6605 + ***********************************************************/
6606 +int32_t
6607 +vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle )
6608 +{
6609 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6610 +
6611 + /* Why would you call vchi_msg_remove without calling vchi_msg_peek first? */
6612 + vcos_assert(service->peek_size >= 0);
6613 +
6614 + /* Invalidate the content but reuse the buffer */
6615 + service->peek_size = -1;
6616 +
6617 + return 0;
6618 +}
6619 +
6620 +/***********************************************************
6621 + * Name: vchi_msg_queue
6622 + *
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,
6628 + *
6629 + * Description: Thin wrapper to queue a message onto a connection
6630 + *
6631 + * Returns: int32_t - success == 0
6632 + *
6633 + ***********************************************************/
6634 +int32_t
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 )
6640 +{
6641 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6642 + VCHIQ_QUEUE_MESSAGE_T args;
6643 + VCHIQ_ELEMENT_T element = {data, data_size};
6644 + int ret;
6645 +
6646 + vcos_unused(msg_handle);
6647 + vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
6648 +
6649 + args.handle = service->handle;
6650 + args.elements = &element;
6651 + args.count = 1;
6652 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
6653 +
6654 + return ret;
6655 +}
6656 +
6657 +/***********************************************************
6658 + * Name: vchi_bulk_queue_receive
6659 + *
6660 + * Arguments: VCHI_BULK_HANDLE_T handle,
6661 + * void *data_dst,
6662 + * const uint32_t data_size,
6663 + * VCHI_FLAGS_T flags
6664 + * void *bulk_handle
6665 + *
6666 + * Description: Routine to setup a rcv buffer
6667 + *
6668 + * Returns: int32_t - success == 0
6669 + *
6670 + ***********************************************************/
6671 +int32_t
6672 +vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
6673 + void * data_dst,
6674 + uint32_t data_size,
6675 + VCHI_FLAGS_T flags,
6676 + void * bulk_handle )
6677 +{
6678 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6679 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6680 + int ret;
6681 +
6682 + switch ((int)flags) {
6683 + case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6684 + args.mode = VCHIQ_BULK_MODE_CALLBACK;
6685 + break;
6686 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
6687 + args.mode = VCHIQ_BULK_MODE_BLOCKING;
6688 + break;
6689 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6690 + case VCHI_FLAGS_NONE:
6691 + args.mode = VCHIQ_BULK_MODE_NOCALLBACK;
6692 + break;
6693 + default:
6694 + vcos_assert(0);
6695 + break;
6696 + }
6697 +
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));
6703 +
6704 + return ret;
6705 +}
6706 +
6707 +/***********************************************************
6708 + * Name: vchi_bulk_queue_transmit
6709 + *
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
6715 + *
6716 + * Description: Routine to transmit some data
6717 + *
6718 + * Returns: int32_t - success == 0
6719 + *
6720 + ***********************************************************/
6721 +int32_t
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 )
6727 +{
6728 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6729 + VCHIQ_QUEUE_BULK_TRANSFER_T args;
6730 + int ret;
6731 +
6732 + switch ((int)flags) {
6733 + case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6734 + args.mode = VCHIQ_BULK_MODE_CALLBACK;
6735 + break;
6736 + case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
6737 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
6738 + args.mode = VCHIQ_BULK_MODE_BLOCKING;
6739 + break;
6740 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6741 + case VCHI_FLAGS_NONE:
6742 + args.mode = VCHIQ_BULK_MODE_NOCALLBACK;
6743 + break;
6744 + default:
6745 + vcos_assert(0);
6746 + break;
6747 + }
6748 +
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));
6754 +
6755 + return ret;
6756 +}
6757 +
6758 +/***********************************************************
6759 + * Name: vchi_msg_dequeue
6760 + *
6761 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
6762 + * void *data,
6763 + * uint32_t max_data_size_to_read,
6764 + * uint32_t *actual_msg_size
6765 + * VCHI_FLAGS_T flags
6766 + *
6767 + * Description: Routine to dequeue a message into the supplied buffer
6768 + *
6769 + * Returns: int32_t - success == 0
6770 + *
6771 + ***********************************************************/
6772 +int32_t
6773 +vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
6774 + void *data,
6775 + uint32_t max_data_size_to_read,
6776 + uint32_t *actual_msg_size,
6777 + VCHI_FLAGS_T flags )
6778 +{
6779 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6780 + VCHIQ_DEQUEUE_MESSAGE_T args;
6781 + int ret;
6782 +
6783 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
6784 +
6785 + if (service->peek_size >= 0)
6786 + {
6787 + fprintf(stderr, "vchi_msg_dequeue -> using peek buffer\n");
6788 + if ((uint32_t)service->peek_size <= max_data_size_to_read)
6789 + {
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;
6794 + ret = 0;
6795 + }
6796 + else
6797 + {
6798 + ret = -1;
6799 + }
6800 + }
6801 + else
6802 + {
6803 + args.handle = service->handle;
6804 + args.blocking = (flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
6805 + args.bufsize = max_data_size_to_read;
6806 + args.buf = data;
6807 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_DEQUEUE_MESSAGE, &args));
6808 + if (ret >= 0)
6809 + {
6810 + *actual_msg_size = ret;
6811 + ret = 0;
6812 + }
6813 + }
6814 +
6815 + if ((ret < 0) && (errno != EWOULDBLOCK))
6816 + fprintf(stderr, "vchi_msg_dequeue -> %d(%d)\n", ret, errno);
6817 +
6818 + return ret;
6819 +}
6820 +
6821 +/***********************************************************
6822 + * Name: vchi_msg_queuev
6823 + *
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
6829 + *
6830 + * Description: Thin wrapper to queue a message onto a connection
6831 + *
6832 + * Returns: int32_t - success == 0
6833 + *
6834 + ***********************************************************/
6835 +
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));
6839 +
6840 +int32_t
6841 +vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
6842 + VCHI_MSG_VECTOR_T * vector,
6843 + uint32_t count,
6844 + VCHI_FLAGS_T flags,
6845 + void *msg_handle )
6846 +{
6847 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6848 + VCHIQ_QUEUE_MESSAGE_T args;
6849 + int ret;
6850 +
6851 + vcos_unused(msg_handle);
6852 +
6853 + vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
6854 +
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));
6859 +
6860 + return ret;
6861 +}
6862 +
6863 +/***********************************************************
6864 + * Name: vchi_held_msg_release
6865 + *
6866 + * Arguments: VCHI_HELD_MSG_T *message
6867 + *
6868 + * Description: Routine to release a held message (after it has been read with vchi_msg_hold)
6869 + *
6870 + * Returns: int32_t - success == 0
6871 + *
6872 + ***********************************************************/
6873 +int32_t
6874 +vchi_held_msg_release( VCHI_HELD_MSG_T *message )
6875 +{
6876 + int ret = -1;
6877 +
6878 + if (message && message->message && !message->service)
6879 + {
6880 + free_msgbuf(message->message);
6881 + ret = 0;
6882 + }
6883 +
6884 + return ret;
6885 +}
6886 +
6887 +/***********************************************************
6888 + * Name: vchi_msg_hold
6889 + *
6890 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
6891 + * void **data,
6892 + * uint32_t *msg_size,
6893 + * VCHI_FLAGS_T flags,
6894 + * VCHI_HELD_MSG_T *message_handle
6895 + *
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
6899 + *
6900 + * Returns: int32_t - success == 0
6901 + *
6902 + ***********************************************************/
6903 +int32_t
6904 +vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
6905 + void **data,
6906 + uint32_t *msg_size,
6907 + VCHI_FLAGS_T flags,
6908 + VCHI_HELD_MSG_T *message_handle )
6909 +{
6910 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6911 + int ret;
6912 +
6913 + ret = fill_peek_buf(service, flags);
6914 +
6915 + if (ret == 0)
6916 + {
6917 + *data = service->peek_buf;
6918 + *msg_size = service->peek_size;
6919 +
6920 + message_handle->message = service->peek_buf;
6921 + message_handle->service = NULL;
6922 +
6923 + service->peek_size = -1;
6924 + service->peek_buf = NULL;
6925 + }
6926 +
6927 + return 0;
6928 +}
6929 +
6930 +/***********************************************************
6931 + * Name: vchi_initialise
6932 + *
6933 + * Arguments: VCHI_INSTANCE_T *instance_handle
6934 + * VCHI_CONNECTION_T **connections
6935 + * const uint32_t num_connections
6936 + *
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
6940 + *
6941 + * Returns: 0 if successful, failure otherwise
6942 + *
6943 + ***********************************************************/
6944 +int32_t
6945 +vchi_initialise( VCHI_INSTANCE_T *instance_handle )
6946 +{
6947 + VCHIQ_INSTANCE_T instance;
6948 +
6949 + instance = vchiq_lib_init();
6950 +
6951 + vcos_log_trace( "%s: returning instance handle %p", __func__, instance );
6952 +
6953 + *instance_handle = (VCHI_INSTANCE_T)instance;
6954 +
6955 + return (instance != NULL) ? 0 : -1;
6956 +}
6957 +
6958 +/***********************************************************
6959 + * Name: vchi_connect
6960 + *
6961 + * Arguments: VCHI_CONNECTION_T **connections
6962 + * const uint32_t num_connections
6963 + * VCHI_INSTANCE_T instance_handle )
6964 + *
6965 + * Description: Starts the command service on each connection,
6966 + * causing INIT messages to be pinged back and forth
6967 + *
6968 + * Returns: 0 if successful, failure otherwise
6969 + *
6970 + ***********************************************************/
6971 +int32_t
6972 +vchi_connect( VCHI_CONNECTION_T **connections,
6973 + const uint32_t num_connections,
6974 + VCHI_INSTANCE_T instance_handle )
6975 +{
6976 + VCHIQ_STATUS_T status;
6977 +
6978 + vcos_unused(connections);
6979 + vcos_unused(num_connections);
6980 +
6981 + status = vchiq_connect((VCHIQ_INSTANCE_T)instance_handle);
6982 +
6983 + return (status == VCHIQ_SUCCESS) ? 0 : -1;
6984 +}
6985 +
6986 +
6987 +/***********************************************************
6988 + * Name: vchi_disconnect
6989 + *
6990 + * Arguments: VCHI_INSTANCE_T instance_handle
6991 + *
6992 + * Description: Stops the command service on each connection,
6993 + * causing DE-INIT messages to be pinged back and forth
6994 + *
6995 + * Returns: 0 if successful, failure otherwise
6996 + *
6997 + ***********************************************************/
6998 +int32_t
6999 +vchi_disconnect( VCHI_INSTANCE_T instance_handle )
7000 +{
7001 + VCHIQ_STATUS_T status;
7002 +
7003 + status = vchiq_shutdown((VCHIQ_INSTANCE_T)instance_handle);
7004 +
7005 + return (status == VCHIQ_SUCCESS) ? 0 : -1;
7006 +}
7007 +
7008 +
7009 +/***********************************************************
7010 + * Name: vchi_service_open
7011 + * Name: vchi_service_create
7012 + *
7013 + * Arguments: VCHI_INSTANCE_T *instance_handle
7014 + * SERVICE_CREATION_T *setup,
7015 + * VCHI_SERVICE_HANDLE_T *handle
7016 + *
7017 + * Description: Routine to open a service
7018 + *
7019 + * Returns: int32_t - success == 0
7020 + *
7021 + ***********************************************************/
7022 +int32_t
7023 +vchi_service_open( VCHI_INSTANCE_T instance_handle,
7024 + SERVICE_CREATION_T *setup,
7025 + VCHI_SERVICE_HANDLE_T *handle )
7026 +{
7027 + VCHIQ_SERVICE_PARAMS_T params;
7028 + VCHIQ_STATUS_T status;
7029 +
7030 + memset(&params, 0, sizeof(params));
7031 + params.fourcc = setup->service_id;
7032 + params.userdata = setup->callback_param;
7033 +
7034 + status = create_service((VCHIQ_INSTANCE_T)instance_handle,
7035 + &params,
7036 + setup->callback,
7037 + 1/*open*/,
7038 + (VCHIQ_SERVICE_HANDLE_T *)handle);
7039 +
7040 + return (status == VCHIQ_SUCCESS) ? 0 : -1;
7041 +}
7042 +
7043 +int32_t
7044 +vchi_service_create( VCHI_INSTANCE_T instance_handle,
7045 + SERVICE_CREATION_T *setup, VCHI_SERVICE_HANDLE_T *handle )
7046 +{
7047 + VCHIQ_SERVICE_PARAMS_T params;
7048 + VCHIQ_STATUS_T status;
7049 +
7050 + memset(&params, 0, sizeof(params));
7051 + params.fourcc = setup->service_id;
7052 + params.userdata = setup->callback_param;
7053 +
7054 + status = create_service((VCHIQ_INSTANCE_T)instance_handle,
7055 + &params,
7056 + setup->callback,
7057 + 0/*!open*/,
7058 + (VCHIQ_SERVICE_HANDLE_T *)handle);
7059 +
7060 + return (status == VCHIQ_SUCCESS) ? 0 : -1;
7061 +}
7062 +
7063 +int32_t
7064 +vchi_service_close( const VCHI_SERVICE_HANDLE_T handle )
7065 +{
7066 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7067 + int ret;
7068 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
7069 +
7070 + if (ret == 0)
7071 + service->handle = VCHIQ_INVALID_HANDLE;
7072 +
7073 + return ret;
7074 +}
7075 +
7076 +int32_t
7077 +vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle )
7078 +{
7079 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7080 + int ret;
7081 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
7082 +
7083 + if (ret == 0)
7084 + service->handle = VCHIQ_INVALID_HANDLE;
7085 +
7086 + return ret;
7087 +}
7088 +
7089 +/* ----------------------------------------------------------------------
7090 + * read a uint32_t from buffer.
7091 + * network format is defined to be little endian
7092 + * -------------------------------------------------------------------- */
7093 +uint32_t
7094 +vchi_readbuf_uint32( const void *_ptr )
7095 +{
7096 + const unsigned char *ptr = _ptr;
7097 + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
7098 +}
7099 +
7100 +/* ----------------------------------------------------------------------
7101 + * write a uint32_t to buffer.
7102 + * network format is defined to be little endian
7103 + * -------------------------------------------------------------------- */
7104 +void
7105 +vchi_writebuf_uint32( void *_ptr, uint32_t value )
7106 +{
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);
7112 +}
7113 +
7114 +/* ----------------------------------------------------------------------
7115 + * read a uint16_t from buffer.
7116 + * network format is defined to be little endian
7117 + * -------------------------------------------------------------------- */
7118 +uint16_t
7119 +vchi_readbuf_uint16( const void *_ptr )
7120 +{
7121 + const unsigned char *ptr = _ptr;
7122 + return ptr[0] | (ptr[1] << 8);
7123 +}
7124 +
7125 +/* ----------------------------------------------------------------------
7126 + * write a uint16_t into the buffer.
7127 + * network format is defined to be little endian
7128 + * -------------------------------------------------------------------- */
7129 +void
7130 +vchi_writebuf_uint16( void *_ptr, uint16_t value )
7131 +{
7132 + unsigned char *ptr = _ptr;
7133 + ptr[0] = (value >> 0) & 0xFF;
7134 + ptr[1] = (value >> 8) & 0xFF;
7135 +}
7136 +
7137 +/***********************************************************
7138 + * Name: vchi_service_use
7139 + *
7140 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
7141 + *
7142 + * Description: Routine to increment refcount on a service
7143 + *
7144 + * Returns: void
7145 + *
7146 + ***********************************************************/
7147 +int32_t
7148 +vchi_service_use( const VCHI_SERVICE_HANDLE_T handle )
7149 +{
7150 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7151 + int ret;
7152 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
7153 + return ret;
7154 +}
7155 +
7156 +/***********************************************************
7157 + * Name: vchi_service_release
7158 + *
7159 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
7160 + *
7161 + * Description: Routine to decrement refcount on a service
7162 + *
7163 + * Returns: void
7164 + *
7165 + ***********************************************************/
7166 +int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle )
7167 +{
7168 + VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7169 + int ret;
7170 + RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
7171 + return ret;
7172 +}
7173 +
7174 +/*
7175 + * Support functions
7176 + */
7177 +
7178 +static VCHIQ_INSTANCE_T
7179 +vchiq_lib_init(void)
7180 +{
7181 + static int mutex_initialised = 0;
7182 + static VCOS_MUTEX_T vchiq_lib_mutex;
7183 + VCHIQ_INSTANCE_T instance = &vchiq_instance;
7184 +
7185 + vcos_global_lock();
7186 + if (!mutex_initialised)
7187 + {
7188 + vcos_mutex_create(&vchiq_lib_mutex, "vchiq-init");
7189 +
7190 + vcos_log_set_level( &vchiq_lib_log_category, vchiq_default_lib_log_level );
7191 + vcos_log_register( "vchiq_lib", &vchiq_lib_log_category );
7192 +
7193 + mutex_initialised = 1;
7194 + }
7195 + vcos_global_unlock();
7196 +
7197 + vcos_mutex_lock(&vchiq_lib_mutex);
7198 +
7199 + if (instance->initialised == 0)
7200 + {
7201 + instance->fd = open("/dev/vchiq", O_RDWR);
7202 + if (instance->fd >= 0)
7203 + {
7204 + VCHIQ_GET_CONFIG_T args;
7205 + VCHIQ_CONFIG_T config;
7206 + int ret;
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))
7211 + {
7212 + instance->used_services = 0;
7213 + vcos_mutex_create(&instance->mutex, "VCHIQ instance");
7214 + instance->initialised = 1;
7215 + }
7216 + else
7217 + {
7218 + if (ret == 0)
7219 + {
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);
7222 + }
7223 + else
7224 + {
7225 + vcos_log_error("Very incompatible VCHIQ library - cannot retrieve driver version");
7226 + }
7227 + close(instance->fd);
7228 + instance = NULL;
7229 + }
7230 + }
7231 + else
7232 + {
7233 + instance = NULL;
7234 + }
7235 + }
7236 + else if (instance->initialised > 0)
7237 + {
7238 + instance->initialised++;
7239 + }
7240 +
7241 + vcos_mutex_unlock(&vchiq_lib_mutex);
7242 +
7243 + return instance;
7244 +}
7245 +
7246 +static void *
7247 +completion_thread(void *arg)
7248 +{
7249 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)arg;
7250 + VCHIQ_AWAIT_COMPLETION_T args;
7251 + VCHIQ_COMPLETION_DATA_T completions[8];
7252 + void *msgbufs[8];
7253 +
7254 + static const VCHI_CALLBACK_REASON_T vchiq_reason_to_vchi[] =
7255 + {
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
7263 + };
7264 +
7265 + args.count = vcos_countof(completions);
7266 + args.buf = completions;
7267 + args.msgbufsize = MSGBUF_SIZE;
7268 + args.msgbufcount = 0;
7269 + args.msgbufs = msgbufs;
7270 +
7271 + while (1)
7272 + {
7273 + int ret, i;
7274 +
7275 + while ((unsigned int)args.msgbufcount < vcos_countof(msgbufs))
7276 + {
7277 + void *msgbuf = alloc_msgbuf();
7278 + if (msgbuf)
7279 + {
7280 + msgbufs[args.msgbufcount++] = msgbuf;
7281 + }
7282 + else
7283 + {
7284 + fprintf(stderr, "vchiq_lib: failed to allocate a message buffer\n");
7285 + vcos_demand(args.msgbufcount != 0);
7286 + }
7287 + }
7288 +
7289 + RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_AWAIT_COMPLETION, &args));
7290 +
7291 + if (ret <= 0)
7292 + break;
7293 +
7294 + for (i = 0; i < ret; i++)
7295 + {
7296 + VCHIQ_COMPLETION_DATA_T *completion = &completions[i];
7297 + VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)completion->service_userdata;
7298 + if (service->base.callback)
7299 + {
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);
7305 + }
7306 + else if (service->vchi_callback)
7307 + {
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);
7311 + }
7312 + }
7313 + }
7314 + return NULL;
7315 +}
7316 +
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,
7321 + int is_open,
7322 + VCHIQ_SERVICE_HANDLE_T *pservice)
7323 +{
7324 + VCHIQ_SERVICE_T *service = NULL;
7325 + VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
7326 + int i;
7327 +
7328 + if (!is_valid_instance(instance))
7329 + return VCHIQ_ERROR;
7330 +
7331 + vcos_mutex_lock(&instance->mutex);
7332 +
7333 + /* Find a free service */
7334 + if (is_open)
7335 + {
7336 + /* Find a free service */
7337 + for (i = 0; i < instance->used_services; i++)
7338 + {
7339 + if (instance->services[i].handle == VCHIQ_INVALID_HANDLE)
7340 + {
7341 + service = &instance->services[i];
7342 + break;
7343 + }
7344 + }
7345 + }
7346 + else
7347 + {
7348 + for (i = (instance->used_services - 1); i >= 0; i--)
7349 + {
7350 + VCHIQ_SERVICE_T *srv = &instance->services[i];
7351 + if (srv->handle == VCHIQ_INVALID_HANDLE)
7352 + {
7353 + service = srv;
7354 + }
7355 + else if (
7356 + (srv->base.fourcc == params->fourcc) &&
7357 + ((srv->base.callback != params->callback) ||
7358 + (srv->vchi_callback != vchi_callback)))
7359 + {
7360 + /* There is another server using this fourcc which doesn't match */
7361 + service = NULL;
7362 + status = VCHIQ_ERROR;
7363 + break;
7364 + }
7365 + }
7366 + }
7367 +
7368 + if (!service && (status == VCHIQ_SUCCESS) &&
7369 + (instance->used_services < VCHIQ_MAX_INSTANCE_SERVICES))
7370 + service = &instance->services[instance->used_services++];
7371 +
7372 + if (service)
7373 + {
7374 + VCHIQ_CREATE_SERVICE_T args;
7375 + int ret;
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;
7383 +
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));
7390 + if (ret == 0)
7391 + service->handle = args.handle;
7392 + else
7393 + status = VCHIQ_ERROR;
7394 + }
7395 +
7396 + *pservice = (status == VCHIQ_SUCCESS) ? &service->base : NULL;
7397 +
7398 + vcos_mutex_unlock(&instance->mutex);
7399 +
7400 + return status;
7401 +}
7402 +
7403 +static int
7404 +fill_peek_buf(VCHI_SERVICE_T *service,
7405 + VCHI_FLAGS_T flags)
7406 +{
7407 + VCHIQ_DEQUEUE_MESSAGE_T args;
7408 + int ret = 0;
7409 +
7410 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
7411 +
7412 + if (service->peek_size < 0)
7413 + {
7414 + if (!service->peek_buf)
7415 + service->peek_buf = alloc_msgbuf();
7416 +
7417 + if (service->peek_buf)
7418 + {
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;
7423 +
7424 + RETRY(ret, ioctl(service->fd, VCHIQ_IOC_DEQUEUE_MESSAGE, &args));
7425 +
7426 + if (ret >= 0)
7427 + {
7428 + service->peek_size = ret;
7429 + ret = 0;
7430 + }
7431 + else
7432 + {
7433 + ret = -1;
7434 + }
7435 + }
7436 + else
7437 + {
7438 + ret = -1;
7439 + }
7440 + }
7441 +
7442 + return ret;
7443 +}
7444 +
7445 +
7446 +static void *
7447 +alloc_msgbuf(void)
7448 +{
7449 + void *msgbuf;
7450 + vcos_mutex_lock(&vchiq_lib_mutex);
7451 + msgbuf = free_msgbufs;
7452 + if (msgbuf)
7453 + free_msgbufs = *(void **)msgbuf;
7454 + vcos_mutex_unlock(&vchiq_lib_mutex);
7455 + if (!msgbuf)
7456 + msgbuf = malloc(MSGBUF_SIZE);
7457 + return msgbuf;
7458 +}
7459 +
7460 +static void
7461 +free_msgbuf(void *buf)
7462 +{
7463 + vcos_mutex_lock(&vchiq_lib_mutex);
7464 + *(void **)buf = free_msgbufs;
7465 + free_msgbufs = buf;
7466 + vcos_mutex_unlock(&vchiq_lib_mutex);
7467 +}
7468 --- /dev/null
7469 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
7470 @@ -0,0 +1,45 @@
7471 +/*****************************************************************************
7472 +* Copyright 2001 - 2010 Broadcom Corporation. All rights reserved.
7473 +*
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").
7478 +*
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
7482 +* consent.
7483 +*****************************************************************************/
7484 +
7485 +#ifndef VCHIQ_MEMDRV_H
7486 +#define VCHIQ_MEMDRV_H
7487 +
7488 +/* ---- Include Files ----------------------------------------------------- */
7489 +
7490 +#include <linux/kernel.h>
7491 +#include "vchiq_if.h"
7492 +
7493 +/* ---- Constants and Types ---------------------------------------------- */
7494 +
7495 +typedef struct
7496 +{
7497 + void *armSharedMemVirt;
7498 + dma_addr_t armSharedMemPhys;
7499 + size_t armSharedMemSize;
7500 +
7501 + void *vcSharedMemVirt;
7502 + dma_addr_t vcSharedMemPhys;
7503 + size_t vcSharedMemSize;
7504 +
7505 +} VCHIQ_SHARED_MEM_INFO_T;
7506 +
7507 +/* ---- Variable Externs ------------------------------------------------- */
7508 +
7509 +/* ---- Function Prototypes ---------------------------------------------- */
7510 +
7511 +void vchiq_get_shared_mem_info( VCHIQ_SHARED_MEM_INFO_T *info );
7512 +
7513 +VCHIQ_STATUS_T vchiq_memdrv_initialise(void);
7514 +
7515 +#endif
7516 --- /dev/null
7517 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
7518 @@ -0,0 +1,43 @@
7519 +/*
7520 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
7521 + *
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.
7526 + *
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.
7531 + *
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
7535 + */
7536 +
7537 +#ifndef VCHIQ_PAGELIST_H
7538 +#define VCHIQ_PAGELIST_H
7539 +
7540 +#ifndef PAGE_SIZE
7541 +#define PAGE_SIZE 4096
7542 +#endif
7543 +#define CACHE_LINE_SIZE 32
7544 +#define PAGELIST_WRITE 0
7545 +#define PAGELIST_READ 1
7546 +#define PAGELIST_READ_WITH_FRAGMENTS 2
7547 +
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. */
7554 +} PAGELIST_T;
7555 +
7556 +typedef struct fragments_struct {
7557 + char headbuf[CACHE_LINE_SIZE];
7558 + char tailbuf[CACHE_LINE_SIZE];
7559 +} FRAGMENTS_T;
7560 +
7561 +#endif /* VCHIQ_PAGELIST_H */
7562 --- /dev/null
7563 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
7564 @@ -0,0 +1,970 @@
7565 +/*
7566 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
7567 + *
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.
7572 + *
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.
7577 + *
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
7581 + */
7582 +
7583 +#include "interface/vchi/vchi.h"
7584 +#include "vchiq.h"
7585 +#include "vchiq_core.h"
7586 +
7587 +#include "vchiq_util.h"
7588 +
7589 +#include <stddef.h>
7590 +
7591 +#if defined(__KERNEL__)
7592 +#include <linux/module.h>
7593 +#endif
7594 +
7595 +#define vchiq_status_to_vchi(status) ((int32_t)status)
7596 +
7597 +typedef struct {
7598 + VCHIQ_SERVICE_HANDLE_T handle;
7599 +
7600 + VCHIU_QUEUE_T queue;
7601 +
7602 + VCHI_CALLBACK_T callback;
7603 + void *callback_param;
7604 +} SHIM_SERVICE_T;
7605 +
7606 +/* ----------------------------------------------------------------------
7607 + * return pointer to the mphi message driver function table
7608 + * -------------------------------------------------------------------- */
7609 +#ifdef WIN32
7610 +const VCHI_MESSAGE_DRIVER_T *
7611 +mphi_get_func_table( void )
7612 +{
7613 + return NULL;
7614 +}
7615 +#endif
7616 +
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 )
7622 +{
7623 + return NULL;
7624 +}
7625 +
7626 +/* ----------------------------------------------------------------------
7627 + * return a pointer to the 'single' connection driver fops
7628 + * -------------------------------------------------------------------- */
7629 +const VCHI_CONNECTION_API_T *
7630 +single_get_func_table( void )
7631 +{
7632 + return NULL;
7633 +}
7634 +
7635 +VCHI_CONNECTION_T * vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
7636 + const VCHI_MESSAGE_DRIVER_T * low_level)
7637 +{
7638 + vcos_unused(function_table);
7639 + vcos_unused(low_level);
7640 + return NULL;
7641 +}
7642 +
7643 +/***********************************************************
7644 + * Name: vchi_msg_peek
7645 + *
7646 + * Arguments: const VCHI_SERVICE_HANDLE_T handle,
7647 + * void **data,
7648 + * uint32_t *msg_size,
7649 + * VCHI_FLAGS_T flags
7650 + *
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
7653 + *
7654 + * Returns: int32_t - success == 0
7655 + *
7656 + ***********************************************************/
7657 +int32_t vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
7658 + void **data,
7659 + uint32_t *msg_size,
7660 + VCHI_FLAGS_T flags )
7661 +{
7662 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7663 + VCHIQ_HEADER_T *header;
7664 +
7665 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
7666 +
7667 + if (flags == VCHI_FLAGS_NONE)
7668 + if (vchiu_queue_is_empty(&service->queue))
7669 + return -1;
7670 +
7671 + header = vchiu_queue_peek(&service->queue);
7672 +
7673 + *data = header->data;
7674 + *msg_size = header->size;
7675 +
7676 + return 0;
7677 +}
7678 +
7679 +/***********************************************************
7680 + * Name: vchi_msg_remove
7681 + *
7682 + * Arguments: const VCHI_SERVICE_HANDLE_T handle,
7683 + *
7684 + * Description: Routine to remove a message (after it has been read with vchi_msg_peek)
7685 + *
7686 + * Returns: int32_t - success == 0
7687 + *
7688 + ***********************************************************/
7689 +int32_t vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle )
7690 +{
7691 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7692 + VCHIQ_HEADER_T *header;
7693 +
7694 + header = vchiu_queue_pop(&service->queue);
7695 +
7696 + vchiq_release_message(service->handle, header);
7697 +
7698 + return 0;
7699 +}
7700 +
7701 +/***********************************************************
7702 + * Name: vchi_msg_queue
7703 + *
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,
7709 + *
7710 + * Description: Thin wrapper to queue a message onto a connection
7711 + *
7712 + * Returns: int32_t - success == 0
7713 + *
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 )
7720 +{
7721 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7722 + VCHIQ_ELEMENT_T element = {data, data_size};
7723 + VCHIQ_STATUS_T status;
7724 +
7725 + vcos_unused(msg_handle);
7726 +
7727 + vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
7728 +
7729 + status = vchiq_queue_message(service->handle, &element, 1);
7730 +
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 )
7735 + {
7736 + vcos_sleep( 1 );
7737 + status = vchiq_queue_message(service->handle, &element, 1);
7738 + }
7739 +
7740 + return vchiq_status_to_vchi(status);
7741 +}
7742 +
7743 +/***********************************************************
7744 + * Name: vchi_bulk_queue_receive
7745 + *
7746 + * Arguments: VCHI_BULK_HANDLE_T handle,
7747 + * void *data_dst,
7748 + * const uint32_t data_size,
7749 + * VCHI_FLAGS_T flags
7750 + * void *bulk_handle
7751 + *
7752 + * Description: Routine to setup a rcv buffer
7753 + *
7754 + * Returns: int32_t - success == 0
7755 + *
7756 + ***********************************************************/
7757 +int32_t vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
7758 + void * data_dst,
7759 + uint32_t data_size,
7760 + VCHI_FLAGS_T flags,
7761 + void * bulk_handle )
7762 +{
7763 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7764 + VCHIQ_BULK_MODE_T mode;
7765 + VCHIQ_STATUS_T status;
7766 +
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;
7771 + break;
7772 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7773 + mode = VCHIQ_BULK_MODE_BLOCKING;
7774 + break;
7775 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7776 + case VCHI_FLAGS_NONE:
7777 + mode = VCHIQ_BULK_MODE_NOCALLBACK;
7778 + break;
7779 + default:
7780 + vcos_assert(0);
7781 + return vchiq_status_to_vchi(VCHIQ_ERROR);
7782 + }
7783 +
7784 + status = vchiq_bulk_receive(service->handle, data_dst, data_size,
7785 + bulk_handle, mode);
7786 +
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 )
7791 + {
7792 + vcos_sleep( 1 );
7793 + status = vchiq_bulk_receive(service->handle, data_dst, data_size,
7794 + bulk_handle, mode);
7795 + }
7796 +
7797 + return vchiq_status_to_vchi(status);
7798 +}
7799 +
7800 +/***********************************************************
7801 + * Name: vchi_bulk_queue_receive_reloc
7802 + *
7803 + * Arguments: VCHI_BULK_HANDLE_T handle,
7804 + * VCHI_MEM_HANDLE_T h
7805 + * uint32_t offset
7806 + * const uint32_t data_size,
7807 + * VCHI_FLAGS_T flags
7808 + * void *bulk_handle
7809 + *
7810 + * Description: Routine to setup a relocatable rcv buffer
7811 + *
7812 + * Returns: int32_t - success == 0
7813 + *
7814 + ***********************************************************/
7815 +int32_t vchi_bulk_queue_receive_reloc( const VCHI_SERVICE_HANDLE_T handle,
7816 + VCHI_MEM_HANDLE_T h,
7817 + uint32_t offset,
7818 + uint32_t data_size,
7819 + const VCHI_FLAGS_T flags,
7820 + void * const bulk_handle )
7821 +{
7822 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7823 + VCHIQ_BULK_MODE_T mode;
7824 + VCHIQ_STATUS_T status;
7825 +
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;
7830 + break;
7831 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7832 + mode = VCHIQ_BULK_MODE_BLOCKING;
7833 + break;
7834 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7835 + case VCHI_FLAGS_NONE:
7836 + mode = VCHIQ_BULK_MODE_NOCALLBACK;
7837 + break;
7838 + default:
7839 + vcos_assert(0);
7840 + return vchiq_status_to_vchi(VCHIQ_ERROR);
7841 + }
7842 +
7843 + status = vchiq_bulk_receive_handle(service->handle, h, (void*)offset,
7844 + data_size, bulk_handle, mode);
7845 +
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 )
7850 + {
7851 + vcos_sleep( 1 );
7852 + status = vchiq_bulk_receive_handle(service->handle, h, (void*)offset,
7853 + data_size, bulk_handle, mode);
7854 + }
7855 +
7856 + return vchiq_status_to_vchi(status);
7857 +}
7858 +
7859 +/***********************************************************
7860 + * Name: vchi_bulk_queue_transmit
7861 + *
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
7867 + *
7868 + * Description: Routine to transmit some data
7869 + *
7870 + * Returns: int32_t - success == 0
7871 + *
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 )
7878 +{
7879 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7880 + VCHIQ_BULK_MODE_T mode;
7881 + VCHIQ_STATUS_T status;
7882 +
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;
7887 + break;
7888 + case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
7889 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7890 + mode = VCHIQ_BULK_MODE_BLOCKING;
7891 + break;
7892 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7893 + case VCHI_FLAGS_NONE:
7894 + mode = VCHIQ_BULK_MODE_NOCALLBACK;
7895 + break;
7896 + default:
7897 + vcos_assert(0);
7898 + return vchiq_status_to_vchi(VCHIQ_ERROR);
7899 + }
7900 +
7901 + status = vchiq_bulk_transmit(service->handle, data_src, data_size,
7902 + bulk_handle, mode);
7903 +
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 )
7908 + {
7909 + vcos_sleep( 1 );
7910 + status = vchiq_bulk_transmit(service->handle, data_src, data_size,
7911 + bulk_handle, mode);
7912 + }
7913 +
7914 + return vchiq_status_to_vchi(status);
7915 +}
7916 +
7917 +/***********************************************************
7918 + * Name: vchi_bulk_queue_transmit_reloc
7919 + *
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
7926 + *
7927 + * Description: Routine to transmit some data from a relocatable buffer
7928 + *
7929 + * Returns: int32_t - success == 0
7930 + *
7931 + ***********************************************************/
7932 +
7933 +int32_t vchi_bulk_queue_transmit_reloc( VCHI_SERVICE_HANDLE_T handle,
7934 + VCHI_MEM_HANDLE_T h_src,
7935 + uint32_t offset,
7936 + uint32_t data_size,
7937 + VCHI_FLAGS_T flags,
7938 + void * const bulk_handle )
7939 +{
7940 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7941 + VCHIQ_BULK_MODE_T mode;
7942 + VCHIQ_STATUS_T status;
7943 +
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;
7948 + break;
7949 + case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
7950 + case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7951 + mode = VCHIQ_BULK_MODE_BLOCKING;
7952 + break;
7953 + case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7954 + case VCHI_FLAGS_NONE:
7955 + mode = VCHIQ_BULK_MODE_NOCALLBACK;
7956 + break;
7957 + default:
7958 + vcos_assert(0);
7959 + return vchiq_status_to_vchi(VCHIQ_ERROR);
7960 + }
7961 +
7962 + status = vchiq_bulk_transmit_handle(service->handle, h_src, (void*)offset,
7963 + data_size, bulk_handle, mode);
7964 +
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 )
7969 + {
7970 + vcos_sleep( 1 );
7971 + status = vchiq_bulk_transmit_handle(service->handle, h_src, (void*)offset,
7972 + data_size, bulk_handle, mode);
7973 + }
7974 +
7975 + return vchiq_status_to_vchi(status);
7976 +}
7977 +
7978 +/***********************************************************
7979 + * Name: vchi_msg_dequeue
7980 + *
7981 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
7982 + * void *data,
7983 + * uint32_t max_data_size_to_read,
7984 + * uint32_t *actual_msg_size
7985 + * VCHI_FLAGS_T flags
7986 + *
7987 + * Description: Routine to dequeue a message into the supplied buffer
7988 + *
7989 + * Returns: int32_t - success == 0
7990 + *
7991 + ***********************************************************/
7992 +int32_t vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
7993 + void *data,
7994 + uint32_t max_data_size_to_read,
7995 + uint32_t *actual_msg_size,
7996 + VCHI_FLAGS_T flags )
7997 +{
7998 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7999 + VCHIQ_HEADER_T *header;
8000 +
8001 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
8002 +
8003 + if (flags == VCHI_FLAGS_NONE)
8004 + if (vchiu_queue_is_empty(&service->queue))
8005 + return -1;
8006 +
8007 + header = vchiu_queue_pop(&service->queue);
8008 +
8009 + memcpy(data, header->data, header->size < max_data_size_to_read ? header->size : max_data_size_to_read);
8010 +
8011 + *actual_msg_size = header->size;
8012 +
8013 + vchiq_release_message(service->handle, header);
8014 +
8015 + return 0;
8016 +}
8017 +
8018 +/***********************************************************
8019 + * Name: vchi_msg_queuev
8020 + *
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
8026 + *
8027 + * Description: Thin wrapper to queue a message onto a connection
8028 + *
8029 + * Returns: int32_t - success == 0
8030 + *
8031 + ***********************************************************/
8032 +
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));
8036 +
8037 +int32_t vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
8038 + VCHI_MSG_VECTOR_T * vector,
8039 + uint32_t count,
8040 + VCHI_FLAGS_T flags,
8041 + void *msg_handle )
8042 +{
8043 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8044 +
8045 + vcos_unused(msg_handle);
8046 +
8047 + vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
8048 +
8049 + return vchiq_status_to_vchi(vchiq_queue_message(service->handle, (const VCHIQ_ELEMENT_T *)vector, count));
8050 +}
8051 +
8052 +#ifdef USE_MEMMGR
8053 +
8054 +/***********************************************************
8055 + * Name: vchi_msg_queuev_ex
8056 + *
8057 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
8058 + * VCHI_MSG_VECTOR_EX_T *vector
8059 + * uint32_t count
8060 + * VCHI_FLAGS_T flags,
8061 + * void *msg_handle
8062 + *
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.
8065 + *
8066 + * Currently just a shim, so deadlocks are still possible!
8067 + *
8068 + * Returns: int32_t - success == 0
8069 + *
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 )
8076 +{
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.
8082 +
8083 + #define max_vecs 16
8084 + VCHI_MSG_VECTOR_T copy[max_vecs];
8085 + const uint8_t *orig[max_vecs];
8086 +
8087 + int i;
8088 + vcos_unused(msg_handle);
8089 +
8090 + if (count > sizeof(copy)/sizeof(copy[0]))
8091 + {
8092 + vcos_assert(0);
8093 + return -1;
8094 + }
8095 +
8096 + for (i=0; i<count; i++)
8097 + {
8098 + VCHI_MSG_VECTOR_EX_T *v = vector+i;
8099 +
8100 + switch (vector[i].type)
8101 + {
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;
8105 + break;
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;
8111 + break;
8112 + case VCHI_VEC_LIST:
8113 + vcos_assert(0); // FIXME: implement this
8114 + break;
8115 + default:
8116 + vcos_assert(0);
8117 + }
8118 + }
8119 + success = vchi_msg_queuev( handle,
8120 + copy,
8121 + count,
8122 + flags &~ VCHI_FLAGS_INTERNAL,
8123 + msg_handle );
8124 + if (vcos_verify(success == 0))
8125 + {
8126 + // now we need to patch up the vectors if any have been only partially consumed, and
8127 + // unlock memory handles.
8128 +
8129 + for (i=0; i<count; i++)
8130 + {
8131 + VCHI_MSG_VECTOR_EX_T *v = vector+i;
8132 +
8133 + switch (vector[i].type)
8134 + {
8135 + case VCHI_VEC_POINTER:
8136 + if (flags & VCHI_FLAGS_ALLOW_PARTIAL)
8137 + {
8138 + v->u.ptr.vec_base = copy[i].vec_base;
8139 + v->u.ptr.vec_len = copy[i].vec_len;
8140 + }
8141 + break;
8142 + case VCHI_VEC_HANDLE:
8143 + mem_unlock(v->u.handle.handle);
8144 + if (flags & VCHI_FLAGS_ALLOW_PARTIAL)
8145 + {
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;
8150 + }
8151 + break;
8152 + default:
8153 + vcos_assert(0);
8154 + }
8155 + }
8156 + }
8157 +
8158 + return vchiq_status_to_vchi(success);
8159 +}
8160 +
8161 +#endif
8162 +
8163 +/***********************************************************
8164 + * Name: vchi_held_msg_release
8165 + *
8166 + * Arguments: VCHI_HELD_MSG_T *message
8167 + *
8168 + * Description: Routine to release a held message (after it has been read with vchi_msg_hold)
8169 + *
8170 + * Returns: int32_t - success == 0
8171 + *
8172 + ***********************************************************/
8173 +int32_t vchi_held_msg_release( VCHI_HELD_MSG_T *message )
8174 +{
8175 + vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service, (VCHIQ_HEADER_T *)message->message);
8176 +
8177 + return 0;
8178 +}
8179 +
8180 +/***********************************************************
8181 + * Name: vchi_msg_hold
8182 + *
8183 + * Arguments: VCHI_SERVICE_HANDLE_T handle,
8184 + * void **data,
8185 + * uint32_t *msg_size,
8186 + * VCHI_FLAGS_T flags,
8187 + * VCHI_HELD_MSG_T *message_handle
8188 + *
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
8192 + *
8193 + * Returns: int32_t - success == 0
8194 + *
8195 + ***********************************************************/
8196 +int32_t vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
8197 + void **data,
8198 + uint32_t *msg_size,
8199 + VCHI_FLAGS_T flags,
8200 + VCHI_HELD_MSG_T *message_handle )
8201 +{
8202 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8203 + VCHIQ_HEADER_T *header;
8204 +
8205 + vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
8206 +
8207 + if (flags == VCHI_FLAGS_NONE)
8208 + if (vchiu_queue_is_empty(&service->queue))
8209 + return -1;
8210 +
8211 + header = vchiu_queue_pop(&service->queue);
8212 +
8213 + *data = header->data;
8214 + *msg_size = header->size;
8215 +
8216 + message_handle->service = (struct opaque_vchi_service_t *)service->handle;
8217 + message_handle->message = header;
8218 +
8219 + return 0;
8220 +}
8221 +
8222 +/***********************************************************
8223 + * Name: vchi_initialise
8224 + *
8225 + * Arguments: VCHI_INSTANCE_T *instance_handle
8226 + * VCHI_CONNECTION_T **connections
8227 + * const uint32_t num_connections
8228 + *
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
8232 + *
8233 + * Returns: 0 if successful, failure otherwise
8234 + *
8235 + ***********************************************************/
8236 +
8237 +int32_t vchi_initialise( VCHI_INSTANCE_T *instance_handle )
8238 +{
8239 + VCHIQ_INSTANCE_T instance;
8240 + VCHIQ_STATUS_T status;
8241 +
8242 + status = vchiq_initialise(&instance);
8243 +
8244 + *instance_handle = (VCHI_INSTANCE_T)instance;
8245 +
8246 + return vchiq_status_to_vchi(status);
8247 +}
8248 +
8249 +/***********************************************************
8250 + * Name: vchi_connect
8251 + *
8252 + * Arguments: VCHI_CONNECTION_T **connections
8253 + * const uint32_t num_connections
8254 + * VCHI_INSTANCE_T instance_handle )
8255 + *
8256 + * Description: Starts the command service on each connection,
8257 + * causing INIT messages to be pinged back and forth
8258 + *
8259 + * Returns: 0 if successful, failure otherwise
8260 + *
8261 + ***********************************************************/
8262 +int32_t vchi_connect( VCHI_CONNECTION_T **connections,
8263 + const uint32_t num_connections,
8264 + VCHI_INSTANCE_T instance_handle )
8265 +{
8266 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8267 +
8268 + vcos_unused(connections);
8269 + vcos_unused(num_connections);
8270 +
8271 + return vchiq_connect(instance);
8272 +}
8273 +
8274 +
8275 +/***********************************************************
8276 + * Name: vchi_disconnect
8277 + *
8278 + * Arguments: VCHI_INSTANCE_T instance_handle
8279 + *
8280 + * Description: Stops the command service on each connection,
8281 + * causing DE-INIT messages to be pinged back and forth
8282 + *
8283 + * Returns: 0 if successful, failure otherwise
8284 + *
8285 + ***********************************************************/
8286 +int32_t vchi_disconnect( VCHI_INSTANCE_T instance_handle )
8287 +{
8288 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8289 + return vchiq_status_to_vchi(vchiq_shutdown(instance));
8290 +}
8291 +
8292 +
8293 +/***********************************************************
8294 + * Name: vchi_service_open
8295 + * Name: vchi_service_create
8296 + *
8297 + * Arguments: VCHI_INSTANCE_T *instance_handle
8298 + * SERVICE_CREATION_T *setup,
8299 + * VCHI_SERVICE_HANDLE_T *handle
8300 + *
8301 + * Description: Routine to open a service
8302 + *
8303 + * Returns: int32_t - success == 0
8304 + *
8305 + ***********************************************************/
8306 +
8307 +static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
8308 +{
8309 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
8310 +
8311 + switch (reason) {
8312 + case VCHIQ_MESSAGE_AVAILABLE:
8313 + vchiu_queue_push(&service->queue, header);
8314 +
8315 + if (service->callback)
8316 + service->callback(service->callback_param, VCHI_CALLBACK_MSG_AVAILABLE, NULL);
8317 + break;
8318 + case VCHIQ_BULK_TRANSMIT_DONE:
8319 + if (service->callback)
8320 + service->callback(service->callback_param, VCHI_CALLBACK_BULK_SENT, bulk_user);
8321 + break;
8322 + case VCHIQ_BULK_RECEIVE_DONE:
8323 + if (service->callback)
8324 + service->callback(service->callback_param, VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
8325 + break;
8326 + case VCHIQ_SERVICE_CLOSED:
8327 + if (service->callback)
8328 + service->callback(service->callback_param, VCHI_CALLBACK_SERVICE_CLOSED, NULL);
8329 + break;
8330 + case VCHIQ_SERVICE_OPENED:
8331 + /* No equivalent VCHI reason */
8332 + break;
8333 + case VCHIQ_BULK_TRANSMIT_ABORTED:
8334 + if (service->callback)
8335 + service->callback(service->callback_param, VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, bulk_user);
8336 + break;
8337 + case VCHIQ_BULK_RECEIVE_ABORTED:
8338 + if (service->callback)
8339 + service->callback(service->callback_param, VCHI_CALLBACK_BULK_RECEIVE_ABORTED, bulk_user);
8340 + break;
8341 + default:
8342 + vcos_assert(0);
8343 + break;
8344 + }
8345 +
8346 + return VCHIQ_SUCCESS;
8347 +}
8348 +
8349 +static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
8350 + SERVICE_CREATION_T *setup)
8351 +{
8352 + SHIM_SERVICE_T *service = vcos_calloc(1, sizeof(SHIM_SERVICE_T), "vchiq_shim");
8353 +
8354 + vcos_unused(instance);
8355 +
8356 + if (service)
8357 + {
8358 + if (vchiu_queue_init(&service->queue, 64))
8359 + {
8360 + service->callback = setup->callback;
8361 + service->callback_param = setup->callback_param;
8362 + }
8363 + else
8364 + {
8365 + vcos_free(service);
8366 + service = NULL;
8367 + }
8368 + }
8369 +
8370 + return service;
8371 +}
8372 +
8373 +static void service_free(SHIM_SERVICE_T *service)
8374 +{
8375 + if (service)
8376 + {
8377 + vchiu_queue_delete(&service->queue);
8378 + vcos_free((void*)service);
8379 + }
8380 +}
8381 +
8382 +int32_t vchi_service_open( VCHI_INSTANCE_T instance_handle,
8383 + SERVICE_CREATION_T *setup,
8384 + VCHI_SERVICE_HANDLE_T *handle)
8385 +{
8386 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8387 + SHIM_SERVICE_T *service = service_alloc(instance, setup);
8388 + if (service)
8389 + {
8390 + VCHIQ_STATUS_T status = vchiq_open_service(instance, setup->service_id, shim_callback, service, &service->handle);
8391 + if (status != VCHIQ_SUCCESS)
8392 + {
8393 + service_free(service);
8394 + service = NULL;
8395 + }
8396 + }
8397 +
8398 + *handle = (VCHI_SERVICE_HANDLE_T)service;
8399 +
8400 + return (service != NULL) ? 0 : -1;
8401 +}
8402 +
8403 +int32_t vchi_service_create( VCHI_INSTANCE_T instance_handle,
8404 + SERVICE_CREATION_T *setup,
8405 + VCHI_SERVICE_HANDLE_T *handle )
8406 +{
8407 + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8408 + SHIM_SERVICE_T *service = service_alloc(instance, setup);
8409 + if (service)
8410 + {
8411 + VCHIQ_STATUS_T status = vchiq_add_service(instance, setup->service_id, shim_callback, service, &service->handle);
8412 + if (status != VCHIQ_SUCCESS)
8413 + {
8414 + service_free(service);
8415 + service = NULL;
8416 + }
8417 + }
8418 +
8419 + *handle = (VCHI_SERVICE_HANDLE_T)service;
8420 +
8421 + return (service != NULL) ? 0 : -1;
8422 +}
8423 +
8424 +int32_t vchi_service_close( const VCHI_SERVICE_HANDLE_T handle )
8425 +{
8426 + vcos_unused(handle);
8427 +
8428 + // YTI??
8429 + return 0;
8430 +}
8431 +
8432 +/* ----------------------------------------------------------------------
8433 + * read a uint32_t from buffer.
8434 + * network format is defined to be little endian
8435 + * -------------------------------------------------------------------- */
8436 +uint32_t
8437 +vchi_readbuf_uint32( const void *_ptr )
8438 +{
8439 + const unsigned char *ptr = _ptr;
8440 + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
8441 +}
8442 +
8443 +/* ----------------------------------------------------------------------
8444 + * write a uint32_t to buffer.
8445 + * network format is defined to be little endian
8446 + * -------------------------------------------------------------------- */
8447 +void
8448 +vchi_writebuf_uint32( void *_ptr, uint32_t value )
8449 +{
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);
8455 +}
8456 +
8457 +/* ----------------------------------------------------------------------
8458 + * read a uint16_t from buffer.
8459 + * network format is defined to be little endian
8460 + * -------------------------------------------------------------------- */
8461 +uint16_t
8462 +vchi_readbuf_uint16( const void *_ptr )
8463 +{
8464 + const unsigned char *ptr = _ptr;
8465 + return ptr[0] | (ptr[1] << 8);
8466 +}
8467 +
8468 +/* ----------------------------------------------------------------------
8469 + * write a uint16_t into the buffer.
8470 + * network format is defined to be little endian
8471 + * -------------------------------------------------------------------- */
8472 +void
8473 +vchi_writebuf_uint16( void *_ptr, uint16_t value )
8474 +{
8475 + unsigned char *ptr = _ptr;
8476 + ptr[0] = (value >> 0) & 0xFF;
8477 + ptr[1] = (value >> 8) & 0xFF;
8478 +}
8479 +
8480 +/***********************************************************
8481 + * Name: vchi_service_use
8482 + *
8483 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
8484 + *
8485 + * Description: Routine to increment refcount on a service
8486 + *
8487 + * Returns: void
8488 + *
8489 + ***********************************************************/
8490 +int32_t vchi_service_use( const VCHI_SERVICE_HANDLE_T handle )
8491 +{
8492 + int32_t ret = -1;
8493 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8494 + if(service)
8495 + {
8496 + ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
8497 + }
8498 + return ret;
8499 +}
8500 +
8501 +/***********************************************************
8502 + * Name: vchi_service_release
8503 + *
8504 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
8505 + *
8506 + * Description: Routine to decrement refcount on a service
8507 + *
8508 + * Returns: void
8509 + *
8510 + ***********************************************************/
8511 +int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle )
8512 +{
8513 + int32_t ret = -1;
8514 + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8515 + if(service)
8516 + {
8517 + ret = vchiq_status_to_vchi(vchiq_release_service(service->handle));
8518 + }
8519 + return ret;
8520 +}
8521 +
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);
8534 +#endif
8535 --- /dev/null
8536 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
8537 @@ -0,0 +1,97 @@
8538 +/*
8539 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
8540 + *
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.
8545 + *
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.
8550 + *
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
8554 + */
8555 +
8556 +#include "vchiq_util.h"
8557 +
8558 +#if !defined(__KERNEL__)
8559 +#include <stdlib.h>
8560 +#endif
8561 +
8562 +static __inline int is_pow2(int i)
8563 +{
8564 + return i && !(i & (i - 1));
8565 +}
8566 +
8567 +int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size)
8568 +{
8569 + vcos_assert(is_pow2(size));
8570 +
8571 + queue->size = size;
8572 + queue->read = 0;
8573 + queue->write = 0;
8574 +
8575 + vcos_event_create(&queue->pop, "vchiu");
8576 + vcos_event_create(&queue->push, "vchiu");
8577 +
8578 + queue->storage = vcos_malloc(size * sizeof(VCHIQ_HEADER_T *), VCOS_FUNCTION);
8579 + if (queue->storage == NULL)
8580 + {
8581 + vchiu_queue_delete(queue);
8582 + return 0;
8583 + }
8584 + return 1;
8585 +}
8586 +
8587 +void vchiu_queue_delete(VCHIU_QUEUE_T *queue)
8588 +{
8589 + vcos_event_delete(&queue->pop);
8590 + vcos_event_delete(&queue->push);
8591 + if (queue->storage != NULL)
8592 + vcos_free(queue->storage);
8593 +}
8594 +
8595 +int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue)
8596 +{
8597 + return queue->read == queue->write;
8598 +}
8599 +
8600 +void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header)
8601 +{
8602 + while (queue->write == queue->read + queue->size)
8603 + vcos_event_wait(&queue->pop);
8604 +
8605 + queue->storage[queue->write & (queue->size - 1)] = header;
8606 +
8607 + queue->write++;
8608 +
8609 + vcos_event_signal(&queue->push);
8610 +}
8611 +
8612 +VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue)
8613 +{
8614 + while (queue->write == queue->read)
8615 + vcos_event_wait(&queue->push);
8616 +
8617 + return queue->storage[queue->read & (queue->size - 1)];
8618 +}
8619 +
8620 +VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue)
8621 +{
8622 + VCHIQ_HEADER_T *header;
8623 +
8624 + while (queue->write == queue->read)
8625 + vcos_event_wait(&queue->push);
8626 +
8627 + header = queue->storage[queue->read & (queue->size - 1)];
8628 +
8629 + queue->read++;
8630 +
8631 + vcos_event_signal(&queue->pop);
8632 +
8633 + return header;
8634 +}
8635 --- /dev/null
8636 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
8637 @@ -0,0 +1,47 @@
8638 +/*
8639 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
8640 + *
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.
8645 + *
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.
8650 + *
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
8654 + */
8655 +
8656 +#ifndef VCHIQ_UTIL_H
8657 +#define VCHIQ_UTIL_H
8658 +
8659 +#include "vchiq_if.h"
8660 +#include "interface/vcos/vcos.h"
8661 +
8662 +typedef struct {
8663 + int size;
8664 + int read;
8665 + int write;
8666 +
8667 + VCOS_EVENT_T pop;
8668 + VCOS_EVENT_T push;
8669 +
8670 + VCHIQ_HEADER_T **storage;
8671 +} VCHIU_QUEUE_T;
8672 +
8673 +extern int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size);
8674 +extern void vchiu_queue_delete(VCHIU_QUEUE_T *queue);
8675 +
8676 +extern int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue);
8677 +
8678 +extern void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header);
8679 +
8680 +extern VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue);
8681 +extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue);
8682 +
8683 +#endif
8684 +
8685 --- /dev/null
8686 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_cmd.c
8687 @@ -0,0 +1,681 @@
8688 +/*****************************************************************************
8689 +* Copyright 2009 - 2011 Broadcom Corporation. All rights reserved.
8690 +*
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").
8695 +*
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
8699 +* consent.
8700 +*****************************************************************************/
8701 +
8702 +/*****************************************************************************
8703 +*
8704 +* This file provides a generic command line interface which allows
8705 +* vcos internals to be manipulated and/or displayed.
8706 +*
8707 +*****************************************************************************/
8708 +
8709 +/* ---- Include Files ---------------------------------------------------- */
8710 +
8711 +#include "interface/vcos/vcos.h"
8712 +
8713 +#ifdef HAVE_VCOS_VERSION
8714 +#include "interface/vcos/vcos_build_info.h"
8715 +#endif
8716 +
8717 + #ifdef _VIDEOCORE
8718 +#include vcfw/logging/logging.h
8719 +#endif
8720 +
8721 +/* ---- Public Variables ------------------------------------------------- */
8722 +
8723 +/* ---- Private Constants and Types -------------------------------------- */
8724 +
8725 +#define VCOS_LOG_CATEGORY (&vcos_cmd_log_category)
8726 +VCOS_LOG_CAT_T vcos_cmd_log_category;
8727 +
8728 +/* ---- Private Variables ------------------------------------------------ */
8729 +
8730 +static struct VCOS_CMD_GLOBALS_T
8731 +{
8732 + VCOS_MUTEX_T lock;
8733 + VCOS_ONCE_T initialized;
8734 +
8735 + unsigned num_cmd_entries;
8736 + unsigned num_cmd_alloc;
8737 + VCOS_CMD_T *cmd_entry;
8738 +
8739 + VCOS_LOG_CAT_T *log_category;
8740 +} cmd_globals;
8741 +
8742 +/* ---- Private Function Prototypes -------------------------------------- */
8743 +
8744 +static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param );
8745 +
8746 +/* ---- Functions ------------------------------------------------------- */
8747 +
8748 +/*****************************************************************************
8749 +*
8750 +* Walks through the commands looking for a particular command
8751 +*
8752 +*****************************************************************************/
8753 +
8754 +static VCOS_CMD_T *find_cmd( VCOS_CMD_T *cmd_entry, const char *name )
8755 +{
8756 + VCOS_CMD_T *scan_entry = cmd_entry;
8757 +
8758 + while ( scan_entry->name != NULL )
8759 + {
8760 + if ( vcos_strcmp( scan_entry->name, name ) == 0 )
8761 + {
8762 + return scan_entry;
8763 + }
8764 + scan_entry++;
8765 + }
8766 +
8767 + return NULL;
8768 +}
8769 +
8770 +/*****************************************************************************
8771 +*
8772 +* Saves away
8773 +* each line individually.
8774 +*
8775 +*****************************************************************************/
8776 +
8777 +void vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category )
8778 +{
8779 + cmd_globals.log_category = log_category;
8780 +}
8781 +
8782 +/*****************************************************************************
8783 +*
8784 +* Walks through a buffer containing newline separated lines, and logs
8785 +* each line individually.
8786 +*
8787 +*****************************************************************************/
8788 +
8789 +static void cmd_log_results( VCOS_CMD_PARAM_T *param )
8790 +{
8791 + char *start;
8792 + char *end;
8793 +
8794 + start = end = param->result_buf;
8795 +
8796 + while ( *start != '\0' )
8797 + {
8798 + while (( *end != '\0' ) && ( *end != '\n' ))
8799 + end++;
8800 +
8801 + if ( *end == '\n' )
8802 + {
8803 + *end++ = '\0';
8804 + }
8805 +
8806 + if ( cmd_globals.log_category != NULL )
8807 + {
8808 + if ( vcos_is_log_enabled( cmd_globals.log_category, VCOS_LOG_INFO ))
8809 + {
8810 + vcos_log_impl( cmd_globals.log_category, VCOS_LOG_INFO, "%s", start );
8811 + }
8812 + }
8813 + else
8814 + {
8815 + vcos_log_info( "%s", start );
8816 + }
8817 +
8818 + start = end;
8819 + }
8820 +
8821 + /* Since we logged the buffer, reset the pointer back to the beginning. */
8822 +
8823 + param->result_ptr = param->result_buf;
8824 + param->result_buf[0] = '\0';
8825 +}
8826 +
8827 +/*****************************************************************************
8828 +*
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.
8832 +*
8833 +*****************************************************************************/
8834 +
8835 +void vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args )
8836 +{
8837 + int bytes_written;
8838 + int bytes_remaining;
8839 +
8840 + bytes_remaining = (int)(param->result_size - ( param->result_ptr - param->result_buf ));
8841 +
8842 + bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
8843 +
8844 + if ( cmd_globals.log_category != NULL )
8845 + {
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.
8848 + */
8849 +
8850 + if ( (( bytes_written + 1 ) >= bytes_remaining )
8851 + || ( param->result_ptr[ bytes_written - 1 ] == '\n' ))
8852 + {
8853 + cmd_log_results( param );
8854 + }
8855 + else
8856 + {
8857 + param->result_ptr += bytes_written;
8858 + }
8859 + }
8860 + else
8861 + {
8862 + if (( bytes_written + 1 ) >= bytes_remaining )
8863 + {
8864 + /* Output doesn't fit - switch over to logging */
8865 +
8866 + param->use_log = 1;
8867 +
8868 + *param->result_ptr = '\0'; /* Zap the partial line that didn't fit above. */
8869 +
8870 + cmd_log_results( param ); /* resets result_ptr */
8871 +
8872 + bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
8873 + }
8874 + param->result_ptr += bytes_written;
8875 + }
8876 +}
8877 +
8878 +/*****************************************************************************
8879 +*
8880 +* Prints the output.
8881 +*
8882 +*****************************************************************************/
8883 +
8884 +void vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
8885 +{
8886 + va_list args;
8887 +
8888 + va_start( args, fmt );
8889 + vcos_cmd_vprintf( param, fmt, args );
8890 + va_end( args );
8891 +}
8892 +
8893 +/*****************************************************************************
8894 +*
8895 +* Prints the arguments which were on the command line prior to ours.
8896 +*
8897 +*****************************************************************************/
8898 +
8899 +static void print_argument_prefix( VCOS_CMD_PARAM_T *param )
8900 +{
8901 + int arg_idx;
8902 +
8903 + for ( arg_idx = 0; &param->argv_orig[arg_idx] != param->argv; arg_idx++ )
8904 + {
8905 + vcos_cmd_printf( param, "%s ", param->argv_orig[arg_idx] );
8906 + }
8907 +}
8908 +
8909 +/*****************************************************************************
8910 +*
8911 +* Prints an error message, prefixed by the command chain required to get
8912 +* to where we're at.
8913 +*
8914 +*****************************************************************************/
8915 +
8916 +void vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
8917 +{
8918 + va_list args;
8919 +
8920 + print_argument_prefix( param );
8921 +
8922 + va_start( args, fmt );
8923 + vcos_cmd_vprintf( param, fmt, args );
8924 + va_end( args );
8925 + vcos_cmd_printf( param, "\n" );
8926 +}
8927 +
8928 +/****************************************************************************
8929 +*
8930 +* usage - prints command usage for an array of commands.
8931 +*
8932 +***************************************************************************/
8933 +
8934 +static void usage( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
8935 +{
8936 + int cmd_idx;
8937 + int nameWidth = 0;
8938 + int argsWidth = 0;
8939 + VCOS_CMD_T *scan_entry;
8940 +
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" );
8946 +
8947 + for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
8948 + {
8949 + int aw;
8950 + int nw;
8951 +
8952 + scan_entry = &cmd_entry[cmd_idx];
8953 +
8954 + nw = vcos_strlen( scan_entry->name );
8955 + aw = vcos_strlen( scan_entry->args );
8956 +
8957 + if ( nw > nameWidth )
8958 + {
8959 + nameWidth = nw;
8960 + }
8961 + if ( aw > argsWidth )
8962 + {
8963 + argsWidth = aw;
8964 + }
8965 + }
8966 +
8967 + for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
8968 + {
8969 + scan_entry = &cmd_entry[cmd_idx];
8970 +
8971 + vcos_cmd_printf( param, " %-*s %-*s - %s\n",
8972 + nameWidth, scan_entry->name,
8973 + argsWidth, scan_entry->args,
8974 + scan_entry->descr );
8975 + }
8976 +}
8977 +
8978 +/****************************************************************************
8979 +*
8980 +* Prints the usage for the current command.
8981 +*
8982 +***************************************************************************/
8983 +
8984 +void vcos_cmd_usage( VCOS_CMD_PARAM_T *param )
8985 +{
8986 + VCOS_CMD_T *cmd_entry;
8987 +
8988 + cmd_entry = param->cmd_entry;
8989 +
8990 + if ( cmd_entry->sub_cmd_entry != NULL )
8991 + {
8992 + /* This command is command with sub-commands */
8993 +
8994 + usage( param, param->cmd_entry->sub_cmd_entry );
8995 + }
8996 + else
8997 + {
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 );
9003 + }
9004 +}
9005 +
9006 +/*****************************************************************************
9007 +*
9008 +* Command to print out the help
9009 +*
9010 +* This help command is only called from the main menu.
9011 +*
9012 +*****************************************************************************/
9013 +
9014 +static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param )
9015 +{
9016 + VCOS_CMD_T *found_entry;
9017 +
9018 +#if 0
9019 + {
9020 + int arg_idx;
9021 +
9022 + vcos_log_trace( "%s: argc = %d", __func__, param->argc );
9023 + for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
9024 + {
9025 + vcos_log_trace( "%s: argv[%d] = '%s'", __func__, arg_idx, param->argv[arg_idx] );
9026 + }
9027 + }
9028 +#endif
9029 +
9030 + /* If there is an argument after the word help, then we want to print
9031 + * help for that command.
9032 + */
9033 +
9034 + if ( param->argc == 1 )
9035 + {
9036 + if ( param->cmd_parent_entry == cmd_globals.cmd_entry )
9037 + {
9038 + /* Bare help - print the command usage for the root */
9039 +
9040 + usage( param, cmd_globals.cmd_entry );
9041 + return VCOS_SUCCESS;
9042 + }
9043 +
9044 + /* For all other cases help requires an argument */
9045 +
9046 + vcos_cmd_error( param, "%s requires an argument", param->argv[0] );
9047 + return VCOS_EINVAL;
9048 + }
9049 +
9050 + /* We were given an argument. */
9051 +
9052 + if (( found_entry = find_cmd( param->cmd_parent_entry, param->argv[1] )) != NULL )
9053 + {
9054 + /* Make it look like the command that was specified is the one that's
9055 + * currently running
9056 + */
9057 +
9058 + param->cmd_entry = found_entry;
9059 + param->argv[0] = param->argv[1];
9060 + param->argv++;
9061 + param->argc--;
9062 +
9063 + vcos_cmd_usage( param );
9064 + return VCOS_SUCCESS;
9065 + }
9066 +
9067 + vcos_cmd_error( param, "- unrecognized command: '%s'", param->argv[1] );
9068 + return VCOS_ENOENT;
9069 +}
9070 +
9071 +/*****************************************************************************
9072 +*
9073 +* Command to print out the version/build information.
9074 +*
9075 +*****************************************************************************/
9076 +
9077 +#ifdef HAVE_VCOS_VERSION
9078 +
9079 +static VCOS_STATUS_T version_cmd( VCOS_CMD_PARAM_T *param )
9080 +{
9081 + static const char* copyright = "Copyright (c) 2011 Broadcom";
9082 +
9083 + vcos_cmd_printf( param, "%s %s\n%s\nversion %s\n",
9084 + vcos_get_build_date(),
9085 + vcos_get_build_time(),
9086 + copyright,
9087 + vcos_get_build_version() );
9088 +
9089 + return VCOS_SUCCESS;
9090 +}
9091 +
9092 +#endif
9093 +
9094 +/*****************************************************************************
9095 +*
9096 +* Internal commands
9097 +*
9098 +*****************************************************************************/
9099 +
9100 +static VCOS_CMD_T cmd_help = { "help", "[command]", help_cmd, NULL, "Prints command help information" };
9101 +
9102 +#ifdef HAVE_VCOS_VERSION
9103 +static VCOS_CMD_T cmd_version = { "version", "", version_cmd, NULL, "Prints build/version information" };
9104 +#endif
9105 +
9106 +/*****************************************************************************
9107 +*
9108 +* Walks the command table and executes the commands
9109 +*
9110 +*****************************************************************************/
9111 +
9112 +static VCOS_STATUS_T execute_cmd( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
9113 +{
9114 + const char *cmdStr;
9115 + VCOS_CMD_T *found_entry;
9116 +
9117 +#if 0
9118 + {
9119 + int arg_idx;
9120 +
9121 + vcos_cmd_printf( param, "%s: argc = %d", __func__, param->argc );
9122 + for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
9123 + {
9124 + vcos_cmd_printf( param, " argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
9125 + }
9126 + vcos_cmd_printf( param, "\n" );
9127 + }
9128 +#endif
9129 +
9130 + if ( param->argc <= 1 )
9131 + {
9132 + /* No command specified */
9133 +
9134 + vcos_cmd_error( param, "%s - no command specified", param->argv[0] );
9135 + return VCOS_EINVAL;
9136 + }
9137 +
9138 + /* argv[0] is the command/program that caused us to get invoked, so we strip
9139 + * it off.
9140 + */
9141 +
9142 + param->argc--;
9143 + param->argv++;
9144 + param->cmd_parent_entry = cmd_entry;
9145 +
9146 + /* Not the help command, scan for the command and execute it. */
9147 +
9148 + cmdStr = param->argv[0];
9149 +
9150 + if (( found_entry = find_cmd( cmd_entry, cmdStr )) != NULL )
9151 + {
9152 + if ( found_entry->sub_cmd_entry != NULL )
9153 + {
9154 + return execute_cmd( param, found_entry->sub_cmd_entry );
9155 + }
9156 +
9157 + param->cmd_entry = found_entry;
9158 + return found_entry->cmd_fn( param );
9159 + }
9160 +
9161 + /* Unrecognized command - check to see if it was the help command */
9162 +
9163 + if ( vcos_strcmp( cmdStr, cmd_help.name ) == 0 )
9164 + {
9165 + return help_cmd( param );
9166 + }
9167 +
9168 + vcos_cmd_error( param, "- unrecognized command: '%s'", cmdStr );
9169 + return VCOS_ENOENT;
9170 +}
9171 +
9172 +/*****************************************************************************
9173 +*
9174 +* Initializes the command line parser.
9175 +*
9176 +*****************************************************************************/
9177 +
9178 +static void vcos_cmd_init( void )
9179 +{
9180 + vcos_mutex_create( &cmd_globals.lock, "vcos_cmd" );
9181 +
9182 + cmd_globals.num_cmd_entries = 0;
9183 + cmd_globals.num_cmd_alloc = 0;
9184 + cmd_globals.cmd_entry = NULL;
9185 +}
9186 +
9187 +/*****************************************************************************
9188 +*
9189 +* Command line processor.
9190 +*
9191 +*****************************************************************************/
9192 +
9193 +VCOS_STATUS_T vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf )
9194 +{
9195 + VCOS_STATUS_T rc = VCOS_EINVAL;
9196 + VCOS_CMD_PARAM_T param;
9197 +
9198 + vcos_once( &cmd_globals.initialized, vcos_cmd_init );
9199 +
9200 + param.argc = argc;
9201 + param.argv = param.argv_orig = argv;
9202 +
9203 + param.use_log = 0;
9204 + param.result_size = result_size;
9205 + param.result_ptr = result_buf;
9206 + param.result_buf = result_buf;
9207 +
9208 + result_buf[0] = '\0';
9209 +
9210 + vcos_mutex_lock( &cmd_globals.lock );
9211 +
9212 + rc = execute_cmd( &param, cmd_globals.cmd_entry );
9213 +
9214 + if ( param.use_log )
9215 + {
9216 + cmd_log_results( &param );
9217 + vcos_snprintf( result_buf, result_size, "results logged" );
9218 + }
9219 + else
9220 + if ( cmd_globals.log_category != NULL )
9221 + {
9222 + if ( result_buf[0] != '\0' )
9223 + {
9224 + /* There is a partial line still buffered. */
9225 +
9226 + vcos_cmd_printf( &param, "\n" );
9227 + }
9228 + }
9229 +
9230 + vcos_mutex_unlock( &cmd_globals.lock );
9231 +
9232 + return rc;
9233 +}
9234 +
9235 +/*****************************************************************************
9236 +*
9237 +* Registers a command entry with the command line processor
9238 +*
9239 +*****************************************************************************/
9240 +
9241 +VCOS_STATUS_T vcos_cmd_register( VCOS_CMD_T *cmd_entry )
9242 +{
9243 + VCOS_STATUS_T rc;
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;
9248 +
9249 + vcos_once( &cmd_globals.initialized, vcos_cmd_init );
9250 +
9251 + vcos_assert( cmd_entry != NULL );
9252 + vcos_assert( cmd_entry->name != NULL );
9253 +
9254 + vcos_log_trace( "%s: cmd '%s'", __FUNCTION__, cmd_entry->name );
9255 +
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 );
9259 +
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.
9263 + */
9264 +
9265 + if ( vcos_cmd_log_category.name == NULL )
9266 + {
9267 + /*
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.
9271 + */
9272 +
9273 + vcos_log_set_level(&vcos_cmd_log_category, VCOS_LOG_INFO);
9274 + vcos_log_register("vcos_cmd", &vcos_cmd_log_category);
9275 +
9276 + /* We register a help command so that it shows up in the usage. */
9277 +
9278 + vcos_cmd_register( &cmd_help );
9279 +#ifdef HAVE_VCOS_VERSION
9280 + vcos_cmd_register( &cmd_version );
9281 +#endif
9282 + }
9283 +
9284 + vcos_mutex_lock( &cmd_globals.lock );
9285 +
9286 + if ( cmd_globals.num_cmd_entries >= cmd_globals.num_cmd_alloc )
9287 + {
9288 + if ( cmd_globals.num_cmd_alloc == 0 )
9289 + {
9290 + /* We haven't allocated a table yet */
9291 + }
9292 +
9293 + /* The number 8 is rather arbitrary. */
9294 +
9295 + new_num_cmd_alloc = cmd_globals.num_cmd_alloc + 8;
9296 +
9297 + /* The + 1 is to ensure that we always have a NULL entry at the end. */
9298 +
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 )
9301 + {
9302 + rc = VCOS_ENOMEM;
9303 + goto out;
9304 + }
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 );
9310 + }
9311 +
9312 + if ( cmd_globals.num_cmd_entries == 0 )
9313 + {
9314 + /* This is the first command being registered */
9315 +
9316 + cmd_globals.cmd_entry[0] = *cmd_entry;
9317 + }
9318 + else
9319 + {
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.
9322 + */
9323 +
9324 + for ( scan_entry = &cmd_globals.cmd_entry[cmd_globals.num_cmd_entries - 1];
9325 + scan_entry >= cmd_globals.cmd_entry; scan_entry-- )
9326 + {
9327 + if ( vcos_strcmp( cmd_entry->name, scan_entry->name ) > 0 )
9328 + {
9329 + /* We found an insertion point. */
9330 +
9331 + break;
9332 + }
9333 +
9334 + scan_entry[1] = scan_entry[0];
9335 + }
9336 + scan_entry[1] = *cmd_entry;
9337 + }
9338 + cmd_globals.num_cmd_entries++;
9339 +
9340 + rc = VCOS_SUCCESS;
9341 +
9342 +out:
9343 +
9344 + vcos_mutex_unlock( &cmd_globals.lock );
9345 + return rc;
9346 +}
9347 +
9348 +/*****************************************************************************
9349 +*
9350 +* Registers multiple commands.
9351 +*
9352 +*****************************************************************************/
9353 +
9354 +VCOS_STATUS_T vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry )
9355 +{
9356 + VCOS_STATUS_T status;
9357 +
9358 + while ( cmd_entry->name != NULL )
9359 + {
9360 + if (( status = vcos_cmd_register( cmd_entry )) != VCOS_SUCCESS )
9361 + {
9362 + return status;
9363 + }
9364 + cmd_entry++;
9365 + }
9366 + return VCOS_SUCCESS;
9367 +}
9368 +
9369 --- /dev/null
9370 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_common.h
9371 @@ -0,0 +1,76 @@
9372 +/*=============================================================================
9373 +Copyright (c) 2009 Broadcom Europe Limited.
9374 +All rights reserved.
9375 +
9376 +Project : vcfw
9377 +Module : chip driver
9378 +
9379 +FILE DESCRIPTION
9380 +VideoCore OS Abstraction Layer - common postamble code
9381 +=============================================================================*/
9382 +
9383 +/** \file
9384 + *
9385 + * Postamble code included by the platform-specific header files
9386 + */
9387 +
9388 +#define VCOS_THREAD_PRI_DEFAULT VCOS_THREAD_PRI_NORMAL
9389 +
9390 +#if !defined(VCOS_THREAD_PRI_INCREASE)
9391 +#error Which way to thread priorities go?
9392 +#endif
9393 +
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)
9398 +#else
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)
9402 +#endif
9403 +
9404 +/* Convenience for Brits: */
9405 +#define VCOS_APPLICATION_INITIALISE VCOS_APPLICATION_INITIALIZE
9406 +
9407 +/*
9408 + * Check for constant definitions
9409 + */
9410 +#ifndef VCOS_TICKS_PER_SECOND
9411 +#error VCOS_TICKS_PER_SECOND not defined
9412 +#endif
9413 +
9414 +#if !defined(VCOS_THREAD_PRI_MIN) || !defined(VCOS_THREAD_PRI_MAX)
9415 +#error Priority range not defined
9416 +#endif
9417 +
9418 +#if !defined(VCOS_THREAD_PRI_HIGHEST) || !defined(VCOS_THREAD_PRI_LOWEST) || !defined(VCOS_THREAD_PRI_NORMAL)
9419 +#error Priority ordering not defined
9420 +#endif
9421 +
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.
9424 +#endif
9425 +
9426 +#if (_VCOS_AFFINITY_CPU0|_VCOS_AFFINITY_CPU1) & (~_VCOS_AFFINITY_MASK)
9427 +#error _VCOS_AFFINITY_CPUxxx values are not consistent with _VCOS_AFFINITY_MASK
9428 +#endif
9429 +
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.
9433 + */
9434 +#define VCOS_QUEUE_APPEND_TAIL(list, item) {\
9435 + (item)->next = NULL;\
9436 + if (!(list)->head) {\
9437 + (list)->head = (list)->tail = (item); \
9438 + } else {\
9439 + (list)->tail->next = (item); \
9440 + (list)->tail = (item); \
9441 + } \
9442 +}
9443 +
9444 +#ifndef VCOS_HAVE_TIMER
9445 +VCOSPRE_ void VCOSPOST_ vcos_timer_init(void);
9446 +#endif
9447 +
9448 --- /dev/null
9449 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_blockpool.h
9450 @@ -0,0 +1,260 @@
9451 +/*=============================================================================
9452 +Copyright (c) 2011 Broadcom Europe Limited.
9453 +All rights reserved.
9454 +
9455 +Project : vcfw
9456 +Module : chip driver
9457 +
9458 +FILE DESCRIPTION
9459 +VideoCore OS Abstraction Layer - event flags implemented via a semaphore
9460 +=============================================================================*/
9461 +
9462 +#ifndef VCOS_GENERIC_BLOCKPOOL_H
9463 +#define VCOS_GENERIC_BLOCKPOOL_H
9464 +
9465 +/**
9466 + * \file
9467 + *
9468 + * This provides a generic, thread safe implementation of a VCOS block pool
9469 + * fixed size memory allocator.
9470 + */
9471 +
9472 +#ifdef __cplusplus
9473 +extern "C" {
9474 +#endif
9475 +
9476 +#include "interface/vcos/vcos_types.h"
9477 +
9478 +/** Bits 0 to (VCOS_BLOCKPOOL_SUBPOOL_BITS - 1) are used to store the
9479 + * subpool id. */
9480 +#define VCOS_BLOCKPOOL_SUBPOOL_BITS 3
9481 +#define VCOS_BLOCKPOOL_MAX_SUBPOOLS (1 << VCOS_BLOCKPOOL_SUBPOOL_BITS)
9482 +
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
9487 + */
9488 +#define INDEX_OFFSET 1
9489 +
9490 +#define VCOS_BLOCKPOOL_HANDLE_GET_INDEX(h) \
9491 + (((h) >> VCOS_BLOCKPOOL_SUBPOOL_BITS) - INDEX_OFFSET)
9492 +
9493 +#define VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(h) \
9494 + ((h) & ((1 << VCOS_BLOCKPOOL_SUBPOOL_BITS) - 1))
9495 +
9496 +#define VCOS_BLOCKPOOL_HANDLE_CREATE(i,s) \
9497 + ((((i) + INDEX_OFFSET) << VCOS_BLOCKPOOL_SUBPOOL_BITS) | (s))
9498 +
9499 +#define VCOS_BLOCKPOOL_INVALID_HANDLE 0
9500 +
9501 +typedef struct VCOS_BLOCKPOOL_HEADER_TAG
9502 +{
9503 + /* Blocks either refer to to the pool if they are allocated
9504 + * or the free list if they are available.
9505 + */
9506 + union {
9507 + struct VCOS_BLOCKPOOL_HEADER_TAG *next;
9508 + struct VCOS_BLOCKPOOL_SUBPOOL_TAG* subpool;
9509 + } owner;
9510 +} VCOS_BLOCKPOOL_HEADER_T;
9511 +
9512 +typedef struct VCOS_BLOCKPOOL_SUBPOOL_TAG
9513 +{
9514 + /** VCOS_BLOCKPOOL_SUBPOOL_MAGIC */
9515 + uint32_t magic;
9516 + VCOS_BLOCKPOOL_HEADER_T* free_list;
9517 + /* The start of the pool memory */
9518 + void *mem;
9519 + /* Address of the first block header */
9520 + void *start;
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 */
9528 + uint32_t flags;
9529 +} VCOS_BLOCKPOOL_SUBPOOL_T;
9530 +
9531 +typedef struct VCOS_BLOCKPOOL_TAG
9532 +{
9533 + /** VCOS_BLOCKPOOL_MAGIC */
9534 + uint32_t 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 */
9542 + const char *name;
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;
9553 +
9554 +#define VCOS_BLOCKPOOL_ROUND_UP(x,s) (((x) + ((s) - 1)) & ~((s) - 1))
9555 +/**
9556 + * Calculates the size in bytes required for a block pool containing
9557 + * num_blocks of size block_size plus any overheads.
9558 + *
9559 + * The block pool header (VCOS_BLOCKPOOL_T) is allocated separately
9560 + *
9561 + * Overheads:
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.
9566 + */
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*))
9570 +
9571 +/**
9572 + * Sanity check to verify whether a handle is potentially a blockpool handle
9573 + * when the pool pointer is not available.
9574 + *
9575 + * If the pool pointer is availabe use vcos_blockpool_elem_to_handle instead.
9576 + *
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.
9580 + */
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))
9584 +
9585 +VCOSPRE_
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);
9589 +
9590 +VCOSPRE_
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);
9594 +
9595 +VCOSPRE_
9596 + VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
9597 + VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks);
9598 +
9599 +VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool);
9600 +
9601 +VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool);
9602 +
9603 +VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_free(void *block);
9604 +
9605 +VCOSPRE_
9606 + VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_available_count(
9607 + VCOS_BLOCKPOOL_T *pool);
9608 +
9609 +VCOSPRE_
9610 + VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_used_count(
9611 + VCOS_BLOCKPOOL_T *pool);
9612 +
9613 +VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool);
9614 +
9615 +VCOSPRE_ uint32_t VCOSPOST_ vcos_generic_blockpool_elem_to_handle(void *block);
9616 +
9617 +VCOSPRE_ void VCOSPOST_
9618 + *vcos_generic_blockpool_elem_from_handle(
9619 + VCOS_BLOCKPOOL_T *pool, uint32_t handle);
9620 +
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)
9625 +
9626 +VCOS_INLINE_IMPL
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)
9630 +{
9631 + return vcos_generic_blockpool_init(pool, num_blocks, block_size,
9632 + start, pool_size, name);
9633 +}
9634 +
9635 +VCOS_INLINE_IMPL
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)
9638 +{
9639 + return vcos_generic_blockpool_create_on_heap(
9640 + pool, num_blocks, block_size, name);
9641 +}
9642 +
9643 +VCOS_INLINE_IMPL
9644 + VCOS_STATUS_T VCOSPOST_ vcos_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
9645 + VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks)
9646 +{
9647 + return vcos_generic_blockpool_extend(pool, num_extensions, num_blocks);
9648 +}
9649 +
9650 +VCOS_INLINE_IMPL
9651 +void *vcos_blockpool_alloc(VCOS_BLOCKPOOL_T *pool)
9652 +{
9653 + return vcos_generic_blockpool_alloc(pool);
9654 +}
9655 +
9656 +VCOS_INLINE_IMPL
9657 +void *vcos_blockpool_calloc(VCOS_BLOCKPOOL_T *pool)
9658 +{
9659 + return vcos_generic_blockpool_calloc(pool);
9660 +}
9661 +
9662 +VCOS_INLINE_IMPL
9663 +void vcos_blockpool_free(void *block)
9664 +{
9665 + vcos_generic_blockpool_free(block);
9666 +}
9667 +
9668 +VCOS_INLINE_IMPL
9669 +VCOS_UNSIGNED vcos_blockpool_available_count(VCOS_BLOCKPOOL_T *pool)
9670 +{
9671 + return vcos_generic_blockpool_available_count(pool);
9672 +}
9673 +
9674 +VCOS_INLINE_IMPL
9675 +VCOS_UNSIGNED vcos_blockpool_used_count(VCOS_BLOCKPOOL_T *pool)
9676 +{
9677 + return vcos_generic_blockpool_used_count(pool);
9678 +}
9679 +
9680 +VCOS_INLINE_IMPL
9681 +void vcos_blockpool_delete(VCOS_BLOCKPOOL_T *pool)
9682 +{
9683 + vcos_generic_blockpool_delete(pool);
9684 +}
9685 +
9686 +VCOS_INLINE_IMPL
9687 +uint32_t vcos_blockpool_elem_to_handle(void *block)
9688 +{
9689 + return vcos_generic_blockpool_elem_to_handle(block);
9690 +}
9691 +
9692 +VCOS_INLINE_IMPL
9693 +void *vcos_blockpool_elem_from_handle(VCOS_BLOCKPOOL_T *pool, uint32_t handle)
9694 +{
9695 + return vcos_generic_blockpool_elem_from_handle(pool, handle);
9696 +}
9697 +
9698 +VCOS_INLINE_IMPL
9699 +uint32_t vcos_blockpool_is_valid_elem(VCOS_BLOCKPOOL_T *pool, const void *block)
9700 +{
9701 + return vcos_generic_blockpool_is_valid_elem(pool, block);
9702 +}
9703 +#endif /* VCOS_INLINE_BODIES */
9704 +
9705 +
9706 +#ifdef __cplusplus
9707 +}
9708 +#endif
9709 +#endif /* VCOS_GENERIC_BLOCKPOOL_H */
9710 +
9711 --- /dev/null
9712 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.c
9713 @@ -0,0 +1,297 @@
9714 +/*=============================================================================
9715 +Copyright (c) 2009 Broadcom Europe Limited.
9716 +All rights reserved.
9717 +
9718 +FILE DESCRIPTION
9719 +VideoCore OS Abstraction Layer - event flags implemented via mutexes
9720 +=============================================================================*/
9721 +
9722 +#include "interface/vcos/vcos.h"
9723 +#include "interface/vcos/generic/vcos_generic_event_flags.h"
9724 +
9725 +#include <stddef.h>
9726 +
9727 +/** A structure created by a thread that waits on the event flags
9728 + * for a particular combination of flags to arrive.
9729 + */
9730 +typedef struct VCOS_EVENT_WAITER_T
9731 +{
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;
9740 +
9741 +#ifndef NDEBUG
9742 +static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags);
9743 +#endif
9744 +static void event_flags_timer_expired(void *cxt);
9745 +
9746 +VCOS_STATUS_T vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name)
9747 +{
9748 + VCOS_STATUS_T rc;
9749 + if ((rc=vcos_mutex_create(&flags->lock, name)) != VCOS_SUCCESS)
9750 + {
9751 + return rc;
9752 + }
9753 +
9754 + flags->events = 0;
9755 + flags->waiters.head = flags->waiters.tail = 0;
9756 + return rc;
9757 +}
9758 +
9759 +void vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
9760 + VCOS_UNSIGNED bitmask,
9761 + VCOS_OPTION op)
9762 +{
9763 + vcos_assert(flags);
9764 + vcos_mutex_lock(&flags->lock);
9765 + if (op == VCOS_OR)
9766 + {
9767 + flags->events |= bitmask;
9768 + }
9769 + else if (op == VCOS_AND)
9770 + {
9771 + flags->events &= bitmask;
9772 + }
9773 + else
9774 + {
9775 + vcos_assert(0);
9776 + }
9777 +
9778 + /* Now wake up any threads that have now become signalled. */
9779 + if (flags->waiters.head != NULL)
9780 + {
9781 + VCOS_UNSIGNED consumed_events = 0;
9782 + VCOS_EVENT_WAITER_T **pcurrent_waiter = &flags->waiters.head;
9783 + VCOS_EVENT_WAITER_T *prev_waiter = NULL;
9784 +
9785 + /* Walk the chain of tasks suspend on this event flag group to determine
9786 + * if any of their requests can be satisfied.
9787 + */
9788 + while ((*pcurrent_waiter) != NULL)
9789 + {
9790 + VCOS_EVENT_WAITER_T *curr_waiter = *pcurrent_waiter;
9791 +
9792 + /* Determine if this request has been satisfied */
9793 +
9794 + /* First, find the event flags in common. */
9795 + VCOS_UNSIGNED waiter_satisfied = flags->events & curr_waiter->requested_events;
9796 +
9797 + /* Second, determine if all the event flags must match */
9798 + if (curr_waiter->op & VCOS_AND)
9799 + {
9800 + /* All requested events must be present */
9801 + waiter_satisfied = (waiter_satisfied == curr_waiter->requested_events);
9802 + }
9803 +
9804 + /* Wake this one up? */
9805 + if (waiter_satisfied)
9806 + {
9807 +
9808 + if (curr_waiter->op & VCOS_CONSUME)
9809 + {
9810 + consumed_events |= curr_waiter->requested_events;
9811 + }
9812 +
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;
9817 +
9818 + vcos_assert(waiter_list_valid(flags));
9819 +
9820 + curr_waiter->return_status = VCOS_SUCCESS;
9821 + curr_waiter->actual_events = flags->events;
9822 +
9823 + _vcos_thread_sem_post(curr_waiter->thread);
9824 + }
9825 + else
9826 + {
9827 + /* move to next element in the list */
9828 + prev_waiter = *pcurrent_waiter;
9829 + pcurrent_waiter = &(curr_waiter->next);
9830 + }
9831 + }
9832 +
9833 + flags->events &= ~consumed_events;
9834 +
9835 + }
9836 +
9837 + vcos_mutex_unlock(&flags->lock);
9838 +}
9839 +
9840 +void vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *flags)
9841 +{
9842 + vcos_mutex_delete(&flags->lock);
9843 +}
9844 +
9845 +extern VCOS_STATUS_T vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
9846 + VCOS_UNSIGNED bitmask,
9847 + VCOS_OPTION op,
9848 + VCOS_UNSIGNED suspend,
9849 + VCOS_UNSIGNED *retrieved_bits)
9850 +{
9851 + VCOS_EVENT_WAITER_T waitreq;
9852 + VCOS_STATUS_T rc = VCOS_EAGAIN;
9853 + int satisfied = 0;
9854 +
9855 + vcos_assert(flags);
9856 +
9857 + /* default retrieved bits to 0 */
9858 + *retrieved_bits = 0;
9859 +
9860 + vcos_mutex_lock(&flags->lock);
9861 + switch (op & VCOS_EVENT_FLAG_OP_MASK)
9862 + {
9863 + case VCOS_AND:
9864 + if ((flags->events & bitmask) == bitmask)
9865 + {
9866 + *retrieved_bits = flags->events;
9867 + rc = VCOS_SUCCESS;
9868 + satisfied = 1;
9869 + if (op & VCOS_CONSUME)
9870 + flags->events &= ~bitmask;
9871 + }
9872 + break;
9873 +
9874 + case VCOS_OR:
9875 + if (flags->events & bitmask)
9876 + {
9877 + *retrieved_bits = flags->events;
9878 + rc = VCOS_SUCCESS;
9879 + satisfied = 1;
9880 + if (op & VCOS_CONSUME)
9881 + flags->events &= ~bitmask;
9882 + }
9883 + break;
9884 +
9885 + default:
9886 + vcos_assert(0);
9887 + rc = VCOS_EINVAL;
9888 + break;
9889 + }
9890 +
9891 + if (!satisfied && suspend)
9892 + {
9893 + /* Have to go to sleep.
9894 + *
9895 + * Append to tail so we get FIFO ordering.
9896 + */
9897 + waitreq.requested_events = bitmask;
9898 + waitreq.op = op;
9899 + waitreq.return_status = VCOS_EAGAIN;
9900 + waitreq.flags = flags;
9901 + waitreq.actual_events = 0;
9902 + waitreq.thread = vcos_thread_current();
9903 + waitreq.next = 0;
9904 + vcos_assert(waitreq.thread != (VCOS_THREAD_T*)-1);
9905 + VCOS_QUEUE_APPEND_TAIL(&flags->waiters, &waitreq);
9906 +
9907 + if (suspend != (VCOS_UNSIGNED)-1)
9908 + _vcos_task_timer_set(event_flags_timer_expired, &waitreq, suspend);
9909 +
9910 + vcos_mutex_unlock(&flags->lock);
9911 + /* go to sleep and wait to be signalled or timeout */
9912 +
9913 + _vcos_thread_sem_wait();
9914 +
9915 + *retrieved_bits = waitreq.actual_events;
9916 + rc = waitreq.return_status;
9917 +
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.
9921 + */
9922 + if (suspend != (VCOS_UNSIGNED)-1)
9923 + _vcos_task_timer_cancel();
9924 + }
9925 + else
9926 + {
9927 + vcos_mutex_unlock(&flags->lock);
9928 + }
9929 +
9930 + return rc;
9931 +}
9932 +
9933 +
9934 +/** Called when a get call times out. Remove this thread's
9935 + * entry from the waiting queue, then resume the thread.
9936 + */
9937 +static void event_flags_timer_expired(void *cxt)
9938 +{
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;
9944 +
9945 + vcos_assert(flags);
9946 +
9947 + vcos_mutex_lock(&flags->lock);
9948 +
9949 + /* walk the list of waiting threads on this event group, and remove
9950 + * the one that has expired.
9951 + *
9952 + * FIXME: could use doubly-linked list if lots of threads are found
9953 + * to be waiting on a single event flag instance.
9954 + */
9955 + plist = &flags->waiters.head;
9956 + while (*plist != NULL)
9957 + {
9958 + if (*plist == waitreq)
9959 + {
9960 + int at_end;
9961 + /* found it */
9962 + thread = (*plist)->thread;
9963 + at_end = ((*plist)->next == NULL);
9964 +
9965 + /* link past */
9966 + *plist = (*plist)->next;
9967 + if (at_end)
9968 + flags->waiters.tail = prev;
9969 +
9970 + break;
9971 + }
9972 + prev = *plist;
9973 + plist = &(*plist)->next;
9974 + }
9975 + vcos_assert(waiter_list_valid(flags));
9976 +
9977 + vcos_mutex_unlock(&flags->lock);
9978 +
9979 + if (thread)
9980 + {
9981 + _vcos_thread_sem_post(thread);
9982 + }
9983 +}
9984 +
9985 +#ifndef NDEBUG
9986 +
9987 +static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags)
9988 +{
9989 + int valid;
9990 + /* Either both head and tail are NULL, or neither are NULL */
9991 + if (flags->waiters.head == NULL)
9992 + {
9993 + valid = (flags->waiters.tail == NULL);
9994 + }
9995 + else
9996 + {
9997 + valid = (flags->waiters.tail != NULL);
9998 + }
9999 +
10000 + /* If head and tail point at the same non-NULL element, then there
10001 + * is only one element in the list.
10002 + */
10003 + if (flags->waiters.head && (flags->waiters.head == flags->waiters.tail))
10004 + {
10005 + valid = (flags->waiters.head->next == NULL);
10006 + }
10007 + return valid;
10008 +}
10009 +
10010 +#endif
10011 --- /dev/null
10012 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.h
10013 @@ -0,0 +1,104 @@
10014 +/*=============================================================================
10015 +Copyright (c) 2009 Broadcom Europe Limited.
10016 +All rights reserved.
10017 +
10018 +FILE DESCRIPTION
10019 +VideoCore OS Abstraction Layer - event flags implemented via a semaphore
10020 +=============================================================================*/
10021 +
10022 +#ifndef VCOS_GENERIC_EVENT_FLAGS_H
10023 +#define VCOS_GENERIC_EVENT_FLAGS_H
10024 +
10025 +#ifdef __cplusplus
10026 +extern "C" {
10027 +#endif
10028 +
10029 +#include "interface/vcos/vcos_types.h"
10030 +
10031 +/**
10032 + * \file
10033 + *
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
10036 + * thread).
10037 + *
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'.
10040 + *
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.
10045 + *
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.
10050 + */
10051 +
10052 +struct VCOS_EVENT_WAITER_T;
10053 +
10054 +typedef struct VCOS_EVENT_FLAGS_T
10055 +{
10056 + VCOS_UNSIGNED events; /**< Events currently set */
10057 + VCOS_MUTEX_T lock; /**< Serialize access */
10058 + struct
10059 + {
10060 + struct VCOS_EVENT_WAITER_T *head; /**< List of threads waiting */
10061 + struct VCOS_EVENT_WAITER_T *tail; /**< List of threads waiting */
10062 + } waiters;
10063 +} VCOS_EVENT_FLAGS_T;
10064 +
10065 +#define VCOS_OR 1
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)
10071 +
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,
10075 + VCOS_OPTION op);
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,
10079 + VCOS_OPTION op,
10080 + VCOS_UNSIGNED suspend,
10081 + VCOS_UNSIGNED *retrieved_events);
10082 +
10083 +#ifdef VCOS_INLINE_BODIES
10084 +
10085 +VCOS_INLINE_IMPL
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);
10088 +}
10089 +
10090 +VCOS_INLINE_IMPL
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);
10095 +}
10096 +
10097 +VCOS_INLINE_IMPL
10098 +void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *f) {
10099 + vcos_generic_event_flags_delete(f);
10100 +}
10101 +
10102 +VCOS_INLINE_IMPL
10103 +VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
10104 + VCOS_UNSIGNED requested_events,
10105 + VCOS_OPTION op,
10106 + VCOS_UNSIGNED suspend,
10107 + VCOS_UNSIGNED *retrieved_events) {
10108 + return vcos_generic_event_flags_get(flags, requested_events, op, suspend, retrieved_events);
10109 +}
10110 +
10111 +#endif /* VCOS_INLINE_BODIES */
10112 +
10113 +#ifdef __cplusplus
10114 +}
10115 +#endif
10116 +#endif
10117 +
10118 --- /dev/null
10119 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_named_sem.h
10120 @@ -0,0 +1,81 @@
10121 +/*=============================================================================
10122 +Copyright (c) 2009 Broadcom Europe Limited.
10123 +All rights reserved.
10124 +
10125 +Project : vcfw
10126 +Module : chip driver
10127 +
10128 +FILE DESCRIPTION
10129 +VideoCore OS Abstraction Layer - named semaphores
10130 +=============================================================================*/
10131 +
10132 +#ifndef VCOS_GENERIC_NAMED_SEM_H
10133 +#define VCOS_GENERIC_NAMED_SEM_H
10134 +
10135 +#ifdef __cplusplus
10136 +extern "C" {
10137 +#endif
10138 +
10139 +#include "interface/vcos/vcos_types.h"
10140 +
10141 +/**
10142 + * \file
10143 + *
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.
10147 + *
10148 + */
10149 +
10150 +#define VCOS_NAMED_SEMAPHORE_NAMELEN 64
10151 +
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.
10156 + */
10157 +typedef struct VCOS_NAMED_SEMAPHORE_T
10158 +{
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;
10162 +
10163 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_
10164 +vcos_generic_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
10165 +
10166 +VCOSPRE_ void VCOSPOST_ vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem);
10167 +
10168 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ _vcos_named_semaphore_init(void);
10169 +VCOSPRE_ void VCOSPOST_ _vcos_named_semaphore_deinit(void);
10170 +
10171 +#if defined(VCOS_INLINE_BODIES)
10172 +
10173 +VCOS_INLINE_IMPL
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);
10176 +}
10177 +
10178 +VCOS_INLINE_IMPL
10179 +void vcos_named_semaphore_wait(VCOS_NAMED_SEMAPHORE_T *sem) {
10180 + vcos_semaphore_wait(sem->sem);
10181 +}
10182 +
10183 +VCOS_INLINE_IMPL
10184 +VCOS_STATUS_T vcos_named_semaphore_trywait(VCOS_NAMED_SEMAPHORE_T *sem) {
10185 + return vcos_semaphore_trywait(sem->sem);
10186 +}
10187 +
10188 +VCOS_INLINE_IMPL
10189 +void vcos_named_semaphore_post(VCOS_NAMED_SEMAPHORE_T *sem) {
10190 + vcos_semaphore_post(sem->sem);
10191 +}
10192 +
10193 +
10194 +#endif
10195 +
10196 +#ifdef __cplusplus
10197 +}
10198 +#endif
10199 +#endif
10200 +
10201 +
10202 --- /dev/null
10203 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_quickslow_mutex.h
10204 @@ -0,0 +1,75 @@
10205 +/*=============================================================================
10206 +Copyright (c) 2009 Broadcom Europe Limited.
10207 +All rights reserved.
10208 +
10209 +Project : vcfw
10210 +Module : chip driver
10211 +
10212 +FILE DESCRIPTION
10213 +VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
10214 +=============================================================================*/
10215 +
10216 +#ifndef VCOS_GENERIC_QUICKSLOW_MUTEX_H
10217 +#define VCOS_GENERIC_QUICKSLOW_MUTEX_H
10218 +
10219 +#ifdef __cplusplus
10220 +extern "C" {
10221 +#endif
10222 +
10223 +#include "interface/vcos/vcos_types.h"
10224 +
10225 +/**
10226 + * \file
10227 + *
10228 + * Quickslow Mutexes implemented as regular ones (i.e. quick and slow modes are the same).
10229 + *
10230 + */
10231 +
10232 +typedef VCOS_MUTEX_T VCOS_QUICKSLOW_MUTEX_T;
10233 +
10234 +#if defined(VCOS_INLINE_BODIES)
10235 +VCOS_INLINE_IMPL
10236 +VCOS_STATUS_T vcos_quickslow_mutex_create(VCOS_QUICKSLOW_MUTEX_T *m, const char *name)
10237 +{
10238 + return vcos_mutex_create(m, name);
10239 +}
10240 +
10241 +VCOS_INLINE_IMPL
10242 +void vcos_quickslow_mutex_delete(VCOS_QUICKSLOW_MUTEX_T *m)
10243 +{
10244 + vcos_mutex_delete(m);
10245 +}
10246 +
10247 +VCOS_INLINE_IMPL
10248 +void vcos_quickslow_mutex_lock(VCOS_QUICKSLOW_MUTEX_T *m)
10249 +{
10250 + while (vcos_mutex_lock(m) == VCOS_EAGAIN);
10251 +}
10252 +
10253 +VCOS_INLINE_IMPL
10254 +void vcos_quickslow_mutex_unlock(VCOS_QUICKSLOW_MUTEX_T *m)
10255 +{
10256 + vcos_mutex_unlock(m);
10257 +}
10258 +
10259 +VCOS_INLINE_IMPL
10260 +void vcos_quickslow_mutex_lock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
10261 +{
10262 + while (vcos_mutex_lock(m) == VCOS_EAGAIN);
10263 +}
10264 +
10265 +VCOS_INLINE_IMPL
10266 +void vcos_quickslow_mutex_unlock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
10267 +{
10268 + vcos_mutex_unlock(m);
10269 +}
10270 +
10271 +#endif
10272 +
10273 +
10274 +#ifdef __cplusplus
10275 +}
10276 +#endif
10277 +#endif
10278 +
10279 +
10280 --- /dev/null
10281 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_reentrant_mtx.h
10282 @@ -0,0 +1,75 @@
10283 +/*=============================================================================
10284 +Copyright (c) 2009 Broadcom Europe Limited.
10285 +All rights reserved.
10286 +
10287 +Project : vcfw
10288 +Module : chip driver
10289 +
10290 +FILE DESCRIPTION
10291 +VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
10292 +=============================================================================*/
10293 +
10294 +#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
10295 +#define VCOS_GENERIC_REENTRANT_MUTEX_H
10296 +
10297 +#ifdef __cplusplus
10298 +extern "C" {
10299 +#endif
10300 +
10301 +#include "interface/vcos/vcos_types.h"
10302 +
10303 +/**
10304 + * \file
10305 + *
10306 + * Reentrant Mutexes from regular ones.
10307 + *
10308 + */
10309 +
10310 +typedef struct VCOS_REENTRANT_MUTEX_T
10311 +{
10312 + VCOS_MUTEX_T mutex;
10313 + VCOS_THREAD_T *owner;
10314 + unsigned count;
10315 +} VCOS_REENTRANT_MUTEX_T;
10316 +
10317 +/* Extern definitions of functions that do the actual work */
10318 +
10319 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name);
10320 +
10321 +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m);
10322 +
10323 +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m);
10324 +
10325 +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m);
10326 +
10327 +/* Inline forwarding functions */
10328 +
10329 +#if defined(VCOS_INLINE_BODIES)
10330 +
10331 +VCOS_INLINE_IMPL
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);
10334 +}
10335 +
10336 +VCOS_INLINE_IMPL
10337 +void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
10338 + vcos_generic_reentrant_mutex_delete(m);
10339 +}
10340 +
10341 +VCOS_INLINE_IMPL
10342 +void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
10343 + vcos_generic_reentrant_mutex_lock(m);
10344 +}
10345 +
10346 +VCOS_INLINE_IMPL
10347 +void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
10348 + vcos_generic_reentrant_mutex_unlock(m);
10349 +}
10350 +#endif
10351 +
10352 +#ifdef __cplusplus
10353 +}
10354 +#endif
10355 +#endif
10356 +
10357 +
10358 --- /dev/null
10359 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_tls.h
10360 @@ -0,0 +1,144 @@
10361 +/*=============================================================================
10362 +Copyright (c) 2009 Broadcom Europe Limited.
10363 +All rights reserved.
10364 +
10365 +Project : vcfw
10366 +Module : chip driver
10367 +
10368 +FILE DESCRIPTION
10369 +VideoCore OS Abstraction Layer - generic thread local storage
10370 +=============================================================================*/
10371 +
10372 +#ifndef VCOS_GENERIC_TLS_H
10373 +#define VCOS_GENERIC_TLS_H
10374 +
10375 +#ifdef __cplusplus
10376 +extern "C" {
10377 +#endif
10378 +
10379 +#include "interface/vcos/vcos_types.h"
10380 +
10381 +/**
10382 + * \file
10383 + *
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.
10387 + *
10388 + *
10389 + * Each thread that wants to join in this scheme needs to call
10390 + * vcos_tls_thread_register().
10391 + *
10392 + * The platform needs to support the macros/functions
10393 + * _vcos_tls_thread_ptr_set() and _vcos_tls_thread_ptr_get().
10394 + */
10395 +
10396 +#ifndef VCOS_WANT_TLS_EMULATION
10397 +#error Should not be included unless TLS emulation is defined
10398 +#endif
10399 +
10400 +/** Number of slots to reserve per thread. This results in an overhead
10401 + * of this many words per thread.
10402 + */
10403 +#define VCOS_TLS_MAX_SLOTS 4
10404 +
10405 +/** TLS key. Allocating one of these reserves the client one of the
10406 + * available slots.
10407 + */
10408 +typedef VCOS_UNSIGNED VCOS_TLS_KEY_T;
10409 +
10410 +/** TLS per-thread structure. Each thread gets one of these
10411 + * if TLS emulation (rather than native TLS support) is
10412 + * being used.
10413 + */
10414 +typedef struct VCOS_TLS_THREAD_T
10415 +{
10416 + void *slots[VCOS_TLS_MAX_SLOTS];
10417 +} VCOS_TLS_THREAD_T;
10418 +
10419 +/*
10420 + * Internal APIs
10421 + */
10422 +
10423 +/** Register this thread's TLS storage area. */
10424 +VCOSPRE_ void VCOSPOST_ vcos_tls_thread_register(VCOS_TLS_THREAD_T *);
10425 +
10426 +/** Create a new TLS key */
10427 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_tls_create(VCOS_TLS_KEY_T *key);
10428 +
10429 +/** Delete a TLS key */
10430 +VCOSPRE_ void VCOSPOST_ vcos_generic_tls_delete(VCOS_TLS_KEY_T tls);
10431 +
10432 +/** Initialise the TLS library */
10433 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_tls_init(void);
10434 +
10435 +/** Deinitialise the TLS library */
10436 +VCOSPRE_ void VCOSPOST_ vcos_tls_deinit(void);
10437 +
10438 +#if defined(VCOS_INLINE_BODIES)
10439 +
10440 +#undef VCOS_ASSERT_LOGGING_DISABLE
10441 +#define VCOS_ASSERT_LOGGING_DISABLE 1
10442 +
10443 +/*
10444 + * Implementations of public API functions
10445 + */
10446 +
10447 +/** Set the given value. Since everything is per-thread, there is no need
10448 + * for any locking.
10449 + */
10450 +VCOS_INLINE_IMPL
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)
10455 + {
10456 + tlsdata->slots[tls] = v;
10457 + return VCOS_SUCCESS;
10458 + }
10459 + else
10460 + {
10461 + vcos_assert(0);
10462 + return VCOS_EINVAL;
10463 + }
10464 +}
10465 +
10466 +/** Get the given value. No locking required.
10467 + */
10468 +VCOS_INLINE_IMPL
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)
10473 + {
10474 + return tlsdata->slots[tls];
10475 + }
10476 + else
10477 + {
10478 + vcos_assert(0);
10479 + return NULL;
10480 + }
10481 +}
10482 +
10483 +VCOS_INLINE_IMPL
10484 +VCOS_STATUS_T vcos_tls_create(VCOS_TLS_KEY_T *key) {
10485 + return vcos_generic_tls_create(key);
10486 +}
10487 +
10488 +VCOS_INLINE_IMPL
10489 +void vcos_tls_delete(VCOS_TLS_KEY_T tls) {
10490 + vcos_generic_tls_delete(tls);
10491 +}
10492 +
10493 +#undef VCOS_ASSERT_LOGGING_DISABLE
10494 +#define VCOS_ASSERT_LOGGING_DISABLE 0
10495 +
10496 +#endif /* VCOS_INLINE_BODIES */
10497 +
10498 +#ifdef __cplusplus
10499 +}
10500 +#endif
10501 +
10502 +#endif
10503 +
10504 +
10505 --- /dev/null
10506 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_joinable_thread_from_plain.h
10507 @@ -0,0 +1,202 @@
10508 +/*=============================================================================
10509 +Copyright (c) 2009 Broadcom Europe Limited.
10510 +All rights reserved.
10511 +
10512 +Module : vcos
10513 +
10514 +FILE DESCRIPTION
10515 +VideoCore OS Abstraction Layer - implementation: joinable thread from plain
10516 +=============================================================================*/
10517 +
10518 +/** \file
10519 + *
10520 + * Header file for platforms creating the joinable thread from a lowlevel
10521 + * thread.
10522 + *
10523 + * In addition to the actual thread, the following are also created:
10524 + *
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)
10528 + */
10529 +
10530 +#ifndef VCOS_JOINABLE_THREAD_FROM_PLAIN_H
10531 +#define VCOS_JOINABLE_THREAD_FROM_PLAIN_H
10532 +
10533 +#ifdef __cplusplus
10534 +extern "C" {
10535 +#endif
10536 +
10537 +#include "interface/vcos/vcos_semaphore.h"
10538 +#include "interface/vcos/vcos_lowlevel_thread.h"
10539 +#include "interface/vcos/vcos_timer.h"
10540 +
10541 +#ifdef VCOS_WANT_TLS_EMULATION
10542 +#include "interface/vcos/generic/vcos_generic_tls.h"
10543 +#endif
10544 +
10545 +#define VCOS_THREAD_MAGIC 0x56436a74
10546 +
10547 +#define VCOS_THREAD_VALID(t) (t->magic == VCOS_THREAD_MAGIC)
10548 +#define VCOS_HAVE_THREAD_AT_EXIT 1
10549 +
10550 +/** Thread attribute structure. Clients should not manipulate this directly, but
10551 + * should instead use the provided functions.
10552 + */
10553 +typedef struct VCOS_THREAD_ATTR_T
10554 +{
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;
10563 +
10564 +/** Each thread gets a timer, which is for internal VCOS use.
10565 + */
10566 +typedef struct _VCOS_THREAD_TIMER_T
10567 +{
10568 + VCOS_TIMER_T timer;
10569 + void (*pfn)(void *);
10570 + void *cxt;
10571 +} _VCOS_THREAD_TIMER_T;
10572 +
10573 +typedef void (*VCOS_THREAD_EXIT_HANDLER_T)(void *);
10574 +/** Called at thread exit.
10575 + */
10576 +typedef struct VCOS_THREAD_EXIT_T
10577 +{
10578 + VCOS_THREAD_EXIT_HANDLER_T pfn;
10579 + void *cxt;
10580 +} VCOS_THREAD_EXIT_T;
10581 +#define VCOS_MAX_EXIT_HANDLERS 8
10582 +
10583 +/* The name field isn't used for anything, so we can just copy the
10584 + * the pointer. Nucleus makes its own copy.
10585 + */
10586 +typedef const char * VCOS_LLTHREAD_T_NAME;
10587 +#define _VCOS_LLTHREAD_NAME(dst,src) (dst)=(src)
10588 +
10589 +/*
10590 + * Simulated TLS support
10591 + */
10592 +
10593 +
10594 +/** Thread structure.
10595 + *
10596 + * \warning Do not access the members of this structure directly!
10597 + */
10598 +typedef struct VCOS_THREAD_T
10599 +{
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 */
10616 +#endif
10617 + /** Array of functions to call at thread exit */
10618 + VCOS_THREAD_EXIT_T at_exit[VCOS_MAX_EXIT_HANDLERS];
10619 +
10620 + struct VCOS_THREAD_T *next; /**< For linked lists of threads */
10621 +} VCOS_THREAD_T;
10622 +
10623 +#if defined(VCOS_INLINE_BODIES)
10624 +
10625 +VCOS_INLINE_IMPL
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;
10629 +}
10630 +
10631 +VCOS_INLINE_IMPL
10632 +void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED stacksz) {
10633 + attrs->ta_stacksz = stacksz;
10634 +}
10635 +
10636 +VCOS_INLINE_IMPL
10637 +void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri) {
10638 + attrs->ta_priority = pri;
10639 +}
10640 +
10641 +VCOS_INLINE_IMPL
10642 +void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED affinity) {
10643 + attrs->ta_affinity = affinity;
10644 +}
10645 +
10646 +VCOS_INLINE_IMPL
10647 +void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts) {
10648 + attrs->ta_timeslice = ts;
10649 +}
10650 +
10651 +VCOS_INLINE_IMPL
10652 +void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy) {
10653 + attrs->legacy = legacy;
10654 +}
10655 +
10656 +VCOS_INLINE_IMPL
10657 +void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart) {
10658 + attrs->ta_autostart = autostart;
10659 +}
10660 +
10661 +VCOS_INLINE_IMPL
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);
10667 + */
10668 + return ret;
10669 +}
10670 +
10671 +VCOS_INLINE_IMPL
10672 +int vcos_thread_running(VCOS_THREAD_T *thread) {
10673 + return vcos_llthread_running(&thread->thread);
10674 +}
10675 +
10676 +VCOS_INLINE_IMPL
10677 +void vcos_thread_resume(VCOS_THREAD_T *thread) {
10678 + vcos_llthread_resume(&thread->thread);
10679 +}
10680 +
10681 +#endif /* VCOS_INLINE_BODIES */
10682 +
10683 +/**
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)
10687 + */
10688 +extern VCOS_STATUS_T _vcos_thread_create_attach(VCOS_THREAD_T *thread,
10689 + const char *name);
10690 +
10691 +/**
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
10695 + */
10696 +extern void _vcos_thread_delete(VCOS_THREAD_T *thread);
10697 +
10698 +/** Register a function to be called when the current thread exits.
10699 + */
10700 +extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt);
10701 +
10702 +/** Deregister a previously registered at-exit function.
10703 + */
10704 +extern void vcos_thread_deregister_at_exit(void (*pfn)(void*), void *cxt);
10705 +
10706 +#ifdef __cplusplus
10707 +}
10708 +#endif
10709 +#endif /* VCOS_JOINABLE_THREAD_FROM_PLAIN_H */
10710 --- /dev/null
10711 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_latch_from_sem.h
10712 @@ -0,0 +1,48 @@
10713 +/*=============================================================================
10714 +Copyright (c) 2009 Broadcom Europe Limited.
10715 +All rights reserved.
10716 +
10717 +Project : vcfw
10718 +Module : vcos
10719 +
10720 +FILE DESCRIPTION
10721 +VideoCore OS Abstraction Layer - Construct a latch from a semaphore
10722 +=============================================================================*/
10723 +
10724 +/** FIXME: rename to vcos_mutex_from_sem.c
10725 + */
10726 +
10727 +typedef struct VCOS_MUTEX_T {
10728 + VCOS_SEMAPHORE_T sem;
10729 + struct VCOS_THREAD_T *owner;
10730 +} VCOS_MUTEX_T;
10731 +
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);
10736 +
10737 +#if defined(VCOS_INLINE_BODIES)
10738 +
10739 +VCOS_INLINE_IMPL
10740 +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *latch, const char *name) {
10741 + return vcos_generic_mutex_create(latch,name);
10742 +}
10743 +
10744 +VCOS_INLINE_IMPL
10745 +void vcos_mutex_delete(VCOS_MUTEX_T *latch) {
10746 + vcos_generic_mutex_delete(latch);
10747 +}
10748 +
10749 +VCOS_INLINE_IMPL
10750 +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *latch) {
10751 + return vcos_generic_mutex_lock(latch);
10752 +}
10753 +
10754 +VCOS_INLINE_IMPL
10755 +void vcos_mutex_unlock(VCOS_MUTEX_T *latch) {
10756 + vcos_generic_mutex_unlock(latch);
10757 +}
10758 +
10759 +#endif /* VCOS_INLINE_BODIES */
10760 +
10761 --- /dev/null
10762 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_logcat.c
10763 @@ -0,0 +1,549 @@
10764 +/*=============================================================================
10765 +Copyright (c) 2010 Broadcom Europe Limited.
10766 +All rights reserved.
10767 +
10768 +Project : vcfw
10769 +Module : vcos
10770 +
10771 +FILE DESCRIPTION
10772 +Categorized logging for VCOS - a generic implementation.
10773 +=============================================================================*/
10774 +
10775 +#include "interface/vcos/vcos.h"
10776 +#include "interface/vcos/vcos_ctype.h"
10777 +#include "interface/vcos/vcos_string.h"
10778 +
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;
10782 +
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;
10787 +
10788 +#if VCOS_HAVE_CMD
10789 +
10790 +/*
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.
10794 + *
10795 + * So pthreads/vcos_platform.h defines VCOS_WANT_LOG_CMD to be 0. It is
10796 + * undefined elsewhere.
10797 + */
10798 +
10799 +# if !defined( VCOS_WANT_LOG_CMD )
10800 +# define VCOS_WANT_LOG_CMD 1
10801 +# endif
10802 +#else
10803 +# define VCOS_WANT_LOG_CMD 0
10804 +#endif
10805 +
10806 +#if VCOS_WANT_LOG_CMD
10807 +
10808 +/*****************************************************************************
10809 +*
10810 +* Does a vcos_assert(0), which is useful to test logging.
10811 +*
10812 +*****************************************************************************/
10813 +
10814 +VCOS_STATUS_T vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param )
10815 +{
10816 + (void)param;
10817 +
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" );
10821 +#else
10822 + vcos_assert(0);
10823 + vcos_cmd_printf( param, "Executed vcos_assert(0)\n" );
10824 +#endif
10825 +
10826 + return VCOS_SUCCESS;
10827 +}
10828 +
10829 +/*****************************************************************************
10830 +*
10831 +* Sets a vcos logging level
10832 +*
10833 +*****************************************************************************/
10834 +
10835 +VCOS_STATUS_T vcos_log_set_cmd( VCOS_CMD_PARAM_T *param )
10836 +{
10837 + VCOS_LOG_CAT_T *cat;
10838 + char *name;
10839 + char *levelStr;
10840 + VCOS_LOG_LEVEL_T level;
10841 + VCOS_STATUS_T status;
10842 +
10843 + if ( param->argc != 3 )
10844 + {
10845 + vcos_cmd_usage( param );
10846 + return VCOS_EINVAL;
10847 + }
10848 +
10849 + name = param->argv[1];
10850 + levelStr = param->argv[2];
10851 +
10852 + if ( vcos_string_to_log_level( levelStr, &level ) != VCOS_SUCCESS )
10853 + {
10854 + vcos_cmd_printf( param, "Unrecognized logging level: '%s'\n", levelStr );
10855 + return VCOS_EINVAL;
10856 + }
10857 +
10858 + vcos_mutex_lock(&lock);
10859 +
10860 + status = VCOS_SUCCESS;
10861 + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10862 + {
10863 + if ( vcos_strcmp( name, cat->name ) == 0 )
10864 + {
10865 + cat->level = level;
10866 + vcos_cmd_printf( param, "Category %s level set to %s\n", name, levelStr );
10867 + break;
10868 + }
10869 + }
10870 + if ( cat == NULL )
10871 + {
10872 + vcos_cmd_printf( param, "Unrecognized category: '%s'\n", name );
10873 + status = VCOS_ENOENT;
10874 + }
10875 +
10876 + vcos_mutex_unlock(&lock);
10877 +
10878 + return status;
10879 +}
10880 +
10881 +/*****************************************************************************
10882 +*
10883 +* Prints out the current settings for a given category (or all cvategories)
10884 +*
10885 +*****************************************************************************/
10886 +
10887 +VCOS_STATUS_T vcos_log_status_cmd( VCOS_CMD_PARAM_T *param )
10888 +{
10889 + VCOS_LOG_CAT_T *cat;
10890 + VCOS_STATUS_T status;
10891 +
10892 + vcos_mutex_lock(&lock);
10893 +
10894 + if ( param->argc == 1)
10895 + {
10896 + int nw;
10897 + int nameWidth = 0;
10898 +
10899 + /* Print information about all of the categories. */
10900 +
10901 + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10902 + {
10903 + nw = (int)strlen( cat->name );
10904 +
10905 + if ( nw > nameWidth )
10906 + {
10907 + nameWidth = nw;
10908 + }
10909 + }
10910 +
10911 + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10912 + {
10913 + vcos_cmd_printf( param, "%-*s - %s\n", nameWidth, cat->name, vcos_log_level_to_string( cat->level ));
10914 + }
10915 + }
10916 + else
10917 + {
10918 + /* Print information about a particular category */
10919 +
10920 + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10921 + {
10922 + if ( vcos_strcmp( cat->name, param->argv[1] ) == 0 )
10923 + {
10924 + vcos_cmd_printf( param, "%s - %s\n", cat->name, vcos_log_level_to_string( cat->level ));
10925 + break;
10926 + }
10927 + }
10928 + if ( cat == NULL )
10929 + {
10930 + vcos_cmd_printf( param, "Unrecognized logging category: '%s'\n", param->argv[1] );
10931 + status = VCOS_ENOENT;
10932 + goto out;
10933 + }
10934 + }
10935 +
10936 + status = VCOS_SUCCESS;
10937 +out:
10938 + vcos_mutex_unlock(&lock);
10939 +
10940 + return status;
10941 +}
10942 +
10943 +/*****************************************************************************
10944 +*
10945 +* Prints out the current settings for a given category (or all cvategories)
10946 +*
10947 +*****************************************************************************/
10948 +
10949 +VCOS_STATUS_T vcos_log_test_cmd( VCOS_CMD_PARAM_T *param )
10950 +{
10951 + if ( param->argc == 1 )
10952 + {
10953 + static int seq_num = 100;
10954 +
10955 + /* No additional arguments - generate a message with an incrementing number */
10956 +
10957 + vcos_log_error( "Test message %d", seq_num );
10958 +
10959 + seq_num++;
10960 + vcos_cmd_printf( param, "Logged 'Test message %d'\n", seq_num );
10961 + }
10962 + else
10963 + {
10964 + int arg_idx;
10965 +
10966 + /* Arguments supplied - log these */
10967 +
10968 + for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
10969 + {
10970 + vcos_log_error( "argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
10971 + }
10972 + vcos_cmd_printf( param, "Logged %d line(s) of test data\n", param->argc );
10973 + }
10974 + return VCOS_SUCCESS;
10975 +}
10976 +
10977 +/*****************************************************************************
10978 +*
10979 +* Internal commands
10980 +*
10981 +*****************************************************************************/
10982 +
10983 +static VCOS_CMD_T log_cmd_entry[] =
10984 +{
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" },
10989 +
10990 + { NULL, NULL, NULL, NULL, NULL }
10991 +};
10992 +
10993 +static VCOS_CMD_T cmd_log =
10994 + { "log", "command [args]", NULL, log_cmd_entry, "Commands related to vcos logging" };
10995 +
10996 +#endif
10997 +
10998 +void vcos_logging_init(void)
10999 +{
11000 + if (inited)
11001 + {
11002 + /* FIXME: should print a warning or something here */
11003 + return;
11004 + }
11005 + vcos_mutex_create(&lock, "vcos_log");
11006 +
11007 + vcos_log_platform_init();
11008 +
11009 + vcos_log_register("default", &dflt_log_category);
11010 +
11011 +#if VCOS_WANT_LOG_CMD
11012 + vcos_cmd_register( &cmd_log );
11013 +#endif
11014 +
11015 + vcos_assert(!inited);
11016 + inited = 1;
11017 +}
11018 +
11019 +/** Read an alphanumeric token, returning True if we succeeded.
11020 + */
11021 +
11022 +static int read_tok(char *tok, size_t toklen, const char **pstr, char sep)
11023 +{
11024 + const char *str = *pstr;
11025 + size_t n = 0;
11026 + char ch;
11027 +
11028 + /* skip past any whitespace */
11029 + while (str[0] && isspace((int)(str[0])))
11030 + str++;
11031 +
11032 + while ((ch = *str) != '\0' &&
11033 + ch != sep &&
11034 + (isalnum((int)ch) || (ch == '_')) &&
11035 + n != toklen-1)
11036 + {
11037 + tok[n++] = ch;
11038 + str++;
11039 + }
11040 +
11041 + /* did it work out? */
11042 + if (ch == '\0' || ch == sep)
11043 + {
11044 + if (ch) str++; /* move to next token if not at end */
11045 + /* yes */
11046 + tok[n] = '\0';
11047 + *pstr = str;
11048 + return 1;
11049 + }
11050 + else
11051 + {
11052 + /* no */
11053 + return 0;
11054 + }
11055 +}
11056 +
11057 +const char *vcos_log_level_to_string( VCOS_LOG_LEVEL_T level )
11058 +{
11059 + switch (level)
11060 + {
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";
11067 + }
11068 + return "???";
11069 +}
11070 +
11071 +VCOS_STATUS_T vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level )
11072 +{
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;
11085 + else
11086 + return VCOS_EINVAL;
11087 +
11088 + return VCOS_SUCCESS;
11089 +}
11090 +
11091 +static int read_level(VCOS_LOG_LEVEL_T *level, const char **pstr, char sep)
11092 +{
11093 + char buf[16];
11094 + int ret = 1;
11095 + if (read_tok(buf,sizeof(buf),pstr,sep))
11096 + {
11097 + if (vcos_string_to_log_level(buf,level) != VCOS_SUCCESS)
11098 + {
11099 + vcos_log("Invalid trace level '%s'\n", buf);
11100 + ret = 0;
11101 + }
11102 + }
11103 + else
11104 + {
11105 + ret = 0;
11106 + }
11107 + return ret;
11108 +}
11109 +
11110 +void vcos_log_register(const char *name, VCOS_LOG_CAT_T *category)
11111 +{
11112 + const char *env;
11113 + VCOS_LOG_CAT_T *i;
11114 +
11115 + category->name = name;
11116 + if ( category->level == VCOS_LOG_UNINITIALIZED )
11117 + {
11118 + category->level = VCOS_LOG_ERROR;
11119 + }
11120 + category->flags.want_prefix = (category != &dflt_log_category );
11121 +
11122 + vcos_mutex_lock(&lock);
11123 +
11124 + /* is it already registered? */
11125 + for (i = vcos_logging_categories; i ; i = i->next )
11126 + {
11127 + if (i == category)
11128 + {
11129 + i->refcount++;
11130 + break;
11131 + }
11132 + }
11133 +
11134 + if (!i)
11135 + {
11136 + /* not yet registered */
11137 + category->next = vcos_logging_categories;
11138 + vcos_logging_categories = category;
11139 + category->refcount++;
11140 +
11141 + vcos_log_platform_register(category);
11142 + }
11143 +
11144 + vcos_mutex_unlock(&lock);
11145 +
11146 + /* Check to see if this log level has been enabled. Look for
11147 + * (<category:level>,)*
11148 + *
11149 + * VC_LOGLEVEL=ilcs:info,vchiq:warn
11150 + */
11151 +
11152 + env = _VCOS_LOG_LEVEL();
11153 + if (env)
11154 + {
11155 + do
11156 + {
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, ','))
11161 + {
11162 + if (strcmp(env_name, name) == 0)
11163 + {
11164 + category->level = level;
11165 + break;
11166 + }
11167 + }
11168 + else
11169 + {
11170 + if (!warned_loglevel)
11171 + {
11172 + vcos_log("VC_LOGLEVEL format invalid at %s\n", env);
11173 + warned_loglevel = 1;
11174 + }
11175 + return;
11176 + }
11177 + } while (env[0] != '\0');
11178 + }
11179 +
11180 + vcos_log_info( "Registered log category '%s' with level %s",
11181 + category->name,
11182 + vcos_log_level_to_string( category->level ));
11183 +}
11184 +
11185 +void vcos_log_unregister(VCOS_LOG_CAT_T *category)
11186 +{
11187 + VCOS_LOG_CAT_T **pcat;
11188 + vcos_mutex_lock(&lock);
11189 + category->refcount--;
11190 + if (category->refcount == 0)
11191 + {
11192 + pcat = &vcos_logging_categories;
11193 + while (*pcat != category)
11194 + {
11195 + if (!*pcat)
11196 + break; /* possibly deregistered twice? */
11197 + if ((*pcat)->next == NULL)
11198 + {
11199 + vcos_assert(0); /* already removed! */
11200 + vcos_mutex_unlock(&lock);
11201 + return;
11202 + }
11203 + pcat = &(*pcat)->next;
11204 + }
11205 + if (*pcat)
11206 + *pcat = category->next;
11207 +
11208 + vcos_log_platform_unregister(category);
11209 + }
11210 + vcos_mutex_unlock(&lock);
11211 +}
11212 +
11213 +VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void)
11214 +{
11215 + return &dflt_log_category;
11216 +}
11217 +
11218 +void vcos_set_log_options(const char *opt)
11219 +{
11220 + (void)opt;
11221 +}
11222 +
11223 +void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
11224 + const char *label,
11225 + uint32_t addr,
11226 + const void *voidMem,
11227 + size_t numBytes )
11228 +{
11229 + const uint8_t *mem = (const uint8_t *)voidMem;
11230 + size_t offset;
11231 + char lineBuf[ 100 ];
11232 + char *s;
11233 +
11234 + while ( numBytes > 0 )
11235 + {
11236 + s = lineBuf;
11237 +
11238 + for ( offset = 0; offset < 16; offset++ )
11239 + {
11240 + if ( offset < numBytes )
11241 + {
11242 + s += vcos_snprintf( s, 4, "%02x ", mem[ offset ]);
11243 + }
11244 + else
11245 + {
11246 + s += vcos_snprintf( s, 4, " " );
11247 + }
11248 + }
11249 +
11250 + for ( offset = 0; offset < 16; offset++ )
11251 + {
11252 + if ( offset < numBytes )
11253 + {
11254 + uint8_t ch = mem[ offset ];
11255 +
11256 + if (( ch < ' ' ) || ( ch > '~' ))
11257 + {
11258 + ch = '.';
11259 + }
11260 + *s++ = (char)ch;
11261 + }
11262 + }
11263 + *s++ = '\0';
11264 +
11265 + if (( label != NULL ) && ( *label != '\0' ))
11266 + {
11267 + vcos_log_impl( cat, VCOS_LOG_INFO, "%s: %08x: %s", label, addr, lineBuf );
11268 + }
11269 + else
11270 + {
11271 + vcos_log_impl( cat, VCOS_LOG_INFO, "%08x: %s", addr, lineBuf );
11272 + }
11273 +
11274 + addr += 16;
11275 + mem += 16;
11276 + if ( numBytes > 16 )
11277 + {
11278 + numBytes -= 16;
11279 + }
11280 + else
11281 + {
11282 + numBytes = 0;
11283 + }
11284 + }
11285 +
11286 +}
11287 +
11288 +void vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...)
11289 +{
11290 + va_list ap;
11291 + va_start(ap,fmt);
11292 + vcos_vlog_impl( cat, _level, fmt, ap );
11293 + va_end(ap);
11294 +}
11295 +
11296 +void vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
11297 +{
11298 + vcos_vlog_impl_func( cat, _level, fmt, args );
11299 +}
11300 +
11301 +void vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func )
11302 +{
11303 + if ( vlog_impl_func == NULL )
11304 + {
11305 + vcos_vlog_impl_func = vcos_vlog_default_impl;
11306 + }
11307 + else
11308 + {
11309 + vcos_vlog_impl_func = vlog_impl_func;
11310 + }
11311 +}
11312 +
11313 --- /dev/null
11314 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.c
11315 @@ -0,0 +1,73 @@
11316 +/*=============================================================================
11317 +Copyright (c) 2009 Broadcom Europe Limited.
11318 +All rights reserved.
11319 +
11320 +Project : vcfw
11321 +Module : vcos
11322 +
11323 +FILE DESCRIPTION
11324 +VideoCore OS Abstraction Layer - memory alloc implementation
11325 +=============================================================================*/
11326 +
11327 +#include "interface/vcos/vcos.h"
11328 +
11329 +#ifndef _vcos_platform_malloc
11330 +#include <stdlib.h>
11331 +#define _vcos_platform_malloc malloc
11332 +#define _vcos_platform_free free
11333 +#endif
11334 +
11335 +typedef struct malloc_header_s {
11336 + uint32_t guardword;
11337 + uint32_t size;
11338 + const char *description;
11339 + void *ptr;
11340 +} MALLOC_HEADER_T;
11341 +
11342 +
11343 +#define MIN_ALIGN sizeof(MALLOC_HEADER_T)
11344 +
11345 +#define GUARDWORDHEAP 0xa55a5aa5
11346 +
11347 +void *vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *desc)
11348 +{
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;
11354 +
11355 + h->size = size;
11356 + h->description = desc;
11357 + h->guardword = GUARDWORDHEAP;
11358 + h->ptr = ptr;
11359 +
11360 + return ret;
11361 +}
11362 +
11363 +void *vcos_generic_mem_alloc(VCOS_UNSIGNED size, const char *desc)
11364 +{
11365 + return vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
11366 +}
11367 +
11368 +void *vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *desc)
11369 +{
11370 + uint32_t size = count*sz;
11371 + void *ptr = vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
11372 + if (ptr)
11373 + {
11374 + memset(ptr, 0, size);
11375 + }
11376 + return ptr;
11377 +}
11378 +
11379 +void vcos_generic_mem_free(void *ptr)
11380 +{
11381 + MALLOC_HEADER_T *h;
11382 + if (! ptr) return;
11383 +
11384 + h = ((MALLOC_HEADER_T *)ptr)-1;
11385 + vcos_assert(h->guardword == GUARDWORDHEAP);
11386 + _vcos_platform_free(h->ptr);
11387 +}
11388 +
11389 --- /dev/null
11390 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.h
11391 @@ -0,0 +1,54 @@
11392 +/*=============================================================================
11393 +Copyright (c) 2009 Broadcom Europe Limited.
11394 +All rights reserved.
11395 +
11396 +Project : VMCS Host Apps
11397 +Module : Framework - VMCS
11398 +
11399 +FILE DESCRIPTION
11400 +Create the vcos_malloc API from the regular system malloc/free
11401 +=============================================================================*/
11402 +
11403 +/**
11404 + * \file
11405 + *
11406 + * Create the vcos malloc API from a regular system malloc/free library.
11407 + *
11408 + * The API lets callers specify an alignment.
11409 + *
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.
11412 + *
11413 + */
11414 +
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);
11419 +
11420 +#ifdef VCOS_INLINE_BODIES
11421 +
11422 +VCOS_INLINE_IMPL
11423 +void *vcos_malloc(VCOS_UNSIGNED size, const char *description) {
11424 + return vcos_generic_mem_alloc(size, description);
11425 +}
11426 +
11427 +VCOS_INLINE_IMPL
11428 +void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description) {
11429 + return vcos_generic_mem_calloc(num, size, description);
11430 +}
11431 +
11432 +VCOS_INLINE_IMPL
11433 +void vcos_free(void *ptr) {
11434 + vcos_generic_mem_free(ptr);
11435 +}
11436 +
11437 +VCOS_INLINE_IMPL
11438 +void * vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description) {
11439 + return vcos_generic_mem_alloc_aligned(size, align, description);
11440 +}
11441 +
11442 +
11443 +#endif /* VCOS_INLINE_BODIES */
11444 +
11445 +
11446 --- /dev/null
11447 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mutexes_are_reentrant.h
11448 @@ -0,0 +1,68 @@
11449 +/*=============================================================================
11450 +Copyright (c) 2009 Broadcom Europe Limited.
11451 +All rights reserved.
11452 +
11453 +Project : vcfw
11454 +Module : chip driver
11455 +
11456 +FILE DESCRIPTION
11457 +VideoCore OS Abstraction Layer - reentrant mutexes mapped directly to regular ones
11458 +=============================================================================*/
11459 +
11460 +#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
11461 +#define VCOS_GENERIC_REENTRANT_MUTEX_H
11462 +
11463 +#ifdef __cplusplus
11464 +extern "C" {
11465 +#endif
11466 +
11467 +#include "interface/vcos/vcos_types.h"
11468 +#include "interface/vcos/vcos_mutex.h"
11469 +
11470 +/**
11471 + * \file
11472 + *
11473 + * Reentrant Mutexes directly using the native re-entrant mutex.
11474 + *
11475 + */
11476 +
11477 +typedef VCOS_MUTEX_T VCOS_REENTRANT_MUTEX_T;
11478 +
11479 +/* Inline forwarding functions */
11480 +
11481 +#if defined(VCOS_INLINE_BODIES)
11482 +
11483 +VCOS_INLINE_IMPL
11484 +VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) {
11485 + return vcos_mutex_create(m,name);
11486 +}
11487 +
11488 +VCOS_INLINE_IMPL
11489 +void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
11490 + vcos_mutex_delete(m);
11491 +}
11492 +
11493 +VCOS_INLINE_IMPL
11494 +void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
11495 + vcos_mutex_lock(m);
11496 +}
11497 +
11498 +VCOS_INLINE_IMPL
11499 +void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
11500 + vcos_mutex_unlock(m);
11501 +}
11502 +
11503 +VCOS_INLINE_IMPL
11504 +int vcos_reentrant_mutex_is_locked(VCOS_REENTRANT_MUTEX_T *m) {
11505 + return vcos_mutex_is_locked(m);
11506 +}
11507 +
11508 +#endif
11509 +
11510 +#ifdef __cplusplus
11511 +}
11512 +#endif
11513 +#endif
11514 +
11515 +
11516 +
11517 --- /dev/null
11518 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_thread_reaper.h
11519 @@ -0,0 +1,35 @@
11520 +/*=============================================================================
11521 +Copyright (c) 2010 Broadcom Europe Limited.
11522 +All rights reserved.
11523 +
11524 +Project : vcfw
11525 +Module : vcos
11526 +
11527 +FILE DESCRIPTION
11528 +VideoCore OS Abstraction Layer - thread reaping
11529 +=============================================================================*/
11530 +
11531 +#ifndef VCOS_THREAD_REAPER_H
11532 +#define VCOS_THREAD_REAPER_H
11533 +
11534 +#define VCOS_HAVE_THREAD_REAPER
11535 +
11536 +/** Initialise the thread reaper.
11537 + */
11538 +VCOS_STATUS_T vcos_thread_reaper_init(void);
11539 +
11540 +/** Reap a thread. Arranges for the thread to be automatically
11541 + * joined.
11542 + *
11543 + * @sa vcos_thread_join().
11544 + *
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
11548 + *
11549 + */
11550 +void vcos_thread_reap(VCOS_THREAD_T *thread, void (*on_terminated)(void*), void *cxt);
11551 +
11552 +#endif
11553 +
11554 +
11555 --- /dev/null
11556 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/stdint.h
11557 @@ -0,0 +1,17 @@
11558 +/*=============================================================================
11559 +Copyright (c) 2010 Broadcom Europe Limited.
11560 +All rights reserved.
11561 +
11562 +FILE DESCRIPTION
11563 +VideoCore OS fAbstraction Layer - stdint.h C standard header
11564 +=============================================================================*/
11565 +
11566 +#ifndef _VCOS_PLATFORM_LINUX_STDINT_H
11567 +#define _VCOS_PLATFORM_LINUX_STDINT_H
11568 +
11569 +/* The Linux kernel does not have a <stdint.h> so we have to provide one of
11570 + our own. */
11571 +
11572 +#include <linux/types.h> /* includes integer types */
11573 +
11574 +#endif /* _VCOS_PLATFORM_LINUX_STDINT_H */
11575 --- /dev/null
11576 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel.c
11577 @@ -0,0 +1,616 @@
11578 +/*=============================================================================
11579 +Copyright (c) 2009 Broadcom Europe Limited.
11580 +All rights reserved.
11581 +
11582 +Project : vcfw
11583 +Module : vcos
11584 +
11585 +FILE DESCRIPTION
11586 +VideoCore OS Abstraction Layer - pthreads types
11587 +=============================================================================*/
11588 +
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>
11596 +
11597 +#if defined( CONFIG_BCM_KNLLOG_SUPPORT )
11598 +#include <linux/broadcom/knllog.h>
11599 +#endif
11600 +#include "interface/vcos/vcos.h"
11601 +#ifdef HAVE_VCOS_VERSION
11602 +#include "interface/vcos/vcos_build_info.h"
11603 +#endif
11604 +
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;
11608 +
11609 +#ifndef VCOS_DEFAULT_STACK_SIZE
11610 +#define VCOS_DEFAULT_STACK_SIZE 4096
11611 +#endif
11612 +
11613 +static VCOS_THREAD_ATTR_T default_attrs = {
11614 + 0,
11615 + VCOS_DEFAULT_STACK_SIZE,
11616 +};
11617 +
11618 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
11619 +static DEFINE_SEMAPHORE(lock);
11620 +#else
11621 +static DECLARE_MUTEX(lock);
11622 +#endif
11623 +
11624 +typedef void (*LEGACY_ENTRY_FN_T)(int, void *);
11625 +
11626 +/** Wrapper function around the real thread function. Posts the semaphore
11627 + * when completed.
11628 + */
11629 +static int vcos_thread_wrapper(void *arg)
11630 +{
11631 + void *ret;
11632 + VCOS_THREAD_T *thread = arg;
11633 +
11634 + vcos_assert(thread->magic == VCOS_THREAD_MAGIC);
11635 +
11636 + thread->thread.thread = current;
11637 +
11638 + vcos_add_thread(thread);
11639 +
11640 +#ifdef VCOS_WANT_TLS_EMULATION
11641 + vcos_tls_thread_register(&thread->_tls);
11642 +#endif
11643 +
11644 + if (thread->legacy)
11645 + {
11646 + LEGACY_ENTRY_FN_T fn = (LEGACY_ENTRY_FN_T)thread->entry;
11647 + fn(0,thread->arg);
11648 + ret = 0;
11649 + }
11650 + else
11651 + {
11652 + ret = thread->entry(thread->arg);
11653 + }
11654 +
11655 + thread->exit_data = ret;
11656 +
11657 + vcos_remove_thread(current);
11658 +
11659 + /* For join and cleanup */
11660 + vcos_semaphore_post(&thread->wait);
11661 +
11662 + return 0;
11663 +}
11664 +
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,
11669 + void *arg)
11670 +{
11671 + VCOS_STATUS_T st;
11672 + struct task_struct *kthread;
11673 +
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;
11680 +
11681 + if (!name)
11682 + {
11683 + vcos_assert(0);
11684 + return VCOS_EINVAL;
11685 + }
11686 +
11687 + st = vcos_semaphore_create(&thread->wait, NULL, 0);
11688 + if (st != VCOS_SUCCESS)
11689 + {
11690 + return st;
11691 + }
11692 +
11693 + st = vcos_semaphore_create(&thread->suspend, NULL, 0);
11694 + if (st != VCOS_SUCCESS)
11695 + {
11696 + return st;
11697 + }
11698 +
11699 + /*required for event groups */
11700 + vcos_timer_create(&thread->_timer.timer, thread->name, NULL, NULL);
11701 +
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;
11708 +}
11709 +
11710 +void vcos_thread_join(VCOS_THREAD_T *thread,
11711 + void **pData)
11712 +{
11713 + vcos_assert(thread);
11714 + vcos_assert(thread->magic == VCOS_THREAD_MAGIC);
11715 +
11716 + thread->joined = 1;
11717 +
11718 + vcos_semaphore_wait(&thread->wait);
11719 +
11720 + if (pData)
11721 + {
11722 + *pData = thread->exit_data;
11723 + }
11724 +
11725 + /* Clean up */
11726 + if (thread->stack)
11727 + vcos_free(thread->stack);
11728 +
11729 + vcos_semaphore_delete(&thread->wait);
11730 + vcos_semaphore_delete(&thread->suspend);
11731 +
11732 +}
11733 +
11734 +uint32_t vcos_getmicrosecs( void )
11735 +{
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;
11740 +}
11741 +
11742 +VCOS_STATUS_T vcos_timer_init(void)
11743 +{
11744 + return VCOS_SUCCESS;
11745 +}
11746 +
11747 +static const char *log_prefix[] =
11748 +{
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 */
11755 +};
11756 +
11757 +void vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
11758 +{
11759 + char *newline = strchr( fmt, '\n' );
11760 + const char *prefix;
11761 + const char *real_fmt;
11762 +
11763 + preempt_disable();
11764 + {
11765 + if ( *fmt == '<' )
11766 + {
11767 + prefix = fmt;
11768 + real_fmt= &fmt[3];
11769 + }
11770 + else
11771 + {
11772 + prefix = log_prefix[_level];
11773 + real_fmt = fmt;
11774 + }
11775 +#if defined( CONFIG_BCM_KNLLOG_SUPPORT )
11776 + knllog_ventry( "vcos", real_fmt, args );
11777 +#endif
11778 + printk( "%.3svcos: [%d]: ", prefix, current->pid );
11779 + vprintk( real_fmt, args );
11780 +
11781 + if ( newline == NULL )
11782 + {
11783 + printk("\n");
11784 + }
11785 + }
11786 + preempt_enable();
11787 +}
11788 +
11789 +
11790 +const char * _vcos_log_level(void)
11791 +{
11792 + return NULL;
11793 +}
11794 +
11795 +/*****************************************************************************
11796 +*
11797 +* Displays the version information in /proc/vcos/version
11798 +*
11799 +*****************************************************************************/
11800 +
11801 +#ifdef HAVE_VCOS_VERSION
11802 +
11803 +static void show_version( VCOS_CFG_BUF_T buf, void *data )
11804 +{
11805 + static const char* copyright = "Copyright (c) 2011 Broadcom";
11806 +
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(),
11811 + copyright,
11812 + vcos_get_build_version() );
11813 +}
11814 +
11815 +#endif
11816 +
11817 +/*****************************************************************************
11818 +*
11819 +* Initialises vcos
11820 +*
11821 +*****************************************************************************/
11822 +
11823 +VCOS_STATUS_T vcos_init(void)
11824 +{
11825 + if ( vcos_cfg_mkdir( &vcos_cfg_dir, NULL, "vcos" ) != VCOS_SUCCESS )
11826 + {
11827 + printk( KERN_ERR "%s: Unable to create vcos cfg entry\n", __func__ );
11828 + }
11829 + vcos_logging_init();
11830 +
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 )
11834 + {
11835 + printk( KERN_ERR "%s: Unable to create vcos cfg entry 'version'\n", __func__ );
11836 + }
11837 +#endif
11838 +
11839 + return VCOS_SUCCESS;
11840 +}
11841 +
11842 +/*****************************************************************************
11843 +*
11844 +* Deinitializes vcos
11845 +*
11846 +*****************************************************************************/
11847 +
11848 +void vcos_deinit(void)
11849 +{
11850 +#ifdef HAVE_VCOS_VERSION
11851 + vcos_cfg_remove_entry( &vcos_version_cfg );
11852 +#endif
11853 + vcos_cfg_remove_entry( &vcos_cfg_dir );
11854 +}
11855 +
11856 +void vcos_global_lock(void)
11857 +{
11858 + down(&lock);
11859 +}
11860 +
11861 +void vcos_global_unlock(void)
11862 +{
11863 + up(&lock);
11864 +}
11865 +
11866 +/* vcos_thread_exit() doesn't really stop this thread here
11867 + *
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.
11871 + *
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
11875 + */
11876 +
11877 +void vcos_thread_exit(void *arg)
11878 +{
11879 + VCOS_THREAD_T *thread = vcos_thread_current();
11880 +
11881 + vcos_assert(thread);
11882 + vcos_assert(thread->magic == VCOS_THREAD_MAGIC);
11883 +
11884 + thread->exit_data = arg;
11885 +}
11886 +
11887 +void vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs)
11888 +{
11889 + *attrs = default_attrs;
11890 +}
11891 +
11892 +void _vcos_task_timer_set(void (*pfn)(void *), void *cxt, VCOS_UNSIGNED ms)
11893 +{
11894 + VCOS_THREAD_T *self = vcos_thread_current();
11895 + vcos_assert(self);
11896 + vcos_assert(self->_timer.pfn == NULL);
11897 +
11898 + vcos_timer_create( &self->_timer.timer, "TaskTimer", pfn, cxt );
11899 + vcos_timer_set(&self->_timer.timer, ms);
11900 +}
11901 +
11902 +void _vcos_task_timer_cancel(void)
11903 +{
11904 + VCOS_THREAD_T *self = vcos_thread_current();
11905 + if (self->_timer.timer.linux_timer.function)
11906 + {
11907 + vcos_timer_cancel(&self->_timer.timer);
11908 + vcos_timer_delete(&self->_timer.timer);
11909 + }
11910 +}
11911 +
11912 +int vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap )
11913 +{
11914 + return vsnprintf( buf, buflen, fmt, ap );
11915 +}
11916 +
11917 +int vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...)
11918 +{
11919 + int ret;
11920 + va_list ap;
11921 + va_start(ap,fmt);
11922 + ret = vsnprintf(buf, buflen, fmt, ap);
11923 + va_end(ap);
11924 + return ret;
11925 +}
11926 +
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! */
11929 + return 1;
11930 +}
11931 +
11932 +static int vcos_verify_bkpts = 1;
11933 +
11934 +int vcos_verify_bkpts_enabled(void)
11935 +{
11936 + return vcos_verify_bkpts;
11937 +}
11938 +
11939 +/*****************************************************************************
11940 +*
11941 +* _vcos_log_platform_init is called from vcos_logging_init
11942 +*
11943 +*****************************************************************************/
11944 +
11945 +void _vcos_log_platform_init(void)
11946 +{
11947 + if ( vcos_cfg_mkdir( &vcos_logging_cfg_dir, &vcos_cfg_dir, "logging" ) != VCOS_SUCCESS )
11948 + {
11949 + printk( KERN_ERR "%s: Unable to create logging cfg entry\n", __func__ );
11950 + }
11951 +}
11952 +
11953 +/*****************************************************************************
11954 +*
11955 +* Called to display the contents of a logging category.
11956 +*
11957 +*****************************************************************************/
11958 +
11959 +static void logging_show_category( VCOS_CFG_BUF_T buf, void *data )
11960 +{
11961 + VCOS_LOG_CAT_T *category = data;
11962 +
11963 + vcos_cfg_buf_printf( buf, "%s\n", vcos_log_level_to_string( category->level ));
11964 +}
11965 +
11966 +/*****************************************************************************
11967 +*
11968 +* Called to parse content for a logging category.
11969 +*
11970 +*****************************************************************************/
11971 +
11972 +static void logging_parse_category( VCOS_CFG_BUF_T buf, void *data )
11973 +{
11974 + VCOS_LOG_CAT_T *category = data;
11975 + const char *str = vcos_cfg_buf_get_str( buf );
11976 + VCOS_LOG_LEVEL_T level;
11977 +
11978 + if ( vcos_string_to_log_level( str, &level ) == VCOS_SUCCESS )
11979 + {
11980 + category->level = level;
11981 + }
11982 + else
11983 + {
11984 + printk( KERN_ERR "%s: Unrecognized logging level: '%s'\n",
11985 + __func__, str );
11986 + }
11987 +}
11988 +
11989 +/*****************************************************************************
11990 +*
11991 +* _vcos_log_platform_register is called from vcos_log_register whenever
11992 +* a new category is registered.
11993 +*
11994 +*****************************************************************************/
11995 +
11996 +void _vcos_log_platform_register(VCOS_LOG_CAT_T *category)
11997 +{
11998 + VCOS_CFG_ENTRY_T entry;
11999 +
12000 + if ( vcos_cfg_create_entry( &entry, &vcos_logging_cfg_dir, category->name,
12001 + logging_show_category, logging_parse_category,
12002 + category ) != VCOS_SUCCESS )
12003 + {
12004 + printk( KERN_ERR "%s: Unable to create cfg entry for logging category '%s'\n",
12005 + __func__, category->name );
12006 + category->platform_data = NULL;
12007 + }
12008 + else
12009 + {
12010 + category->platform_data = entry;
12011 + }
12012 +}
12013 +
12014 +/*****************************************************************************
12015 +*
12016 +* _vcos_log_platform_unregister is called from vcos_log_unregister whenever
12017 +* a new category is unregistered.
12018 +*
12019 +*****************************************************************************/
12020 +
12021 +void _vcos_log_platform_unregister(VCOS_LOG_CAT_T *category)
12022 +{
12023 + VCOS_CFG_ENTRY_T entry;
12024 +
12025 + entry = category->platform_data;
12026 + if ( entry != NULL )
12027 + {
12028 + if ( vcos_cfg_remove_entry( &entry ) != VCOS_SUCCESS )
12029 + {
12030 + printk( KERN_ERR "%s: Unable to remove cfg entry for logging category '%s'\n",
12031 + __func__, category->name );
12032 + }
12033 + }
12034 +}
12035 +
12036 +/*****************************************************************************
12037 +*
12038 +* Allocate memory.
12039 +*
12040 +*****************************************************************************/
12041 +
12042 +void *vcos_platform_malloc( VCOS_UNSIGNED required_size )
12043 +{
12044 + if ( required_size >= ( 2 * PAGE_SIZE ))
12045 + {
12046 + /* For larger allocations, use vmalloc, whose underlying allocator
12047 + * returns pages
12048 + */
12049 +
12050 + return vmalloc( required_size );
12051 + }
12052 +
12053 + /* For smaller allocation, use kmalloc */
12054 +
12055 + return kmalloc( required_size, GFP_KERNEL );
12056 +}
12057 +
12058 +/*****************************************************************************
12059 +*
12060 +* Free previously allocated memory
12061 +*
12062 +*****************************************************************************/
12063 +
12064 +void vcos_platform_free( void *ptr )
12065 +{
12066 + if (((unsigned long)ptr >= VMALLOC_START )
12067 + && ((unsigned long)ptr < VMALLOC_END ))
12068 + {
12069 + vfree( ptr );
12070 + }
12071 + else
12072 + {
12073 + kfree( ptr );
12074 + }
12075 +}
12076 +
12077 +/*****************************************************************************
12078 +*
12079 +* Execute a routine exactly once.
12080 +*
12081 +*****************************************************************************/
12082 +
12083 +VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
12084 + void (*init_routine)(void))
12085 +{
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.
12090 + */
12091 +
12092 + if ( *once_control == 0 )
12093 + {
12094 + vcos_global_lock();
12095 + if ( *once_control == 0 )
12096 + {
12097 + init_routine();
12098 + *once_control = 1;
12099 + }
12100 + vcos_global_unlock();
12101 + }
12102 +
12103 + return VCOS_SUCCESS;
12104 +}
12105 +
12106 +/*****************************************************************************
12107 +*
12108 +* String duplication routine.
12109 +*
12110 +*****************************************************************************/
12111 +
12112 +char *vcos_strdup(const char *str)
12113 +{
12114 + return kstrdup(str, GFP_KERNEL);
12115 +}
12116 +
12117 +
12118 +/* Export functions for modules to use */
12119 +EXPORT_SYMBOL( vcos_init );
12120 +
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 );
12126 +
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 );
12137 +
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 );
12144 +
12145 +EXPORT_SYMBOL( vcos_getmicrosecs );
12146 +
12147 +EXPORT_SYMBOL( vcos_strcasecmp );
12148 +EXPORT_SYMBOL( vcos_snprintf );
12149 +EXPORT_SYMBOL( vcos_vsnprintf );
12150 +
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 );
12157 +
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 );
12163 +
12164 +EXPORT_SYMBOL( vcos_event_flags_create );
12165 +EXPORT_SYMBOL( vcos_event_flags_delete );
12166 +EXPORT_SYMBOL( vcos_event_flags_get );
12167 +
12168 +EXPORT_SYMBOL( vcos_sleep );
12169 +
12170 +EXPORT_SYMBOL( vcos_calloc );
12171 +EXPORT_SYMBOL( vcos_malloc );
12172 +EXPORT_SYMBOL( vcos_malloc_aligned );
12173 +EXPORT_SYMBOL( vcos_free );
12174 +
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 );
12180 +
12181 +EXPORT_SYMBOL( vcos_timer_cancel );
12182 +EXPORT_SYMBOL( vcos_timer_create );
12183 +EXPORT_SYMBOL( vcos_timer_delete );
12184 +EXPORT_SYMBOL( vcos_timer_set );
12185 +
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 );
12190 +
12191 +EXPORT_SYMBOL( vcos_verify_bkpts_enabled );
12192 +
12193 +EXPORT_SYMBOL( vcos_strdup );
12194 --- /dev/null
12195 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_cfg.c
12196 @@ -0,0 +1,332 @@
12197 +/*****************************************************************************
12198 +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved.
12199 +*
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").
12204 +*
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
12208 +* consent.
12209 +*****************************************************************************/
12210 +
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>
12216 +
12217 +struct opaque_vcos_cfg_buf_t
12218 +{
12219 + struct seq_file *seq;
12220 + char *charBuf;
12221 +};
12222 +
12223 +struct opaque_vcos_cfg_entry_t
12224 +{
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;
12229 + void *data;
12230 + const char *name;
12231 +};
12232 +
12233 +/*****************************************************************************
12234 +*
12235 +* cfg_proc_show
12236 +*
12237 +*****************************************************************************/
12238 +
12239 +static int cfg_proc_show( struct seq_file *s, void *v )
12240 +{
12241 + VCOS_CFG_ENTRY_T entry;
12242 + struct opaque_vcos_cfg_buf_t buf;
12243 +
12244 + entry = s->private;
12245 +
12246 + if ( entry->showFunc )
12247 + {
12248 + memset( &buf, 0, sizeof( buf ));
12249 + buf.seq = s;
12250 +
12251 + entry->showFunc( &buf, entry->data );
12252 + }
12253 +
12254 + return 0;
12255 +}
12256 +
12257 +/*****************************************************************************
12258 +*
12259 +* cfg_proc_write
12260 +*
12261 +*****************************************************************************/
12262 +
12263 +static ssize_t cfg_proc_write( struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
12264 +{
12265 + VCOS_CFG_ENTRY_T entry = PDE(file->f_path.dentry->d_inode)->data;
12266 + char *charBuf;
12267 + struct opaque_vcos_cfg_buf_t buf;
12268 + size_t len;
12269 +
12270 + if ( entry->parseFunc != NULL )
12271 + {
12272 + /* The number 4000 is rather arbitrary. It just needs to be bigger than any input
12273 + * string we expect to use.
12274 + */
12275 +
12276 + len = count;
12277 + if ( count > 4000 )
12278 + {
12279 + len = 4000;
12280 + }
12281 +
12282 + /* Allocate a kernel buffer to contain the string being written. */
12283 +
12284 + charBuf = kmalloc( len + 1, GFP_KERNEL );
12285 + if ( copy_from_user( charBuf, buffer, len ))
12286 + {
12287 + kfree( charBuf );
12288 + return -EFAULT;
12289 + }
12290 +
12291 + /* echo puts a trailing newline in the buffer - strip it out. */
12292 +
12293 + if (( len > 0 ) && ( charBuf[ len - 1 ] == '\n' ))
12294 + {
12295 + len--;
12296 + }
12297 + charBuf[len] = '\0';
12298 +
12299 + memset( &buf, 0, sizeof( buf ));
12300 + buf.charBuf = charBuf;
12301 +
12302 + entry->parseFunc( &buf, entry->data );
12303 + kfree( charBuf );
12304 + }
12305 + return count;
12306 +}
12307 +
12308 +/*****************************************************************************
12309 +*
12310 +* cfg_proc_open
12311 +*
12312 +*****************************************************************************/
12313 +
12314 +static int cfg_proc_open( struct inode *inode, struct file *file )
12315 +{
12316 + return single_open( file, cfg_proc_show, PDE(inode)->data );
12317 +}
12318 +
12319 +static const struct file_operations cfg_proc_fops =
12320 +{
12321 + .open = cfg_proc_open,
12322 + .read = seq_read,
12323 + .llseek = seq_lseek,
12324 + .release = single_release,
12325 + .write = cfg_proc_write,
12326 +};
12327 +
12328 +/*****************************************************************************
12329 +*
12330 +* vcos_cfg_mkdir
12331 +*
12332 +*****************************************************************************/
12333 +
12334 +VCOS_STATUS_T vcos_cfg_mkdir( VCOS_CFG_ENTRY_T *entryp,
12335 + VCOS_CFG_ENTRY_T *parent,
12336 + const char *dirName )
12337 +{
12338 + VCOS_CFG_ENTRY_T entry;
12339 +
12340 + if (( entry = kzalloc( sizeof( *entry ), GFP_KERNEL )) == NULL )
12341 + {
12342 + return VCOS_ENOMEM;
12343 + }
12344 +
12345 + if ( parent == NULL )
12346 + {
12347 + entry->pde = proc_mkdir( dirName, NULL );
12348 + }
12349 + else
12350 + {
12351 + entry->pde = proc_mkdir( dirName, (*parent)->pde );
12352 + entry->parent_pde = (*parent)->pde;
12353 + }
12354 + if ( entry->pde == NULL )
12355 + {
12356 + kfree( entry );
12357 + return VCOS_ENOMEM;
12358 + }
12359 +
12360 + entry->name = dirName;
12361 +
12362 + *entryp = entry;
12363 + return VCOS_SUCCESS;
12364 +}
12365 +
12366 +/*****************************************************************************
12367 +*
12368 +* vcos_cfg_create_entry
12369 +*
12370 +*****************************************************************************/
12371 +
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,
12377 + void *data )
12378 +{
12379 + VCOS_CFG_ENTRY_T entry;
12380 + mode_t mode;
12381 +
12382 + *entryp = NULL;
12383 +
12384 + if (( entry = kzalloc( sizeof( *entry ), GFP_KERNEL )) == NULL )
12385 + {
12386 + return VCOS_ENOMEM;
12387 + }
12388 +
12389 + mode = 0;
12390 + if ( showFunc != NULL )
12391 + {
12392 + mode |= 0444;
12393 + }
12394 + if ( parseFunc != NULL )
12395 + {
12396 + mode |= 0200;
12397 + }
12398 +
12399 + if ( parent == NULL )
12400 + {
12401 + entry->pde = create_proc_entry( entryName, mode, NULL );
12402 + }
12403 + else
12404 + {
12405 + entry->pde = create_proc_entry( entryName, mode, (*parent)->pde );
12406 + entry->parent_pde = (*parent)->pde;
12407 + }
12408 + if ( entry->pde == NULL )
12409 + {
12410 + kfree( entry );
12411 + return -ENOMEM;
12412 + }
12413 + entry->showFunc = showFunc;
12414 + entry->parseFunc = parseFunc;
12415 + entry->data = data;
12416 + entry->name = entryName;
12417 +
12418 + entry->pde->data = entry;
12419 + entry->pde->proc_fops = &cfg_proc_fops;
12420 +
12421 + *entryp = entry;
12422 + return VCOS_SUCCESS;
12423 +}
12424 +
12425 +/*****************************************************************************
12426 +*
12427 +* vcos_cfg_remove_entry
12428 +*
12429 +*****************************************************************************/
12430 +
12431 +VCOS_STATUS_T vcos_cfg_remove_entry( VCOS_CFG_ENTRY_T *entryp )
12432 +{
12433 + if (( entryp != NULL ) && ( *entryp != NULL ))
12434 + {
12435 + remove_proc_entry( (*entryp)->name, (*entryp)->parent_pde );
12436 +
12437 + kfree( *entryp );
12438 + *entryp = NULL;
12439 + }
12440 +
12441 + return VCOS_SUCCESS;
12442 +}
12443 +
12444 +/*****************************************************************************
12445 +*
12446 +* vcos_cfg_is_entry_created
12447 +*
12448 +*****************************************************************************/
12449 +
12450 +int vcos_cfg_is_entry_created( VCOS_CFG_ENTRY_T entry )
12451 +{
12452 + return ( entry != NULL ) && ( entry->pde != NULL );
12453 +}
12454 +
12455 +/*****************************************************************************
12456 +*
12457 +* vcos_cfg_buf_printf
12458 +*
12459 +*****************************************************************************/
12460 +
12461 +void vcos_cfg_buf_printf( VCOS_CFG_BUF_T buf, const char *fmt, ... )
12462 +{
12463 + struct seq_file *m = buf->seq;
12464 +
12465 + /* Bah - there is no seq_vprintf */
12466 +
12467 + va_list args;
12468 + int len;
12469 +
12470 + if (m->count < m->size) {
12471 + va_start(args, fmt);
12472 + len = vsnprintf(m->buf + m->count, m->size - m->count, fmt, args);
12473 + va_end(args);
12474 + if (m->count + len < m->size) {
12475 + m->count += len;
12476 + return;
12477 + }
12478 + }
12479 + m->count = m->size;
12480 +}
12481 +
12482 +/*****************************************************************************
12483 +*
12484 +* vcos_cfg_buf_get_str
12485 +*
12486 +*****************************************************************************/
12487 +
12488 +char *vcos_cfg_buf_get_str( VCOS_CFG_BUF_T buf )
12489 +{
12490 + return buf->charBuf;
12491 +}
12492 +
12493 +/*****************************************************************************
12494 +*
12495 +* vcos_cfg_get_proc_entry
12496 +*
12497 +* This function is only created for a couple of backwards compatibility '
12498 +* issues and shouldn't normally be used.
12499 +*
12500 +*****************************************************************************/
12501 +
12502 +void *vcos_cfg_get_proc_entry( VCOS_CFG_ENTRY_T entry )
12503 +{
12504 + return entry->pde;
12505 +}
12506 +
12507 +/*****************************************************************************
12508 +*
12509 +* vcos_cfg_get_entry_name
12510 +*
12511 +*****************************************************************************/
12512 +
12513 +const char *vcos_cfg_get_entry_name( VCOS_CFG_ENTRY_T entry )
12514 +{
12515 + return entry->pde->name;
12516 +}
12517 +
12518 +
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 );
12526 +
12527 +EXPORT_SYMBOL_GPL( vcos_cfg_get_proc_entry );
12528 +
12529 --- /dev/null
12530 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_misc.c
12531 @@ -0,0 +1,113 @@
12532 +// #############################################################################
12533 +// START #######################################################################
12534 +/*****************************************************************************
12535 +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved.
12536 +*
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").
12541 +*
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
12545 +* consent.
12546 +*****************************************************************************/
12547 +
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>
12554 +
12555 +/*****************************************************************************
12556 +*
12557 +* vcos_semaphore_wait_freezable
12558 +*
12559 +*****************************************************************************/
12560 +
12561 +VCOS_STATUS_T vcos_semaphore_wait_freezable(VCOS_SEMAPHORE_T *sem)
12562 +{
12563 + int rval, sig_pended = 0;
12564 + unsigned long flags;
12565 + struct task_struct *task = current;
12566 +
12567 + while (1) {
12568 + rval = down_interruptible((struct semaphore *)sem);
12569 + if (rval == 0) { /* down now */
12570 + break;
12571 + } else {
12572 + if (freezing(current)) {
12573 + try_to_freeze();
12574 + } else {
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);
12578 + sig_pended = 1;
12579 + }
12580 + spin_unlock_irqrestore(&task->sighand->siglock, flags);
12581 + }
12582 + }
12583 + }
12584 +
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);
12589 + }
12590 +
12591 + return 0;
12592 +}
12593 +
12594 +EXPORT_SYMBOL( vcos_semaphore_wait_freezable );
12595 +
12596 +/*****************************************************************************
12597 +*
12598 +* vcos_kmalloc
12599 +*
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.
12602 +*
12603 +*****************************************************************************/
12604 +
12605 +void *vcos_kmalloc(VCOS_UNSIGNED size, const char *description)
12606 +{
12607 + (void)description;
12608 +
12609 + return kmalloc( size, GFP_KERNEL );
12610 +}
12611 +
12612 +/*****************************************************************************
12613 +*
12614 +* vcos_kmalloc
12615 +*
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.
12618 +*
12619 +*****************************************************************************/
12620 +
12621 +void *vcos_kcalloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description)
12622 +{
12623 + (void)description;
12624 +
12625 + return kzalloc( num * size, GFP_KERNEL );
12626 +}
12627 +
12628 +/*****************************************************************************
12629 +*
12630 +* vcos_kfree
12631 +*
12632 +*****************************************************************************/
12633 +
12634 +void vcos_kfree(void *ptr)
12635 +{
12636 + kfree( ptr );
12637 +}
12638 +
12639 +EXPORT_SYMBOL( vcos_kmalloc );
12640 +EXPORT_SYMBOL( vcos_kcalloc );
12641 +EXPORT_SYMBOL( vcos_kfree );
12642 +
12643 +// END #########################################################################
12644 +// #############################################################################
12645 --- /dev/null
12646 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_mod_init.c
12647 @@ -0,0 +1,64 @@
12648 +/*****************************************************************************
12649 +* Copyright 2006 - 2008 Broadcom Corporation. All rights reserved.
12650 +*
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").
12655 +*
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
12659 +* consent.
12660 +****************************************************************************/
12661 +
12662 +/* ---- Include Files ---------------------------------------------------- */
12663 +
12664 +#include "interface/vcos/vcos.h"
12665 +#include <linux/module.h>
12666 +
12667 +/* ---- Public Variables ------------------------------------------------- */
12668 +
12669 +/* ---- Private Constants and Types -------------------------------------- */
12670 +
12671 +/* ---- Private Variables ------------------------------------------------ */
12672 +
12673 +/* ---- Private Function Prototypes -------------------------------------- */
12674 +
12675 +/* ---- Functions -------------------------------------------------------- */
12676 +
12677 +/****************************************************************************
12678 +*
12679 +* Called to perform module initialization when the module is loaded
12680 +*
12681 +***************************************************************************/
12682 +
12683 +static int __init vcos_mod_init( void )
12684 +{
12685 + printk( KERN_INFO "VCOS Module\n" );
12686 +
12687 + vcos_init();
12688 + return 0;
12689 +}
12690 +
12691 +/****************************************************************************
12692 +*
12693 +* Called to perform module cleanup when the module is unloaded.
12694 +*
12695 +***************************************************************************/
12696 +
12697 +static void __exit vcos_mod_exit( void )
12698 +{
12699 + vcos_deinit();
12700 +}
12701 +
12702 +/****************************************************************************/
12703 +
12704 +module_init( vcos_mod_init );
12705 +module_exit( vcos_mod_exit );
12706 +
12707 +MODULE_AUTHOR("Broadcom");
12708 +MODULE_DESCRIPTION( "VCOS Module Functions" );
12709 +MODULE_LICENSE( "GPL" );
12710 +MODULE_VERSION( "1.0" );
12711 +
12712 --- /dev/null
12713 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform.h
12714 @@ -0,0 +1,496 @@
12715 +/*=============================================================================
12716 +Copyright (c) 2009 Broadcom Europe Limited.
12717 +All rights reserved.
12718 +
12719 +Project : vcfw
12720 +Module : vcos
12721 +
12722 +FILE DESCRIPTION
12723 +VideoCore OS Abstraction Layer - Linux kernel (partial) implementation.
12724 +=============================================================================*/
12725 +
12726 +/* Do not include this file directly - instead include it via vcos.h */
12727 +
12728 +/** @file
12729 + *
12730 + * Linux kernel (partial) implementation of VCOS.
12731 + *
12732 + */
12733 +
12734 +#ifndef VCOS_PLATFORM_H
12735 +#define VCOS_PLATFORM_H
12736 +
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>
12756 +
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
12775 +
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 */
12785 +
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;
12790 +
12791 +typedef unsigned int VCOS_UNSIGNED;
12792 +typedef unsigned int VCOS_OPTION;
12793 +typedef atomic_t VCOS_ATOMIC_FLAGS_T;
12794 +
12795 +typedef struct
12796 +{
12797 + struct timer_list linux_timer;
12798 + void *context;
12799 + void (*expiration_routine)(void *context);
12800 +
12801 +} VCOS_TIMER_T;
12802 +
12803 +typedef struct VCOS_LLTHREAD_T
12804 +{
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;
12808 +
12809 +typedef enum
12810 +{
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;
12816 +
12817 +typedef struct file *VCOS_FILE_T;
12818 +
12819 +#define VCOS_SUSPEND -1
12820 +#define VCOS_NO_SUSPEND 0
12821 +
12822 +#define VCOS_START 1
12823 +#define VCOS_NO_START 0
12824 +
12825 +#define VCOS_THREAD_PRI_MIN -20
12826 +#define VCOS_THREAD_PRI_MAX 19
12827 +
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
12834 +
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
12840 +
12841 +#define VCOS_TICKS_PER_SECOND HZ
12842 +
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"
12846 +
12847 +/***********************************************************
12848 + *
12849 + * Memory allcoation
12850 + *
12851 + ***********************************************************/
12852 +
12853 +#define _vcos_platform_malloc vcos_platform_malloc
12854 +#define _vcos_platform_free vcos_platform_free
12855 +
12856 +void *vcos_platform_malloc( VCOS_UNSIGNED required_size );
12857 +void vcos_platform_free( void *ptr );
12858 +
12859 +#if defined(VCOS_INLINE_BODIES)
12860 +
12861 +#undef VCOS_ASSERT_LOGGING_DISABLE
12862 +#define VCOS_ASSERT_LOGGING_DISABLE 1
12863 +
12864 +/***********************************************************
12865 + *
12866 + * Counted Semaphores
12867 + *
12868 + ***********************************************************/
12869 +
12870 +VCOS_INLINE_IMPL
12871 +VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem) {
12872 + int ret = down_interruptible(sem);
12873 + if ( ret == 0 )
12874 + /* Success */
12875 + return VCOS_SUCCESS;
12876 + else if ( ret == -EINTR )
12877 + /* Interrupted */
12878 + return VCOS_EINTR;
12879 + else
12880 + /* Default (timeout) */
12881 + return VCOS_EAGAIN;
12882 +}
12883 +
12884 +VCOS_INLINE_IMPL
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;
12889 +}
12890 +
12891 +VCOS_INLINE_IMPL
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;
12897 +}
12898 +
12899 +VCOS_INLINE_IMPL
12900 +void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem) {
12901 +}
12902 +
12903 +VCOS_INLINE_IMPL
12904 +VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem) {
12905 + up(sem);
12906 + return VCOS_SUCCESS;
12907 +}
12908 +
12909 +/***********************************************************
12910 + *
12911 + * Threads
12912 + *
12913 + ***********************************************************/
12914 +
12915 +#include "vcos_thread_map.h"
12916 +
12917 +VCOS_INLINE_IMPL
12918 +VCOS_LLTHREAD_T *vcos_llthread_current(void) {
12919 + return &vcos_kthread_current()->thread;
12920 +}
12921 +
12922 +VCOS_INLINE_IMPL
12923 +void vcos_llthread_resume(VCOS_LLTHREAD_T *thread) {
12924 + vcos_assert(0);
12925 +}
12926 +
12927 +VCOS_INLINE_IMPL
12928 +void vcos_sleep(uint32_t ms) {
12929 + msleep(ms);
12930 +}
12931 +
12932 +VCOS_INLINE_IMPL
12933 +void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED p) {
12934 + /* not implemented */
12935 +}
12936 +VCOS_INLINE_IMPL
12937 +VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread) {
12938 + /* not implemented */
12939 + return 0;
12940 +}
12941 +
12942 +/***********************************************************
12943 + *
12944 + * Miscellaneous
12945 + *
12946 + ***********************************************************/
12947 +
12948 +VCOS_INLINE_IMPL
12949 +int vcos_strcasecmp(const char *s1, const char *s2) {
12950 + return strcasecmp(s1,s2);
12951 +}
12952 +
12953 +
12954 +/***********************************************************
12955 + *
12956 + * Mutexes
12957 + *
12958 + ***********************************************************/
12959 +
12960 +VCOS_INLINE_IMPL
12961 +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *m, const char *name) {
12962 + mutex_init(m);
12963 + return VCOS_SUCCESS;
12964 +}
12965 +
12966 +VCOS_INLINE_IMPL
12967 +void vcos_mutex_delete(VCOS_MUTEX_T *m) {
12968 +}
12969 +
12970 +VCOS_INLINE_IMPL
12971 +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *m) {
12972 + int ret = mutex_lock_interruptible(m);
12973 + if ( ret == 0 )
12974 + /* Success */
12975 + return VCOS_SUCCESS;
12976 + else if ( ret == -EINTR )
12977 + /* Interrupted */
12978 + return VCOS_EINTR;
12979 + else
12980 + /* Default */
12981 + return VCOS_EAGAIN;
12982 +}
12983 +
12984 +VCOS_INLINE_IMPL
12985 +void vcos_mutex_unlock(VCOS_MUTEX_T *m) {
12986 + mutex_unlock(m);
12987 +}
12988 +
12989 +VCOS_INLINE_IMPL
12990 +int vcos_mutex_is_locked(VCOS_MUTEX_T *m) {
12991 + if (mutex_trylock(m) != 0)
12992 + return 1; /* it was locked */
12993 + mutex_unlock(m);
12994 + /* it wasn't locked */
12995 + return 0;
12996 +}
12997 +
12998 +VCOS_INLINE_IMPL
12999 +VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m) {
13000 + if (mutex_trylock(m) == 0)
13001 + return VCOS_SUCCESS;
13002 + else
13003 + return VCOS_EAGAIN;
13004 +}
13005 +
13006 +/* For supporting event groups - per thread semaphore */
13007 +VCOS_INLINE_IMPL
13008 +void _vcos_thread_sem_wait(void) {
13009 + VCOS_THREAD_T *t = vcos_thread_current();
13010 + vcos_semaphore_wait(&t->suspend);
13011 +}
13012 +
13013 +VCOS_INLINE_IMPL
13014 +void _vcos_thread_sem_post(VCOS_THREAD_T *target) {
13015 + vcos_semaphore_post(&target->suspend);
13016 +}
13017 +
13018 +/***********************************************************
13019 + *
13020 + * Events
13021 + *
13022 + ***********************************************************/
13023 +
13024 +VCOS_INLINE_IMPL
13025 +VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *debug_name)
13026 +{
13027 + sema_init(event, 0);
13028 + return VCOS_SUCCESS;
13029 +}
13030 +
13031 +VCOS_INLINE_IMPL
13032 +void vcos_event_signal(VCOS_EVENT_T *event)
13033 +{
13034 + up(event);
13035 +}
13036 +
13037 +VCOS_INLINE_IMPL
13038 +VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event)
13039 +{
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;
13050 +}
13051 +
13052 +VCOS_INLINE_DECL
13053 +VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event)
13054 +{
13055 + return (down_trylock(event) == 0) ? VCOS_SUCCESS : VCOS_EAGAIN;
13056 +}
13057 +
13058 +VCOS_INLINE_IMPL
13059 +void vcos_event_delete(VCOS_EVENT_T *event)
13060 +{
13061 +}
13062 +
13063 +/***********************************************************
13064 + *
13065 + * Timers
13066 + *
13067 + ***********************************************************/
13068 +
13069 +VCOS_INLINE_DECL
13070 +void vcos_timer_linux_func(unsigned long data)
13071 +{
13072 + VCOS_TIMER_T *vcos_timer = (VCOS_TIMER_T *)data;
13073 +
13074 + vcos_timer->expiration_routine( vcos_timer->context );
13075 +}
13076 +
13077 +VCOS_INLINE_DECL
13078 +VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
13079 + const char *name,
13080 + void (*expiration_routine)(void *context),
13081 + 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;
13085 +
13086 + timer->context = context;
13087 + timer->expiration_routine = expiration_routine;
13088 +
13089 + return VCOS_SUCCESS;
13090 +}
13091 +
13092 +VCOS_INLINE_IMPL
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);
13096 +}
13097 +
13098 +VCOS_INLINE_IMPL
13099 +void vcos_timer_cancel(VCOS_TIMER_T *timer) {
13100 + del_timer(&timer->linux_timer);
13101 +}
13102 +
13103 +VCOS_INLINE_IMPL
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);
13108 +}
13109 +
13110 +VCOS_INLINE_IMPL
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;
13116 + return;
13117 +}
13118 +
13119 +VCOS_INLINE_IMPL
13120 +VCOS_UNSIGNED vcos_process_id_current(void) {
13121 + return (VCOS_UNSIGNED)current->pid;
13122 +}
13123 +
13124 +
13125 +VCOS_INLINE_IMPL
13126 +int vcos_in_interrupt(void) {
13127 + return in_interrupt();
13128 +}
13129 +
13130 +/***********************************************************
13131 + *
13132 + * Atomic flags
13133 + *
13134 + ***********************************************************/
13135 +
13136 +VCOS_INLINE_IMPL
13137 +VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags)
13138 +{
13139 + atomic_set(atomic_flags, 0);
13140 + return VCOS_SUCCESS;
13141 +}
13142 +
13143 +VCOS_INLINE_IMPL
13144 +void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags)
13145 +{
13146 + uint32_t value;
13147 + do {
13148 + value = atomic_read(atomic_flags);
13149 + } while (atomic_cmpxchg(atomic_flags, value, value | flags) != value);
13150 +}
13151 +
13152 +VCOS_INLINE_IMPL
13153 +uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags)
13154 +{
13155 + return atomic_xchg(atomic_flags, 0);
13156 +}
13157 +
13158 +VCOS_INLINE_IMPL
13159 +void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags)
13160 +{
13161 +}
13162 +
13163 +#undef VCOS_ASSERT_LOGGING_DISABLE
13164 +#define VCOS_ASSERT_LOGGING_DISABLE 0
13165 +
13166 +#endif /* VCOS_INLINE_BODIES */
13167 +
13168 +VCOS_INLINE_DECL void _vcos_thread_sem_wait(void);
13169 +VCOS_INLINE_DECL void _vcos_thread_sem_post(VCOS_THREAD_T *);
13170 +
13171 +/***********************************************************
13172 + *
13173 + * Misc
13174 + *
13175 + ***********************************************************/
13176 +VCOS_INLINE_DECL char *vcos_strdup(const char *str);
13177 +
13178 +/***********************************************************
13179 + *
13180 + * Logging
13181 + *
13182 + ***********************************************************/
13183 +
13184 +VCOSPRE_ const char * VCOSPOST_ _vcos_log_level(void);
13185 +#define _VCOS_LOG_LEVEL() _vcos_log_level()
13186 +
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)
13190 +
13191 +struct VCOS_LOG_CAT_T; /* Forward declaration since vcos_logging.h hasn't been included yet */
13192 +
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);
13196 +
13197 +/***********************************************************
13198 + *
13199 + * Memory barriers
13200 + *
13201 + ***********************************************************/
13202 +
13203 +#define vcos_wmb(x) wmb()
13204 +#define vcos_rmb() rmb()
13205 +
13206 +#include "interface/vcos/generic/vcos_common.h"
13207 +/*#include "interface/vcos/generic/vcos_generic_quickslow_mutex.h" */
13208 +
13209 +#endif /* VCOS_PLATFORM_H */
13210 +
13211 --- /dev/null
13212 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform_types.h
13213 @@ -0,0 +1,47 @@
13214 +/*=============================================================================
13215 +Copyright (c) 2009 Broadcom Europe Limited.
13216 +All rights reserved.
13217 +
13218 +Project : vcfw
13219 +Module : osal
13220 +
13221 +FILE DESCRIPTION
13222 +VideoCore OS Abstraction Layer - platform-specific types and defines
13223 +=============================================================================*/
13224 +
13225 +#ifndef VCOS_PLATFORM_TYPES_H
13226 +#define VCOS_PLATFORM_TYPES_H
13227 +
13228 +#include <stddef.h>
13229 +#include <linux/types.h>
13230 +#include <linux/bug.h>
13231 +
13232 +#define VCOSPRE_ extern
13233 +#define VCOSPOST_
13234 +
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)))
13237 +#else
13238 +#define VCOS_FORMAT_ATTR_(ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK)
13239 +#endif
13240 +
13241 +#if !defined( __STDC_VERSION__ )
13242 +#define __STDC_VERSION__ 199901L
13243 +#endif
13244 +
13245 +#if !defined( __STDC_VERSION )
13246 +#define __STDC_VERSION __STDC_VERSION__
13247 +#endif
13248 +
13249 +static inline void __vcos_bkpt( void ) { BUG(); }
13250 +#define VCOS_BKPT __vcos_bkpt()
13251 +
13252 +#define VCOS_ASSERT_MSG(...) printk( KERN_ERR "vcos_assert: " __VA_ARGS__ )
13253 +
13254 +#define PRId64 "lld"
13255 +#define PRIi64 "lli"
13256 +#define PRIo64 "llo"
13257 +#define PRIu64 "llu"
13258 +#define PRIx64 "llx"
13259 +
13260 +#endif
13261 --- /dev/null
13262 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.c
13263 @@ -0,0 +1,129 @@
13264 +/*****************************************************************************
13265 +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved.
13266 +*
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").
13271 +*
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
13275 +* consent.
13276 +*****************************************************************************/
13277 +
13278 +/** Support to allow VCOS thread-related functions to be called from
13279 + * threads that were not created by VCOS.
13280 + */
13281 +
13282 +#include <linux/semaphore.h>
13283 +#include <linux/vmalloc.h>
13284 +#include <linux/list.h>
13285 +#include <linux/sched.h>
13286 +
13287 +#include "vcos_thread_map.h"
13288 +#include "interface/vcos/vcos_logging.h"
13289 +
13290 +/*
13291 + * Store the vcos_thread pointer at the end of
13292 + * current kthread stack, right after the thread_info
13293 + * structure.
13294 + *
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
13298 + *
13299 + * NOTE: This scheme will not work on architectures with stack growing up
13300 + */
13301 +
13302 +/* Shout, if we are not being compiled for ARM kernel */
13303 +
13304 +#ifndef CONFIG_ARM
13305 +#error " **** The vcos kthread implementation may not work for non-ARM kernel ****"
13306 +#endif
13307 +
13308 +static inline void *to_current_vcos_thread(void)
13309 +{
13310 + unsigned long *vcos_data;
13311 +
13312 + vcos_data = (unsigned long *)((char *)current_thread_info() + sizeof(struct thread_info));
13313 +
13314 + return (void *)vcos_data;
13315 +}
13316 +
13317 +
13318 +static inline void *to_vcos_thread(struct task_struct *tsk)
13319 +{
13320 + unsigned long *vcos_data;
13321 +
13322 + vcos_data = (unsigned long *)((char *)tsk->stack + sizeof(struct thread_info));
13323 +
13324 + return (void *)vcos_data;
13325 +}
13326 +
13327 +/**
13328 + @fn uint32_t vcos_add_thread(THREAD_MAP_T *vcos_thread);
13329 +*/
13330 +uint32_t vcos_add_thread(VCOS_THREAD_T *vcos_thread)
13331 +{
13332 + VCOS_THREAD_T **vcos_thread_storage = (VCOS_THREAD_T **)to_current_vcos_thread();
13333 +
13334 + *vcos_thread_storage = vcos_thread;
13335 +
13336 + return(0);
13337 +}
13338 +
13339 +
13340 +/**
13341 + @fn uint32_t vcos_remove_thread(struct task_struct * thread_id);
13342 +*/
13343 +uint32_t vcos_remove_thread(struct task_struct *thread_id)
13344 +{
13345 + /* Remove thread_id -> VCOS_THREAD_T relationship */
13346 + VCOS_THREAD_T **vcos_thread_storage;
13347 +
13348 + /*
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.
13352 + */
13353 +
13354 + BUG_ON( thread_id != current );
13355 +
13356 + vcos_thread_storage = (VCOS_THREAD_T **)to_vcos_thread(thread_id);
13357 +
13358 + *(unsigned long *)vcos_thread_storage = 0xCAFEBABE;
13359 +
13360 + return(0);
13361 +}
13362 +
13363 +
13364 +VCOS_THREAD_T *vcos_kthread_current(void)
13365 +{
13366 + VCOS_THREAD_T **vcos_thread_storage = (VCOS_THREAD_T **)to_current_vcos_thread();
13367 +
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.
13370 + *
13371 + * Since there's no way to differentiate between these 2 cases, we just dump
13372 + * the current task name to the log.
13373 + *
13374 + * If the current thread is created using VCOS API, you should *never* see this
13375 + * print.
13376 + *
13377 + * If its a non-VCOS thread, just let it go ...
13378 + *
13379 + * To debug VCOS, uncomment printk's under the "if" condition below
13380 + *
13381 + */
13382 + if (*vcos_thread_storage == (void *)0xCAFEBABE)
13383 + {
13384 + #if 0
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");
13388 + #endif
13389 + }
13390 +
13391 + return *vcos_thread_storage;
13392 +}
13393 --- /dev/null
13394 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.h
13395 @@ -0,0 +1,39 @@
13396 +/*****************************************************************************
13397 +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved.
13398 +*
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").
13403 +*
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
13407 +* consent.
13408 +*****************************************************************************/
13409 +
13410 +
13411 +#ifndef VCOS_THREAD_MAP_H
13412 +#define VCOS_THREAD_MAP_H
13413 +
13414 +#include <linux/string.h>
13415 +
13416 +#include "vcos_platform.h"
13417 +
13418 +static inline void vcos_thread_map_init(void)
13419 +{
13420 + return;
13421 +}
13422 +
13423 +static inline void vcos_thread_map_cleanup(void)
13424 +{
13425 + return;
13426 +}
13427 +
13428 +uint32_t vcos_add_thread(VCOS_THREAD_T *vcos_thread);
13429 +
13430 +uint32_t vcos_remove_thread(struct task_struct *thread_id);
13431 +
13432 +VCOS_THREAD_T *vcos_kthread_current(void);
13433 +
13434 +#endif /*VCOS_THREAD_MAP_H */
13435 --- /dev/null
13436 +++ b/drivers/misc/vc04_services/interface/vcos/vcos.h
13437 @@ -0,0 +1,201 @@
13438 +/*=============================================================================
13439 +Copyright (c) 2009 Broadcom Europe Limited.
13440 +All rights reserved.
13441 +
13442 +Project : vcfw
13443 +Module : chip driver
13444 +
13445 +FILE DESCRIPTION
13446 +VideoCore OS Abstraction Layer - public header file
13447 +=============================================================================*/
13448 +
13449 +/**
13450 + * \mainpage OS Abstraction Layer
13451 + *
13452 + * \section intro Introduction
13453 + *
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.
13456 + *
13457 + * \subsection error Error handling
13458 + *
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.
13463 + *
13464 + * \section thread_synch Threads and synchronisation
13465 + *
13466 + * \subsection thread Threads
13467 + *
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.
13473 + *
13474 + * \subsection sema Semaphores
13475 + *
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.
13479 + *
13480 + * \subsection mtx Mutexes
13481 + *
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).
13486 + *
13487 + * \subsection evflags Event flags
13488 + *
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.
13494 + *
13495 + * \subsection event Events
13496 + *
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.
13501 + *
13502 + * \subsection tls Thread local storage
13503 + *
13504 + * Thread local storage is supported using vcos_tls.h. This is emulated on Nucleus
13505 + * and ThreadX.
13506 + *
13507 + * \section int Interrupts
13508 + *
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.
13512 + *
13513 + * Registering an interrupt handler, and disabling/restoring interrupts, is handled
13514 + * using the functions in vcos_isr.h.
13515 + *
13516 + */
13517 +
13518 +/**
13519 + * \file vcos.h
13520 + *
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
13524 + * directly.
13525 + *
13526 + */
13527 +
13528 +#ifndef VCOS_H
13529 +#define VCOS_H
13530 +
13531 +#include "interface/vcos/vcos_assert.h"
13532 +#include "vcos_types.h"
13533 +#include "vcos_platform.h"
13534 +
13535 +#ifndef VCOS_INIT_H
13536 +#include "interface/vcos/vcos_init.h"
13537 +#endif
13538 +
13539 +#ifndef VCOS_SEMAPHORE_H
13540 +#include "interface/vcos/vcos_semaphore.h"
13541 +#endif
13542 +
13543 +#ifndef VCOS_THREAD_H
13544 +#include "interface/vcos/vcos_thread.h"
13545 +#endif
13546 +
13547 +#ifndef VCOS_MUTEX_H
13548 +#include "interface/vcos/vcos_mutex.h"
13549 +#endif
13550 +
13551 +#ifndef VCOS_MEM_H
13552 +#include "interface/vcos/vcos_mem.h"
13553 +#endif
13554 +
13555 +#ifndef VCOS_LOGGING_H
13556 +#include "interface/vcos/vcos_logging.h"
13557 +#endif
13558 +
13559 +#ifndef VCOS_STRING_H
13560 +#include "interface/vcos/vcos_string.h"
13561 +#endif
13562 +
13563 +#ifndef VCOS_EVENT_H
13564 +#include "interface/vcos/vcos_event.h"
13565 +#endif
13566 +
13567 +#ifndef VCOS_THREAD_ATTR_H
13568 +#include "interface/vcos/vcos_thread_attr.h"
13569 +#endif
13570 +
13571 +#ifndef VCOS_TLS_H
13572 +#include "interface/vcos/vcos_tls.h"
13573 +#endif
13574 +
13575 +#ifndef VCOS_REENTRANT_MUTEX_H
13576 +#include "interface/vcos/vcos_reentrant_mutex.h"
13577 +#endif
13578 +
13579 +#ifndef VCOS_NAMED_SEMAPHORE_H
13580 +#include "interface/vcos/vcos_named_semaphore.h"
13581 +#endif
13582 +
13583 +#ifndef VCOS_QUICKSLOW_MUTEX_H
13584 +#include "interface/vcos/vcos_quickslow_mutex.h"
13585 +#endif
13586 +
13587 +/* Headers with predicates */
13588 +
13589 +#if VCOS_HAVE_EVENT_FLAGS
13590 +#include "interface/vcos/vcos_event_flags.h"
13591 +#endif
13592 +
13593 +#if VCOS_HAVE_QUEUE
13594 +#include "interface/vcos/vcos_queue.h"
13595 +#endif
13596 +
13597 +#if VCOS_HAVE_LEGACY_ISR
13598 +#include "interface/vcos/vcos_legacy_isr.h"
13599 +#endif
13600 +
13601 +#if VCOS_HAVE_TIMER
13602 +#include "interface/vcos/vcos_timer.h"
13603 +#endif
13604 +
13605 +#if VCOS_HAVE_MEMPOOL
13606 +#include "interface/vcos/vcos_mempool.h"
13607 +#endif
13608 +
13609 +#if VCOS_HAVE_ISR
13610 +#include "interface/vcos/vcos_isr.h"
13611 +#endif
13612 +
13613 +#if VCOS_HAVE_ATOMIC_FLAGS
13614 +#include "interface/vcos/vcos_atomic_flags.h"
13615 +#endif
13616 +
13617 +#if VCOS_HAVE_ONCE
13618 +#include "interface/vcos/vcos_once.h"
13619 +#endif
13620 +
13621 +#if VCOS_HAVE_BLOCK_POOL
13622 +#include "interface/vcos/vcos_blockpool.h"
13623 +#endif
13624 +
13625 +#if VCOS_HAVE_FILE
13626 +#include "interface/vcos/vcos_file.h"
13627 +#endif
13628 +
13629 +#if VCOS_HAVE_CFG
13630 +#include "interface/vcos/vcos_cfg.h"
13631 +#endif
13632 +
13633 +#if VCOS_HAVE_CMD
13634 +#include "interface/vcos/vcos_cmd.h"
13635 +#endif
13636 +
13637 +#endif /* VCOS_H */
13638 +
13639 --- /dev/null
13640 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_assert.h
13641 @@ -0,0 +1,269 @@
13642 +/*=============================================================================
13643 +Copyright (c) 2009 Broadcom Europe Limited.
13644 +All rights reserved.
13645 +
13646 +Project : vcfw
13647 +Module : osal
13648 +
13649 +FILE DESCRIPTION
13650 +VideoCore OS Abstraction Layer - Assertion and error-handling macros.
13651 +=============================================================================*/
13652 +
13653 +
13654 +#ifndef VCOS_ASSERT_H
13655 +#define VCOS_ASSERT_H
13656 +
13657 +/*
13658 + * Macro:
13659 + * vcos_assert(cond)
13660 + * vcos_assert_msg(cond, fmt, ...)
13661 + * Use:
13662 + * Detecting programming errors by ensuring that assumptions are correct.
13663 + * On failure:
13664 + * Performs a platform-dependent "breakpoint", usually with an assert-style
13665 + * message. The '_msg' variant expects a printf-style format string and
13666 + * parameters.
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'.
13670 + * Returns:
13671 + * Nothing.
13672 + *
13673 + * Macro:
13674 + * vcos_demand(cond)
13675 + * vcos_demand_msg(cond, fmt, ...)
13676 + * Use:
13677 + * Detecting fatal system errors that require a reboot.
13678 + * On failure:
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.
13683 + * Returns:
13684 + * Nothing (never, on failure).
13685 + *
13686 + * Macro:
13687 + * vcos_verify(cond)
13688 + * vcos_verify_msg(cond, fmt, ...)
13689 + * Use:
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();
13693 + * On failure:
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'.
13698 + * Returns:
13699 + * Non-zero if 'cond' is true, otherwise zero.
13700 + *
13701 + * Macro:
13702 + * vcos_static_assert(cond)
13703 + * Use:
13704 + * Detecting compile-time errors.
13705 + * On failure:
13706 + * Generates a compiler error.
13707 + * In release builds:
13708 + * Generates a compiler error.
13709 + *
13710 + * Function:
13711 + * void vcos_abort(void)
13712 + * Use:
13713 + * Invokes the fatal error handling mechanism, alerting the host where
13714 + * applicable.
13715 + * Returns:
13716 + * Never.
13717 + *
13718 + * Macro:
13719 + * VCOS_VERIFY_BKPTS
13720 + * Use:
13721 + * Define in a module (before including vcos.h) to specify an alternative
13722 + * flag to control breakpoints on vcos_verify() failures.
13723 + * Returns:
13724 + * Non-zero values enable breakpoints.
13725 + *
13726 + * Function:
13727 + * int vcos_verify_bkpts_enable(int enable);
13728 + * Use:
13729 + * Sets the global flag controlling breakpoints on vcos_verify failures,
13730 + * enabling the breakpoints iff 'enable' is non-zero.
13731 + * Returns:
13732 + * The previous state of the flag.
13733 + *
13734 + * Function:
13735 + * int vcos_verify_bkpts_enabled(void);
13736 + * Use:
13737 + * Queries the state of the global flag enabling breakpoints on vcos_verify
13738 + * failures.
13739 + * Returns:
13740 + * The current state of the flag.
13741 + *
13742 + * Examples:
13743 + *
13744 + * int my_breakpoint_enable_flag = 1;
13745 + *
13746 + * #define VCOS_VERIFY_BKPTS my_breakpoint_enable_flag
13747 + *
13748 + * #include "interface/vcos/vcos.h"
13749 + *
13750 + * vcos_static_assert((sizeof(object) % 32) == 0);
13751 + *
13752 + * // ...
13753 + *
13754 + * vcos_assert_msg(postcondition_is_true, "Coding error");
13755 + *
13756 + * if (!vcos_verify_msg(buf, "Buffer allocation failed (%d bytes)", size))
13757 + * {
13758 + * // Tidy up
13759 + * // ...
13760 + * return OUT_OF_MEMORY;
13761 + * }
13762 + *
13763 + * vcos_demand(*p++==GUARDWORDHEAP);
13764 + */
13765 +
13766 +#ifdef __cplusplus
13767 +extern "C" {
13768 +#endif
13769 +
13770 +#include "interface/vcos/vcos_types.h"
13771 +
13772 +#ifdef __COVERITY__
13773 +#undef VCOS_ASSERT_BKPT
13774 +#define VCOS_ASSERT_BKPT __coverity_panic__()
13775 +#endif
13776 +
13777 +#ifndef VCOS_VERIFY_BKPTS
13778 +#define VCOS_VERIFY_BKPTS vcos_verify_bkpts_enabled()
13779 +#endif
13780 +
13781 +#ifndef VCOS_BKPT
13782 +#if defined(__VIDEOCORE__) && !defined(VCOS_ASSERT_NO_BKPTS)
13783 +#define VCOS_BKPT _bkpt()
13784 +#else
13785 +#define VCOS_BKPT (void )0
13786 +#endif
13787 +#endif
13788 +
13789 +#ifndef VCOS_ASSERT_BKPT
13790 +#define VCOS_ASSERT_BKPT VCOS_BKPT
13791 +#endif
13792 +
13793 +#ifndef VCOS_VERIFY_BKPT
13794 +#define VCOS_VERIFY_BKPT (VCOS_VERIFY_BKPTS ? VCOS_BKPT : (void)0)
13795 +#endif
13796 +
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);
13800 +
13801 +#ifndef VCOS_ASSERT_MSG
13802 +#ifdef LOGGING
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)
13805 +#else
13806 +#define VCOS_ASSERT_MSG(...) ((void)0)
13807 +#endif
13808 +#endif
13809 +
13810 +#ifndef VCOS_VERIFY_MSG
13811 +#define VCOS_VERIFY_MSG(...) VCOS_ASSERT_MSG(__VA_ARGS__)
13812 +#endif
13813 +
13814 +#ifndef VCOS_ASSERT_LOGGING
13815 +#define VCOS_ASSERT_LOGGING 0
13816 +#endif
13817 +
13818 +#ifndef VCOS_ASSERT_LOGGING_DISABLE
13819 +#define VCOS_ASSERT_LOGGING_DISABLE 0
13820 +#endif
13821 +
13822 +#if !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS)
13823 +
13824 +#ifndef vcos_assert
13825 +#define vcos_assert(cond) \
13826 + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG("%s", #cond), VCOS_ASSERT_BKPT) )
13827 +#endif
13828 +
13829 +#ifndef vcos_assert_msg
13830 +#define vcos_assert_msg(cond, ...) \
13831 + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT) )
13832 +#endif
13833 +
13834 +#else /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */
13835 +
13836 +#ifndef vcos_assert
13837 +#define vcos_assert(cond) (void)0
13838 +#endif
13839 +
13840 +#ifndef vcos_assert_msg
13841 +#define vcos_assert_msg(cond, ...) (void)0
13842 +#endif
13843 +
13844 +#endif /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */
13845 +
13846 +#if !defined(NDEBUG)
13847 +
13848 +#ifndef vcos_demand
13849 +#define vcos_demand(cond) \
13850 + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG("%s", #cond), VCOS_ASSERT_BKPT, vcos_abort()) )
13851 +#endif
13852 +
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()) )
13856 +#endif
13857 +
13858 +#ifndef vcos_verify
13859 +#define vcos_verify(cond) \
13860 + ( (cond) ? 1 : (VCOS_VERIFY_MSG("%s", #cond), VCOS_VERIFY_BKPT, 0) )
13861 +#endif
13862 +
13863 +#ifndef vcos_verify_msg
13864 +#define vcos_verify_msg(cond, ...) \
13865 + ( (cond) ? 1 : (VCOS_VERIFY_MSG(__VA_ARGS__), VCOS_VERIFY_BKPT, 0) )
13866 +#endif
13867 +
13868 +#else /* !defined(NDEBUG) */
13869 +
13870 +#ifndef vcos_demand
13871 +#define vcos_demand(cond) \
13872 + ( (cond) ? (void)0 : vcos_abort() )
13873 +#endif
13874 +
13875 +#ifndef vcos_demand_msg
13876 +#define vcos_demand_msg(cond, ...) \
13877 + ( (cond) ? (void)0 : vcos_abort() )
13878 +#endif
13879 +
13880 +#ifndef vcos_verify
13881 +#define vcos_verify(cond) (cond)
13882 +#endif
13883 +
13884 +#ifndef vcos_verify_msg
13885 +#define vcos_verify_msg(cond, ...) (cond)
13886 +#endif
13887 +
13888 +#endif /* !defined(NDEBUG) */
13889 +
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]
13893 +#else
13894 +#define vcos_static_assert(cond) extern int vcos_static_assert[(cond)?1:-1]
13895 +#endif
13896 +#endif
13897 +
13898 +#ifndef vc_assert
13899 +#define vc_assert(cond) vcos_assert(cond)
13900 +#endif
13901 +
13902 +/** Print out a backtrace, on supported platforms.
13903 + */
13904 +extern void vcos_backtrace_self(void);
13905 +
13906 +#ifdef __cplusplus
13907 +}
13908 +#endif
13909 +
13910 +#endif /* VCOS_ASSERT_H */
13911 --- /dev/null
13912 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_atomic_flags.h
13913 @@ -0,0 +1,72 @@
13914 +/*=============================================================================
13915 +Copyright (c) 2009 Broadcom Europe Limited.
13916 +All rights reserved.
13917 +
13918 +Project : vcfw
13919 +Module : chip driver (just for consistency with the rest of vcos ;)
13920 +
13921 +FILE DESCRIPTION
13922 +VideoCore OS Abstraction Layer - public header file
13923 +=============================================================================*/
13924 +
13925 +#ifndef VCOS_ATOMIC_FLAGS_H
13926 +#define VCOS_ATOMIC_FLAGS_H
13927 +
13928 +#ifdef __cplusplus
13929 +extern "C" {
13930 +#endif
13931 +
13932 +#include "interface/vcos/vcos_types.h"
13933 +#include "vcos_platform.h"
13934 +
13935 +/**
13936 + * \file vcos_atomic_flags.h
13937 + *
13938 + * Defines atomic flags API.
13939 + *
13940 + * 32 flags. Atomic "or" and "get and clear" operations
13941 + */
13942 +
13943 +/**
13944 + * Create an atomic flags instance.
13945 + *
13946 + * @param atomic_flags Pointer to atomic flags instance, filled in on return
13947 + *
13948 + * @return VCOS_SUCCESS if succeeded.
13949 + */
13950 +VCOS_INLINE_DECL
13951 +VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags);
13952 +
13953 +/**
13954 + * Atomically set the specified flags.
13955 + *
13956 + * @param atomic_flags Instance to set flags on
13957 + * @param flags Mask of flags to set
13958 + */
13959 +VCOS_INLINE_DECL
13960 +void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags);
13961 +
13962 +/**
13963 + * Retrieve the current flags and then clear them. The entire operation is
13964 + * atomic.
13965 + *
13966 + * @param atomic_flags Instance to get/clear flags from/on
13967 + *
13968 + * @return Mask of flags which were set (and we cleared)
13969 + */
13970 +VCOS_INLINE_DECL
13971 +uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags);
13972 +
13973 +/**
13974 + * Delete an atomic flags instance.
13975 + *
13976 + * @param atomic_flags Instance to delete
13977 + */
13978 +VCOS_INLINE_DECL
13979 +void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags);
13980 +
13981 +#ifdef __cplusplus
13982 +}
13983 +#endif
13984 +
13985 +#endif
13986 --- /dev/null
13987 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_build_info.h
13988 @@ -0,0 +1,5 @@
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 );
13993 +
13994 --- /dev/null
13995 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_cfg.h
13996 @@ -0,0 +1,113 @@
13997 +/*****************************************************************************
13998 +* Copyright 2009 - 2011 Broadcom Corporation. All rights reserved.
13999 +*
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").
14004 +*
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
14008 +* consent.
14009 +*****************************************************************************/
14010 +
14011 +#if !defined( VCOS_CFG_H )
14012 +#define VCOS_CFG_H
14013 +
14014 +#ifdef __cplusplus
14015 +extern "C" {
14016 +#endif
14017 +
14018 +#include "interface/vcos/vcos_types.h"
14019 +#include "vcos_platform.h"
14020 +
14021 +typedef struct opaque_vcos_cfg_buf_t *VCOS_CFG_BUF_T;
14022 +typedef struct opaque_vcos_cfg_entry_t *VCOS_CFG_ENTRY_T;
14023 +
14024 +/** \file vcos_file.h
14025 + *
14026 + * API for accessing configuration/statistics information. This
14027 + * is loosely modelled on the linux proc entries.
14028 + */
14029 +
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 );
14032 +
14033 +/** Create a configuration directory.
14034 + *
14035 + * @param entry Place to store the created config entry.
14036 + * @param parent Parent entry (for directory like config
14037 + * options).
14038 + * @param entryName Name of the directory.
14039 + */
14040 +
14041 +VCOS_STATUS_T vcos_cfg_mkdir( VCOS_CFG_ENTRY_T *entry,
14042 + VCOS_CFG_ENTRY_T *parent,
14043 + const char *dirName );
14044 +
14045 +/** Create a configuration entry.
14046 + *
14047 + * @param entry Place to store the created config entry.
14048 + * @param parent Parent entry (for directory like config
14049 + * options).
14050 + * @param entryName Name of the configuration entry.
14051 + * @param showFunc Function pointer to show configuration
14052 + * data.
14053 + * @param parseFunc Function pointer to parse new data.
14054 + */
14055 +
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,
14061 + void *data );
14062 +
14063 +/** Determines if a configuration entry has been created or not.
14064 + *
14065 + * @param entry Configuration entry to query.
14066 + */
14067 +
14068 +int vcos_cfg_is_entry_created( VCOS_CFG_ENTRY_T entry );
14069 +
14070 +/** Returns the name of a configuration entry.
14071 + *
14072 + * @param entry Configuration entry to query.
14073 + */
14074 +
14075 +const char *vcos_cfg_get_entry_name( VCOS_CFG_ENTRY_T entry );
14076 +
14077 +/** Removes a configuration entry.
14078 + *
14079 + * @param entry Configuration entry to remove.
14080 + */
14081 +
14082 +VCOS_STATUS_T vcos_cfg_remove_entry( VCOS_CFG_ENTRY_T *entry );
14083 +
14084 +
14085 +/** Writes data into a configuration buffer. Only valid inside
14086 + * the show function.
14087 + *
14088 + * @param buf Buffer to write data into.
14089 + * @param fmt printf style format string.
14090 + */
14091 +
14092 +void vcos_cfg_buf_printf( VCOS_CFG_BUF_T buf, const char *fmt, ... );
14093 +
14094 +/** Retrieves a null terminated string of the data associated
14095 + * with the buffer. Only valid inside the parse function.
14096 + *
14097 + * @param buf Buffer to get data from.
14098 + * @param fmt printf style format string.
14099 + */
14100 +
14101 +char *vcos_cfg_buf_get_str( VCOS_CFG_BUF_T buf );
14102 +
14103 +void *vcos_cfg_get_proc_entry( VCOS_CFG_ENTRY_T entry );
14104 +
14105 +#ifdef __cplusplus
14106 +}
14107 +#endif
14108 +#endif
14109 +
14110 --- /dev/null
14111 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_cmd.h
14112 @@ -0,0 +1,98 @@
14113 +/*****************************************************************************
14114 +* Copyright 2009 - 2011 Broadcom Corporation. All rights reserved.
14115 +*
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").
14120 +*
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
14124 +* consent.
14125 +*****************************************************************************/
14126 +
14127 +#if !defined( VCOS_CMD_H )
14128 +#define VCOS_CMD_H
14129 +
14130 +/* ---- Include Files ----------------------------------------------------- */
14131 +
14132 +#include "interface/vcos/vcos.h"
14133 +#include "interface/vcos/vcos_stdint.h"
14134 +
14135 +
14136 +/* ---- Constants and Types ---------------------------------------------- */
14137 +
14138 +struct VCOS_CMD_S;
14139 +typedef struct VCOS_CMD_S VCOS_CMD_T;
14140 +
14141 +typedef struct
14142 +{
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 */
14146 +
14147 + VCOS_CMD_T *cmd_entry;
14148 + VCOS_CMD_T *cmd_parent_entry;
14149 +
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. */
14154 +
14155 +} VCOS_CMD_PARAM_T;
14156 +
14157 +typedef VCOS_STATUS_T (*VCOS_CMD_FUNC_T)( VCOS_CMD_PARAM_T *param );
14158 +
14159 +struct VCOS_CMD_S
14160 +{
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;
14166 +
14167 +};
14168 +
14169 +/* ---- Variable Externs ------------------------------------------------- */
14170 +
14171 +/* ---- Function Prototypes ---------------------------------------------- */
14172 +
14173 +/*
14174 + * Common printing routine for generating command output.
14175 + */
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);
14179 +
14180 +/*
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.
14185 + */
14186 +VCOSPRE_ void VCOSPOST_ vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category );
14187 +
14188 +/*
14189 + * Prints command usage for the current command.
14190 + */
14191 +VCOSPRE_ void VCOSPOST_ vcos_cmd_usage( VCOS_CMD_PARAM_T *param );
14192 +
14193 +/*
14194 + * Register commands to be processed
14195 + */
14196 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register( VCOS_CMD_T *cmd_entry );
14197 +
14198 +/*
14199 + * Registers multiple commands to be processed. The array should
14200 + * be terminated by an entry with all zeros.
14201 + */
14202 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry );
14203 +
14204 +/*
14205 + * Executes a command based on a command line.
14206 + */
14207 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf );
14208 +
14209 +#endif /* VCOS_CMD_H */
14210 +
14211 --- /dev/null
14212 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_ctype.h
14213 @@ -0,0 +1,29 @@
14214 +/*=============================================================================
14215 +Copyright (c) 2009 Broadcom Europe Limited.
14216 +All rights reserved.
14217 +
14218 +Project : vcfw
14219 +Module : chip driver
14220 +
14221 +FILE DESCRIPTION
14222 +VideoCore OS Abstraction Layer - public header file
14223 +=============================================================================*/
14224 +
14225 +#ifndef VCOS_CTYPE_H
14226 +#define VCOS_CTYPE_H
14227 +
14228 +/**
14229 + * \file
14230 + *
14231 + * ctype functions.
14232 + *
14233 + */
14234 +
14235 +#ifdef __KERNEL__
14236 +#include <linux/ctype.h>
14237 +#else
14238 +#include <ctype.h>
14239 +#endif
14240 +
14241 +#endif
14242 +
14243 --- /dev/null
14244 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_dlfcn.h
14245 @@ -0,0 +1,69 @@
14246 +/*=============================================================================
14247 +Copyright (c) 2010 Broadcom Europe Limited.
14248 +All rights reserved.
14249 +
14250 +Project : vcfw
14251 +Module : chip driver
14252 +
14253 +FILE DESCRIPTION
14254 +VCOS - abstraction over dynamic library opening
14255 +=============================================================================*/
14256 +
14257 +#ifndef VCOS_DLFCN_H
14258 +#define VCOS_DLFCN_H
14259 +
14260 +#include "interface/vcos/vcos_types.h"
14261 +#include "vcos_platform.h"
14262 +
14263 +#ifdef __cplusplus
14264 +extern "C" {
14265 +#endif
14266 +
14267 +#define VCOS_DL_LAZY 1
14268 +#define VCOS_DL_NOW 2
14269 +
14270 +/**
14271 + * \file
14272 + *
14273 + * Loading dynamic libraries. See also dlfcn.h.
14274 + */
14275 +
14276 +/** Open a dynamic library.
14277 + *
14278 + * @param name name of the library
14279 + * @param mode Load lazily or immediately (VCOS_DL_LAZY, VCOS_DL_NOW).
14280 + *
14281 + * @return A handle for use in subsequent calls.
14282 + */
14283 +VCOSPRE_ void * VCOSPOST_ vcos_dlopen(const char *name, int mode);
14284 +
14285 +/** Look up a symbol.
14286 + *
14287 + * @param handle Handle to open
14288 + * @param name Name of function
14289 + *
14290 + * @return Function pointer, or NULL.
14291 + */
14292 +VCOSPRE_ void VCOSPOST_ (*vcos_dlsym(void *handle, const char *name))(void);
14293 +
14294 +/** Close a library
14295 + *
14296 + * @param handle Handle to close
14297 + */
14298 +VCOSPRE_ int VCOSPOST_ vcos_dlclose (void *handle);
14299 +
14300 +/** Return error message from library.
14301 + *
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).
14305 + */
14306 +VCOSPRE_ int VCOSPOST_ vcos_dlerror(int *err, char *buf, size_t buflen);
14307 +
14308 +
14309 +#ifdef __cplusplus
14310 +}
14311 +#endif
14312 +#endif
14313 +
14314 +
14315 --- /dev/null
14316 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_event.h
14317 @@ -0,0 +1,97 @@
14318 +/*=============================================================================
14319 +Copyright (c) 2009 Broadcom Europe Limited.
14320 +All rights reserved.
14321 +
14322 +Project : vcfw
14323 +Module : chip driver
14324 +
14325 +FILE DESCRIPTION
14326 +VideoCore OS Abstraction Layer - public header file for events
14327 +=============================================================================*/
14328 +
14329 +#ifndef VCOS_EVENT_H
14330 +#define VCOS_EVENT_H
14331 +
14332 +#ifdef __cplusplus
14333 +extern "C" {
14334 +#endif
14335 +
14336 +#include "interface/vcos/vcos_types.h"
14337 +#include "vcos_platform.h"
14338 +
14339 +/**
14340 + * \file
14341 + *
14342 + * An event is akin to the Win32 auto-reset event.
14343 + *
14344 + *
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
14347 + * state.
14348 + *
14349 + * If no threads are waiting on the event when it is signalled it remains
14350 + * signalled.
14351 + *
14352 + * This is almost, but not quite, completely unlike the "event flags"
14353 + * object based on Nucleus event groups and ThreadX event flags.
14354 + *
14355 + * In particular, it should be similar in speed to a semaphore, unlike
14356 + * the event flags.
14357 + */
14358 +
14359 +/**
14360 + * Create an event instance.
14361 + *
14362 + * @param event Filled in with constructed event.
14363 + * @param name Name of the event (for debugging)
14364 + *
14365 + * @return VCOS_SUCCESS on success, or error code.
14366 + */
14367 +VCOS_INLINE_DECL
14368 +VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *name);
14369 +
14370 +#ifndef vcos_event_signal
14371 +
14372 +/**
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.
14376 + *
14377 + * @param event The event to signal
14378 + */
14379 +VCOS_INLINE_DECL
14380 +void vcos_event_signal(VCOS_EVENT_T *event);
14381 +
14382 +/**
14383 + * Wait for the event.
14384 + *
14385 + * @param event The event to wait for
14386 + * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the wait was interrupted.
14387 + */
14388 +VCOS_INLINE_DECL
14389 +VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event);
14390 +
14391 +/**
14392 + * Try event, but don't block.
14393 + *
14394 + * @param event The event to try
14395 + * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the event is not currently signalled
14396 + */
14397 +VCOS_INLINE_DECL
14398 +VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event);
14399 +
14400 +#endif
14401 +
14402 +/*
14403 + * Destroy an event.
14404 + */
14405 +VCOS_INLINE_DECL
14406 +void vcos_event_delete(VCOS_EVENT_T *event);
14407 +
14408 +#ifdef __cplusplus
14409 +}
14410 +#endif
14411 +
14412 +#endif
14413 +
14414 +
14415 --- /dev/null
14416 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_event_flags.h
14417 @@ -0,0 +1,98 @@
14418 +/*=============================================================================
14419 +Copyright (c) 2009 Broadcom Europe Limited.
14420 +All rights reserved.
14421 +
14422 +Project : vcfw
14423 +Module : chip driver
14424 +
14425 +FILE DESCRIPTION
14426 +VideoCore OS Abstraction Layer - public header file
14427 +=============================================================================*/
14428 +
14429 +#ifndef VCOS_EVENT_FLAGS_H
14430 +#define VCOS_EVENT_FLAGS_H
14431 +
14432 +
14433 +#ifdef __cplusplus
14434 +extern "C" {
14435 +#endif
14436 +
14437 +#include "interface/vcos/vcos_types.h"
14438 +#include "vcos_platform.h"
14439 +
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;
14443 +
14444 +/**
14445 + * \file vcos_event_flags.h
14446 + *
14447 + * Defines event flags API.
14448 + *
14449 + * Similar to Nucleus event groups.
14450 + *
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.
14454 + *
14455 + */
14456 +
14457 +/**
14458 + * Create an event flags instance.
14459 + *
14460 + * @param flags Pointer to event flags instance, filled in on return.
14461 + * @param name Name for the event flags, used for debug.
14462 + *
14463 + * @return VCOS_SUCCESS if succeeded.
14464 + */
14465 +
14466 +VCOS_INLINE_DECL
14467 +VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name);
14468 +
14469 +/**
14470 + * Set some events.
14471 + *
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.
14476 + */
14477 +VCOS_INLINE_DECL
14478 +void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
14479 + VCOS_UNSIGNED events,
14480 + VCOS_OPTION op);
14481 +
14482 +/**
14483 + * Retrieve some events.
14484 + *
14485 + * Waits until the specified events have been set.
14486 + *
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.
14492 + *
14493 + * @return VCOS_SUCCESS if events were retrieved. VCOS_EAGAIN if the
14494 + * timeout expired.
14495 + */
14496 +VCOS_INLINE_DECL
14497 +VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
14498 + VCOS_UNSIGNED requested_events,
14499 + VCOS_OPTION op,
14500 + VCOS_UNSIGNED ms_suspend,
14501 + VCOS_UNSIGNED *retrieved_events);
14502 +
14503 +
14504 +/**
14505 + * Delete an event flags instance.
14506 + */
14507 +VCOS_INLINE_DECL
14508 +void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *);
14509 +
14510 +#ifdef __cplusplus
14511 +}
14512 +#endif
14513 +
14514 +#endif
14515 +
14516 --- /dev/null
14517 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_init.h
14518 @@ -0,0 +1,43 @@
14519 +/*=============================================================================
14520 +Copyright (c) 2009 Broadcom Europe Limited.
14521 +All rights reserved.
14522 +
14523 +Project : vcfw
14524 +Module : chip driver
14525 +
14526 +FILE DESCRIPTION
14527 +VideoCore OS Abstraction Layer - initialization routines
14528 +=============================================================================*/
14529 +
14530 +
14531 +#include "interface/vcos/vcos_types.h"
14532 +#include "vcos_platform.h"
14533 +
14534 +#ifdef __cplusplus
14535 +extern "C" {
14536 +#endif
14537 +
14538 +/** \file
14539 + *
14540 + * Some OS support libraries need some initialization. To support this, call this
14541 + * function at the start of day.
14542 + */
14543 +
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);
14548 +
14549 +/** Pass in the argv/argc arguments passed to main() */
14550 +VCOSPRE_ void VCOSPOST_ vcos_set_args(int argc, const char **argv);
14551 +
14552 +/** Return argc. */
14553 +VCOSPRE_ int VCOSPOST_ vcos_get_argc(void);
14554 +
14555 +/** Return argv. */
14556 +VCOSPRE_ const char ** VCOSPOST_ vcos_get_argv(void);
14557 +
14558 +#ifdef __cplusplus
14559 +}
14560 +#endif
14561 +
14562 --- /dev/null
14563 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_logging.h
14564 @@ -0,0 +1,279 @@
14565 +/*=============================================================================
14566 +Copyright (c) 2009-2011 Broadcom Europe Limited.
14567 +All rights reserved.
14568 +
14569 +Project : vcfw
14570 +Module : chip driver
14571 +
14572 +FILE DESCRIPTION
14573 +VideoCore OS Abstraction Layer - logging support
14574 +=============================================================================*/
14575 +
14576 +#ifndef VCOS_LOGGING_H
14577 +#define VCOS_LOGGING_H
14578 +
14579 +#ifdef __cplusplus
14580 +extern "C" {
14581 +#endif
14582 +
14583 +#include <stdarg.h>
14584 +
14585 +#include "interface/vcos/vcos_types.h"
14586 +#include "vcos_platform.h"
14587 +
14588 +/**
14589 + * \file
14590 + *
14591 + * Logging support
14592 + *
14593 + * This provides categorised logging. Clients register
14594 + * a category, and then get a number of logging levels for
14595 + * that category.
14596 + *
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.
14601 + *
14602 + * \section VCOS_LOG_CATEGORY
14603 + *
14604 + * As a convenience, clients define VCOS_LOG_CATEGORY to point to
14605 + * their category; the various vcos_log_xxx() macros then expand to
14606 + * use this.
14607 + *
14608 + * e.g.
14609 + *
14610 + * #define VCOS_LOG_CATEGORY (&my_category)
14611 + *
14612 + * #include <interface/vcos/vcos.h>
14613 + *
14614 + * VCOS_LOG_CAT_T my_category;
14615 + *
14616 + * ....
14617 + *
14618 + * vcos_log_trace("Stuff happened: %d", n_stuff);
14619 + *
14620 + */
14621 +
14622 +/** Logging levels */
14623 +typedef enum VCOS_LOG_LEVEL_T
14624 +{
14625 + VCOS_LOG_UNINITIALIZED = 0,
14626 + VCOS_LOG_NEVER,
14627 + VCOS_LOG_ERROR,
14628 + VCOS_LOG_WARN,
14629 + VCOS_LOG_INFO,
14630 + VCOS_LOG_TRACE,
14631 +} VCOS_LOG_LEVEL_T;
14632 +
14633 +
14634 +/** Initialize a logging category without going through vcos_log_register().
14635 + *
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.
14640 + */
14641 +#define VCOS_LOG_INIT(n,l) { l, n, 0, {0}, 0, 0 }
14642 +
14643 +/** A registered logging category.
14644 + */
14645 +typedef struct VCOS_LOG_CAT_T
14646 +{
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;
14650 + struct {
14651 + unsigned int want_prefix:1;
14652 + } flags;
14653 + unsigned int refcount;
14654 + void *platform_data; /** platform specific data */
14655 +} VCOS_LOG_CAT_T;
14656 +
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);
14658 +
14659 +/** Convert a VCOS_LOG_LEVEL_T into a printable string.
14660 + * The platform needs to implement this function.
14661 + */
14662 +VCOSPRE_ const char * VCOSPOST_ vcos_log_level_to_string( VCOS_LOG_LEVEL_T level );
14663 +
14664 +/** Convert a string into a VCOS_LOG_LEVEL_T
14665 + * The platform needs to implement this function.
14666 + */
14667 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level );
14668 +
14669 +/** Log a message. Basic API. Normal code should not use this.
14670 + * The platform needs to implement this function.
14671 + */
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);
14673 +
14674 +/** Log a message using a varargs parameter list. Normal code should
14675 + * not use this.
14676 + */
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);
14678 +
14679 +/** Set the function which does the actual logging output.
14680 + * Passing in NULL causes the default logging function to be
14681 + * used.
14682 + */
14683 +VCOSPRE_ void VCOSPOST_ vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func );
14684 +
14685 +/** The default logging function, which is provided by each
14686 + * platform.
14687 + */
14688 +
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);
14690 +
14691 +/*
14692 + * Initialise the logging subsystem. This is called from
14693 + * vcos_init() so you don't normally need to call it.
14694 + */
14695 +VCOSPRE_ void VCOSPOST_ vcos_logging_init(void);
14696 +
14697 +/** Register a logging category.
14698 + *
14699 + * @param name the name of this category.
14700 + * @param category the category to register.
14701 + */
14702 +VCOSPRE_ void VCOSPOST_ vcos_log_register(const char *name, VCOS_LOG_CAT_T *category);
14703 +
14704 +/** Unregister a logging category.
14705 + */
14706 +VCOSPRE_ void VCOSPOST_ vcos_log_unregister(VCOS_LOG_CAT_T *category);
14707 +
14708 +/** Return a default logging category, for people too lazy to create their own.
14709 + *
14710 + * Using the default category will be slow (there's an extra function
14711 + * call overhead). Don't do this in normal code.
14712 + */
14713 +VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void);
14714 +
14715 +VCOSPRE_ void VCOSPOST_ vcos_set_log_options(const char *opt);
14716 +
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.
14719 + *
14720 + * @param category the category to modify.
14721 + * @param level the new logging level for this category.
14722 + */
14723 +VCOS_STATIC_INLINE void vcos_log_set_level(VCOS_LOG_CAT_T *category, VCOS_LOG_LEVEL_T level)
14724 +{
14725 + category->level = level;
14726 +}
14727 +
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)
14729 +
14730 +void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
14731 + const char *label,
14732 + uint32_t addr,
14733 + const void *voidMem,
14734 + size_t numBytes );
14735 +
14736 +/*
14737 + * Platform specific hooks (optional).
14738 + */
14739 +#ifndef vcos_log_platform_init
14740 +#define vcos_log_platform_init() (void)0
14741 +#endif
14742 +
14743 +#ifndef vcos_log_platform_register
14744 +#define vcos_log_platform_register(category) (void)0
14745 +#endif
14746 +
14747 +#ifndef vcos_log_platform_unregister
14748 +#define vcos_log_platform_unregister(category) (void)0
14749 +#endif
14750 +
14751 +/* VCOS_TRACE() - deprecated macro which just outputs in a debug build and
14752 + * is a no-op in a release build.
14753 + *
14754 + * _VCOS_LOG_X() - internal macro which outputs if the current level for the
14755 + * particular category is higher than the supplied message level.
14756 + */
14757 +
14758 +#define VCOS_LOG_DFLT_CATEGORY vcos_log_get_default_category()
14759 +
14760 +#define _VCOS_LEVEL(x) (x)
14761 +
14762 +#define vcos_is_log_enabled(cat,_level) (_VCOS_LEVEL((cat)->level) >= _VCOS_LEVEL(_level))
14763 +
14764 +#if defined(_VCOS_METAWARE) || defined(__GNUC__)
14765 +
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)
14770 +# else
14771 +# define _VCOS_LOG_X(cat, _level, fmt...) (void)0
14772 +# define _VCOS_VLOG_X(cat, _level, fmt, ap) (void)0
14773 +# endif
14774 +
14775 +
14776 +
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__)
14781 +
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)
14786 +
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__)
14791 +
14792 +/*
14793 + * MS Visual Studio - pre 2005 does not grok variadic macros
14794 + */
14795 +#elif defined(_MSC_VER)
14796 +
14797 +# if _MSC_VER >= 1400
14798 +
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)
14802 +# else
14803 +# define _VCOS_LOG_X(cat, _level, fmt,...) (void)0
14804 +# endif
14805 +
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__)
14810 +
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)
14814 +
14815 +# else /* _MSC_VER >= 1400 */
14816 +
14817 +/* do not define these */
14818 +
14819 +# endif /* _MSC_VER >= 1400 */
14820 +
14821 +#endif
14822 +
14823 +#if VCOS_HAVE_CMD
14824 +
14825 +#include "interface/vcos/vcos_cmd.h"
14826 +
14827 +/*
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).
14831 + */
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 );
14836 +#endif
14837 +
14838 +#ifdef __cplusplus
14839 +}
14840 +#endif
14841 +#endif /* VCOS_LOGGING_H */
14842 +
14843 +
14844 --- /dev/null
14845 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_lowlevel_thread.h
14846 @@ -0,0 +1,107 @@
14847 +/*=============================================================================
14848 +Copyright (c) 2009 Broadcom Europe Limited.
14849 +All rights reserved.
14850 +
14851 +Project : vcfw
14852 +Module : chip driver
14853 +
14854 +FILE DESCRIPTION
14855 +VideoCore OS Abstraction Layer - low level thread support
14856 +=============================================================================*/
14857 +
14858 +#ifndef VCOS_LOWLEVEL_THREAD_H
14859 +#define VCOS_LOWLEVEL_THREAD_H
14860 +
14861 +#ifdef __cplusplus
14862 +extern "C" {
14863 +#endif
14864 +
14865 +#include "interface/vcos/vcos_types.h"
14866 +#include "vcos_platform.h"
14867 +
14868 +/**
14869 + * \file
14870 + *
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
14873 + * systems.
14874 + *
14875 + * Most clients will not need to use this code.
14876 + *
14877 + * \sa vcos_joinable_thread.h
14878 + */
14879 +
14880 +/**
14881 + * \brief Create a thread.
14882 + *
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
14887 + * thread.
14888 + *
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.
14891 + *
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
14901 + *
14902 + * @sa vcos_llthread_terminate vcos_llthread_delete
14903 + */
14904 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_llthread_create(VCOS_LLTHREAD_T *thread,
14905 + const char *name,
14906 + VCOS_LLTHREAD_ENTRY_FN_T entry,
14907 + void *arg,
14908 + void *stack,
14909 + VCOS_UNSIGNED stacksz,
14910 + VCOS_UNSIGNED priority,
14911 + VCOS_UNSIGNED affinity,
14912 + VCOS_UNSIGNED timeslice,
14913 + VCOS_UNSIGNED autostart);
14914 +
14915 +/**
14916 + * \brief Exits the current thread.
14917 + */
14918 +VCOSPRE_ void VCOSPOST_ vcos_llthread_exit(void);
14919 +
14920 +/**
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.
14925 + */
14926 +VCOSPRE_ void VCOSPOST_ vcos_llthread_delete(VCOS_LLTHREAD_T *thread);
14927 +
14928 +/**
14929 + * \brief Return current lowlevel thread pointer.
14930 + */
14931 +VCOS_INLINE_DECL
14932 +VCOS_LLTHREAD_T *vcos_llthread_current(void);
14933 +
14934 +/**
14935 + * Resume a thread.
14936 + */
14937 +VCOS_INLINE_DECL
14938 +void vcos_llthread_resume(VCOS_LLTHREAD_T *thread);
14939 +
14940 +VCOSPRE_ int VCOSPOST_ vcos_llthread_running(VCOS_LLTHREAD_T *thread);
14941 +
14942 +/**
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).
14946 + */
14947 +extern VCOS_STATUS_T _vcos_llthread_create_attach(VCOS_LLTHREAD_T *thread);
14948 +
14949 +#ifdef __cplusplus
14950 +}
14951 +#endif
14952 +#endif
14953 +
14954 --- /dev/null
14955 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_mem.h
14956 @@ -0,0 +1,81 @@
14957 +/*=============================================================================
14958 +Copyright (c) 2009 Broadcom Europe Limited.
14959 +All rights reserved.
14960 +
14961 +Project : vcfw
14962 +Module : chip driver
14963 +
14964 +FILE DESCRIPTION
14965 +VideoCore OS Abstraction Layer - memory support
14966 +=============================================================================*/
14967 +
14968 +#ifndef VCOS_MEM_H
14969 +#define VCOS_MEM_H
14970 +
14971 +#ifdef __cplusplus
14972 +extern "C" {
14973 +#endif
14974 +
14975 +#include "interface/vcos/vcos_types.h"
14976 +#include "vcos_platform.h"
14977 +
14978 +/** \file
14979 + *
14980 + * Memory allocation api (malloc/free equivalents) is for benefit of host
14981 + * applications. VideoCore code should use rtos_XXX functions.
14982 + *
14983 + */
14984 +
14985 +
14986 +/** Allocate memory
14987 + *
14988 + * @param size Size of memory to allocate
14989 + * @param description Description, to aid in debugging. May be ignored internally on some platforms.
14990 + */
14991 +VCOS_INLINE_DECL
14992 +void *vcos_malloc(VCOS_UNSIGNED size, const char *description);
14993 +
14994 +void *vcos_kmalloc(VCOS_UNSIGNED size, const char *description);
14995 +void *vcos_kcalloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description);
14996 +
14997 +/** Allocate cleared memory
14998 + *
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.
15002 + */
15003 +VCOS_INLINE_DECL
15004 +void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description);
15005 +
15006 +/** Free memory
15007 + *
15008 + * Free memory that has been allocated.
15009 + */
15010 +VCOS_INLINE_DECL
15011 +void vcos_free(void *ptr);
15012 +
15013 +void vcos_kfree(void *ptr);
15014 +
15015 +/** Allocate aligned memory
15016 + *
15017 + * Allocate memory aligned on the specified boundary.
15018 + *
15019 + * @param size Size of memory to allocate
15020 + * @param description Description, to aid in debugging. May be ignored internally on some platforms.
15021 + */
15022 +VCOS_INLINE_DECL
15023 +void *vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description);
15024 +
15025 +/** Return the amount of free heap memory
15026 + *
15027 + */
15028 +VCOS_INLINE_DECL
15029 +unsigned long vcos_get_free_mem(void);
15030 +
15031 +#ifdef __cplusplus
15032 +}
15033 +#endif
15034 +
15035 +#endif
15036 +
15037 +
15038 --- /dev/null
15039 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_msgqueue.h
15040 @@ -0,0 +1,157 @@
15041 +/*=============================================================================
15042 +Copyright (c) 2009 Broadcom Europe Limited.
15043 +All rights reserved.
15044 +
15045 +Project : vcfw
15046 +Module : chip driver
15047 +
15048 +FILE DESCRIPTION
15049 +VCOS - packet-like messages, based loosely on those found in TRIPOS.
15050 +=============================================================================*/
15051 +
15052 +#ifndef VCOS_MSGQUEUE_H
15053 +#define VCOS_MSGQUEUE_H
15054 +
15055 +#ifdef __cplusplus
15056 +extern "C" {
15057 +#endif
15058 +
15059 +#include "interface/vcos/vcos_types.h"
15060 +#include "vcos_platform.h"
15061 +
15062 +/**
15063 + * \file
15064 + *
15065 + * Packet-like messages, based loosely on those found in TRIPOS and
15066 + * derivatives thereof.
15067 + *
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.
15072 + *
15073 + * A caller can wait for the reply to a specific message - any other
15074 + * messages that arrive in the meantime are queued separately.
15075 + *
15076 + *
15077 + * All messages have a standard common layout, but the payload area can
15078 + * be used freely to extend this.
15079 + */
15080 +
15081 +/** Map the payload portion of a message to a structure pointer.
15082 + */
15083 +#define VCOS_MSG_DATA(_msg) (void*)((_msg)->data)
15084 +
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)
15090 +
15091 +#define VCOS_MSG_REPLY_BIT (1<<31)
15092 +
15093 +/** Make gnuc compiler be happy about pointer punning */
15094 +#ifdef __GNUC__
15095 +#define __VCOS_MAY_ALIAS __attribute__((__may_alias__))
15096 +#else
15097 +#define __VCOS_MAY_ALIAS
15098 +#endif
15099 +
15100 +/** A single message queue.
15101 + */
15102 +typedef struct VCOS_MSGQUEUE_T
15103 +{
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;
15109 +
15110 +/** A single message
15111 + */
15112 +typedef struct VCOS_MSG_T
15113 +{
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 */
15121 +} VCOS_MSG_T;
15122 +
15123 +/** An endpoint
15124 + */
15125 +typedef struct VCOS_MSG_ENDPOINT_T
15126 +{
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)
15133 +
15134 +/** Initalise the library. Normally called from vcos_init().
15135 + */
15136 +extern VCOS_STATUS_T vcos_msgq_init(void);
15137 +
15138 +/** Find a message queue by name and get a handle to it.
15139 + *
15140 + * @param name the name of the queue to find
15141 + *
15142 + * @return The message queue, or NULL if not found.
15143 + */
15144 +VCOSPRE_ VCOS_MSGQUEUE_T VCOSPOST_ *vcos_msgq_find(const char *name);
15145 +
15146 +/** Wait for a message queue to come into existence. If it already exists,
15147 + * return immediately, otherwise block.
15148 + *
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.
15152 + *
15153 + * @param name the name of the queue to find
15154 + * @return The message queue
15155 + */
15156 +VCOSPRE_ VCOS_MSGQUEUE_T VCOSPOST_ *vcos_msgq_wait(const char *name);
15157 +
15158 +/** Send a message.
15159 + */
15160 +VCOSPRE_ void VCOSPOST_ vcos_msg_send(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg);
15161 +
15162 +/** Send a message and wait for a reply.
15163 + */
15164 +VCOSPRE_ void VCOSPOST_ vcos_msg_sendwait(VCOS_MSGQUEUE_T *queue, uint32_t code, VCOS_MSG_T *msg);
15165 +
15166 +/** Wait for a message on this thread's endpoint.
15167 + */
15168 +VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_wait(void);
15169 +
15170 +/** Wait for a specific message.
15171 + */
15172 +VCOS_MSG_T * vcos_msg_wait_specific(VCOS_MSGQUEUE_T *queue, VCOS_MSG_T *msg);
15173 +
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.
15176 + */
15177 +VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_peek(void);
15178 +
15179 +/** Send a reply to a message
15180 + */
15181 +VCOSPRE_ void VCOSPOST_ vcos_msg_reply(VCOS_MSG_T *msg);
15182 +
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.
15185 + */
15186 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_endpoint_create(VCOS_MSG_ENDPOINT_T *ep, const char *name);
15187 +
15188 +/** Destroy an endpoint.
15189 + */
15190 +VCOSPRE_ void VCOSPOST_ vcos_msgq_endpoint_delete(VCOS_MSG_ENDPOINT_T *ep);
15191 +
15192 +#ifdef __cplusplus
15193 +}
15194 +#endif
15195 +#endif
15196 +
15197 +
15198 --- /dev/null
15199 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_mutex.h
15200 @@ -0,0 +1,92 @@
15201 +/*=============================================================================
15202 +Copyright (c) 2009 Broadcom Europe Limited.
15203 +All rights reserved.
15204 +
15205 +Project : vcfw
15206 +Module : chip driver
15207 +
15208 +FILE DESCRIPTION
15209 +VideoCore OS Abstraction Layer - mutex public header file
15210 +=============================================================================*/
15211 +
15212 +#ifndef VCOS_MUTEX_H
15213 +#define VCOS_MUTEX_H
15214 +
15215 +#ifdef __cplusplus
15216 +extern "C" {
15217 +#endif
15218 +
15219 +#include "interface/vcos/vcos_types.h"
15220 +#include "vcos_platform.h"
15221 +
15222 +/**
15223 + * \file vcos_mutex.h
15224 + *
15225 + * Mutex API. Mutexes are not re-entrant, as supporting this adds extra code
15226 + * that slows down clients which have been written sensibly.
15227 + *
15228 + * \sa vcos_reentrant_mutex.h
15229 + *
15230 + */
15231 +
15232 +/** Create a mutex.
15233 + *
15234 + * @param m Filled in with mutex on return
15235 + * @param name A non-null name for the mutex, used for diagnostics.
15236 + *
15237 + * @return VCOS_SUCCESS if mutex was created, or error code.
15238 + */
15239 +VCOS_INLINE_DECL
15240 +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *m, const char *name);
15241 +
15242 +/** Delete the mutex.
15243 + */
15244 +VCOS_INLINE_DECL
15245 +void vcos_mutex_delete(VCOS_MUTEX_T *m);
15246 +
15247 +/**
15248 + * \brief Wait to claim the mutex.
15249 + *
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.
15253 + *
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.
15258 + */
15259 +#ifndef vcos_mutex_lock
15260 +VCOS_INLINE_DECL
15261 +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *m);
15262 +
15263 +/** Release the mutex.
15264 + */
15265 +VCOS_INLINE_DECL
15266 +void vcos_mutex_unlock(VCOS_MUTEX_T *m);
15267 +#endif
15268 +
15269 +/** Test if the mutex is already locked.
15270 + *
15271 + * @return 1 if mutex is locked, 0 if it is unlocked.
15272 + */
15273 +VCOS_INLINE_DECL
15274 +int vcos_mutex_is_locked(VCOS_MUTEX_T *m);
15275 +
15276 +/** Obtain the mutex if possible.
15277 + *
15278 + * @param m the mutex to try to obtain
15279 + *
15280 + * @return VCOS_SUCCESS if mutex is succesfully obtained, or VCOS_EAGAIN
15281 + * if it is already in use by another thread.
15282 + */
15283 +#ifndef vcos_mutex_trylock
15284 +VCOS_INLINE_DECL
15285 +VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m);
15286 +#endif
15287 +
15288 +
15289 +#ifdef __cplusplus
15290 +}
15291 +#endif
15292 +#endif
15293 --- /dev/null
15294 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_once.h
15295 @@ -0,0 +1,42 @@
15296 +/*=============================================================================
15297 +Copyright (c) 2011 Broadcom Europe Limited.
15298 +All rights reserved.
15299 +
15300 +Project : vcfw
15301 +Module : chip driver
15302 +
15303 +FILE DESCRIPTION
15304 +VideoCore OS Abstraction Layer - 'once'
15305 +=============================================================================*/
15306 +
15307 +#ifndef VCOS_ONCE_H
15308 +#define VCOS_ONCE_H
15309 +
15310 +#ifdef __cplusplus
15311 +extern "C" {
15312 +#endif
15313 +
15314 +#include "interface/vcos/vcos_types.h"
15315 +#include "vcos_platform.h"
15316 +
15317 +/**
15318 + * \file vcos_once.h
15319 + *
15320 + * Ensure something is called only once.
15321 + *
15322 + * Initialize once_control to VCOS_ONCE_INIT. The first
15323 + * time this is called, the init_routine will be called. Thereafter
15324 + * it won't.
15325 + *
15326 + * \sa pthread_once()
15327 + *
15328 + */
15329 +
15330 +VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
15331 + void (*init_routine)(void));
15332 +
15333 +#ifdef __cplusplus
15334 +}
15335 +#endif
15336 +#endif
15337 +
15338 --- /dev/null
15339 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_semaphore.h
15340 @@ -0,0 +1,115 @@
15341 +/*=============================================================================
15342 +Copyright (c) 2009 Broadcom Europe Limited.
15343 +All rights reserved.
15344 +
15345 +Project : vcfw
15346 +Module : chip driver
15347 +
15348 +FILE DESCRIPTION
15349 +VideoCore OS Abstraction Layer - public header file
15350 +=============================================================================*/
15351 +
15352 +#ifndef VCOS_SEMAPHORE_H
15353 +#define VCOS_SEMAPHORE_H
15354 +
15355 +#ifdef __cplusplus
15356 +extern "C" {
15357 +#endif
15358 +
15359 +#include "interface/vcos/vcos_types.h"
15360 +#include "vcos_platform.h"
15361 +
15362 +/**
15363 + * \file vcos_semaphore.h
15364 + *
15365 + * \section sem Semaphores
15366 + *
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.
15371 + *
15372 + * \subsection timeout Timeout
15373 + *
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).
15379 + *
15380 + * \subsection sem_nucleus Changes from Nucleus:
15381 + *
15382 + * Semaphores are always "FIFO" - i.e. sleeping threads are woken in FIFO order. That's
15383 + * because:
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.
15387 + *
15388 + */
15389 +
15390 +/**
15391 + * \brief Create a semaphore.
15392 + *
15393 + * Create a semaphore.
15394 + *
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.
15398 + *
15399 + * @return VCOS_SUCCESS if the semaphore was created.
15400 + *
15401 + */
15402 +VCOS_INLINE_DECL
15403 +VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
15404 +
15405 +/**
15406 + * \brief Wait on a semaphore.
15407 + *
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.
15411 + *
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.
15415 + *
15416 + * @param sem Semaphore to wait on
15417 + * @return VCOS_SUCCESS - semaphore was taken.
15418 + * VCOS_EAGAIN - could not take semaphore
15419 + *
15420 + */
15421 +VCOS_INLINE_DECL
15422 +VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem);
15423 +
15424 +/**
15425 + * \brief Try to wait for a semaphore.
15426 + *
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
15431 + */
15432 +VCOS_INLINE_DECL
15433 +VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem);
15434 +
15435 +/**
15436 + * \brief Post a semaphore.
15437 + *
15438 + * @param sem Semaphore to wait on
15439 + */
15440 +VCOS_INLINE_DECL
15441 +VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem);
15442 +
15443 +/**
15444 + * \brief Delete a semaphore, releasing any resources consumed by it.
15445 + *
15446 + * @param sem Semaphore to wait on
15447 + */
15448 +VCOS_INLINE_DECL
15449 +void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem);
15450 +
15451 +#ifdef __cplusplus
15452 +}
15453 +#endif
15454 +#endif
15455 +
15456 --- /dev/null
15457 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_stdbool.h
15458 @@ -0,0 +1,17 @@
15459 +#ifndef VCOS_STDBOOL_H
15460 +#define VCOS_STDBOOL_H
15461 +
15462 +#ifndef __cplusplus
15463 +
15464 +#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
15465 +#include <stdbool.h>
15466 +#else
15467 +typedef enum {
15468 + false,
15469 + true
15470 +} bool;
15471 +#endif
15472 +
15473 +#endif /* __cplusplus */
15474 +
15475 +#endif
15476 --- /dev/null
15477 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_stdint.h
15478 @@ -0,0 +1,193 @@
15479 +/*=============================================================================
15480 +Copyright (c) 2011 Broadcom Europe Limited.
15481 +All rights reserved.
15482 +
15483 +FILE DESCRIPTION
15484 +
15485 +=============================================================================*/
15486 +
15487 +#ifndef VCOS_STDINT_H
15488 +#define VCOS_STDINT_H
15489 +
15490 +/* Attempt to provide the types defined in stdint.h.
15491 + *
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
15495 + * use #ifdefs.
15496 + */
15497 +
15498 +#ifdef __cplusplus
15499 +extern "C" {
15500 +#endif
15501 +
15502 +#ifdef __SYMBIAN32__
15503 +
15504 +typedef signed char int8_t;
15505 +typedef unsigned char uint8_t;
15506 +
15507 +typedef signed short int16_t;
15508 +typedef unsigned short uint16_t;
15509 +
15510 +typedef int16_t int_least16_t;
15511 +
15512 +typedef signed long int32_t;
15513 +typedef unsigned long uint32_t;
15514 +
15515 +typedef signed long long int64_t;
15516 +typedef unsigned long long uint64_t;
15517 +
15518 +typedef int32_t intptr_t;
15519 +typedef uint32_t uintptr_t;
15520 +
15521 +typedef int64_t intmax_t;
15522 +typedef uint64_t uintmax_t;
15523 +
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
15536 +
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
15544 +
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 */
15546 +
15547 +#elif defined( __STDC__ ) && __STDC_VERSION__ >= 199901L
15548 +
15549 +#include <stdint.h>
15550 +
15551 +#elif defined( __GNUC__ )
15552 +
15553 +#include <stdint.h>
15554 +
15555 +#elif defined(_MSC_VER) /* Visual C define equivalent types */
15556 +
15557 +#include <stddef.h> /* Avoids intptr_t being defined in vadefs.h */
15558 +
15559 +typedef __int8 int8_t;
15560 +typedef unsigned __int8 uint8_t;
15561 +
15562 +typedef __int16 int16_t;
15563 +typedef unsigned __int16 uint16_t;
15564 +
15565 +typedef __int32 int32_t;
15566 +typedef unsigned __int32 uint32_t;
15567 +
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;
15574 +
15575 +#elif defined (VCMODS_LCC)
15576 +#include <limits.h>
15577 +
15578 +typedef signed char int8_t;
15579 +typedef unsigned char uint8_t;
15580 +
15581 +typedef signed short int16_t;
15582 +typedef unsigned short uint16_t;
15583 +
15584 +typedef signed long int32_t;
15585 +typedef unsigned long uint32_t;
15586 +
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 */
15589 +
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;
15595 +
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 */
15608 +
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
15616 +
15617 +#elif defined(__VIDEOCORE__)
15618 +
15619 +typedef signed char int8_t;
15620 +typedef unsigned char uint8_t;
15621 +
15622 +typedef signed short int16_t;
15623 +typedef unsigned short uint16_t;
15624 +
15625 +typedef signed long int32_t;
15626 +typedef unsigned long uint32_t;
15627 +
15628 +typedef signed long long int64_t;
15629 +typedef unsigned long long uint64_t;
15630 +
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;
15636 +
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
15649 +
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
15657 +
15658 +#elif defined (__HIGHC__) && defined(_I386)
15659 +
15660 +#include <stdint.h>
15661 +
15662 +#else
15663 +#error Unknown platform
15664 +#endif
15665 +
15666 +#ifdef __cplusplus
15667 +}
15668 +#endif
15669 +#endif /* VCOS_STDINT_H */
15670 +
15671 +
15672 --- /dev/null
15673 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_string.h
15674 @@ -0,0 +1,73 @@
15675 +/*=============================================================================
15676 +Copyright (c) 2009 Broadcom Europe Limited.
15677 +All rights reserved.
15678 +
15679 +Project : vcfw
15680 +Module : chip driver
15681 +
15682 +FILE DESCRIPTION
15683 +VideoCore OS Abstraction Layer - public header file
15684 +=============================================================================*/
15685 +
15686 +#ifndef VCOS_STRING_H
15687 +#define VCOS_STRING_H
15688 +
15689 +/**
15690 + * \file
15691 + *
15692 + * String functions.
15693 + *
15694 + */
15695 +
15696 +#ifdef __cplusplus
15697 +extern "C" {
15698 +#endif
15699 +
15700 +#include "interface/vcos/vcos_types.h"
15701 +#include "vcos_platform.h"
15702 +
15703 +#ifdef __KERNEL__
15704 +#include <linux/string.h>
15705 +#else
15706 +#include <string.h>
15707 +#endif
15708 +
15709 +/** Case insensitive string comparison.
15710 + *
15711 + */
15712 +
15713 +VCOS_INLINE_DECL
15714 +int vcos_strcasecmp(const char *s1, const char *s2);
15715 +
15716 +VCOS_INLINE_DECL
15717 +int vcos_strncasecmp(const char *s1, const char *s2, size_t n);
15718 +
15719 +VCOSPRE_ int VCOSPOST_ vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap );
15720 +
15721 +VCOSPRE_ int VCOSPOST_ vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...);
15722 +
15723 +VCOS_STATIC_INLINE
15724 +int vcos_strlen(const char *s) { return (int)strlen(s); }
15725 +
15726 +VCOS_STATIC_INLINE
15727 +int vcos_strcmp(const char *s1, const char *s2) { return strcmp(s1,s2); }
15728 +
15729 +VCOS_STATIC_INLINE
15730 +int vcos_strncmp(const char *cs, const char *ct, size_t count) { return strncmp(cs, ct, count); }
15731 +
15732 +VCOS_STATIC_INLINE
15733 +char *vcos_strcpy(char *dst, const char *src) { return strcpy(dst, src); }
15734 +
15735 +VCOS_STATIC_INLINE
15736 +char *vcos_strncpy(char *dst, const char *src, size_t count) { return strncpy(dst, src, count); }
15737 +
15738 +VCOS_STATIC_INLINE
15739 +void *vcos_memcpy(void *dst, const void *src, size_t n) { memcpy(dst, src, n); return dst; }
15740 +
15741 +VCOS_STATIC_INLINE
15742 +void *vcos_memset(void *p, int c, size_t n) { return memset(p, c, n); }
15743 +
15744 +#ifdef __cplusplus
15745 +}
15746 +#endif
15747 +#endif
15748 --- /dev/null
15749 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_thread.h
15750 @@ -0,0 +1,259 @@
15751 +/*=============================================================================
15752 +Copyright (c) 2009 Broadcom Europe Limited.
15753 +All rights reserved.
15754 +
15755 +Project : vcfw
15756 +Module : chip driver
15757 +
15758 +FILE DESCRIPTION
15759 +VideoCore OS Abstraction Layer - public header file
15760 +=============================================================================*/
15761 +
15762 +#ifndef VCOS_THREAD_H
15763 +#define VCOS_THREAD_H
15764 +
15765 +#ifdef __cplusplus
15766 +extern "C" {
15767 +#endif
15768 +
15769 +#include "interface/vcos/vcos_types.h"
15770 +#include "vcos_platform.h"
15771 +
15772 +/**
15773 + * \file vcos_thread.h
15774 + *
15775 + * \section thread Threads
15776 + *
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.
15780 + *
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.
15784 + *
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.
15787 + *
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).
15792 + *
15793 + * \subsection stack Stack
15794 + *
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.
15798 + *
15799 + * \subsection thr_create Creating a thread
15800 + *
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().
15804 + *
15805 + * \subsection back Backward compatibility
15806 + *
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.
15810 + *
15811 + */
15812 +
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
15818 +
15819 +/** Report whether or not we have an RTOS at all, and hence the ability to
15820 + * create threads.
15821 + */
15822 +VCOSPRE_ int VCOSPOST_ vcos_have_rtos(void);
15823 +
15824 +/** Create a thread. It must be cleaned up by calling vcos_thread_join().
15825 + *
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.
15831 + */
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,
15836 + void *arg);
15837 +
15838 +/** Exit the thread from within the thread function itself.
15839 + * Resources must still be cleaned up via a call to thread_join().
15840 + *
15841 + * The thread can also be terminated by simply exiting the thread function.
15842 + *
15843 + * @param data Data passed to thread_join. May be NULL.
15844 + */
15845 +VCOSPRE_ void VCOSPOST_ vcos_thread_exit(void *data);
15846 +
15847 +/** Wait for a thread to terminate and then clean up its resources.
15848 + *
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.
15852 + */
15853 +VCOSPRE_ void VCOSPOST_ vcos_thread_join(VCOS_THREAD_T *thread,
15854 + void **pData);
15855 +
15856 +
15857 +/**
15858 + * \brief Create a thread using an API similar to the one "traditionally"
15859 + * used under Nucleus.
15860 + *
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.
15864 + *
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.
15875 + *
15876 + * @sa vcos_thread_terminate vcos_thread_delete
15877 + */
15878 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create_classic(VCOS_THREAD_T *thread,
15879 + const char *name,
15880 + void *(*entry)(void *arg),
15881 + void *arg,
15882 + void *stack,
15883 + VCOS_UNSIGNED stacksz,
15884 + VCOS_UNSIGNED priaff,
15885 + VCOS_UNSIGNED timeslice,
15886 + VCOS_UNSIGNED autostart);
15887 +
15888 +/**
15889 + * \brief Set a thread's priority
15890 + *
15891 + * Set the priority for a thread.
15892 + *
15893 + * @param thread The thread
15894 + * @param pri Thread priority in VCOS_PRI_MASK bits; affinity in VCOS_AFFINITY_MASK bits.
15895 + */
15896 +VCOS_INLINE_DECL
15897 +void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED pri);
15898 +
15899 +/**
15900 + * \brief Return the currently executing thread.
15901 + *
15902 + */
15903 +VCOS_INLINE_DECL
15904 +VCOS_THREAD_T *vcos_thread_current(void);
15905 +
15906 +/**
15907 + * \brief Return the thread's priority.
15908 + */
15909 +VCOS_INLINE_DECL
15910 +VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread);
15911 +
15912 +/**
15913 + * \brief Return the thread's cpu affinity.
15914 + */
15915 +VCOS_INLINE_DECL
15916 +VCOS_UNSIGNED vcos_thread_get_affinity(VCOS_THREAD_T *thread);
15917 +
15918 +/**
15919 + * \brief Set the thread's cpu affinity.
15920 + */
15921 +
15922 +VCOS_INLINE_DECL
15923 +void vcos_thread_set_affinity(VCOS_THREAD_T *thread, VCOS_UNSIGNED affinity);
15924 +
15925 +/**
15926 + * \brief Query whether we are in an interrupt.
15927 + *
15928 + * @return 1 if in interrupt context.
15929 + */
15930 +VCOS_INLINE_DECL
15931 +int vcos_in_interrupt(void);
15932 +
15933 +/**
15934 + * \brief Sleep a while.
15935 + *
15936 + * @param ms Number of milliseconds to sleep for
15937 + *
15938 + * This may actually sleep a whole number of ticks.
15939 + */
15940 +VCOS_INLINE_DECL
15941 +void vcos_sleep(uint32_t ms);
15942 +
15943 +/**
15944 + * \brief Return the value of the hardware microsecond counter.
15945 + *
15946 + */
15947 +VCOS_INLINE_DECL
15948 +uint32_t vcos_getmicrosecs(void);
15949 +
15950 +#define vcos_get_ms() (vcos_getmicrosecs()/1000)
15951 +
15952 +/**
15953 + * \brief Return a unique identifier for the current process
15954 + *
15955 + */
15956 +VCOS_INLINE_DECL
15957 +VCOS_UNSIGNED vcos_process_id_current(void);
15958 +
15959 +/** Relinquish this time slice. */
15960 +VCOS_INLINE_DECL
15961 +void vcos_thread_relinquish(void);
15962 +
15963 +/** Return the name of the given thread.
15964 + */
15965 +VCOSPRE_ const char * VCOSPOST_ vcos_thread_get_name(const VCOS_THREAD_T *thread);
15966 +
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).
15970 + *
15971 + * It's mainly here to ease migration. If you're using it in new code, you
15972 + * probably need to think again.
15973 + *
15974 + * @param pe New preemption, VCOS_PREEMPT or VCOS_NO_PREEMPT
15975 + * @return Old value of preemption.
15976 + */
15977 +VCOS_INLINE_DECL
15978 +VCOS_UNSIGNED vcos_change_preemption(VCOS_UNSIGNED pe);
15979 +
15980 +/** Is a thread still running, or has it exited?
15981 + *
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.
15984 + *
15985 + * @param thread thread to query
15986 + * @return non-zero if thread is running, or zero if it has exited.
15987 + */
15988 +VCOS_INLINE_DECL
15989 +int vcos_thread_running(VCOS_THREAD_T *thread);
15990 +
15991 +/** Resume a thread.
15992 + *
15993 + * @param thread thread to resume
15994 + */
15995 +VCOS_INLINE_DECL
15996 +void vcos_thread_resume(VCOS_THREAD_T *thread);
15997 +
15998 +/*
15999 + * Internal APIs - may not always be present and should not be used in
16000 + * client code.
16001 + */
16002 +
16003 +extern void _vcos_task_timer_set(void (*pfn)(void*), void *, VCOS_UNSIGNED ms);
16004 +extern void _vcos_task_timer_cancel(void);
16005 +
16006 +#ifdef __cplusplus
16007 +}
16008 +#endif
16009 +#endif
16010 --- /dev/null
16011 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_thread_attr.h
16012 @@ -0,0 +1,73 @@
16013 +/*=============================================================================
16014 +Copyright (c) 2009 Broadcom Europe Limited.
16015 +All rights reserved.
16016 +
16017 +FILE DESCRIPTION
16018 +VideoCore OS Abstraction Layer - thread attributes
16019 +=============================================================================*/
16020 +
16021 +#ifndef VCOS_THREAD_ATTR_H
16022 +#define VCOS_THREAD_ATTR_H
16023 +
16024 +#ifdef __cplusplus
16025 +extern "C" {
16026 +#endif
16027 +
16028 +/**
16029 + * \file
16030 + *
16031 + * Attributes for thread creation.
16032 + *
16033 + */
16034 +
16035 +/** Initialize thread attribute struct. This call does not allocate memory,
16036 + * and so cannot fail.
16037 + *
16038 + */
16039 +VCOSPRE_ void VCOSPOST_ vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs);
16040 +
16041 +/** Set the stack address and size. If not set, a stack will be allocated automatically.
16042 + *
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.
16045 + */
16046 +#if VCOS_CAN_SET_STACK_ADDR
16047 +VCOS_INLINE_DECL
16048 +void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED sz);
16049 +#endif
16050 +
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.
16053 + */
16054 +VCOS_INLINE_DECL
16055 +void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED sz);
16056 +
16057 +/** Set the task priority. If not set, a default value will be used.
16058 + */
16059 +VCOS_INLINE_DECL
16060 +void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri);
16061 +
16062 +/** Set the task cpu affinity. If not set, the default will be used.
16063 + */
16064 +VCOS_INLINE_DECL
16065 +void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED aff);
16066 +
16067 +/** Set the timeslice. If not set the default will be used.
16068 + */
16069 +VCOS_INLINE_DECL
16070 +void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts);
16071 +
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.
16075 + */
16076 +VCOS_INLINE_DECL
16077 +void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy);
16078 +
16079 +VCOS_INLINE_DECL
16080 +void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart);
16081 +
16082 +#ifdef __cplusplus
16083 +}
16084 +#endif
16085 +#endif
16086 --- /dev/null
16087 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_timer.h
16088 @@ -0,0 +1,95 @@
16089 +/*=============================================================================
16090 +Copyright (c) 2009 Broadcom Europe Limited.
16091 +All rights reserved.
16092 +
16093 +Project : vcfw
16094 +Module : chip driver
16095 +
16096 +FILE DESCRIPTION
16097 +VideoCore OS Abstraction Layer - timer support
16098 +=============================================================================*/
16099 +
16100 +#ifndef VCOS_TIMER_H
16101 +#define VCOS_TIMER_H
16102 +
16103 +#ifdef __cplusplus
16104 +extern "C" {
16105 +#endif
16106 +
16107 +#include "interface/vcos/vcos_types.h"
16108 +#include "vcos_platform.h"
16109 +
16110 +/** \file vcos_timer.h
16111 + *
16112 + * Timers are single shot.
16113 + *
16114 + * Timer times are in milliseconds.
16115 + *
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.
16119 + *
16120 + * \note On Windows, the separate function vcos_timer_init() must be called
16121 + * as timer initialization from DllMain is not possible.
16122 + */
16123 +
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).
16129 + *
16130 + * @return VCOS_SUCCESS on success. VCOS_EEXIST if this has already been called
16131 + * once. VCOS_ENOMEM if resource allocation failed.
16132 + */
16133 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_timer_init(void);
16134 +
16135 +/** Create a timer in a disabled state.
16136 + *
16137 + * The timer is initially disabled.
16138 + *
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
16143 + *
16144 + */
16145 +VCOS_INLINE_DECL
16146 +VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
16147 + const char *name,
16148 + void (*expiration_routine)(void *context),
16149 + void *context);
16150 +
16151 +
16152 +
16153 +/** Start a timer running.
16154 + *
16155 + * Timer must be stopped.
16156 + *
16157 + * @param timer timer handle
16158 + * @param delay Delay to wait for, in ms
16159 + */
16160 +VCOS_INLINE_DECL
16161 +void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay);
16162 +
16163 +/** Stop an already running timer.
16164 + *
16165 + * @param timer timer handle
16166 + */
16167 +VCOS_INLINE_DECL
16168 +void vcos_timer_cancel(VCOS_TIMER_T *timer);
16169 +
16170 +/** Stop a timer and restart it.
16171 + * @param timer timer handle
16172 + * @param delay delay in ms
16173 + */
16174 +VCOS_INLINE_DECL
16175 +void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay);
16176 +
16177 +VCOS_INLINE_DECL
16178 +void vcos_timer_delete(VCOS_TIMER_T *timer);
16179 +
16180 +#ifdef __cplusplus
16181 +}
16182 +#endif
16183 +#endif
16184 --- /dev/null
16185 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_types.h
16186 @@ -0,0 +1,197 @@
16187 +/*=============================================================================
16188 +Copyright (c) 2009 Broadcom Europe Limited.
16189 +All rights reserved.
16190 +
16191 +FILE DESCRIPTION
16192 +VideoCore OS Abstraction Layer - basic types
16193 +=============================================================================*/
16194 +
16195 +#ifndef VCOS_TYPES_H
16196 +#define VCOS_TYPES_H
16197 +
16198 +#define VCOS_VERSION 1
16199 +
16200 +#include "vcos_platform_types.h"
16201 +
16202 +#if !defined(VCOSPRE_) || !defined(VCOSPOST_)
16203 +#error VCOSPRE_ and VCOSPOST_ not defined!
16204 +#endif
16205 +
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.
16209 + */
16210 +#ifndef VCHPOST_
16211 +#define VCHPOST_ VCOSPOST_
16212 +#endif
16213 +#ifndef VCHPRE_
16214 +#define VCHPRE_ VCOSPRE_
16215 +#endif
16216 +
16217 +/** Entry function for a lowlevel thread.
16218 + *
16219 + * Returns void for consistency with Nucleus/ThreadX.
16220 + */
16221 +typedef void (*VCOS_LLTHREAD_ENTRY_FN_T)(void *);
16222 +
16223 +/** Thread entry point. Returns a void* for consistency
16224 + * with pthreads.
16225 + */
16226 +typedef void *(*VCOS_THREAD_ENTRY_FN_T)(void*);
16227 +
16228 +
16229 +/* Error return codes - chosen to be similar to errno values */
16230 +typedef enum
16231 +{
16232 + VCOS_SUCCESS,
16233 + VCOS_EAGAIN,
16234 + VCOS_ENOENT,
16235 + VCOS_ENOSPC,
16236 + VCOS_EINVAL,
16237 + VCOS_EACCESS,
16238 + VCOS_ENOMEM,
16239 + VCOS_ENOSYS,
16240 + VCOS_EEXIST,
16241 + VCOS_ENXIO,
16242 + VCOS_EINTR
16243 +} VCOS_STATUS_T;
16244 +
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.
16248 + *
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.
16252 + *
16253 + * VCOS_INLINE_DECL - put this at the start of an inline forward declaration of a VCOS
16254 + * function.
16255 + *
16256 + * VCOS_INLINE_IMPL - put this at the start of an inlined implementation of a VCOS
16257 + * function.
16258 + *
16259 + */
16260 +
16261 +/* VCOS_EXPORT - it turns out that in some circumstances we need the implementation of
16262 + * a function even if it is usually inlined.
16263 + *
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.
16269 + *
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.
16273 + *
16274 + */
16275 +
16276 +#ifdef __cplusplus
16277 +#define _VCOS_INLINE inline
16278 +#else
16279 +#define _VCOS_INLINE __inline
16280 +#endif
16281 +
16282 +#if defined(NDEBUG)
16283 +
16284 +#ifdef __GNUC__
16285 +# define VCOS_INLINE_DECL extern __inline__
16286 +# define VCOS_INLINE_IMPL static __inline__
16287 +#else
16288 +# define VCOS_INLINE_DECL static _VCOS_INLINE /* declare a func */
16289 +# define VCOS_INLINE_IMPL static _VCOS_INLINE /* implement a func inline */
16290 +#endif
16291 +
16292 +# if defined(VCOS_WANT_IMPL)
16293 +# define VCOS_EXPORT
16294 +# else
16295 +# define VCOS_EXPORT VCOS_INLINE_IMPL
16296 +# endif /* VCOS_WANT_IMPL */
16297 +
16298 +#define VCOS_INLINE_BODIES
16299 +
16300 +#else /* NDEBUG */
16301 +
16302 +#if !defined(VCOS_INLINE_DECL)
16303 + #define VCOS_INLINE_DECL extern
16304 +#endif
16305 +#if !defined(VCOS_INLINE_IMPL)
16306 + #define VCOS_INLINE_IMPL
16307 +#endif
16308 +#define VCOS_EXPORT VCOS_INLINE_IMPL
16309 +#endif
16310 +
16311 +#define VCOS_STATIC_INLINE static _VCOS_INLINE
16312 +
16313 +#if defined(__HIGHC__) || defined(__HIGHC_ANSI__)
16314 +#define _VCOS_METAWARE
16315 +#endif
16316 +
16317 +/** It seems that __FUNCTION__ isn't standard!
16318 + */
16319 +#if __STDC_VERSION__ < 199901L
16320 +# if __GNUC__ >= 2 || defined(__VIDEOCORE__)
16321 +# define VCOS_FUNCTION __FUNCTION__
16322 +# else
16323 +# define VCOS_FUNCTION "<unknown>"
16324 +# endif
16325 +#else
16326 +# define VCOS_FUNCTION __func__
16327 +#endif
16328 +
16329 +#define _VCOS_MS_PER_TICK (1000/VCOS_TICKS_PER_SECOND)
16330 +
16331 +/* Convert a number of milliseconds to a tick count. Internal use only - fails to
16332 + * convert VCOS_SUSPEND correctly.
16333 + */
16334 +#define _VCOS_MS_TO_TICKS(ms) (((ms)+_VCOS_MS_PER_TICK-1)/_VCOS_MS_PER_TICK)
16335 +
16336 +#define VCOS_TICKS_TO_MS(ticks) ((ticks) * _VCOS_MS_PER_TICK)
16337 +
16338 +/** VCOS version of DATESTR, from pcdisk.h. Used by the hostreq service.
16339 + */
16340 +typedef struct vcos_datestr
16341 +{
16342 + uint8_t cmsec; /**< Centesimal mili second */
16343 + uint16_t date; /**< Date */
16344 + uint16_t time; /**< Time */
16345 +
16346 +} VCOS_DATESTR;
16347 +
16348 +/* Compile-time assert - declares invalid array length if condition
16349 + * not met, or array of length one if OK.
16350 + */
16351 +#define VCOS_CASSERT(e) extern char vcos_compile_time_check[1/(e)]
16352 +
16353 +#define vcos_min(x,y) ((x) < (y) ? (x) : (y))
16354 +#define vcos_max(x,y) ((x) > (y) ? (x) : (y))
16355 +
16356 +/** Return the count of an array. FIXME: under gcc we could make
16357 + * this report an error for pointers using __builtin_types_compatible().
16358 + */
16359 +#define vcos_countof(x) (sizeof((x)) / sizeof((x)[0]))
16360 +
16361 +/* for backward compatibility */
16362 +#define countof(x) (sizeof((x)) / sizeof((x)[0]))
16363 +
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))
16366 +
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.
16369 + */
16370 +typedef int32_t vcos_bool_t;
16371 +typedef int32_t vcos_fourcc_t;
16372 +
16373 +#define VCOS_FALSE 0
16374 +#define VCOS_TRUE (!VCOS_FALSE)
16375 +
16376 +/** Mark unused arguments to keep compilers quiet */
16377 +#define vcos_unused(x) (void)(x)
16378 +
16379 +/** For backward compatibility */
16380 +typedef vcos_fourcc_t fourcc_t;
16381 +typedef vcos_fourcc_t FOURCC_T;
16382 +
16383 +#endif