Root/target/linux/brcm2708/patches-3.3/0005-bcm2708-vchiq-driver.patch

1From a2e42fbc97cde9e851f5b036f46b8f34a5be6eb9 Mon Sep 17 00:00:00 2001
2From: popcornmix <popcornmix@gmail.com>
3Date: Tue, 17 Jan 2012 19:22:19 +0000
4Subject: [PATCH 5/7] bcm2708 vchiq driver
5
6Signed-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_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
16384

Archive Download this file



interactive