[brcm2708] adds target used by rapsberry pi
[openwrt.git] / target / linux / brcm2708 / patches-3.3 / 0005-bcm2708-vchiq-driver.patch
1 From a2e42fbc97cde9e851f5b036f46b8f34a5be6eb9 Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Tue, 17 Jan 2012 19:22:19 +0000
4 Subject: [PATCH 5/7] bcm2708 vchiq driver
5
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
7 ---
8  drivers/misc/Kconfig                               |    1 +
9  drivers/misc/Makefile                              |    1 +
10  drivers/misc/vc04_services/Kconfig                 |    7 +
11  drivers/misc/vc04_services/Makefile                |   19 +
12  .../misc/vc04_services/interface/vchi/vchi_mh.h    |   19 +
13  .../misc/vc04_services/interface/vchiq_arm/vchiq.h |   27 +
14  .../vc04_services/interface/vchiq_arm/vchiq_2835.h |   27 +
15  .../interface/vchiq_arm/vchiq_2835_arm.c           |  487 ++++
16  .../vc04_services/interface/vchiq_arm/vchiq_arm.c  | 1293 ++++++++++
17  .../vc04_services/interface/vchiq_arm/vchiq_arm.h  |   38 +
18  .../vc04_services/interface/vchiq_arm/vchiq_cfg.h  |   43 +
19  .../interface/vchiq_arm/vchiq_connected.c          |  101 +
20  .../interface/vchiq_arm/vchiq_connected.h          |   32 +
21  .../vc04_services/interface/vchiq_arm/vchiq_core.c | 2604 ++++++++++++++++++++
22  .../vc04_services/interface/vchiq_arm/vchiq_core.h |  480 ++++
23  .../vc04_services/interface/vchiq_arm/vchiq_if.h   |  148 ++
24  .../interface/vchiq_arm/vchiq_ioctl.h              |  105 +
25  .../interface/vchiq_arm/vchiq_kern_lib.c           |  297 +++
26  .../vc04_services/interface/vchiq_arm/vchiq_lib.c  | 1518 ++++++++++++
27  .../interface/vchiq_arm/vchiq_memdrv.h             |   45 +
28  .../interface/vchiq_arm/vchiq_pagelist.h           |   43 +
29  .../vc04_services/interface/vchiq_arm/vchiq_shim.c |  970 ++++++++
30  .../vc04_services/interface/vchiq_arm/vchiq_util.c |   97 +
31  .../vc04_services/interface/vchiq_arm/vchiq_util.h |   47 +
32  .../interface/vcos/generic/vcos_cmd.c              |  681 +++++
33  .../interface/vcos/generic/vcos_common.h           |   76 +
34  .../vcos/generic/vcos_generic_blockpool.h          |  260 ++
35  .../vcos/generic/vcos_generic_event_flags.c        |  297 +++
36  .../vcos/generic/vcos_generic_event_flags.h        |  104 +
37  .../vcos/generic/vcos_generic_named_sem.h          |   81 +
38  .../vcos/generic/vcos_generic_quickslow_mutex.h    |   75 +
39  .../vcos/generic/vcos_generic_reentrant_mtx.h      |   75 +
40  .../interface/vcos/generic/vcos_generic_tls.h      |  144 ++
41  .../vcos/generic/vcos_joinable_thread_from_plain.h |  202 ++
42  .../interface/vcos/generic/vcos_latch_from_sem.h   |   48 +
43  .../interface/vcos/generic/vcos_logcat.c           |  549 +++++
44  .../interface/vcos/generic/vcos_mem_from_malloc.c  |   73 +
45  .../interface/vcos/generic/vcos_mem_from_malloc.h  |   54 +
46  .../vcos/generic/vcos_mutexes_are_reentrant.h      |   68 +
47  .../interface/vcos/generic/vcos_thread_reaper.h    |   35 +
48  .../interface/vcos/linuxkernel/stdint.h            |   17 +
49  .../interface/vcos/linuxkernel/vcos_linuxkernel.c  |  616 +++++
50  .../vcos/linuxkernel/vcos_linuxkernel_cfg.c        |  332 +++
51  .../vcos/linuxkernel/vcos_linuxkernel_misc.c       |  113 +
52  .../interface/vcos/linuxkernel/vcos_mod_init.c     |   64 +
53  .../interface/vcos/linuxkernel/vcos_platform.h     |  496 ++++
54  .../vcos/linuxkernel/vcos_platform_types.h         |   47 +
55  .../interface/vcos/linuxkernel/vcos_thread_map.c   |  129 +
56  .../interface/vcos/linuxkernel/vcos_thread_map.h   |   39 +
57  drivers/misc/vc04_services/interface/vcos/vcos.h   |  201 ++
58  .../vc04_services/interface/vcos/vcos_assert.h     |  269 ++
59  .../interface/vcos/vcos_atomic_flags.h             |   72 +
60  .../vc04_services/interface/vcos/vcos_build_info.h |    5 +
61  .../misc/vc04_services/interface/vcos/vcos_cfg.h   |  113 +
62  .../misc/vc04_services/interface/vcos/vcos_cmd.h   |   98 +
63  .../misc/vc04_services/interface/vcos/vcos_ctype.h |   29 +
64  .../misc/vc04_services/interface/vcos/vcos_dlfcn.h |   69 +
65  .../misc/vc04_services/interface/vcos/vcos_event.h |   97 +
66  .../interface/vcos/vcos_event_flags.h              |   98 +
67  .../misc/vc04_services/interface/vcos/vcos_init.h  |   43 +
68  .../vc04_services/interface/vcos/vcos_logging.h    |  279 +++
69  .../interface/vcos/vcos_lowlevel_thread.h          |  107 +
70  .../misc/vc04_services/interface/vcos/vcos_mem.h   |   81 +
71  .../vc04_services/interface/vcos/vcos_msgqueue.h   |  157 ++
72  .../misc/vc04_services/interface/vcos/vcos_mutex.h |   92 +
73  .../misc/vc04_services/interface/vcos/vcos_once.h  |   42 +
74  .../vc04_services/interface/vcos/vcos_semaphore.h  |  115 +
75  .../vc04_services/interface/vcos/vcos_stdbool.h    |   17 +
76  .../vc04_services/interface/vcos/vcos_stdint.h     |  193 ++
77  .../vc04_services/interface/vcos/vcos_string.h     |   73 +
78  .../vc04_services/interface/vcos/vcos_thread.h     |  259 ++
79  .../interface/vcos/vcos_thread_attr.h              |   73 +
80  .../misc/vc04_services/interface/vcos/vcos_timer.h |   95 +
81  .../misc/vc04_services/interface/vcos/vcos_types.h |  197 ++
82  74 files changed, 15998 insertions(+), 0 deletions(-)
83  create mode 100644 drivers/misc/vc04_services/Kconfig
84  create mode 100644 drivers/misc/vc04_services/Makefile
85  create mode 100644 drivers/misc/vc04_services/interface/vchi/vchi_mh.h
86  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
87  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
88  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
89  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
90  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
91  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
92  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
93  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
94  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
95  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
96  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
97  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
98  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
99  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_lib.c
100  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
101  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
102  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
103  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
104  create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
105  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_cmd.c
106  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_common.h
107  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_blockpool.h
108  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.c
109  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.h
110  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_named_sem.h
111  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_quickslow_mutex.h
112  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_reentrant_mtx.h
113  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_tls.h
114  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_joinable_thread_from_plain.h
115  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_latch_from_sem.h
116  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_logcat.c
117  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.c
118  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.h
119  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_mutexes_are_reentrant.h
120  create mode 100644 drivers/misc/vc04_services/interface/vcos/generic/vcos_thread_reaper.h
121  create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/stdint.h
122  create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel.c
123  create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_cfg.c
124  create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_misc.c
125  create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_mod_init.c
126  create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform.h
127  create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform_types.h
128  create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.c
129  create mode 100644 drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.h
130  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos.h
131  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_assert.h
132  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_atomic_flags.h
133  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_build_info.h
134  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_cfg.h
135  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_cmd.h
136  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_ctype.h
137  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_dlfcn.h
138  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_event.h
139  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_event_flags.h
140  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_init.h
141  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_logging.h
142  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_lowlevel_thread.h
143  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_mem.h
144  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_msgqueue.h
145  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_mutex.h
146  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_once.h
147  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_semaphore.h
148  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_stdbool.h
149  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_stdint.h
150  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_string.h
151  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_thread.h
152  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_thread_attr.h
153  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_timer.h
154  create mode 100644 drivers/misc/vc04_services/interface/vcos/vcos_types.h
155
156 --- a/drivers/misc/Kconfig
157 +++ b/drivers/misc/Kconfig
158 @@ -506,4 +506,5 @@ source "drivers/misc/ti-st/Kconfig"
159  source "drivers/misc/lis3lv02d/Kconfig"
160  source "drivers/misc/carma/Kconfig"
161  source "drivers/misc/altera-stapl/Kconfig"
162 +source "drivers/misc/vc04_services/Kconfig"
163  endmenu
164 --- a/drivers/misc/Makefile
165 +++ b/drivers/misc/Makefile
166 @@ -49,3 +49,5 @@ obj-y                         += carma/
167  obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
168  obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
169  obj-$(CONFIG_MAX8997_MUIC)     += max8997-muic.o
170 +obj-y                          += vc04_services/
171 +
172 --- /dev/null
173 +++ b/drivers/misc/vc04_services/Kconfig
174 @@ -0,0 +1,7 @@
175 +config BCM2708_VCHIQ
176 +       tristate "Videocore VCHIQ"
177 +       depends on MACH_BCM2708
178 +        default y
179 +        help
180 +          Helper for communication for VideoCore.
181 +
182 --- /dev/null
183 +++ b/drivers/misc/vc04_services/Makefile
184 @@ -0,0 +1,19 @@
185 +obj-$(CONFIG_BCM2708_VCHIQ)    += vchiq.o
186 +
187 +vchiq-objs := \
188 +   interface/vchiq_arm/vchiq_core.o  \
189 +   interface/vchiq_arm/vchiq_arm.o \
190 +   interface/vchiq_arm/vchiq_kern_lib.o \
191 +   interface/vchiq_arm/vchiq_2835_arm.o \
192 +   interface/vcos/linuxkernel/vcos_linuxkernel.o \
193 +   interface/vcos/linuxkernel/vcos_thread_map.o \
194 +   interface/vcos/linuxkernel/vcos_linuxkernel_cfg.o \
195 +   interface/vcos/generic/vcos_generic_event_flags.o \
196 +   interface/vcos/generic/vcos_logcat.o \
197 +   interface/vcos/generic/vcos_mem_from_malloc.o \
198 +   interface/vcos/generic/vcos_cmd.o
199 +
200 +EXTRA_CFLAGS += -DVCOS_VERIFY_BKPTS=1 -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel
201 +
202 +
203 +
204 --- /dev/null
205 +++ b/drivers/misc/vc04_services/interface/vchi/vchi_mh.h
206 @@ -0,0 +1,19 @@
207 +/*=============================================================================
208 +Copyright (c) 2010 Broadcom Europe Limited. All rights reserved.
209 +
210 +Project  :  vchi
211 +Module   :  vchi
212 +
213 +FILE DESCRIPTION:
214 +Definitions for memory handle types.
215 +=============================================================================*/
216 +
217 +#ifndef VCHI_MH_H_
218 +#define VCHI_MH_H_
219 +
220 +#include <interface/vcos/vcos.h>
221 +
222 +typedef int32_t VCHI_MEM_HANDLE_T;
223 +#define VCHI_MEM_HANDLE_INVALID 0
224 +
225 +#endif
226 --- /dev/null
227 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq.h
228 @@ -0,0 +1,27 @@
229 +/*
230 + * Copyright (c) 2010-2011 Broadcom. All rights reserved.
231 + *
232 + * This program is free software; you can redistribute it and/or modify
233 + * it under the terms of the GNU General Public License as published by
234 + * the Free Software Foundation; either version 2 of the License, or
235 + * (at your option) any later version.
236 + *
237 + * This program is distributed in the hope that it will be useful,
238 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
239 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
240 + * GNU General Public License for more details.
241 + *
242 + * You should have received a copy of the GNU General Public License
243 + * along with this program; if not, write to the Free Software
244 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
245 + */
246 +
247 +#ifndef VCHIQ_VCHIQ_H
248 +#define VCHIQ_VCHIQ_H
249 +
250 +#include "vchiq_if.h"
251 +#include "vchiq_util.h"
252 +#include "interface/vcos/vcos.h"
253 +
254 +#endif
255 +
256 --- /dev/null
257 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835.h
258 @@ -0,0 +1,27 @@
259 +/*
260 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
261 + *
262 + * This program is free software; you can redistribute it and/or modify
263 + * it under the terms of the GNU General Public License as published by
264 + * the Free Software Foundation; either version 2 of the License, or
265 + * (at your option) any later version.
266 + *
267 + * This program is distributed in the hope that it will be useful,
268 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
269 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
270 + * GNU General Public License for more details.
271 + *
272 + * You should have received a copy of the GNU General Public License
273 + * along with this program; if not, write to the Free Software
274 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
275 + */
276 +
277 +#ifndef VCHIQ_2835_H
278 +#define VCHIQ_2835_H
279 +
280 +#include "vchiq_pagelist.h"
281 +
282 +#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0
283 +#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX  1
284 +
285 +#endif /* VCHIQ_2835_H */
286 --- /dev/null
287 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
288 @@ -0,0 +1,487 @@
289 +/*
290 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
291 + *
292 + * This program is free software; you can redistribute it and/or modify
293 + * it under the terms of the GNU General Public License as published by
294 + * the Free Software Foundation; either version 2 of the License, or
295 + * (at your option) any later version.
296 + *
297 + * This program is distributed in the hope that it will be useful,
298 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
299 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
300 + * GNU General Public License for more details.
301 + *
302 + * You should have received a copy of the GNU General Public License
303 + * along with this program; if not, write to the Free Software
304 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
305 + */
306 +
307 +#include <linux/kernel.h>
308 +#include <linux/types.h>
309 +#include <linux/errno.h>
310 +#include <linux/interrupt.h>
311 +#include <linux/irq.h>
312 +#include <linux/pagemap.h>
313 +#include <linux/dma-mapping.h>
314 +#include <linux/version.h>
315 +#include <asm/pgtable.h>
316 +#include <asm/io.h>
317 +#include <asm/uaccess.h>
318 +
319 +#include <mach/irqs.h>
320 +
321 +#include <mach/platform.h>
322 +#include <mach/vcio.h>
323 +
324 +#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
325 +
326 +#define VCHIQ_DOORBELL_IRQ IRQ_ARM_DOORBELL_0
327 +#define VCHIQ_ARM_ADDRESS(x) __virt_to_bus(x)
328 +
329 +#include "vchiq_arm.h"
330 +#include "vchiq_2835.h"
331 +
332 +#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
333 +
334 +#define VCOS_LOG_CATEGORY (&vchiq_arm_log_category)
335 +
336 +static char *g_slot_mem;
337 +static int g_slot_mem_size;
338 +dma_addr_t g_slot_phys;
339 +static FRAGMENTS_T *g_fragments_base;
340 +static FRAGMENTS_T *g_free_fragments;
341 +struct semaphore g_free_fragments_sema;
342 +
343 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
344 +static DEFINE_SEMAPHORE(g_free_fragments_mutex);
345 +#else
346 +static DECLARE_MUTEX(g_free_fragments_mutex);
347 +#endif
348 +
349 +static irqreturn_t
350 +vchiq_doorbell_irq(int irq, void *dev_id);
351 +
352 +static int
353 +create_pagelist(char __user *buf, size_t count, unsigned short type,
354 +       struct task_struct *task, PAGELIST_T ** ppagelist);
355 +
356 +static void
357 +free_pagelist(PAGELIST_T *pagelist, int actual);
358 +
359 +int __init
360 +vchiq_platform_vcos_init(void)
361 +{
362 +       return (vcos_init() == VCOS_SUCCESS) ? 0 : -EINVAL;
363 +}
364 +
365 +int __init
366 +vchiq_platform_init(VCHIQ_STATE_T *state)
367 +{
368 +       VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
369 +       int frag_mem_size;
370 +       int err;
371 +       int i;
372 +
373 +       /* Allocate space for the channels in coherent memory */
374 +       g_slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
375 +       frag_mem_size = PAGE_ALIGN(sizeof(FRAGMENTS_T) * MAX_FRAGMENTS);
376 +
377 +       g_slot_mem = dma_alloc_coherent(NULL, g_slot_mem_size + frag_mem_size,
378 +               &g_slot_phys, GFP_ATOMIC);
379 +
380 +       if (!g_slot_mem) {
381 +               vcos_log_error("Unable to allocate channel memory");
382 +               err = -ENOMEM;
383 +               goto failed_alloc;
384 +       }
385 +
386 +       vcos_assert(((int)g_slot_mem & (PAGE_SIZE - 1)) == 0);
387 +
388 +       vchiq_slot_zero = vchiq_init_slots(g_slot_mem, g_slot_mem_size);
389 +       if (!vchiq_slot_zero)
390 +       {
391 +          err = -EINVAL;
392 +          goto failed_init_slots;
393 +       }
394 +
395 +       vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] = (int)g_slot_phys + g_slot_mem_size;
396 +       vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] = MAX_FRAGMENTS;
397 +
398 +       g_fragments_base = (FRAGMENTS_T *)(g_slot_mem + g_slot_mem_size);
399 +       g_slot_mem_size += frag_mem_size;
400 +
401 +       g_free_fragments = g_fragments_base;
402 +       for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
403 +               *(FRAGMENTS_T **) & g_fragments_base[i] =
404 +                       &g_fragments_base[i + 1];
405 +       }
406 +       *(FRAGMENTS_T **) & g_fragments_base[i] = NULL;
407 +       sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
408 +
409 +       if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) !=
410 +               VCHIQ_SUCCESS)
411 +       {
412 +               err = -EINVAL;
413 +               goto failed_vchiq_init;
414 +       }
415 +
416 +       err = request_irq(VCHIQ_DOORBELL_IRQ, vchiq_doorbell_irq,
417 +               IRQF_SAMPLE_RANDOM | IRQF_IRQPOLL, "VCHIQ doorbell",
418 +               state);
419 +       if (err < 0)
420 +       {
421 +               printk( KERN_ERR "%s: failed to register irq=%d err=%d\n", __func__,
422 +                       VCHIQ_DOORBELL_IRQ, err );
423 +               goto failed_request_irq;
424 +       }
425 +
426 +       /* Send the base address of the slots to VideoCore */
427 +
428 +       dsb(); /* Ensure all writes have completed */
429 +
430 +       bcm_mailbox_write(MBOX_CHAN_VCHIQ, (unsigned int)g_slot_phys);
431 +
432 +       vcos_log_info("vchiq_init - done (slots %x, phys %x)",
433 +               (unsigned int)vchiq_slot_zero, g_slot_phys);
434 +
435 +       return 0;
436 +
437 +failed_request_irq:
438 +failed_vchiq_init:
439 +failed_init_slots:
440 +       dma_free_coherent(NULL, g_slot_mem_size, g_slot_mem, g_slot_phys);
441 +
442 +failed_alloc:
443 +       return err;
444 +}
445 +
446 +void __exit
447 +vchiq_platform_exit(VCHIQ_STATE_T *state)
448 +{
449 +       free_irq(VCHIQ_DOORBELL_IRQ, state);
450 +       dma_free_coherent(NULL, g_slot_mem_size,
451 +               g_slot_mem, g_slot_phys);
452 +}
453 +
454 +void
455 +remote_event_signal(REMOTE_EVENT_T *event)
456 +{
457 +       event->fired = 1;
458 +
459 +       /* The test on the next line also ensures the write on the previous line
460 +               has completed */
461 +
462 +       if (event->armed) {
463 +               /* trigger vc interrupt */
464 +               dsb();         /* data barrier operation */
465 +
466 +               writel(0, __io_address(ARM_0_BELL2));
467 +       }
468 +}
469 +
470 +int
471 +vchiq_copy_from_user(void *dst, const void *src, int size)
472 +{
473 +       return copy_from_user(dst, src, size);
474 +}
475 +
476 +VCHIQ_STATUS_T
477 +vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
478 +       void *offset, int size, int dir)
479 +{
480 +       PAGELIST_T *pagelist;
481 +       int ret;
482 +
483 +       vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
484 +
485 +       ret = create_pagelist((char __user *)offset, size,
486 +                       (dir == VCHIQ_BULK_RECEIVE)
487 +                       ? PAGELIST_READ
488 +                       : PAGELIST_WRITE,
489 +                       current,
490 +                       &pagelist);
491 +       if (ret != 0)
492 +               return VCHIQ_ERROR;
493 +
494 +       bulk->handle = memhandle;
495 +       bulk->data = VCHIQ_ARM_ADDRESS(pagelist);
496 +
497 +       /* Store the pagelist address in remote_data, which isn't used by the
498 +          slave. */
499 +       bulk->remote_data = pagelist;
500 +
501 +       return VCHIQ_SUCCESS;
502 +}
503 +
504 +void
505 +vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
506 +{
507 +       free_pagelist((PAGELIST_T *)bulk->remote_data, bulk->actual);
508 +}
509 +
510 +void
511 +vchiq_transfer_bulk(VCHIQ_BULK_T *bulk)
512 +{
513 +       /*
514 +        * This should only be called on the master (VideoCore) side, but
515 +        * provide an implementation to avoid the need for ifdefery.
516 +        */
517 +       vcos_assert(!"This code should not be called by the ARM on BCM2835");
518 +}
519 +
520 +void
521 +vchiq_dump_platform_state(void *dump_context)
522 +{
523 +        char buf[80];
524 +        int len;
525 +        len = vcos_snprintf(buf, sizeof(buf),
526 +                "  Platform: 2835 (VC master)");
527 +        vchiq_dump(dump_context, buf, len + 1);
528 +}
529 +
530 +void
531 +vchiq_platform_paused(VCHIQ_STATE_T *state)
532 +{
533 +   vcos_unused(state);
534 +   vcos_assert_msg(0, "Suspend/resume not supported");
535 +}
536 +
537 +void
538 +vchiq_platform_resumed(VCHIQ_STATE_T *state)
539 +{
540 +   vcos_unused(state);
541 +   vcos_assert_msg(0, "Suspend/resume not supported");
542 +}
543 +
544 +VCHIQ_STATUS_T
545 +vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle)
546 +{
547 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
548 +   if (!service)
549 +      return VCHIQ_ERROR;
550 +   return VCHIQ_SUCCESS;
551 +}
552 +
553 +VCHIQ_STATUS_T
554 +vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle)
555 +{
556 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
557 +   if (!service)
558 +      return VCHIQ_ERROR;
559 +   return VCHIQ_SUCCESS;
560 +}
561 +
562 +VCHIQ_STATUS_T
563 +vchiq_check_service(VCHIQ_SERVICE_HANDLE_T handle)
564 +{
565 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
566 +   if (!service)
567 +      return VCHIQ_ERROR;
568 +   return VCHIQ_SUCCESS;
569 +}
570 +
571 +/*
572 + * Local functions
573 + */
574 +
575 +static irqreturn_t
576 +vchiq_doorbell_irq(int irq, void *dev_id)
577 +{
578 +   VCHIQ_STATE_T *state = dev_id;
579 +       irqreturn_t ret = IRQ_NONE;
580 +       unsigned int status;
581 +
582 +       /* Read (and clear) the doorbell */
583 +       status = readl(__io_address(ARM_0_BELL0));
584 +
585 +       if (status & 0x4) {  /* Was the doorbell rung? */
586 +               remote_event_pollall(state);
587 +               ret = IRQ_HANDLED;
588 +       }
589 +
590 +       return ret;
591 +}
592 +
593 +/* There is a potential problem with partial cache lines (pages?)
594 +       at the ends of the block when reading. If the CPU accessed anything in
595 +       the same line (page?) then it may have pulled old data into the cache,
596 +       obscuring the new data underneath. We can solve this by transferring the
597 +       partial cache lines separately, and allowing the ARM to copy into the
598 +       cached area.
599 +
600 +       N.B. This implementation plays slightly fast and loose with the Linux
601 +       driver programming rules, e.g. its use of __virt_to_bus instead of
602 +       dma_map_single, but it isn't a multi-platform driver and it benefits
603 +       from increased speed as a result.
604 + */
605 +
606 +static int
607 +create_pagelist(char __user *buf, size_t count, unsigned short type,
608 +       struct task_struct *task, PAGELIST_T ** ppagelist)
609 +{
610 +       PAGELIST_T *pagelist;
611 +       struct page **pages;
612 +       struct page *page;
613 +       unsigned long *addrs;
614 +       unsigned int num_pages, offset, i;
615 +       char *addr, *base_addr, *next_addr;
616 +       int run, addridx, actual_pages;
617 +
618 +       offset = (unsigned int)buf & (PAGE_SIZE - 1);
619 +       num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE;
620 +
621 +       *ppagelist = NULL;
622 +
623 +       /* Allocate enough storage to hold the page pointers and the page list */
624 +       pagelist = (PAGELIST_T *) kmalloc(sizeof(PAGELIST_T) +
625 +               (num_pages * sizeof(unsigned long)) +
626 +               (num_pages * sizeof(pages[0])),
627 +               GFP_KERNEL);
628 +
629 +       vcos_log_trace("create_pagelist - %x", (unsigned int)pagelist);
630 +       if (!pagelist)
631 +               return -ENOMEM;
632 +
633 +       addrs = pagelist->addrs;
634 +       pages = (struct page **)(addrs + num_pages);
635 +
636 +       down_read(&task->mm->mmap_sem);
637 +       actual_pages = get_user_pages(task, task->mm,
638 +               (unsigned long)buf & ~(PAGE_SIZE - 1), num_pages,
639 +               (type == PAGELIST_READ) /*Write */ , 0 /*Force */ ,
640 +               pages, NULL /*vmas */ );
641 +       up_read(&task->mm->mmap_sem);
642 +
643 +        if (actual_pages != num_pages)
644 +       {
645 +               for (i = 0; i < actual_pages; i++) {
646 +                       page_cache_release(pages[i]);
647 +               }
648 +               kfree(pagelist);
649 +               return -EINVAL;
650 +       }
651 +
652 +       pagelist->length = count;
653 +       pagelist->type = type;
654 +       pagelist->offset = offset;
655 +
656 +       /* Group the pages into runs of contiguous pages */
657 +
658 +       base_addr = VCHIQ_ARM_ADDRESS(page_address(pages[0]));
659 +       next_addr = base_addr + PAGE_SIZE;
660 +       addridx = 0;
661 +       run = 0;
662 +
663 +       for (i = 1; i < num_pages; i++) {
664 +               addr = VCHIQ_ARM_ADDRESS(page_address(pages[i]));
665 +               if ((addr == next_addr) && (run < (PAGE_SIZE - 1))) {
666 +                       next_addr += PAGE_SIZE;
667 +                       run++;
668 +               } else {
669 +                       addrs[addridx] = (unsigned long)base_addr + run;
670 +                       addridx++;
671 +                       base_addr = addr;
672 +                       next_addr = addr + PAGE_SIZE;
673 +                       run = 0;
674 +               }
675 +       }
676 +
677 +       addrs[addridx] = (unsigned long)base_addr + run;
678 +       addridx++;
679 +
680 +       /* Partial cache lines (fragments) require special measures */
681 +       if ((type == PAGELIST_READ) &&
682 +               ((pagelist->offset & (CACHE_LINE_SIZE - 1)) ||
683 +               ((pagelist->offset + pagelist->length) & (CACHE_LINE_SIZE - 1)))) {
684 +               FRAGMENTS_T *fragments;
685 +
686 +               if (down_interruptible(&g_free_fragments_sema) != 0) {
687 +                       kfree(pagelist);
688 +                       return -EINTR;
689 +               }
690 +
691 +               vcos_assert(g_free_fragments != NULL);
692 +
693 +               down(&g_free_fragments_mutex);
694 +               fragments = (FRAGMENTS_T *) g_free_fragments;
695 +               vcos_assert(fragments != NULL);
696 +               g_free_fragments = *(FRAGMENTS_T **) g_free_fragments;
697 +               up(&g_free_fragments_mutex);
698 +               pagelist->type =
699 +                        PAGELIST_READ_WITH_FRAGMENTS + (fragments -
700 +                                                        g_fragments_base);
701 +       }
702 +
703 +       for (page = virt_to_page(pagelist);
704 +               page <= virt_to_page(addrs + num_pages - 1); page++) {
705 +               flush_dcache_page(page);
706 +       }
707 +
708 +       *ppagelist = pagelist;
709 +
710 +       return 0;
711 +}
712 +
713 +static void
714 +free_pagelist(PAGELIST_T *pagelist, int actual)
715 +{
716 +       struct page **pages;
717 +       unsigned int num_pages, i;
718 +
719 +       vcos_log_trace("free_pagelist - %x, %d", (unsigned int)pagelist, actual);
720 +
721 +       num_pages =
722 +                (pagelist->length + pagelist->offset + PAGE_SIZE - 1) / PAGE_SIZE;
723 +
724 +       pages = (struct page **)(pagelist->addrs + num_pages);
725 +
726 +       /* Deal with any partial cache lines (fragments) */
727 +       if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
728 +               FRAGMENTS_T *fragments =
729 +                        g_fragments_base + (pagelist->type -
730 +                                       PAGELIST_READ_WITH_FRAGMENTS);
731 +               int head_bytes, tail_bytes;
732 +
733 +               if (actual >= 0)
734 +               {
735 +                       if ((head_bytes = (CACHE_LINE_SIZE - pagelist->offset) & (CACHE_LINE_SIZE - 1)) != 0) {
736 +                               if (head_bytes > actual)
737 +                                       head_bytes = actual;
738 +
739 +                               memcpy((char *)page_address(pages[0]) +
740 +                                                pagelist->offset, fragments->headbuf,
741 +                                                head_bytes);
742 +                       }
743 +                       if ((head_bytes < actual) &&
744 +                               (tail_bytes =
745 +                               (pagelist->offset + actual) & (CACHE_LINE_SIZE -
746 +                                                                               1)) != 0) {
747 +                               memcpy((char *)page_address(pages[num_pages - 1]) +
748 +                                                ((pagelist->offset + actual) & (PAGE_SIZE -
749 +                                                                       1) & ~(CACHE_LINE_SIZE - 1)),
750 +                                                fragments->tailbuf, tail_bytes);
751 +                       }
752 +               }
753 +
754 +               down(&g_free_fragments_mutex);
755 +               *(FRAGMENTS_T **) fragments = g_free_fragments;
756 +               g_free_fragments = fragments;
757 +               up(&g_free_fragments_mutex);
758 +               up(&g_free_fragments_sema);
759 +       }
760 +
761 +       for (i = 0; i < num_pages; i++) {
762 +               if (pagelist->type != PAGELIST_WRITE)
763 +                       set_page_dirty(pages[i]);
764 +               page_cache_release(pages[i]);
765 +       }
766 +
767 +       kfree(pagelist);
768 +}
769 +
770 +VCHIQ_STATUS_T
771 +vchiq_platform_suspend(VCHIQ_STATE_T *state)
772 +{
773 +   vcos_unused(state);
774 +   return VCHIQ_ERROR;
775 +}
776 --- /dev/null
777 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
778 @@ -0,0 +1,1293 @@
779 +/*
780 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
781 + *
782 + * This program is free software; you can redistribute it and/or modify
783 + * it under the terms of the GNU General Public License as published by
784 + * the Free Software Foundation; either version 2 of the License, or
785 + * (at your option) any later version.
786 + *
787 + * This program is distributed in the hope that it will be useful,
788 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
789 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
790 + * GNU General Public License for more details.
791 + *
792 + * You should have received a copy of the GNU General Public License
793 + * along with this program; if not, write to the Free Software
794 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
795 + */
796 +
797 +#include <linux/kernel.h>
798 +#include <linux/module.h>
799 +#include <linux/types.h>
800 +#include <linux/errno.h>
801 +#include <linux/cdev.h>
802 +#include <linux/fs.h>
803 +#include <linux/device.h>
804 +
805 +#include "vchiq_core.h"
806 +#include "vchiq_ioctl.h"
807 +#include "vchiq_arm.h"
808 +
809 +#define DEVICE_NAME "vchiq"
810 +
811 +/* Override the default prefix, which would be vchiq_arm (from the filename) */
812 +#undef MODULE_PARAM_PREFIX
813 +#define MODULE_PARAM_PREFIX DEVICE_NAME "."
814 +
815 +#define VCHIQ_MINOR 0
816 +
817 +/* Some per-instance constants */
818 +#define MAX_COMPLETIONS 16
819 +#define MAX_SERVICES 64
820 +#define MAX_ELEMENTS 8
821 +#define MSG_QUEUE_SIZE 64
822 +
823 +#define VCOS_LOG_CATEGORY (&vchiq_arm_log_category)
824 +
825 +typedef struct client_service_struct {
826 +   VCHIQ_SERVICE_T *service;
827 +   void *userdata;
828 +   VCHIQ_INSTANCE_T instance;
829 +   int handle;
830 +   int is_vchi;
831 +   volatile int dequeue_pending;
832 +   volatile int message_available_pos;
833 +   volatile int msg_insert;
834 +   volatile int msg_remove;
835 +   VCOS_EVENT_T insert_event;
836 +   VCOS_EVENT_T remove_event;
837 +   VCHIQ_HEADER_T *msg_queue[MSG_QUEUE_SIZE];
838 +} USER_SERVICE_T;
839 +
840 +struct vchiq_instance_struct {
841 +   VCHIQ_STATE_T *state;
842 +   VCHIQ_COMPLETION_DATA_T completions[MAX_COMPLETIONS];
843 +   volatile int completion_insert;
844 +   volatile int completion_remove;
845 +   VCOS_EVENT_T insert_event;
846 +   VCOS_EVENT_T remove_event;
847 +
848 +   USER_SERVICE_T services[MAX_SERVICES];
849 +
850 +   int connected;
851 +   int closing;
852 +   int pid;
853 +   int mark;
854 +};
855 +
856 +typedef struct dump_context_struct
857 +{
858 +   char __user *buf;
859 +   size_t actual;
860 +   size_t space;
861 +   loff_t offset;
862 +} DUMP_CONTEXT_T;
863 +
864 +VCOS_LOG_CAT_T vchiq_arm_log_category;
865 +
866 +static struct cdev    vchiq_cdev;
867 +static dev_t          vchiq_devid;
868 +static VCHIQ_STATE_T g_state;
869 +static struct class  *vchiq_class;
870 +static struct device *vchiq_dev;
871 +
872 +static const char *ioctl_names[] =
873 +{
874 +   "CONNECT",
875 +   "SHUTDOWN",
876 +   "CREATE_SERVICE",
877 +   "REMOVE_SERVICE",
878 +   "QUEUE_MESSAGE",
879 +   "QUEUE_BULK_TRANSMIT",
880 +   "QUEUE_BULK_RECEIVE",
881 +   "AWAIT_COMPLETION",
882 +   "DEQUEUE_MESSAGE",
883 +   "GET_CLIENT_ID",
884 +   "GET_CONFIG",
885 +   "CLOSE_SERVICE",
886 +   "USE_SERVICE",
887 +   "RELEASE_SERIVCE"
888 +};
889 +
890 +VCOS_LOG_LEVEL_T vchiq_default_arm_log_level = VCOS_LOG_WARN;
891 +
892 +/****************************************************************************
893 +*
894 +*   find_service_by_handle
895 +*
896 +***************************************************************************/
897 +
898 +static inline USER_SERVICE_T *find_service_by_handle(
899 +       VCHIQ_INSTANCE_T instance, int handle )
900 +{
901 +   USER_SERVICE_T *user_service;
902 +
903 +   if (( handle >= 0 )
904 +      && ( handle < MAX_SERVICES ))
905 +   {
906 +      user_service = &instance->services[ handle ];
907 +
908 +      if ( user_service->service != NULL )
909 +      {
910 +         return user_service;
911 +      }
912 +   }
913 +
914 +   return NULL;
915 +}
916 +
917 +/****************************************************************************
918 +*
919 +*   find_avail_service_handle
920 +*
921 +***************************************************************************/
922 +
923 +static inline USER_SERVICE_T *find_avail_service_handle(
924 +   VCHIQ_INSTANCE_T instance)
925 +{
926 +   int handle;
927 +
928 +   for ( handle = 0; handle < MAX_SERVICES; handle++ )
929 +   {
930 +      if ( instance->services[handle].service == NULL )
931 +      {
932 +         instance->services[handle].instance = instance;
933 +         instance->services[handle].handle = handle;
934 +
935 +         return &instance->services[handle];
936 +      }
937 +   }
938 +   return NULL;
939 +}
940 +
941 +/****************************************************************************
942 +*
943 +*   add_completion
944 +*
945 +***************************************************************************/
946 +
947 +static VCHIQ_STATUS_T
948 +add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
949 +   VCHIQ_HEADER_T *header, USER_SERVICE_T *service, void *bulk_userdata)
950 +{
951 +   VCHIQ_COMPLETION_DATA_T *completion;
952 +   DEBUG_INITIALISE(g_state.local)
953 +
954 +   while (instance->completion_insert ==
955 +          (instance->completion_remove + MAX_COMPLETIONS)) {
956 +      /* Out of space - wait for the client */
957 +      DEBUG_TRACE(SERVICE_CALLBACK_LINE);
958 +      vcos_log_trace("add_completion - completion queue full");
959 +      DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
960 +      if (vcos_event_wait(&instance->remove_event) != VCOS_SUCCESS) {
961 +         vcos_log_info("service_callback interrupted");
962 +         return VCHIQ_RETRY;
963 +      } else if (instance->closing) {
964 +         vcos_log_info("service_callback closing");
965 +         return VCHIQ_ERROR;
966 +      }
967 +      DEBUG_TRACE(SERVICE_CALLBACK_LINE);
968 +   }
969 +
970 +   completion =
971 +       &instance->
972 +       completions[instance->completion_insert & (MAX_COMPLETIONS - 1)];
973 +
974 +   completion->header = header;
975 +   completion->reason = reason;
976 +   completion->service_userdata = service;
977 +   completion->bulk_userdata = bulk_userdata;
978 +
979 +   /* A write barrier is needed here to ensure that the entire completion
980 +      record is written out before the insert point. */
981 +   vcos_wmb(&completion->bulk_userdata);
982 +
983 +   if (reason == VCHIQ_MESSAGE_AVAILABLE)
984 +      service->message_available_pos = instance->completion_insert;
985 +   instance->completion_insert++;
986 +
987 +   vcos_event_signal(&instance->insert_event);
988 +
989 +   return VCHIQ_SUCCESS;
990 +}
991 +
992 +/****************************************************************************
993 +*
994 +*   service_callback
995 +*
996 +***************************************************************************/
997 +
998 +static VCHIQ_STATUS_T
999 +service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
1000 +   VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
1001 +{
1002 +   /* How do we ensure the callback goes to the right client?
1003 +      The service_user data points to a USER_SERVICE_T record containing the
1004 +      original callback and the user state structure, which contains a circular
1005 +      buffer for completion records.
1006 +    */
1007 +   USER_SERVICE_T *service =
1008 +       (USER_SERVICE_T *) VCHIQ_GET_SERVICE_USERDATA(handle);
1009 +   VCHIQ_INSTANCE_T instance = service->instance;
1010 +   DEBUG_INITIALISE(g_state.local)
1011 +
1012 +   DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1013 +   vcos_log_trace
1014 +       ("service_callback - service %lx(%d), reason %d, header %lx, "
1015 +        "instance %lx, bulk_userdata %lx",
1016 +        (unsigned long)service, ((VCHIQ_SERVICE_T *) handle)->localport,
1017 +        reason, (unsigned long)header,
1018 +        (unsigned long)instance, (unsigned long)bulk_userdata);
1019 +
1020 +   if (!instance || instance->closing) {
1021 +      return VCHIQ_SUCCESS;
1022 +   }
1023 +
1024 +   if (header && service->is_vchi)
1025 +   {
1026 +      while (service->msg_insert == (service->msg_remove + MSG_QUEUE_SIZE))
1027 +      {
1028 +         DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1029 +         DEBUG_COUNT(MSG_QUEUE_FULL_COUNT);
1030 +         vcos_log_trace("service_callback - msg queue full");
1031 +         /* If there is no MESSAGE_AVAILABLE in the completion queue, add one */
1032 +         if ((service->message_available_pos - instance->completion_remove) < 0)
1033 +         {
1034 +            VCHIQ_STATUS_T status;
1035 +            vcos_log_warn("Inserting extra MESSAGE_AVAILABLE");
1036 +            DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1037 +            status = add_completion(instance, reason, NULL, service, bulk_userdata);
1038 +            if (status != VCHIQ_SUCCESS)
1039 +            {
1040 +               DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1041 +               return status;
1042 +            }
1043 +         }
1044 +         
1045 +         DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1046 +         if (vcos_event_wait(&service->remove_event) != VCOS_SUCCESS) {
1047 +            vcos_log_info("service_callback interrupted");
1048 +            DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1049 +            return VCHIQ_RETRY;
1050 +         } else if (instance->closing) {
1051 +            vcos_log_info("service_callback closing");
1052 +            DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1053 +            return VCHIQ_ERROR;
1054 +         }
1055 +         DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1056 +      }
1057 +
1058 +      service->msg_queue[service->msg_insert & (MSG_QUEUE_SIZE - 1)] =
1059 +         header;
1060 +
1061 +      /* A write memory barrier is needed to ensure that the store of header
1062 +         is completed before the insertion point is updated */
1063 +      vcos_wmb(&service->msg_queue[service->msg_insert & (MSG_QUEUE_SIZE - 1)]);
1064 +
1065 +      service->msg_insert++;
1066 +      vcos_event_signal(&service->insert_event);
1067 +
1068 +      /* If there is a thread waiting in DEQUEUE_MESSAGE, or if
1069 +         there is a MESSAGE_AVAILABLE in the completion queue then
1070 +         bypass the completion queue. */
1071 +      if (((service->message_available_pos - instance->completion_remove) >= 0) ||
1072 +          service->dequeue_pending)
1073 +      {
1074 +         DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1075 +         service->dequeue_pending = 0;
1076 +         return VCHIQ_SUCCESS;
1077 +      }
1078 +
1079 +      header = NULL;
1080 +   }
1081 +   DEBUG_TRACE(SERVICE_CALLBACK_LINE);
1082 +
1083 +   return add_completion(instance, reason, header, service, bulk_userdata);
1084 +}
1085 +
1086 +/****************************************************************************
1087 +*
1088 +*   vchiq_ioctl
1089 +*
1090 +***************************************************************************/
1091 +
1092 +static long
1093 +vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1094 +{
1095 +   VCHIQ_INSTANCE_T instance = file->private_data;
1096 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
1097 +   long ret = 0;
1098 +   int i, rc;
1099 +   DEBUG_INITIALISE(g_state.local)
1100 +
1101 +   vcos_log_trace("vchiq_ioctl - instance %x, cmd %s, arg %lx",
1102 +      (unsigned int)instance,
1103 +      ((_IOC_TYPE(cmd) == VCHIQ_IOC_MAGIC) && (_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ?
1104 +      ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
1105 +
1106 +   switch (cmd) {
1107 +   case VCHIQ_IOC_SHUTDOWN:
1108 +      if (!instance->connected)
1109 +         break;
1110 +
1111 +      /* Remove all services */
1112 +      for (i = 0; i < MAX_SERVICES; i++) {
1113 +         USER_SERVICE_T *service = &instance->services[i];
1114 +         if (service->service != NULL) {
1115 +            status = vchiq_remove_service(&service->service->base);
1116 +            if (status != VCHIQ_SUCCESS)
1117 +               break;
1118 +            service->service = NULL;
1119 +         }
1120 +      }
1121 +
1122 +      if (status == VCHIQ_SUCCESS) {
1123 +         /* Wake the completion thread and ask it to exit */
1124 +         instance->closing = 1;
1125 +         vcos_event_signal(&instance->insert_event);
1126 +      }
1127 +
1128 +      break;
1129 +
1130 +   case VCHIQ_IOC_CONNECT:
1131 +      if (instance->connected) {
1132 +         ret = -EINVAL;
1133 +         break;
1134 +      }
1135 +      if ((rc=vcos_mutex_lock(&instance->state->mutex)) != VCOS_SUCCESS) {
1136 +         vcos_log_error("vchiq: connect: could not lock mutex for state %d: %d",
1137 +                        instance->state->id, rc);
1138 +         ret = -EINTR;
1139 +         break;
1140 +      }
1141 +      status = vchiq_connect_internal(instance->state, instance);
1142 +      vcos_mutex_unlock(&instance->state->mutex);
1143 +
1144 +      if (status == VCHIQ_SUCCESS)
1145 +         instance->connected = 1;
1146 +      else
1147 +         vcos_log_error("vchiq: could not connect: %d", status);
1148 +      break;
1149 +
1150 +   case VCHIQ_IOC_CREATE_SERVICE:
1151 +      {
1152 +         VCHIQ_CREATE_SERVICE_T args;
1153 +         VCHIQ_SERVICE_T *service = NULL;
1154 +         USER_SERVICE_T *user_service = NULL;
1155 +         void *userdata;
1156 +         int srvstate;
1157 +
1158 +         if (copy_from_user
1159 +             (&args, (const void __user *)arg,
1160 +              sizeof(args)) != 0) {
1161 +            ret = -EFAULT;
1162 +            break;
1163 +         }
1164 +
1165 +         for (i = 0; i < MAX_SERVICES; i++) {
1166 +            if (instance->services[i].service == NULL) {
1167 +               user_service = &instance->services[i];
1168 +               break;
1169 +            }
1170 +         }
1171 +
1172 +         if (!user_service) {
1173 +            ret = -EMFILE;
1174 +            break;
1175 +         }
1176 +
1177 +         if (args.is_open) {
1178 +            if (instance->connected)
1179 +               srvstate = VCHIQ_SRVSTATE_OPENING;
1180 +            else {
1181 +               ret = -ENOTCONN;
1182 +               break;
1183 +            }
1184 +         } else {
1185 +            srvstate =
1186 +                instance->connected ?
1187 +                VCHIQ_SRVSTATE_LISTENING :
1188 +                VCHIQ_SRVSTATE_HIDDEN;
1189 +         }
1190 +
1191 +         vcos_mutex_lock(&instance->state->mutex);
1192 +
1193 +         userdata = args.params.userdata;
1194 +         args.params.callback = service_callback;
1195 +         args.params.userdata = user_service;
1196 +         service =
1197 +             vchiq_add_service_internal(instance->state,
1198 +                         &args.params, srvstate,
1199 +                         instance);
1200 +
1201 +         vcos_mutex_unlock(&instance->state->mutex);
1202 +
1203 +         if (service != NULL) {
1204 +            user_service->service = service;
1205 +            user_service->userdata = userdata;
1206 +            user_service->instance = instance;
1207 +            user_service->handle = i;
1208 +            user_service->is_vchi = args.is_vchi;
1209 +            user_service->dequeue_pending = 0;
1210 +            user_service->message_available_pos = instance->completion_remove - 1;
1211 +            user_service->msg_insert = 0;
1212 +            user_service->msg_remove = 0;
1213 +            vcos_event_create(&user_service->insert_event, "insert_event");
1214 +            vcos_event_create(&user_service->remove_event, "remove_event");
1215 +
1216 +            if (args.is_open) {
1217 +               status =
1218 +                   vchiq_open_service_internal
1219 +                   (service, instance->pid);
1220 +               if (status != VCHIQ_SUCCESS) {
1221 +                  vchiq_remove_service
1222 +                      (&service->base);
1223 +                  ret =
1224 +                      (status ==
1225 +                       VCHIQ_RETRY) ? -EINTR :
1226 +                      -EIO;
1227 +                  user_service->service = NULL;
1228 +                  user_service->instance = NULL;
1229 +                  vcos_event_delete(&user_service->insert_event);
1230 +                  vcos_event_delete(&user_service->remove_event);
1231 +                  break;
1232 +               }
1233 +            }
1234 +
1235 +            if (copy_to_user((void __user *)
1236 +                   &(((VCHIQ_CREATE_SERVICE_T __user
1237 +                       *) arg)->handle),
1238 +                   (const void *)&user_service->
1239 +                   handle,
1240 +                   sizeof(user_service->
1241 +                     handle)) != 0)
1242 +               ret = -EFAULT;
1243 +         } else {
1244 +            ret = -EEXIST;
1245 +         }
1246 +      }
1247 +      break;
1248 +
1249 +   case VCHIQ_IOC_CLOSE_SERVICE:
1250 +      {
1251 +         USER_SERVICE_T *user_service;
1252 +         int handle = (int)arg;
1253 +
1254 +         user_service = find_service_by_handle(instance, handle);
1255 +         if (user_service != NULL)
1256 +         {
1257 +            int is_server = (user_service->service->public_fourcc != VCHIQ_FOURCC_INVALID);
1258 +
1259 +            status =
1260 +                vchiq_close_service(&user_service->service->base);
1261 +            if ((status == VCHIQ_SUCCESS) && !is_server)
1262 +            {
1263 +               vcos_event_delete(&user_service->insert_event);
1264 +               vcos_event_delete(&user_service->remove_event);
1265 +               user_service->service = NULL;
1266 +            }
1267 +         } else
1268 +            ret = -EINVAL;
1269 +      }
1270 +      break;
1271 +
1272 +   case VCHIQ_IOC_REMOVE_SERVICE:
1273 +      {
1274 +         USER_SERVICE_T *user_service;
1275 +         int handle = (int)arg;
1276 +
1277 +         user_service = find_service_by_handle(instance, handle);
1278 +         if (user_service != NULL)
1279 +         {
1280 +            status =
1281 +                vchiq_remove_service(&user_service->service->base);
1282 +            if (status == VCHIQ_SUCCESS)
1283 +            {
1284 +               vcos_event_delete(&user_service->insert_event);
1285 +               vcos_event_delete(&user_service->remove_event);
1286 +               user_service->service = NULL;
1287 +            }
1288 +         } else
1289 +            ret = -EINVAL;
1290 +      }
1291 +      break;
1292 +
1293 +   case VCHIQ_IOC_USE_SERVICE:
1294 +   case VCHIQ_IOC_RELEASE_SERVICE:
1295 +      {
1296 +         USER_SERVICE_T *user_service;
1297 +         int handle = (int)arg;
1298 +
1299 +         user_service = find_service_by_handle(instance, handle);
1300 +         if (user_service != NULL)
1301 +         {
1302 +            status = (cmd == VCHIQ_IOC_USE_SERVICE) ? vchiq_use_service(&user_service->service->base) : vchiq_release_service(&user_service->service->base);
1303 +            if (status != VCHIQ_SUCCESS)
1304 +            {
1305 +               ret = -EINVAL; // ???
1306 +            }
1307 +         }
1308 +      }
1309 +      break;
1310 +
1311 +   case VCHIQ_IOC_QUEUE_MESSAGE:
1312 +      {
1313 +         VCHIQ_QUEUE_MESSAGE_T args;
1314 +         USER_SERVICE_T *user_service;
1315 +
1316 +         if (copy_from_user
1317 +             (&args, (const void __user *)arg,
1318 +              sizeof(args)) != 0) {
1319 +            ret = -EFAULT;
1320 +            break;
1321 +         }
1322 +         user_service = find_service_by_handle(instance, args.handle);
1323 +         if ((user_service != NULL) && (args.count <= MAX_ELEMENTS))
1324 +         {
1325 +            /* Copy elements into kernel space */
1326 +            VCHIQ_ELEMENT_T elements[MAX_ELEMENTS];
1327 +            if (copy_from_user
1328 +                (elements, args.elements,
1329 +                 args.count * sizeof(VCHIQ_ELEMENT_T)) == 0)
1330 +               status =
1331 +                  vchiq_queue_message
1332 +                  (&user_service->service->base,
1333 +                   elements, args.count);
1334 +            else
1335 +               ret = -EFAULT;
1336 +         } else {
1337 +            ret = -EINVAL;
1338 +         }
1339 +      }
1340 +      break;
1341 +
1342 +   case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
1343 +   case VCHIQ_IOC_QUEUE_BULK_RECEIVE:
1344 +      {
1345 +         VCHIQ_QUEUE_BULK_TRANSFER_T args;
1346 +         USER_SERVICE_T *user_service;
1347 +         VCHIQ_BULK_DIR_T dir =
1348 +           (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
1349 +           VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
1350 +
1351 +         if (copy_from_user
1352 +             (&args, (const void __user *)arg,
1353 +              sizeof(args)) != 0) {
1354 +            ret = -EFAULT;
1355 +            break;
1356 +         }
1357 +         user_service = find_service_by_handle(instance, args.handle);
1358 +         if (user_service != NULL)
1359 +         {
1360 +            status =
1361 +               vchiq_bulk_transfer
1362 +               ((VCHIQ_SERVICE_T *)user_service->service,
1363 +                VCHI_MEM_HANDLE_INVALID,
1364 +                args.data, args.size,
1365 +                args.userdata, args.mode,
1366 +                dir);
1367 +         } else {
1368 +            ret = -EINVAL;
1369 +         }
1370 +      }
1371 +      break;
1372 +
1373 +   case VCHIQ_IOC_AWAIT_COMPLETION:
1374 +      {
1375 +         VCHIQ_AWAIT_COMPLETION_T args;
1376 +
1377 +         DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1378 +         if (!instance->connected) {
1379 +            ret = -ENOTCONN;
1380 +            break;
1381 +         }
1382 +
1383 +         if (copy_from_user
1384 +             (&args, (const void __user *)arg,
1385 +              sizeof(args)) != 0) {
1386 +            ret = -EFAULT;
1387 +            break;
1388 +         }
1389 +         DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1390 +         while ((instance->completion_remove ==
1391 +            instance->completion_insert)
1392 +                && !instance->closing) {
1393 +            DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1394 +            if (vcos_event_wait(&instance->insert_event) !=
1395 +                VCOS_SUCCESS) {
1396 +               DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1397 +               vcos_log_info
1398 +                   ("AWAIT_COMPLETION interrupted");
1399 +               ret = -EINTR;
1400 +               break;
1401 +            }
1402 +         }
1403 +         DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1404 +
1405 +         /* A read memory barrier is needed to stop prefetch of a stale
1406 +            completion record */
1407 +         vcos_rmb();
1408 +
1409 +         if (ret == 0) {
1410 +            int msgbufcount = args.msgbufcount;
1411 +            for (ret = 0; ret < args.count; ret++) {
1412 +               VCHIQ_COMPLETION_DATA_T *completion;
1413 +               USER_SERVICE_T *service;
1414 +               VCHIQ_HEADER_T *header;
1415 +               if (instance->completion_remove ==
1416 +                   instance->completion_insert)
1417 +                  break;
1418 +               completion =
1419 +                   &instance->
1420 +                   completions
1421 +                   [instance->completion_remove &
1422 +                    (MAX_COMPLETIONS - 1)];
1423 +
1424 +               service = (USER_SERVICE_T *)completion->service_userdata;
1425 +               completion->service_userdata = service->userdata;
1426 +
1427 +               header = completion->header;
1428 +               if (header)
1429 +               {
1430 +                  void __user *msgbuf;
1431 +                  int msglen;
1432 +
1433 +                  msglen = header->size + sizeof(VCHIQ_HEADER_T);
1434 +                  /* This must be a VCHIQ-style service */
1435 +                  if (args.msgbufsize < msglen)
1436 +                  {
1437 +                     vcos_log_error("header %x: msgbufsize %x < msglen %x",
1438 +                        (unsigned int)header, args.msgbufsize, msglen);
1439 +                     vcos_assert(0);
1440 +                     if (ret == 0)
1441 +                        ret = -EMSGSIZE;
1442 +                     break;
1443 +                  }
1444 +                  if (msgbufcount <= 0)
1445 +                  {
1446 +                     /* Stall here for lack of a buffer for the message */
1447 +                     break;
1448 +                  }
1449 +                  /* Get the pointer from user space */
1450 +                  msgbufcount--;
1451 +                  if (copy_from_user(&msgbuf,
1452 +                     (const void __user *)&args.msgbufs[msgbufcount],
1453 +                     sizeof(msgbuf)) != 0)
1454 +                  {
1455 +                     if (ret == 0)
1456 +                        ret = -EFAULT;
1457 +                     break;
1458 +                  }
1459 +
1460 +                  /* Copy the message to user space */
1461 +                  if (copy_to_user(msgbuf, header, msglen) != 0)
1462 +                  {
1463 +                     if (ret == 0)
1464 +                        ret = -EFAULT;
1465 +                     break;
1466 +                  }
1467 +
1468 +                  /* Now it has been copied, the message can be released. */
1469 +                  vchiq_release_message(&service->service->base, header);
1470 +
1471 +                  /* The completion must point to the msgbuf */
1472 +                  completion->header = msgbuf;
1473 +               }
1474 +
1475 +               if (copy_to_user
1476 +                   ((void __user *)((size_t) args.buf +
1477 +                          ret *
1478 +                          sizeof
1479 +                          (VCHIQ_COMPLETION_DATA_T)),
1480 +                    completion,
1481 +                    sizeof(VCHIQ_COMPLETION_DATA_T)) !=
1482 +                   0) {
1483 +                  if (ret == 0)
1484 +                     ret = -EFAULT;
1485 +                  break;
1486 +               }
1487 +               instance->completion_remove++;
1488 +            }
1489 +
1490 +            if (msgbufcount != args.msgbufcount)
1491 +            {
1492 +               if (copy_to_user((void __user *)
1493 +                  &((VCHIQ_AWAIT_COMPLETION_T *)arg)->msgbufcount,
1494 +                  &msgbufcount, sizeof(msgbufcount)) != 0)
1495 +               {
1496 +                  ret = -EFAULT;
1497 +                  break;
1498 +               }
1499 +            }
1500 +         }
1501 +
1502 +         if (ret != 0)
1503 +            vcos_event_signal(&instance->remove_event);
1504 +         DEBUG_TRACE(AWAIT_COMPLETION_LINE);
1505 +      }
1506 +      break;
1507 +
1508 +   case VCHIQ_IOC_DEQUEUE_MESSAGE:
1509 +      {
1510 +         VCHIQ_DEQUEUE_MESSAGE_T args;
1511 +         USER_SERVICE_T *user_service;
1512 +         VCHIQ_HEADER_T *header;
1513 +
1514 +         DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1515 +         if (copy_from_user
1516 +             (&args, (const void __user *)arg,
1517 +              sizeof(args)) != 0) {
1518 +            ret = -EFAULT;
1519 +            break;
1520 +         }
1521 +         user_service = &instance->services[args.handle];
1522 +         if ((args.handle < 0) || (args.handle >= MAX_SERVICES) ||
1523 +            (user_service->service == NULL) ||
1524 +            (user_service->is_vchi == 0)) {
1525 +            ret = -EINVAL;
1526 +            break;
1527 +         }
1528 +         if (user_service->msg_remove == user_service->msg_insert)
1529 +         {
1530 +            if (!args.blocking)
1531 +            {
1532 +               DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1533 +               ret = -EWOULDBLOCK;
1534 +               break;
1535 +            }
1536 +            user_service->dequeue_pending = 1;
1537 +            do {
1538 +               DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1539 +               if (vcos_event_wait(&user_service->insert_event) !=
1540 +                   VCOS_SUCCESS) {
1541 +                  vcos_log_info("DEQUEUE_MESSAGE interrupted");
1542 +                  ret = -EINTR;
1543 +                  break;
1544 +               }
1545 +            }
1546 +            while (user_service->msg_remove == user_service->msg_insert);
1547 +         }
1548 +
1549 +         /* A read memory barrier is needed to stop prefetch of a stale
1550 +            header value */
1551 +         vcos_rmb();
1552 +
1553 +         header = user_service->msg_queue[user_service->msg_remove &
1554 +            (MSG_QUEUE_SIZE - 1)];
1555 +         if (header == NULL)
1556 +            ret = -ENOTCONN;
1557 +         else if (header->size <= args.bufsize)
1558 +         {
1559 +            /* Copy to user space if msgbuf is not NULL */
1560 +            if ((args.buf == NULL) ||
1561 +               (copy_to_user((void __user *)args.buf, header->data,
1562 +               header->size) == 0))
1563 +            {
1564 +               ret = header->size;
1565 +               vchiq_release_message(&user_service->service->base,
1566 +                  header);
1567 +               user_service->msg_remove++;
1568 +               vcos_event_signal(&user_service->remove_event);
1569 +            }
1570 +            else
1571 +               ret = -EFAULT;
1572 +         }
1573 +         else
1574 +         {
1575 +            vcos_log_error("header %x: bufsize %x < size %x",
1576 +               (unsigned int)header, args.bufsize, header->size);
1577 +            vcos_assert(0);
1578 +            ret = -EMSGSIZE;
1579 +         }
1580 +         DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
1581 +      }
1582 +      break;
1583 +
1584 +   case VCHIQ_IOC_GET_CLIENT_ID:
1585 +      {
1586 +         USER_SERVICE_T *user_service;
1587 +         int handle = (int)arg;
1588 +
1589 +         user_service = find_service_by_handle(instance, handle);
1590 +         if (user_service != NULL)
1591 +            ret = vchiq_get_client_id(&user_service->service->base);
1592 +         else
1593 +            ret = 0;
1594 +      }
1595 +      break;
1596 +
1597 +   case VCHIQ_IOC_GET_CONFIG:
1598 +      {
1599 +         VCHIQ_GET_CONFIG_T args;
1600 +         VCHIQ_CONFIG_T config;
1601 +
1602 +         if (copy_from_user
1603 +             (&args, (const void __user *)arg,
1604 +              sizeof(args)) != 0) {
1605 +            ret = -EFAULT;
1606 +            break;
1607 +         }
1608 +         if (args.config_size > sizeof(config))
1609 +         {
1610 +            ret = -EINVAL;
1611 +            break;
1612 +         }
1613 +         status = vchiq_get_config(instance, args.config_size, &config);
1614 +         if (status == VCHIQ_SUCCESS)
1615 +         {
1616 +            if (copy_to_user((void __user *)args.pconfig,
1617 +                   &config, args.config_size) != 0)
1618 +            {
1619 +               ret = -EFAULT;
1620 +               break;
1621 +            }
1622 +         }
1623 +      }
1624 +      break;
1625 +
1626 +   case VCHIQ_IOC_SET_SERVICE_OPTION:
1627 +      {
1628 +         VCHIQ_SET_SERVICE_OPTION_T args;
1629 +         USER_SERVICE_T *user_service;
1630 +
1631 +         if (copy_from_user(
1632 +            &args, (const void __user *)arg,
1633 +            sizeof(args)) != 0)
1634 +         {
1635 +            ret = -EFAULT;
1636 +            break;
1637 +         }
1638 +
1639 +         user_service = find_service_by_handle(instance, args.handle);
1640 +         if (user_service != NULL)
1641 +         {
1642 +            status = vchiq_set_service_option(
1643 +               &user_service->service->base,
1644 +               args.option, args.value);
1645 +         }
1646 +         else
1647 +         {
1648 +            ret = -EINVAL;
1649 +         }
1650 +      }
1651 +      break;
1652 +
1653 +   default:
1654 +      ret = -ENOTTY;
1655 +      break;
1656 +   }
1657 +
1658 +   if (ret == 0) {
1659 +      if (status == VCHIQ_ERROR)
1660 +         ret = -EIO;
1661 +      else if (status == VCHIQ_RETRY)
1662 +         ret = -EINTR;
1663 +   }
1664 +
1665 +   if ((ret < 0) && (ret != -EINTR) && (ret != -EWOULDBLOCK))
1666 +      vcos_log_warn("  ioctl instance %lx, cmd %s -> status %d, %ld",
1667 +         (unsigned long)instance,
1668 +         (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ? ioctl_names[_IOC_NR(cmd)] :
1669 +         "<invalid>", status, ret);
1670 +   else
1671 +      vcos_log_trace("  ioctl instance %lx, cmd %s -> status %d, %ld",
1672 +         (unsigned long)instance,
1673 +         (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ? ioctl_names[_IOC_NR(cmd)] :
1674 +         "<invalid>", status, ret);
1675 +
1676 +   return ret;
1677 +}
1678 +
1679 +/****************************************************************************
1680 +*
1681 +*   vchiq_open
1682 +*
1683 +***************************************************************************/
1684 +
1685 +static int
1686 +vchiq_open(struct inode *inode, struct file *file)
1687 +{
1688 +   int dev = iminor(inode) & 0x0f;
1689 +   vcos_log_info("vchiq_open");
1690 +   switch (dev) {
1691 +   case VCHIQ_MINOR:
1692 +      {
1693 +         VCHIQ_STATE_T *state = vchiq_get_state();
1694 +         VCHIQ_INSTANCE_T instance;
1695 +
1696 +         if (!state)
1697 +         {
1698 +            vcos_log_error( "vchiq has no connection to VideoCore");
1699 +            return -ENOTCONN;
1700 +         }
1701 +
1702 +         instance = kzalloc(sizeof(*instance), GFP_KERNEL);
1703 +         if (!instance)
1704 +            return -ENOMEM;
1705 +
1706 +         instance->state = state;
1707 +         instance->pid = current->tgid;
1708 +         vcos_event_create(&instance->insert_event, DEVICE_NAME);
1709 +         vcos_event_create(&instance->remove_event, DEVICE_NAME);
1710 +
1711 +         file->private_data = instance;
1712 +      }
1713 +      break;
1714 +
1715 +   default:
1716 +      vcos_log_error("Unknown minor device: %d", dev);
1717 +      return -ENXIO;
1718 +   }
1719 +
1720 +   return 0;
1721 +}
1722 +
1723 +/****************************************************************************
1724 +*
1725 +*   vchiq_release
1726 +*
1727 +***************************************************************************/
1728 +
1729 +static int
1730 +vchiq_release(struct inode *inode, struct file *file)
1731 +{
1732 +   int dev = iminor(inode) & 0x0f;
1733 +   int ret = 0;
1734 +   switch (dev) {
1735 +   case VCHIQ_MINOR:
1736 +      {
1737 +         VCHIQ_INSTANCE_T instance = file->private_data;
1738 +         int i;
1739 +
1740 +         vcos_log_info("vchiq_release: instance=%lx",
1741 +                  (unsigned long)instance);
1742 +
1743 +         instance->closing = 1;
1744 +
1745 +         /* Wake the slot handler if the completion queue is full */
1746 +         vcos_event_signal(&instance->remove_event);
1747 +
1748 +         /* Mark all services for termination... */
1749 +
1750 +         for (i = 0; i < MAX_SERVICES; i++) {
1751 +            USER_SERVICE_T *user_service =
1752 +                &instance->services[i];
1753 +            if (user_service->service != NULL)
1754 +            {
1755 +               /* Wake the slot handler if the msg queue is full */
1756 +               vcos_event_signal(&user_service->remove_event);
1757 +
1758 +               if ((user_service->service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) &&
1759 +                  (user_service->service->srvstate != VCHIQ_SRVSTATE_LISTENING))
1760 +               {
1761 +                  vchiq_terminate_service_internal(user_service->service);
1762 +               }
1763 +            }
1764 +         }
1765 +
1766 +         /* ...and wait for them to die */
1767 +
1768 +         for (i = 0; i < MAX_SERVICES; i++) {
1769 +            USER_SERVICE_T *user_service =
1770 +                &instance->services[i];
1771 +            if (user_service->service != NULL)
1772 +            {
1773 +               /* Wait in this non-portable fashion because interruptible
1774 +                  calls will not block in this context. */
1775 +               while ((user_service->service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) &&
1776 +                  (user_service->service->srvstate != VCHIQ_SRVSTATE_LISTENING))
1777 +               {
1778 +                  down(&user_service->service->remove_event);
1779 +               }
1780 +
1781 +               vchiq_free_service_internal
1782 +                      (user_service->service);
1783 +            }
1784 +         }
1785 +
1786 +         vcos_event_delete(&instance->insert_event);
1787 +         vcos_event_delete(&instance->remove_event);
1788 +
1789 +         kfree(instance);
1790 +         file->private_data = NULL;
1791 +      }
1792 +      break;
1793 +
1794 +   default:
1795 +      vcos_log_error("Unknown minor device: %d", dev);
1796 +      ret = -ENXIO;
1797 +   }
1798 +
1799 +   return ret;
1800 +}
1801 +
1802 +/****************************************************************************
1803 +*
1804 +*   vchiq_dump
1805 +*
1806 +***************************************************************************/
1807 +
1808 +void
1809 +vchiq_dump(void *dump_context, const char *str, int len)
1810 +{
1811 +   DUMP_CONTEXT_T *context = (DUMP_CONTEXT_T *)dump_context;
1812 +
1813 +   if ((context->actual >= 0) && (context->actual < context->space))
1814 +   {
1815 +      int copy_bytes;
1816 +      if (context->offset > 0)
1817 +      {
1818 +         int skip_bytes = vcos_min(len, context->offset);
1819 +         str += skip_bytes;
1820 +         len -= skip_bytes;
1821 +         context->offset -= skip_bytes;
1822 +         if (context->offset > 0)
1823 +            return;
1824 +      }
1825 +      copy_bytes = vcos_min(len, context->space - context->actual);
1826 +      if (copy_bytes == 0)
1827 +         return;
1828 +      if (copy_to_user(context->buf + context->actual, str, copy_bytes))
1829 +         context->actual = -EFAULT;
1830 +      context->actual += copy_bytes;
1831 +      len -= copy_bytes;
1832 +
1833 +      /* If tne terminating NUL is included in the length, then it marks
1834 +       * the end of a line and should be replaced with a carriage return.
1835 +       */
1836 +      if ((len == 0) && (str[copy_bytes - 1] == '\0'))
1837 +      {
1838 +         char cr = '\n';
1839 +         if (copy_to_user(context->buf + context->actual - 1, &cr, 1))
1840 +         {
1841 +           context->actual = -EFAULT;
1842 +         }
1843 +      }
1844 +   }
1845 +}
1846 +
1847 +/****************************************************************************
1848 +*
1849 +*   vchiq_dump_platform_instance_state
1850 +*
1851 +***************************************************************************/
1852 +
1853 +void
1854 +vchiq_dump_platform_instances(void *dump_context)
1855 +{
1856 +   VCHIQ_STATE_T *state = vchiq_get_state();
1857 +   char buf[80];
1858 +   int len;
1859 +   int i;
1860 +
1861 +   /* There is no list of instances, so instead scan all services,
1862 +      marking those that have been dumped. */
1863 +
1864 +   for (i = 0; i < state->unused_service; i++)
1865 +   {
1866 +      VCHIQ_SERVICE_T *service = state->services[i];
1867 +      VCHIQ_INSTANCE_T instance;
1868 +
1869 +      if (service
1870 +         && ((instance = service->instance) != NULL)
1871 +         && (service->base.callback == service_callback))
1872 +         instance->mark = 0;
1873 +   }
1874 +
1875 +   for (i = 0; i < state->unused_service; i++)
1876 +   {
1877 +      VCHIQ_SERVICE_T *service = state->services[i];
1878 +      VCHIQ_INSTANCE_T instance;
1879 +
1880 +      if (service
1881 +         && ((instance = service->instance) != NULL)
1882 +         && (service->base.callback == service_callback))
1883 +      {
1884 +         if (!instance->mark)
1885 +         {
1886 +            len = vcos_snprintf(buf, sizeof(buf),
1887 +               "Instance %x: pid %d,%s completions %d/%d",
1888 +               (unsigned int)instance, instance->pid,
1889 +               instance->connected ? " connected," : "",
1890 +               instance->completion_insert - instance->completion_remove,
1891 +               MAX_COMPLETIONS);
1892 +
1893 +            vchiq_dump(dump_context, buf, len + 1);
1894 +
1895 +            instance->mark = 1;
1896 +         }
1897 +      }
1898 +   }
1899 +}
1900 +
1901 +/****************************************************************************
1902 +*
1903 +*   vchiq_dump_platform_service_state
1904 +*
1905 +***************************************************************************/
1906 +
1907 +void
1908 +vchiq_dump_platform_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
1909 +{
1910 +   USER_SERVICE_T *user_service = (USER_SERVICE_T *)service->base.userdata;
1911 +   char buf[80];
1912 +   int len;
1913 +
1914 +   len = vcos_snprintf(buf, sizeof(buf), "  instance %x",
1915 +      service->instance);
1916 +
1917 +   if ((service->base.callback == service_callback) && user_service->is_vchi)
1918 +   {
1919 +      len += vcos_snprintf(buf + len, sizeof(buf) - len,
1920 +         ", %d/%d messages",
1921 +         user_service->msg_insert - user_service->msg_remove,
1922 +         MSG_QUEUE_SIZE);
1923 +
1924 +      if (user_service->dequeue_pending)
1925 +         len += vcos_snprintf(buf + len, sizeof(buf) - len,
1926 +            " (dequeue pending)");
1927 +   }
1928 +
1929 +   vchiq_dump(dump_context, buf, len + 1);
1930 +}
1931 +
1932 +/****************************************************************************
1933 +*
1934 +*   vchiq_read
1935 +*
1936 +***************************************************************************/
1937 +
1938 +static ssize_t
1939 +vchiq_read(struct file * file, char __user * buf,
1940 +   size_t count, loff_t *ppos)
1941 +{
1942 +   DUMP_CONTEXT_T context;
1943 +   context.buf = buf;
1944 +   context.actual = 0;
1945 +   context.space = count;
1946 +   context.offset = *ppos;
1947 +
1948 +   vchiq_dump_state(&context, &g_state);
1949 +
1950 +   if (context.actual >= 0)
1951 +      *ppos += context.actual;
1952 +
1953 +   return context.actual;
1954 +}
1955 +
1956 +VCHIQ_STATE_T *
1957 +vchiq_get_state(void)
1958 +{
1959 +
1960 +   if (g_state.remote == NULL)
1961 +   {
1962 +      printk( "%s: g_state.remote == NULL\n", __func__ );
1963 +   }
1964 +   else
1965 +   {
1966 +      if ( g_state.remote->initialised != 1)
1967 +      {
1968 +         printk( "%s: g_state.remote->initialised != 1 (%d)\n", __func__, g_state.remote->initialised );
1969 +      }
1970 +   }
1971 +
1972 +   return ((g_state.remote != NULL) &&
1973 +      (g_state.remote->initialised == 1)) ? &g_state : NULL;
1974 +}
1975 +
1976 +static const struct file_operations
1977 +vchiq_fops = {
1978 +   .owner = THIS_MODULE,
1979 +   .unlocked_ioctl = vchiq_ioctl,
1980 +   .open = vchiq_open,
1981 +   .release = vchiq_release,
1982 +   .read = vchiq_read
1983 +};
1984 +
1985 +/****************************************************************************
1986 +*
1987 +*   vchiq_init - called when the module is loaded.
1988 +*
1989 +***************************************************************************/
1990 +
1991 +static int __init
1992 +vchiq_init(void)
1993 +{
1994 +   int err;
1995 +   void *ptr_err;
1996 +
1997 +   err = vchiq_platform_vcos_init();
1998 +   if (err != 0)
1999 +      goto failed_platform_vcos_init;
2000 +
2001 +   vcos_log_set_level(VCOS_LOG_CATEGORY, vchiq_default_arm_log_level);
2002 +   vcos_log_register("vchiq_arm", VCOS_LOG_CATEGORY);
2003 +
2004 +   if ((err =
2005 +        alloc_chrdev_region(&vchiq_devid, VCHIQ_MINOR, 1,
2006 +             DEVICE_NAME)) != 0) {
2007 +      vcos_log_error("Unable to allocate device number");
2008 +      goto failed_alloc_chrdev;
2009 +   }
2010 +   cdev_init(&vchiq_cdev, &vchiq_fops);
2011 +   vchiq_cdev.owner = THIS_MODULE;
2012 +   if ((err = cdev_add(&vchiq_cdev, vchiq_devid, 1)) != 0) {
2013 +      vcos_log_error("Unable to register device");
2014 +      goto failed_cdev_add;
2015 +   }
2016 +
2017 +   /* create sysfs entries */
2018 +   vchiq_class = class_create(THIS_MODULE, DEVICE_NAME);
2019 +   if (IS_ERR(ptr_err = vchiq_class))
2020 +      goto failed_class_create;
2021 +
2022 +   vchiq_dev = device_create(vchiq_class, NULL,
2023 +      vchiq_devid, NULL, "vchiq");
2024 +   if (IS_ERR(ptr_err = vchiq_dev))
2025 +      goto failed_device_create;
2026 +
2027 +   err = vchiq_platform_init(&g_state);
2028 +   if (err != 0)
2029 +      goto failed_platform_init;
2030 +
2031 +   vcos_log_error("vchiq: initialised - version %d (min %d), device %d.%d",
2032 +      VCHIQ_VERSION, VCHIQ_VERSION_MIN,
2033 +      MAJOR(vchiq_devid), MINOR(vchiq_devid));
2034 +
2035 +   return 0;
2036 +
2037 +failed_platform_init:
2038 +   device_destroy(vchiq_class, vchiq_devid);
2039 +failed_device_create:
2040 +   class_destroy(vchiq_class);
2041 +failed_class_create:
2042 +   cdev_del(&vchiq_cdev);
2043 +   err = PTR_ERR(ptr_err);
2044 +failed_cdev_add:
2045 +   unregister_chrdev_region(vchiq_devid, 1);
2046 +failed_alloc_chrdev:
2047 +failed_platform_vcos_init:
2048 +   printk(KERN_WARNING "could not load vchiq\n");
2049 +   return err;
2050 +}
2051 +/****************************************************************************
2052 +*
2053 +*   vchiq_exit - called when the module is unloaded.
2054 +*
2055 +***************************************************************************/
2056 +
2057 +static void __exit
2058 +vchiq_exit(void)
2059 +{
2060 +   vchiq_platform_exit(&g_state);
2061 +   device_destroy(vchiq_class, vchiq_devid);
2062 +   class_destroy(vchiq_class);
2063 +   cdev_del(&vchiq_cdev);
2064 +   unregister_chrdev_region(vchiq_devid, 1);
2065 +   vcos_log_unregister(VCOS_LOG_CATEGORY);
2066 +}
2067 +
2068 +module_init(vchiq_init);
2069 +module_exit(vchiq_exit);
2070 +MODULE_LICENSE("GPL");
2071 +MODULE_AUTHOR("Broadcom Corporation");
2072 --- /dev/null
2073 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.h
2074 @@ -0,0 +1,38 @@
2075 +/*
2076 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
2077 + *
2078 + * This program is free software; you can redistribute it and/or modify
2079 + * it under the terms of the GNU General Public License as published by
2080 + * the Free Software Foundation; either version 2 of the License, or
2081 + * (at your option) any later version.
2082 + *
2083 + * This program is distributed in the hope that it will be useful,
2084 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2085 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2086 + * GNU General Public License for more details.
2087 + *
2088 + * You should have received a copy of the GNU General Public License
2089 + * along with this program; if not, write to the Free Software
2090 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2091 + */
2092 +
2093 +#ifndef VCHIQ_ARM_H
2094 +#define VCHIQ_ARM_H
2095 +
2096 +#include "vchiq_core.h"
2097 +
2098 +extern VCOS_LOG_CAT_T vchiq_arm_log_category;
2099 +
2100 +extern int __init
2101 +vchiq_platform_vcos_init(void);
2102 +
2103 +extern int __init
2104 +vchiq_platform_init(VCHIQ_STATE_T *state);
2105 +
2106 +extern void __exit
2107 +vchiq_platform_exit(VCHIQ_STATE_T *state);
2108 +
2109 +extern VCHIQ_STATE_T *
2110 +vchiq_get_state(void);
2111 +
2112 +#endif /* VCHIQ_ARM_H */
2113 --- /dev/null
2114 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
2115 @@ -0,0 +1,43 @@
2116 +/*
2117 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
2118 + *
2119 + * This program is free software; you can redistribute it and/or modify
2120 + * it under the terms of the GNU General Public License as published by
2121 + * the Free Software Foundation; either version 2 of the License, or
2122 + * (at your option) any later version.
2123 + *
2124 + * This program is distributed in the hope that it will be useful,
2125 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2126 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2127 + * GNU General Public License for more details.
2128 + *
2129 + * You should have received a copy of the GNU General Public License
2130 + * along with this program; if not, write to the Free Software
2131 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2132 + */
2133 +
2134 +#ifndef VCHIQ_CFG_H
2135 +#define VCHIQ_CFG_H
2136 +
2137 +#define VCHIQ_MAGIC              VCHIQ_MAKE_FOURCC('V','C','H','I')
2138 +/* The version of VCHIQ - change with any non-trivial change */
2139 +#define VCHIQ_VERSION            2
2140 +/* The minimum compatible version - update to match VCHIQ_VERSION with any incompatible change */
2141 +#define VCHIQ_VERSION_MIN        2
2142 +
2143 +#define VCHIQ_MAX_SERVICES       4096
2144 +#define VCHIQ_MAX_SLOTS          128
2145 +#define VCHIQ_MAX_SLOTS_PER_SIDE 64
2146 +
2147 +#define VCHIQ_NUM_CURRENT_BULKS        32
2148 +#define VCHIQ_NUM_SERVICE_BULKS        4
2149 +
2150 +#ifndef VCHIQ_ENABLE_DEBUG
2151 +#define VCHIQ_ENABLE_DEBUG             1
2152 +#endif
2153 +
2154 +#ifndef VCHIQ_ENABLE_STATS
2155 +#define VCHIQ_ENABLE_STATS             1
2156 +#endif
2157 +
2158 +#endif /* VCHIQ_CFG_H */
2159 --- /dev/null
2160 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
2161 @@ -0,0 +1,101 @@
2162 +/*****************************************************************************
2163 +* Copyright 2001 - 2010 Broadcom Corporation.  All rights reserved.
2164 +*
2165 +* Unless you and Broadcom execute a separate written software license
2166 +* agreement governing use of this software, this software is licensed to you
2167 +* under the terms of the GNU General Public License version 2, available at
2168 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2169 +*
2170 +* Notwithstanding the above, under no circumstances may you combine this
2171 +* software in any way with any other Broadcom software provided under a
2172 +* license other than the GPL, without Broadcom's express prior written
2173 +* consent.
2174 +*****************************************************************************/
2175 +
2176 +#include "vcos.h"
2177 +#include "vchiq_connected.h"
2178 +#include <linux/module.h>
2179 +
2180 +#define  MAX_CALLBACKS  10
2181 +
2182 +static   int                        g_connected = 0;
2183 +static   int                        g_num_deferred_callbacks;
2184 +static   VCHIQ_CONNECTED_CALLBACK_T g_deferred_callback[ MAX_CALLBACKS ];
2185 +static   VCOS_ONCE_T                g_once_init;
2186 +static   VCOS_MUTEX_T               g_connected_mutex;
2187 +
2188 +extern VCOS_LOG_CAT_T vchiq_core_log_category;
2189 +#define  VCOS_LOG_CATEGORY (&vchiq_core_log_category)
2190 +
2191 +/****************************************************************************
2192 +*
2193 +* Function to initialize our lock.
2194 +*
2195 +***************************************************************************/
2196 +
2197 +static void connected_init( void )
2198 +{
2199 +   vcos_mutex_create( &g_connected_mutex, "connected_mutex");
2200 +}
2201 +
2202 +/****************************************************************************
2203 +*
2204 +* This function is used to defer initialization until the vchiq stack is
2205 +* initialized. If the stack is already initialized, then the callback will
2206 +* be made immediately, otherwise it will be deferred until
2207 +* vchiq_call_connected_callbacks is called.
2208 +*
2209 +***************************************************************************/
2210 +
2211 +void vchiq_add_connected_callback( VCHIQ_CONNECTED_CALLBACK_T callback )
2212 +{
2213 +   vcos_once( &g_once_init, connected_init );
2214 +
2215 +   vcos_mutex_lock( &g_connected_mutex );
2216 +
2217 +   if ( g_connected )
2218 +   {
2219 +      // We're already connected. Call the callback immediately.
2220 +
2221 +      callback();
2222 +   }
2223 +   else
2224 +   {
2225 +      if ( g_num_deferred_callbacks >= MAX_CALLBACKS )
2226 +      {
2227 +         vcos_log_error( "There already %d callback registered - please increase MAX_CALLBACKS",
2228 +                         g_num_deferred_callbacks );
2229 +      }
2230 +      else
2231 +      {
2232 +         g_deferred_callback[ g_num_deferred_callbacks ] = callback;
2233 +         g_num_deferred_callbacks++;
2234 +      }
2235 +   }
2236 +   vcos_mutex_unlock( &g_connected_mutex );
2237 +}
2238 +
2239 +/****************************************************************************
2240 +*
2241 +* This function is called by the vchiq stack once it has been connected to
2242 +* the videocore and clients can start to use the stack.
2243 +*
2244 +***************************************************************************/
2245 +
2246 +void vchiq_call_connected_callbacks( void )
2247 +{
2248 +   int   i;
2249 +
2250 +   vcos_once( &g_once_init, connected_init );
2251 +
2252 +   vcos_mutex_lock( &g_connected_mutex );
2253 +   for ( i = 0; i <  g_num_deferred_callbacks; i++ )\
2254 +   {
2255 +      g_deferred_callback[i]();
2256 +   }
2257 +   g_num_deferred_callbacks = 0;
2258 +   g_connected = 1;
2259 +   vcos_mutex_unlock( &g_connected_mutex );
2260 +}
2261 +
2262 +EXPORT_SYMBOL( vchiq_add_connected_callback );
2263 --- /dev/null
2264 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.h
2265 @@ -0,0 +1,32 @@
2266 +/*****************************************************************************
2267 +* Copyright 2001 - 2010 Broadcom Corporation.  All rights reserved.
2268 +*
2269 +* Unless you and Broadcom execute a separate written software license
2270 +* agreement governing use of this software, this software is licensed to you
2271 +* under the terms of the GNU General Public License version 2, available at
2272 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2273 +*
2274 +* Notwithstanding the above, under no circumstances may you combine this
2275 +* software in any way with any other Broadcom software provided under a
2276 +* license other than the GPL, without Broadcom's express prior written
2277 +* consent.
2278 +*****************************************************************************/
2279 +
2280 +#ifndef VCHIQ_CONNECTED_H
2281 +#define VCHIQ_CONNECTED_H
2282 +
2283 +/* ---- Include Files ----------------------------------------------------- */
2284 +
2285 +/* ---- Constants and Types ---------------------------------------------- */
2286 +
2287 +typedef void (*VCHIQ_CONNECTED_CALLBACK_T)( void );
2288 +
2289 +/* ---- Variable Externs ------------------------------------------------- */
2290 +
2291 +/* ---- Function Prototypes ---------------------------------------------- */
2292 +
2293 +void vchiq_add_connected_callback( VCHIQ_CONNECTED_CALLBACK_T callback );
2294 +void vchiq_call_connected_callbacks( void );
2295 +
2296 +#endif /* VCHIQ_CONNECTED_H */
2297 +
2298 --- /dev/null
2299 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
2300 @@ -0,0 +1,2604 @@
2301 +/*
2302 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
2303 + *
2304 + * This program is free software; you can redistribute it and/or modify
2305 + * it under the terms of the GNU General Public License as published by
2306 + * the Free Software Foundation; either version 2 of the License, or
2307 + * (at your option) any later version.
2308 + *
2309 + * This program is distributed in the hope that it will be useful,
2310 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2311 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2312 + * GNU General Public License for more details.
2313 + *
2314 + * You should have received a copy of the GNU General Public License
2315 + * along with this program; if not, write to the Free Software
2316 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2317 + */
2318 +
2319 +#include "vchiq_core.h"
2320 +
2321 +#define VCHIQ_SLOT_HANDLER_STACK 8192
2322 +
2323 +#define SLOT_INFO_FROM_INDEX(state, index) (state->slot_info + (index))
2324 +#define SLOT_DATA_FROM_INDEX(state, index) (state->slot_data + (index))
2325 +#define SLOT_INDEX_FROM_DATA(state, data) (((unsigned int)((char *)data - (char *)state->slot_data)) / VCHIQ_SLOT_SIZE)
2326 +#define SLOT_INDEX_FROM_INFO(state, info) ((unsigned int)(info - state->slot_info))
2327 +#define SLOT_QUEUE_INDEX_FROM_POS(pos) ((int)((unsigned int)(pos) / VCHIQ_SLOT_SIZE))
2328 +
2329 +#define VCOS_LOG_CATEGORY (&vchiq_core_log_category)
2330 +
2331 +#define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1))
2332 +
2333 +typedef struct bulk_waiter_struct
2334 +{
2335 +   VCOS_EVENT_T event;
2336 +   int actual;
2337 +} BULK_WAITER_T;
2338 +
2339 +typedef struct vchiq_open_payload_struct{
2340 +   int fourcc;
2341 +   int client_id;
2342 +   short version;
2343 +   short version_min;
2344 +} VCHIQ_OPEN_PAYLOAD_T;
2345 +
2346 +vcos_static_assert(sizeof(VCHIQ_HEADER_T) == 8);   /* we require this for consistency between endpoints */
2347 +vcos_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T)));
2348 +vcos_static_assert(IS_POW2(VCHIQ_NUM_CURRENT_BULKS));
2349 +vcos_static_assert(IS_POW2(VCHIQ_NUM_SERVICE_BULKS));
2350 +
2351 +VCOS_LOG_CAT_T vchiq_core_log_category;
2352 +VCOS_LOG_CAT_T vchiq_core_msg_log_category;
2353 +VCOS_LOG_LEVEL_T vchiq_default_core_log_level = VCOS_LOG_WARN;
2354 +VCOS_LOG_LEVEL_T vchiq_default_core_msg_log_level = VCOS_LOG_WARN;
2355 +
2356 +static const char *const srvstate_names[] =
2357 +{
2358 +   "FREE",
2359 +   "HIDDEN",
2360 +   "LISTENING",
2361 +   "OPENING",
2362 +   "OPEN",
2363 +   "CLOSESENT",
2364 +   "CLOSING",
2365 +   "CLOSEWAIT"
2366 +};
2367 +
2368 +static const char *const reason_names[] =
2369 +{
2370 +   "SERVICE_OPENED",
2371 +   "SERVICE_CLOSED",
2372 +   "MESSAGE_AVAILABLE",
2373 +   "BULK_TRANSMIT_DONE",
2374 +   "BULK_RECEIVE_DONE",
2375 +   "BULK_TRANSMIT_ABORTED",
2376 +   "BULK_RECEIVE_ABORTED"
2377 +};
2378 +
2379 +static const char *const conn_state_names[] =
2380 +{
2381 +   "DISCONNECTED",
2382 +   "CONNECTED",
2383 +   "PAUSING",
2384 +   "PAUSE_SENT",
2385 +   "PAUSED",
2386 +   "RESUMING"
2387 +};
2388 +
2389 +static const char *msg_type_str( unsigned int msg_type )
2390 +{
2391 +   switch (msg_type) {
2392 +   case VCHIQ_MSG_PADDING:       return "PADDING";
2393 +   case VCHIQ_MSG_CONNECT:       return "CONNECT";
2394 +   case VCHIQ_MSG_OPEN:          return "OPEN";
2395 +   case VCHIQ_MSG_OPENACK:       return "OPENACK";
2396 +   case VCHIQ_MSG_CLOSE:         return "CLOSE";
2397 +   case VCHIQ_MSG_DATA:          return "DATA";
2398 +   case VCHIQ_MSG_BULK_RX:       return "BULK_RX";
2399 +   case VCHIQ_MSG_BULK_TX:       return "BULK_TX";
2400 +   case VCHIQ_MSG_BULK_RX_DONE:  return "BULK_RX_DONE";
2401 +   case VCHIQ_MSG_BULK_TX_DONE:  return "BULK_TX_DONE";
2402 +   case VCHIQ_MSG_PAUSE:         return "PAUSE";
2403 +   case VCHIQ_MSG_RESUME:        return "RESUME";
2404 +   }
2405 +   return "???";
2406 +}
2407 +
2408 +static inline void
2409 +vchiq_set_service_state(VCHIQ_SERVICE_T *service, int newstate)
2410 +{
2411 +   vcos_log_info("%d: srv:%d %s->%s", service->state->id, service->localport,
2412 +      srvstate_names[service->srvstate],
2413 +      srvstate_names[newstate]);
2414 +   service->srvstate = newstate;
2415 +}
2416 +
2417 +static inline VCHIQ_STATUS_T
2418 +make_service_callback(VCHIQ_SERVICE_T *service, VCHIQ_REASON_T reason,
2419 +   VCHIQ_HEADER_T *header, void *bulk_userdata)
2420 +{
2421 +   vcos_log_trace("%d: callback:%d (%s, %x, %x)", service->state->id,
2422 +      service->localport, reason_names[reason],
2423 +      (unsigned int)header, (unsigned int)bulk_userdata);
2424 +   return service->base.callback(reason, header, &service->base, bulk_userdata);
2425 +}
2426 +
2427 +static inline void
2428 +vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate)
2429 +{
2430 +   vcos_log_info("%d: %s->%s", state->id,
2431 +      conn_state_names[state->conn_state],
2432 +      conn_state_names[newstate]);
2433 +   state->conn_state = newstate;
2434 +}
2435 +
2436 +static inline void
2437 +remote_event_create(REMOTE_EVENT_T *event)
2438 +{
2439 +   event->armed = 0;
2440 +   /* Don't clear the 'fired' flag because it may already have been set by the other side */
2441 +   vcos_event_create(event->event, "vchiq");
2442 +}
2443 +
2444 +static inline void
2445 +remote_event_destroy(REMOTE_EVENT_T *event)
2446 +{
2447 +   vcos_event_delete(event->event);
2448 +}
2449 +
2450 +static inline int
2451 +remote_event_wait(REMOTE_EVENT_T *event)
2452 +{
2453 +   if (!event->fired)
2454 +   {
2455 +      event->armed = 1;
2456 +      if (event->fired) /* Also ensures the write has completed */
2457 +         event->armed = 0;
2458 +      else if (vcos_event_wait(event->event) != VCOS_SUCCESS)
2459 +         return 0;
2460 +   }
2461 +
2462 +   event->fired = 0;
2463 +   return 1;
2464 +}
2465 +
2466 +static inline void
2467 +remote_event_signal_local(REMOTE_EVENT_T *event)
2468 +{
2469 +   event->armed = 0;
2470 +   vcos_event_signal(event->event);
2471 +}
2472 +
2473 +static inline void
2474 +remote_event_poll(REMOTE_EVENT_T *event)
2475 +{
2476 +   if (event->armed)
2477 +      remote_event_signal_local(event);
2478 +}
2479 +
2480 +void
2481 +remote_event_pollall(VCHIQ_STATE_T *state)
2482 +{
2483 +   remote_event_poll(&state->local->trigger);
2484 +   remote_event_poll(&state->local->recycle);
2485 +}
2486 +
2487 +/* Round up message sizes so that any space at the end of a slot is always big
2488 +   enough for a header. This relies on header size being a power of two, which
2489 +   has been verified earlier by a static assertion. */
2490 +
2491 +static inline unsigned int
2492 +calc_stride(unsigned int size)
2493 +{
2494 +   /* Allow room for the header */
2495 +   size += sizeof(VCHIQ_HEADER_T);
2496 +
2497 +   /* Round up */
2498 +   return (size + sizeof(VCHIQ_HEADER_T) - 1) & ~(sizeof(VCHIQ_HEADER_T) - 1);
2499 +}
2500 +
2501 +static VCHIQ_SERVICE_T *
2502 +get_listening_service(VCHIQ_STATE_T *state, int fourcc)
2503 +{
2504 +   int i;
2505 +
2506 +   vcos_assert(fourcc != VCHIQ_FOURCC_INVALID);
2507 +
2508 +   for (i = 0; i < state->unused_service; i++)
2509 +   {
2510 +      VCHIQ_SERVICE_T *service = state->services[i];
2511 +      if (service &&
2512 +         (service->public_fourcc == fourcc) &&
2513 +         ((service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
2514 +         ((service->srvstate == VCHIQ_SRVSTATE_OPEN) &&
2515 +         (service->remoteport == VCHIQ_PORT_FREE))))
2516 +         return service;
2517 +   }
2518 +
2519 +   return NULL;
2520 +}
2521 +
2522 +static VCHIQ_SERVICE_T *
2523 +get_connected_service(VCHIQ_STATE_T *state, unsigned int port)
2524 +{
2525 +   int i;
2526 +   for (i = 0; i < state->unused_service; i++) {
2527 +      VCHIQ_SERVICE_T *service = state->services[i];
2528 +      if (service && (service->srvstate == VCHIQ_SRVSTATE_OPEN)
2529 +         && (service->remoteport == port)) {
2530 +         return service;
2531 +      }
2532 +   }
2533 +   return NULL;
2534 +}
2535 +
2536 +static inline void
2537 +request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type)
2538 +{
2539 +   if (service)
2540 +   {
2541 +      vcos_atomic_flags_or(&service->poll_flags, (1 << poll_type));
2542 +      vcos_atomic_flags_or(&state->poll_services[service->localport>>5],
2543 +         (1 <<(service->localport & 0x1f)));
2544 +   }
2545 +
2546 +   state->poll_needed = 1;
2547 +   vcos_wmb(&state->poll_needed);
2548 +
2549 +   /* ... and ensure the slot handler runs. */
2550 +   remote_event_signal_local(&state->local->trigger);
2551 +}
2552 +
2553 +/* Called from queue_message, by the slot handler and application threads,
2554 +   with slot_mutex held */
2555 +static VCHIQ_HEADER_T *
2556 +reserve_space(VCHIQ_STATE_T *state, int space, int is_blocking)
2557 +{
2558 +   VCHIQ_SHARED_STATE_T *local = state->local;
2559 +   int tx_pos = state->local_tx_pos;
2560 +   int slot_space = VCHIQ_SLOT_SIZE - (tx_pos & VCHIQ_SLOT_MASK);
2561 +
2562 +   if (space > slot_space) {
2563 +      VCHIQ_HEADER_T *header;
2564 +      /* Fill the remaining space with padding */
2565 +      vcos_assert(state->tx_data != NULL);
2566 +      header = (VCHIQ_HEADER_T *) (state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
2567 +      header->msgid = VCHIQ_MSGID_PADDING;
2568 +      header->size = slot_space - sizeof(VCHIQ_HEADER_T);
2569 +
2570 +      tx_pos += slot_space;
2571 +   }
2572 +
2573 +   /* If necessary, get the next slot. */
2574 +   if ((tx_pos & VCHIQ_SLOT_MASK) == 0)
2575 +   {
2576 +      int slot_index;
2577 +
2578 +      /* If there is no free slot... */
2579 +      if (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE))
2580 +      {
2581 +         /* ...wait for one. */
2582 +         VCHIQ_STATS_INC(state, slot_stalls);
2583 +
2584 +         /* But first, flush through the last slot. */
2585 +         local->tx_pos = tx_pos;
2586 +         remote_event_signal(&state->remote->trigger);
2587 +
2588 +         do {
2589 +            if (!is_blocking ||
2590 +               (vcos_event_wait(&state->slot_available_event) != VCOS_SUCCESS))
2591 +            {
2592 +               return NULL; /* No space available now */
2593 +            }
2594 +         }
2595 +         while (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE));
2596 +      }
2597 +
2598 +      slot_index = local->slot_queue[SLOT_QUEUE_INDEX_FROM_POS(tx_pos) & VCHIQ_SLOT_QUEUE_MASK];
2599 +      state->tx_data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
2600 +   }
2601 +
2602 +   state->local_tx_pos = tx_pos + space;
2603 +
2604 +   return (VCHIQ_HEADER_T *)(state->tx_data + (tx_pos & VCHIQ_SLOT_MASK));
2605 +}
2606 +
2607 +/* Called with slot_mutex held */
2608 +static void
2609 +process_free_queue(VCHIQ_STATE_T *state)
2610 +{
2611 +   VCHIQ_SHARED_STATE_T *local = state->local;
2612 +   BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
2613 +   int slot_queue_available;
2614 +
2615 +   /* Use a read memory barrier to ensure that any state that may have
2616 +      been modified by another thread is not masked by stale prefetched
2617 +      values. */
2618 +   vcos_rmb();
2619 +
2620 +   /* Find slots which have been freed by the other side, and return them to
2621 +      the available queue. */
2622 +   slot_queue_available = state->slot_queue_available;
2623 +
2624 +   while (slot_queue_available != local->slot_queue_recycle)
2625 +   {
2626 +      int pos;
2627 +      int slot_index = local->slot_queue[slot_queue_available++ & VCHIQ_SLOT_QUEUE_MASK];
2628 +      char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
2629 +
2630 +      vcos_log_trace("%d: pfq %d=%x %x %x", state->id, slot_index,
2631 +         (unsigned int)data, local->slot_queue_recycle,
2632 +         slot_queue_available);
2633 +
2634 +      /* Initialise the bitmask for services which have used this slot */
2635 +      BITSET_ZERO(service_found);
2636 +
2637 +      pos = 0;
2638 +
2639 +      while (pos < VCHIQ_SLOT_SIZE)
2640 +      {
2641 +         VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)(data + pos);
2642 +         int msgid = header->msgid;
2643 +         if (VCHIQ_MSG_TYPE(msgid) == VCHIQ_MSG_DATA)
2644 +         {
2645 +            int port = VCHIQ_MSG_SRCPORT(msgid);
2646 +            if (!BITSET_IS_SET(service_found, port))
2647 +            {
2648 +               VCHIQ_SERVICE_QUOTA_T *service_quota =
2649 +                  &state->service_quotas[port];
2650 +
2651 +               /* Set the found bit for this service */
2652 +               BITSET_SET(service_found, port);
2653 +
2654 +               if (service_quota->slot_use_count > 0)
2655 +               {
2656 +                  service_quota->slot_use_count--;
2657 +                  /* Signal the service in case it has dropped below its quota */
2658 +                  vcos_event_signal(&service_quota->quota_event);
2659 +                  vcos_log_trace("%d: pfq:%d %x@%x - slot_use->%d",
2660 +                     state->id, port,
2661 +                     header->size, (unsigned int)header,
2662 +                     service_quota->slot_use_count);
2663 +               }
2664 +               else
2665 +               {
2666 +                  vcos_log_error("service %d slot_use_count=%d (header %x,"
2667 +                                 " msgid %x, header->msgid %x, header->size %x)",
2668 +                     port, service_quota->slot_use_count,
2669 +                     (unsigned int)header, msgid, header->msgid,
2670 +                     header->size);
2671 +                  vcos_assert(0);
2672 +               }
2673 +            }
2674 +         }
2675 +
2676 +         pos += calc_stride(header->size);
2677 +         if (pos > VCHIQ_SLOT_SIZE)
2678 +         {
2679 +            vcos_log_error("pos %x: header %x, msgid %x, header->msgid %x, header->size %x",
2680 +               pos, (unsigned int)header, msgid, header->msgid, header->size);
2681 +            vcos_assert(0);
2682 +         }
2683 +      }
2684 +   }
2685 +
2686 +   if (slot_queue_available != state->slot_queue_available)
2687 +   {
2688 +      state->slot_queue_available = slot_queue_available;
2689 +      vcos_wmb(&state->slot_queue_available);
2690 +      vcos_event_signal(&state->slot_available_event);
2691 +   }
2692 +}
2693 +
2694 +/* Called by the slot handler and application threads */
2695 +static VCHIQ_STATUS_T
2696 +queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
2697 +   int msgid, const VCHIQ_ELEMENT_T *elements,
2698 +   int count, int size, int is_blocking)
2699 +{
2700 +   VCHIQ_SHARED_STATE_T *local;
2701 +   VCHIQ_SERVICE_QUOTA_T *service_quota = NULL;
2702 +   VCHIQ_HEADER_T *header;
2703 +
2704 +   unsigned int stride;
2705 +
2706 +   local = state->local;
2707 +
2708 +   stride = calc_stride(size);
2709 +
2710 +   vcos_assert(stride <= VCHIQ_SLOT_SIZE);
2711 +
2712 +   /* On platforms where vcos_mutex_lock cannot fail, the return will never
2713 +      be taken and the compiler may optimise out that code. Let Coverity
2714 +      know this is intentional.
2715 +   */
2716 +   /* coverity[constant_expression_result] */
2717 +   if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) &&
2718 +      (vcos_mutex_lock(&state->slot_mutex) != VCOS_SUCCESS))
2719 +      return VCHIQ_RETRY;
2720 +
2721 +   if (service)
2722 +   {
2723 +      int tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1);
2724 +
2725 +      if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
2726 +      {
2727 +         /* The service has been closed, probably while waiting for the mutex */
2728 +         vcos_mutex_unlock(&state->slot_mutex);
2729 +         return VCHIQ_ERROR;
2730 +      }
2731 +
2732 +      service_quota = &state->service_quotas[service->localport];
2733 +
2734 +      /* ...ensure it doesn't use more than its quota of slots */
2735 +      while ((tx_end_index != service_quota->previous_tx_index) &&
2736 +         (service_quota->slot_use_count == service_quota->slot_quota))
2737 +      {
2738 +         vcos_log_trace("%d: qm:%d %s,%x - quota stall",
2739 +            state->id, service->localport,
2740 +            msg_type_str(VCHIQ_MSG_TYPE(msgid)), size);
2741 +         VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
2742 +         vcos_mutex_unlock(&state->slot_mutex);
2743 +         if (vcos_event_wait(&service_quota->quota_event) != VCOS_SUCCESS)
2744 +            return VCHIQ_RETRY;
2745 +         if (vcos_mutex_lock(&state->slot_mutex) != VCOS_SUCCESS)
2746 +            return VCHIQ_RETRY;
2747 +         vcos_assert(service_quota->slot_use_count <= service_quota->slot_quota);
2748 +         tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1);
2749 +      }
2750 +   }
2751 +
2752 +   header = reserve_space(state, stride, is_blocking);
2753 +
2754 +   if (!header) {
2755 +      if (service)
2756 +         VCHIQ_SERVICE_STATS_INC(service, slot_stalls);
2757 +      vcos_mutex_unlock(&state->slot_mutex);
2758 +      return VCHIQ_RETRY;
2759 +   }
2760 +
2761 +   if (service) {
2762 +      int i, pos;
2763 +      int tx_end_index;
2764 +
2765 +      vcos_log_info("%d: qm %s@%x,%x (%d->%d)", state->id,
2766 +         msg_type_str(VCHIQ_MSG_TYPE(msgid)),
2767 +         (unsigned int)header, size,
2768 +         VCHIQ_MSG_SRCPORT(msgid),
2769 +         VCHIQ_MSG_DSTPORT(msgid));
2770 +
2771 +      for (i = 0, pos = 0; i < (unsigned int)count;
2772 +         pos += elements[i++].size)
2773 +         if (elements[i].size) {
2774 +            if (vchiq_copy_from_user
2775 +               (header->data + pos, elements[i].data,
2776 +               (size_t) elements[i].size) !=
2777 +               VCHIQ_SUCCESS) {
2778 +               vcos_mutex_unlock(&state->slot_mutex);
2779 +               VCHIQ_SERVICE_STATS_INC(service, error_count);
2780 +               return VCHIQ_ERROR;
2781 +            }
2782 +            if (i == 0) {
2783 +               vcos_log_dump_mem( &vchiq_core_msg_log_category,
2784 +                              "Sent", 0, header->data + pos,
2785 +                              vcos_min( 64, elements[0].size ));
2786 +            }
2787 +         }
2788 +
2789 +      /* If this transmission can't fit in the last slot used by this service... */
2790 +      tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos - 1);
2791 +      if (tx_end_index != service_quota->previous_tx_index)
2792 +      {
2793 +         service_quota->slot_use_count++;
2794 +         vcos_log_trace("%d: qm:%d %s,%x - slot_use->%d",
2795 +            state->id, service->localport,
2796 +            msg_type_str(VCHIQ_MSG_TYPE(msgid)), size,
2797 +            service_quota->slot_use_count);
2798 +      }
2799 +
2800 +      service_quota->previous_tx_index = tx_end_index;
2801 +      VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
2802 +      VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
2803 +   } else {
2804 +      vcos_log_info("%d: qm %s@%x,%x (%d->%d)", state->id,
2805 +         msg_type_str(VCHIQ_MSG_TYPE(msgid)),
2806 +         (unsigned int)header, size,
2807 +         VCHIQ_MSG_SRCPORT(msgid),
2808 +         VCHIQ_MSG_DSTPORT(msgid));
2809 +      if (size != 0)
2810 +      { 
2811 +         vcos_assert((count == 1) && (size == elements[0].size));
2812 +         memcpy(header->data, elements[0].data, elements[0].size);
2813 +      }
2814 +      VCHIQ_STATS_INC(state, ctrl_tx_count);
2815 +   }
2816 +
2817 +   header->msgid = msgid;
2818 +   header->size = size;
2819 +
2820 +   if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
2821 +   {
2822 +      int svc_fourcc;
2823 +
2824 +      svc_fourcc = service
2825 +         ? service->base.fourcc
2826 +         : VCHIQ_MAKE_FOURCC('?','?','?','?');
2827 +
2828 +      vcos_log_impl( &vchiq_core_msg_log_category,
2829 +         VCOS_LOG_INFO,
2830 +         "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
2831 +         msg_type_str(VCHIQ_MSG_TYPE(msgid)),
2832 +         VCHIQ_MSG_TYPE(msgid),
2833 +         VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
2834 +         VCHIQ_MSG_SRCPORT(msgid),
2835 +         VCHIQ_MSG_DSTPORT(msgid),
2836 +         size );
2837 +   }
2838 +
2839 +   /* Make the new tx_pos visible to the peer. */
2840 +   local->tx_pos = state->local_tx_pos;
2841 +   vcos_wmb(&local->tx_pos);
2842 +
2843 +   if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
2844 +      vcos_mutex_unlock(&state->slot_mutex);
2845 +
2846 +   remote_event_signal(&state->remote->trigger);
2847 +
2848 +   return VCHIQ_SUCCESS;
2849 +}
2850 +
2851 +static inline void
2852 +claim_slot(VCHIQ_SLOT_INFO_T *slot)
2853 +{
2854 +   slot->use_count++;
2855 +}
2856 +
2857 +static void
2858 +release_slot(VCHIQ_STATE_T *state, VCHIQ_SLOT_INFO_T *slot_info)
2859 +{
2860 +   int release_count;
2861 +   vcos_mutex_lock(&state->recycle_mutex);
2862 +
2863 +   release_count = slot_info->release_count;
2864 +   slot_info->release_count = ++release_count;
2865 +
2866 +   if (release_count == slot_info->use_count)
2867 +   {
2868 +      int slot_queue_recycle;
2869 +      /* Add to the freed queue */
2870 +
2871 +      /* A read barrier is necessary here to prevent speculative fetches of
2872 +         remote->slot_queue_recycle from overtaking the mutex. */
2873 +      vcos_rmb();
2874 +
2875 +      slot_queue_recycle = state->remote->slot_queue_recycle;
2876 +      state->remote->slot_queue[slot_queue_recycle & VCHIQ_SLOT_QUEUE_MASK] =
2877 +         SLOT_INDEX_FROM_INFO(state, slot_info);
2878 +      state->remote->slot_queue_recycle = slot_queue_recycle + 1;
2879 +      vcos_log_info("%d: release_slot %d - recycle->%x",
2880 +         state->id, SLOT_INDEX_FROM_INFO(state, slot_info),
2881 +         state->remote->slot_queue_recycle);
2882 +
2883 +      /* A write barrier is necessary, but remote_event_signal contains one. */
2884 +      remote_event_signal(&state->remote->recycle);
2885 +   }
2886 +
2887 +   vcos_mutex_unlock(&state->recycle_mutex);
2888 +}
2889 +
2890 +/* Called by the slot handler - don't hold the bulk mutex */
2891 +static VCHIQ_STATUS_T
2892 +notify_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
2893 +{
2894 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
2895 +
2896 +   vcos_log_trace("%d: nb:%d %cx - p=%x rn=%x r=%x",
2897 +      service->state->id, service->localport,
2898 +      (queue == &service->bulk_tx) ? 't' : 'r',
2899 +      queue->process, queue->remote_notify, queue->remove);
2900 +
2901 +   if (service->state->is_master)
2902 +   {
2903 +      while (queue->remote_notify != queue->process)
2904 +      {
2905 +         VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->remote_notify)];
2906 +         int msgtype = (bulk->dir == VCHIQ_BULK_TRANSMIT) ?
2907 +            VCHIQ_MSG_BULK_RX_DONE : VCHIQ_MSG_BULK_TX_DONE;
2908 +         int msgid = VCHIQ_MAKE_MSG(msgtype, service->localport, service->remoteport);
2909 +         VCHIQ_ELEMENT_T element = { &bulk->actual, 4 };
2910 +         /* Only reply to non-dummy bulk requests */
2911 +         if (bulk->remote_data)
2912 +         {
2913 +            status = queue_message(service->state, NULL, msgid, &element, 1, 4, 0);
2914 +            if (status != VCHIQ_SUCCESS)
2915 +               break;
2916 +         }
2917 +         queue->remote_notify++;
2918 +      }
2919 +   }
2920 +   else
2921 +   {
2922 +      queue->remote_notify = queue->process;
2923 +   }
2924 +
2925 +   if (status == VCHIQ_SUCCESS)
2926 +   {
2927 +      while (queue->remove != queue->remote_notify)
2928 +      {
2929 +         VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->remove)];
2930 +
2931 +         /* Only generate callbacks for non-dummy bulk requests */
2932 +         if (bulk->data)
2933 +         {
2934 +            if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED)
2935 +            {
2936 +               if (bulk->dir == VCHIQ_BULK_TRANSMIT)
2937 +               {
2938 +                  VCHIQ_SERVICE_STATS_INC(service, bulk_tx_count);
2939 +                  VCHIQ_SERVICE_STATS_ADD(service, bulk_tx_bytes, bulk->actual);
2940 +               }
2941 +               else
2942 +               {
2943 +                  VCHIQ_SERVICE_STATS_INC(service, bulk_rx_count);
2944 +                  VCHIQ_SERVICE_STATS_ADD(service, bulk_rx_bytes, bulk->actual);
2945 +               }
2946 +            }
2947 +            else
2948 +            {
2949 +               VCHIQ_SERVICE_STATS_INC(service, bulk_aborted_count);
2950 +            }
2951 +            if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING)
2952 +            {
2953 +               BULK_WAITER_T *waiter = (BULK_WAITER_T *)bulk->userdata;
2954 +               if (waiter)
2955 +               {
2956 +                  waiter->actual = bulk->actual;
2957 +                  vcos_event_signal(&waiter->event);
2958 +               }
2959 +            }
2960 +            else if (bulk->mode == VCHIQ_BULK_MODE_CALLBACK)
2961 +            {
2962 +               VCHIQ_REASON_T reason = (bulk->dir == VCHIQ_BULK_TRANSMIT) ?
2963 +                  ((bulk->actual == VCHIQ_BULK_ACTUAL_ABORTED) ?
2964 +                     VCHIQ_BULK_TRANSMIT_ABORTED : VCHIQ_BULK_TRANSMIT_DONE) :
2965 +                  ((bulk->actual == VCHIQ_BULK_ACTUAL_ABORTED) ?
2966 +                     VCHIQ_BULK_RECEIVE_ABORTED : VCHIQ_BULK_RECEIVE_DONE);
2967 +               status = make_service_callback(service, reason,
2968 +                  NULL, bulk->userdata);
2969 +               if (status == VCHIQ_RETRY)
2970 +                  break;
2971 +            }
2972 +         }
2973 +
2974 +         queue->remove++;
2975 +         vcos_event_signal(&service->bulk_remove_event);
2976 +      }
2977 +   }
2978 +
2979 +   if (status != VCHIQ_SUCCESS)
2980 +      request_poll(service->state, service, (queue == &service->bulk_tx) ?
2981 +         VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
2982 +
2983 +   return status;
2984 +}
2985 +
2986 +/* Called by the slot handler thread */
2987 +static void
2988 +poll_services(VCHIQ_STATE_T *state)
2989 +{
2990 +   int group, i;
2991 +
2992 +   for (group = 0; group < BITSET_SIZE(state->unused_service); group++)
2993 +   {
2994 +      uint32_t flags;
2995 +      flags = vcos_atomic_flags_get_and_clear(&state->poll_services[group]);
2996 +      for (i = 0; flags; i++)
2997 +      {
2998 +         if (flags & (1 << i))
2999 +         {
3000 +            VCHIQ_SERVICE_T *service = state->services[(group<<5) + i];
3001 +            uint32_t service_flags =
3002 +               vcos_atomic_flags_get_and_clear(&service->poll_flags);
3003 +            if (service_flags & (1 << VCHIQ_POLL_TERMINATE))
3004 +            {
3005 +               vcos_log_info("%d: ps - terminate %d<->%d", state->id, service->localport, service->remoteport);
3006 +               if (vchiq_close_service_internal(service, 0/*!close_recvd*/) != VCHIQ_SUCCESS)
3007 +                  request_poll(state, service, VCHIQ_POLL_TERMINATE);
3008 +            }
3009 +            if (service_flags & (1 << VCHIQ_POLL_TXNOTIFY))
3010 +               notify_bulks(service, &service->bulk_tx);
3011 +            if (service_flags & (1 << VCHIQ_POLL_RXNOTIFY))
3012 +               notify_bulks(service, &service->bulk_rx);
3013 +            flags &= ~(1 << i);
3014 +         }
3015 +      }
3016 +   }
3017 +}
3018 +
3019 +/* Called by the slot handler or application threads, holding the bulk mutex. */
3020 +static int
3021 +resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
3022 +{
3023 +   VCHIQ_STATE_T *state = service->state;
3024 +   int resolved = 0;
3025 +
3026 +   while ((queue->process != queue->local_insert) &&
3027 +      (queue->process != queue->remote_insert))
3028 +   {
3029 +      VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
3030 +
3031 +      vcos_log_trace("%d: rb:%d %cx - li=%x ri=%x p=%x",
3032 +         state->id, service->localport,
3033 +         (queue == &service->bulk_tx) ? 't' : 'r',
3034 +         queue->local_insert, queue->remote_insert,
3035 +         queue->process);
3036 +
3037 +      vcos_assert((int)(queue->local_insert - queue->process) > 0);
3038 +      vcos_assert((int)(queue->remote_insert - queue->process) > 0);
3039 +      vchiq_transfer_bulk(bulk);
3040 +
3041 +      if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3042 +      {
3043 +         const char *header = (queue == &service->bulk_tx) ?
3044 +            "Send Bulk to" : "Recv Bulk from";
3045 +         if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED)
3046 +            vcos_log_impl( &vchiq_core_msg_log_category,
3047 +               VCOS_LOG_INFO,
3048 +               "%s %c%c%c%c d:%d len:%d %x<->%x",
3049 +               header,
3050 +               VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3051 +               service->remoteport,
3052 +               bulk->size,
3053 +               (unsigned int)bulk->data,
3054 +               (unsigned int)bulk->remote_data );
3055 +         else
3056 +            vcos_log_impl( &vchiq_core_msg_log_category,
3057 +               VCOS_LOG_INFO,
3058 +               "%s %c%c%c%c d:%d ABORTED - tx len:%d, rx len:%d %x<->%x",
3059 +               header,
3060 +               VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3061 +               service->remoteport,
3062 +               bulk->size,
3063 +               bulk->remote_size,
3064 +               (unsigned int)bulk->data,
3065 +               (unsigned int)bulk->remote_data );
3066 +      }
3067 +
3068 +      vchiq_complete_bulk(bulk);
3069 +      queue->process++;
3070 +      resolved++;
3071 +   }
3072 +   return resolved;
3073 +}
3074 +
3075 +/* Called with the bulk_mutex held */
3076 +static void
3077 +abort_outstanding_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
3078 +{
3079 +   int is_tx = (queue == &service->bulk_tx);
3080 +   vcos_log_trace("%d: aob:%d %cx - li=%x ri=%x p=%x",
3081 +      service->state->id, service->localport, is_tx ? 't' : 'r',
3082 +      queue->local_insert, queue->remote_insert, queue->process);
3083 +
3084 +   vcos_assert((int)(queue->local_insert - queue->process) >= 0);
3085 +   vcos_assert((int)(queue->remote_insert - queue->process) >= 0);
3086 +
3087 +   while ((queue->process != queue->local_insert) ||
3088 +      (queue->process != queue->remote_insert))
3089 +   {
3090 +      VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)];
3091 +
3092 +      if (queue->process == queue->remote_insert)
3093 +      {
3094 +         /* fabricate a matching dummy bulk */
3095 +         bulk->remote_data = NULL;
3096 +         bulk->remote_size = 0;
3097 +         queue->remote_insert++;
3098 +      }
3099 +
3100 +      if (queue->process != queue->local_insert)
3101 +      {
3102 +         vchiq_complete_bulk(bulk);
3103 +
3104 +         if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3105 +         {
3106 +            vcos_log_impl( &vchiq_core_msg_log_category,
3107 +               VCOS_LOG_INFO,
3108 +               "%s %c%c%c%c d:%d ABORTED - tx len:%d, rx len:%d",
3109 +               is_tx ? "Send Bulk to" : "Recv Bulk from",
3110 +               VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3111 +               service->remoteport,
3112 +               bulk->size,
3113 +               bulk->remote_size );
3114 +         }
3115 +      }
3116 +      else
3117 +      {
3118 +         /* fabricate a matching dummy bulk */
3119 +         bulk->data = NULL;
3120 +         bulk->size = 0;
3121 +         bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
3122 +         bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
3123 +         queue->local_insert++;
3124 +      }
3125 +
3126 +      queue->process++;
3127 +   }
3128 +}
3129 +
3130 +static void
3131 +pause_bulks(VCHIQ_STATE_T *state)
3132 +{
3133 +   int i;
3134 +
3135 +   /* Block bulk transfers from all services */
3136 +   for (i = 0; i < state->unused_service; i++)
3137 +   {
3138 +      VCHIQ_SERVICE_T *service = state->services[i];
3139 +      if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN))
3140 +         continue;
3141 +
3142 +      vcos_log_trace("locking bulk_mutex for service %d", i);
3143 +      vcos_mutex_lock(&service->bulk_mutex);
3144 +   }
3145 +}
3146 +
3147 +static void
3148 +resume_bulks(VCHIQ_STATE_T *state)
3149 +{
3150 +   int i;
3151 +
3152 +   /* Poll all services in case any bulk transfers have been
3153 +      deferred */
3154 +   for (i = 0; i < state->unused_service; i++)
3155 +   {
3156 +      VCHIQ_SERVICE_T *service = state->services[i];
3157 +      if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN))
3158 +         continue;
3159 +
3160 +      if (resolve_bulks(service, &service->bulk_tx))
3161 +         request_poll(state, service, VCHIQ_POLL_TXNOTIFY);
3162 +      if (resolve_bulks(service, &service->bulk_rx))
3163 +         request_poll(state, service, VCHIQ_POLL_RXNOTIFY);
3164 +      vcos_log_trace("unlocking bulk_mutex for service %d", i);
3165 +      vcos_mutex_unlock(&service->bulk_mutex);
3166 +   }
3167 +}
3168 +
3169 +/* Called by the slot handler thread */
3170 +static void
3171 +parse_rx_slots(VCHIQ_STATE_T *state)
3172 +{
3173 +   VCHIQ_SHARED_STATE_T *remote = state->remote;
3174 +   int tx_pos;
3175 +   DEBUG_INITIALISE(state->local)
3176 +
3177 +   tx_pos = remote->tx_pos;
3178 +
3179 +   while (state->rx_pos != tx_pos) {
3180 +      VCHIQ_SERVICE_T *service = NULL;
3181 +      VCHIQ_HEADER_T *header;
3182 +      int msgid, size;
3183 +      int type;
3184 +      unsigned int localport, remoteport;
3185 +
3186 +      DEBUG_TRACE(PARSE_LINE);
3187 +      if (!state->rx_data)
3188 +      {
3189 +         int rx_index;
3190 +         vcos_assert((state->rx_pos & VCHIQ_SLOT_MASK) == 0);
3191 +         rx_index = remote->slot_queue[SLOT_QUEUE_INDEX_FROM_POS(state->rx_pos) & VCHIQ_SLOT_QUEUE_MASK];
3192 +         state->rx_data = (char *)SLOT_DATA_FROM_INDEX(state, rx_index);
3193 +         state->rx_info = SLOT_INFO_FROM_INDEX(state, rx_index);
3194 +
3195 +         /* Initialise use_count to one, and increment release_count at the end
3196 +            of the slot to avoid releasing the slot prematurely. */
3197 +         state->rx_info->use_count = 1;
3198 +         state->rx_info->release_count = 0;
3199 +      }
3200 +
3201 +      header = (VCHIQ_HEADER_T *)(state->rx_data + (state->rx_pos & VCHIQ_SLOT_MASK));
3202 +      DEBUG_VALUE(PARSE_HEADER, (int)header);
3203 +      msgid = header->msgid;
3204 +      DEBUG_VALUE(PARSE_MSGID, msgid);
3205 +      size = header->size;
3206 +      type = VCHIQ_MSG_TYPE(msgid);
3207 +      localport = VCHIQ_MSG_DSTPORT(msgid);
3208 +      remoteport = VCHIQ_MSG_SRCPORT(msgid);
3209 +
3210 +      if (type != VCHIQ_MSG_DATA)
3211 +      {
3212 +         VCHIQ_STATS_INC(state, ctrl_rx_count);
3213 +      }
3214 +
3215 +      switch (type)
3216 +      {
3217 +      case VCHIQ_MSG_OPENACK:
3218 +      case VCHIQ_MSG_CLOSE:
3219 +      case VCHIQ_MSG_DATA:
3220 +      case VCHIQ_MSG_BULK_RX:
3221 +      case VCHIQ_MSG_BULK_TX:
3222 +      case VCHIQ_MSG_BULK_RX_DONE:
3223 +      case VCHIQ_MSG_BULK_TX_DONE:
3224 +         if (localport <= VCHIQ_PORT_MAX)
3225 +         {
3226 +            service = state->services[localport];
3227 +            if (service && (service->srvstate == VCHIQ_SRVSTATE_FREE))
3228 +               service = NULL;
3229 +         }
3230 +         if (!service)
3231 +         {
3232 +            vcos_log_error(
3233 +               "%d: prs %s@%x (%d->%d) - invalid/closed service %d",
3234 +               state->id, msg_type_str(type), (unsigned int)header,
3235 +               remoteport, localport, localport);
3236 +            goto skip_message;
3237 +         }
3238 +      default:
3239 +         break;
3240 +      }
3241 +
3242 +      if ( vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3243 +      {
3244 +         int svc_fourcc;
3245 +
3246 +         svc_fourcc = service
3247 +            ? service->base.fourcc
3248 +            : VCHIQ_MAKE_FOURCC('?','?','?','?');
3249 +         vcos_log_impl( &vchiq_core_msg_log_category,
3250 +            VCOS_LOG_INFO,
3251 +            "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d len:%d",
3252 +            msg_type_str(type), type,
3253 +            VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
3254 +            remoteport, localport, size );
3255 +         if (size > 0) {
3256 +            vcos_log_dump_mem( &vchiq_core_msg_log_category,
3257 +                           "Rcvd", 0, header->data,
3258 +                           vcos_min( 64, size ));
3259 +         }
3260 +      }
3261 +
3262 +      if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size) > VCHIQ_SLOT_SIZE)
3263 +      {
3264 +         vcos_log_error("header %x (msgid %x) - size %x too big for slot",
3265 +            (unsigned int)header, (unsigned int)msgid, (unsigned int)size);
3266 +         vcos_assert(0);
3267 +      }
3268 +
3269 +      switch (type) {
3270 +      case VCHIQ_MSG_OPEN:
3271 +         vcos_assert(VCHIQ_MSG_DSTPORT(msgid) == 0);
3272 +         if (vcos_verify(size == sizeof(VCHIQ_OPEN_PAYLOAD_T))) {
3273 +            const VCHIQ_OPEN_PAYLOAD_T *payload = (VCHIQ_OPEN_PAYLOAD_T *)header->data;
3274 +            unsigned int fourcc;
3275 +
3276 +            fourcc = payload->fourcc;
3277 +            vcos_log_info("%d: prs OPEN@%x (%d->'%c%c%c%c')",
3278 +               state->id, (unsigned int)header,
3279 +               localport,
3280 +               VCHIQ_FOURCC_AS_4CHARS(fourcc));
3281 +
3282 +            service = get_listening_service(state, fourcc);
3283 +
3284 +            if (service)
3285 +            {
3286 +               /* A matching service exists */
3287 +               short version = payload->version;
3288 +               short version_min = payload->version_min;
3289 +               if ((service->version < version_min) ||
3290 +                  (version < service->version_min))
3291 +               {
3292 +                  /* Version mismatch */
3293 +                  vcos_log_error("%d: service %d (%c%c%c%c) version mismatch -"
3294 +                     " local (%d, min %d) vs. remote (%d, min %d)",
3295 +                     state->id, service->localport,
3296 +                     VCHIQ_FOURCC_AS_4CHARS(fourcc),
3297 +                     service->version, service->version_min,
3298 +                     version, version_min);
3299 +                  goto fail_open;
3300 +               }
3301 +               if (service->srvstate == VCHIQ_SRVSTATE_LISTENING)
3302 +               {
3303 +                  /* Acknowledge the OPEN */
3304 +                  if (queue_message(state, NULL,
3305 +                     VCHIQ_MAKE_MSG(VCHIQ_MSG_OPENACK, service->localport, remoteport),
3306 +                     NULL, 0, 0, 0) == VCHIQ_RETRY)
3307 +                     return;  /* Bail out if not ready */
3308 +
3309 +                  /* The service is now open */
3310 +                  vchiq_set_service_state(service, VCHIQ_SRVSTATE_OPEN);
3311 +               }
3312 +
3313 +               service->remoteport = remoteport;
3314 +               service->client_id = ((int *)header->data)[1];
3315 +               if (make_service_callback(service, VCHIQ_SERVICE_OPENED,
3316 +                  NULL, NULL) == VCHIQ_RETRY)
3317 +               {
3318 +                  /* Bail out if not ready */
3319 +                  service->remoteport = VCHIQ_PORT_FREE;
3320 +                  return;
3321 +               }
3322 +
3323 +               /* Break out, and skip the failure handling */
3324 +               break;
3325 +            }
3326 +         }
3327 +      fail_open:
3328 +         /* No available service, or an invalid request - send a CLOSE */
3329 +         if (queue_message(state, NULL,
3330 +            VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE, 0, VCHIQ_MSG_SRCPORT(msgid)),
3331 +            NULL, 0, 0, 0) == VCHIQ_RETRY)
3332 +            return;  /* Bail out if not ready */
3333 +         break;
3334 +      case VCHIQ_MSG_OPENACK:
3335 +         {
3336 +            vcos_log_info("%d: prs OPENACK@%x (%d->%d)",
3337 +               state->id, (unsigned int)header,
3338 +               remoteport, localport);
3339 +            if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
3340 +               service->remoteport = remoteport;
3341 +               vchiq_set_service_state(service,
3342 +                        VCHIQ_SRVSTATE_OPEN);
3343 +               vcos_event_signal(&service->remove_event);
3344 +            }
3345 +         }
3346 +         break;
3347 +      case VCHIQ_MSG_CLOSE:
3348 +         {
3349 +            vcos_assert(size == 0); /* There should be no data */
3350 +
3351 +            vcos_log_info("%d: prs CLOSE@%x (%d->%d)",
3352 +               state->id, (unsigned int)header,
3353 +               remoteport, localport);
3354 +
3355 +            if ((service->remoteport != remoteport) &&
3356 +               VCHIQ_PORT_IS_VALID(service->remoteport)) {
3357 +               /* This could be from a client which hadn't yet received
3358 +                  the OPENACK - look for the connected service */
3359 +               service = get_connected_service(state, remoteport);
3360 +               if (!service)
3361 +                  break;
3362 +            }
3363 +
3364 +            if (vchiq_close_service_internal(service,
3365 +               1/*close_recvd*/) == VCHIQ_RETRY)
3366 +               return;  /* Bail out if not ready */
3367 +
3368 +            if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO))
3369 +            {
3370 +               vcos_log_impl( &vchiq_core_msg_log_category,
3371 +                           VCOS_LOG_INFO,
3372 +                           "Close Service %c%c%c%c s:%u d:%d",
3373 +                           VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
3374 +                           service->localport,
3375 +                           service->remoteport );
3376 +            }
3377 +         }
3378 +         break;
3379 +      case VCHIQ_MSG_DATA:
3380 +         {
3381 +            vcos_log_trace("%d: prs DATA@%x,%x (%d->%d)",
3382 +               state->id, (unsigned int)header, size,
3383 +               remoteport, localport);
3384 +
3385 +            if ((service->remoteport == remoteport)
3386 +               && (service->srvstate ==
3387 +               VCHIQ_SRVSTATE_OPEN)) {
3388 +               header->msgid = msgid | VCHIQ_MSGID_CLAIMED;
3389 +               claim_slot(state->rx_info);
3390 +               DEBUG_TRACE(PARSE_LINE);
3391 +               if (make_service_callback(service,
3392 +                  VCHIQ_MESSAGE_AVAILABLE, header,
3393 +                  NULL) == VCHIQ_RETRY)
3394 +               {
3395 +                  DEBUG_TRACE(PARSE_LINE);
3396 +                  return;  /* Bail out if not ready */
3397 +               }
3398 +               VCHIQ_SERVICE_STATS_INC(service, ctrl_rx_count);
3399 +               VCHIQ_SERVICE_STATS_ADD(service, ctrl_rx_bytes, size);
3400 +            }
3401 +            else
3402 +            {
3403 +               VCHIQ_STATS_INC(state, error_count);
3404 +            }
3405 +         }
3406 +         break;
3407 +      case VCHIQ_MSG_CONNECT:
3408 +         vcos_log_info("%d: prs CONNECT@%x",
3409 +            state->id, (unsigned int)header);
3410 +         vcos_event_signal(&state->connect);
3411 +         break;
3412 +      case VCHIQ_MSG_BULK_RX:
3413 +      case VCHIQ_MSG_BULK_TX:
3414 +         {
3415 +            VCHIQ_BULK_QUEUE_T *queue;
3416 +            vcos_assert(state->is_master);
3417 +            queue = (type == VCHIQ_MSG_BULK_RX) ?
3418 +               &service->bulk_tx : &service->bulk_rx;
3419 +            if ((service->remoteport == remoteport)
3420 +               && (service->srvstate ==
3421 +               VCHIQ_SRVSTATE_OPEN))
3422 +            {
3423 +               VCHIQ_BULK_T *bulk;
3424 +               int resolved;
3425 +
3426 +               vcos_assert(queue->remote_insert < queue->remove +
3427 +                  VCHIQ_NUM_SERVICE_BULKS);
3428 +               bulk = &queue->bulks[BULK_INDEX(queue->remote_insert)];
3429 +               bulk->remote_data = (void *)((int *)header->data)[0];
3430 +               bulk->remote_size = ((int *)header->data)[1];
3431 +
3432 +               vcos_log_info("%d: prs %s@%x (%d->%d) %x@%x",
3433 +                  state->id, msg_type_str(type),
3434 +                  (unsigned int)header,
3435 +                  remoteport, localport,
3436 +                  bulk->remote_size,
3437 +                  (unsigned int)bulk->remote_data);
3438 +
3439 +               queue->remote_insert++;
3440 +
3441 +               if (state->conn_state != VCHIQ_CONNSTATE_CONNECTED)
3442 +                  break;
3443 +
3444 +               DEBUG_TRACE(PARSE_LINE);
3445 +               if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
3446 +               {
3447 +                  DEBUG_TRACE(PARSE_LINE);
3448 +                  return;
3449 +               }
3450 +               DEBUG_TRACE(PARSE_LINE);
3451 +               resolved = resolve_bulks(service, queue);
3452 +               vcos_mutex_unlock(&service->bulk_mutex);
3453 +               if (resolved)
3454 +                  notify_bulks(service, queue);
3455 +            }
3456 +         }
3457 +         break;
3458 +      case VCHIQ_MSG_BULK_RX_DONE:
3459 +      case VCHIQ_MSG_BULK_TX_DONE:
3460 +         {
3461 +            vcos_assert(!state->is_master);
3462 +            if ((service->remoteport == remoteport)
3463 +               && (service->srvstate !=
3464 +               VCHIQ_SRVSTATE_FREE)) {
3465 +               VCHIQ_BULK_QUEUE_T *queue;
3466 +               VCHIQ_BULK_T *bulk;
3467 +
3468 +               queue = (type == VCHIQ_MSG_BULK_RX_DONE) ?
3469 +                  &service->bulk_rx : &service->bulk_tx;
3470 +
3471 +               bulk = &queue->bulks[BULK_INDEX(queue->process)];
3472 +               bulk->actual = *(int *)header->data;
3473 +
3474 +               vcos_log_info("%d: prs %s@%x (%d->%d) %x@%x",
3475 +                  state->id, msg_type_str(type),
3476 +                  (unsigned int)header,
3477 +                  remoteport, localport,
3478 +                  bulk->actual, (unsigned int)bulk->data);
3479 +
3480 +               vcos_log_trace("%d: prs:%d %cx li=%x ri=%x p=%x",
3481 +                  state->id, localport,
3482 +                  (type == VCHIQ_MSG_BULK_RX_DONE) ? 'r' : 't',
3483 +                  queue->local_insert,
3484 +                  queue->remote_insert, queue->process);
3485 +
3486 +               DEBUG_TRACE(PARSE_LINE);
3487 +               if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
3488 +               {
3489 +                  DEBUG_TRACE(PARSE_LINE);
3490 +                  return;
3491 +               }
3492 +               DEBUG_TRACE(PARSE_LINE);
3493 +               vcos_assert(queue->process != queue->local_insert);
3494 +               vchiq_complete_bulk(bulk);
3495 +               queue->process++;
3496 +               vcos_mutex_unlock(&service->bulk_mutex);
3497 +               DEBUG_TRACE(PARSE_LINE);
3498 +               notify_bulks(service, queue);
3499 +               DEBUG_TRACE(PARSE_LINE);
3500 +            }
3501 +         }
3502 +         break;
3503 +      case VCHIQ_MSG_PADDING:
3504 +         vcos_log_trace("%d: prs PADDING@%x,%x",
3505 +            state->id, (unsigned int)header, size);
3506 +         break;
3507 +      case VCHIQ_MSG_PAUSE:
3508 +         /* If initiated, signal the application thread */
3509 +         vcos_log_trace("%d: prs PAUSE@%x,%x",
3510 +            state->id, (unsigned int)header, size);
3511 +         if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT)
3512 +         {
3513 +            /* Send a PAUSE in response */
3514 +            if (queue_message(state, NULL,
3515 +               VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
3516 +               NULL, 0, 0, 0) == VCHIQ_RETRY)
3517 +               return;  /* Bail out if not ready */
3518 +            if (state->is_master)
3519 +               pause_bulks(state);
3520 +         }
3521 +         /* At this point slot_mutex is held */
3522 +         vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
3523 +         vchiq_platform_paused(state);
3524 +         break;
3525 +      case VCHIQ_MSG_RESUME:
3526 +         vcos_log_trace("%d: prs RESUME@%x,%x",
3527 +            state->id, (unsigned int)header, size);
3528 +         /* Release the slot mutex */
3529 +         vcos_mutex_unlock(&state->slot_mutex);
3530 +         if (state->is_master)
3531 +            resume_bulks(state);
3532 +         vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
3533 +         vchiq_platform_resumed(state);
3534 +         break;
3535 +      default:
3536 +         vcos_log_error("%d: prs invalid msgid %x@%x,%x",
3537 +            state->id, msgid, (unsigned int)header, size);
3538 +         vcos_assert(0);
3539 +         break;
3540 +      }
3541 +
3542 +   skip_message:
3543 +      state->rx_pos += calc_stride(size);
3544 +
3545 +      DEBUG_TRACE(PARSE_LINE);
3546 +      /* Perform some housekeeping when the end of the slot is reached. */
3547 +      if ((state->rx_pos & VCHIQ_SLOT_MASK) == 0)
3548 +      {
3549 +         /* Remove the extra reference count. */
3550 +         release_slot(state, state->rx_info);
3551 +         state->rx_data = NULL;
3552 +      }
3553 +   }
3554 +}
3555 +
3556 +/* Called by the slot handler thread */
3557 +static void *
3558 +slot_handler_func(void *v)
3559 +{
3560 +   VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
3561 +   VCHIQ_SHARED_STATE_T *local = state->local;
3562 +   DEBUG_INITIALISE(local)
3563 +
3564 +   while (1) {
3565 +      DEBUG_COUNT(SLOT_HANDLER_COUNT);
3566 +      DEBUG_TRACE(SLOT_HANDLER_LINE);
3567 +      remote_event_wait(&local->trigger);
3568 +
3569 +      vcos_rmb();
3570 +
3571 +      DEBUG_TRACE(SLOT_HANDLER_LINE);
3572 +      if (state->poll_needed)
3573 +      {
3574 +         state->poll_needed = 0;
3575 +
3576 +         /* Handle service polling and other rare conditions here out
3577 +            of the mainline code */
3578 +         switch (state->conn_state)
3579 +         {
3580 +         case VCHIQ_CONNSTATE_CONNECTED:
3581 +            /* Poll the services as requested */
3582 +            poll_services(state);
3583 +            break;
3584 +
3585 +         case VCHIQ_CONNSTATE_PAUSING:
3586 +            if (queue_message(state, NULL,
3587 +               VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), NULL, 0, 0, 0)
3588 +               != VCHIQ_RETRY)
3589 +            {
3590 +               if (state->is_master)
3591 +                  pause_bulks(state);
3592 +               vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSE_SENT);
3593 +            }
3594 +            else
3595 +            {
3596 +               state->poll_needed = 1; /* Retry later */
3597 +            }
3598 +            break;
3599 +
3600 +         case VCHIQ_CONNSTATE_RESUMING:
3601 +            if (queue_message(state, NULL,
3602 +               VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0), NULL, 0, 0, 0)
3603 +               != VCHIQ_RETRY)
3604 +            {
3605 +               if (state->is_master)
3606 +                  resume_bulks(state);
3607 +               vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
3608 +               vchiq_platform_resumed(state);
3609 +            }
3610 +            else
3611 +            {
3612 +               /* This should really be impossible, since the PAUSE should
3613 +                  have flushed through outstanding messages. */
3614 +               vcos_log_error("Failed to send RESUME message");
3615 +               vcos_demand(0);
3616 +            }
3617 +            break;
3618 +         default:
3619 +            break;
3620 +         }
3621 +      }
3622 +
3623 +      DEBUG_TRACE(SLOT_HANDLER_LINE);
3624 +      parse_rx_slots(state);
3625 +   }
3626 +   return NULL;
3627 +}
3628 +
3629 +extern VCHIQ_STATUS_T
3630 +vchiq_platform_suspend(VCHIQ_STATE_T *state);
3631 +
3632 +/* Called by the recycle thread */
3633 +static void *
3634 +recycle_func(void *v)
3635 +{
3636 +   VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
3637 +   VCHIQ_SHARED_STATE_T *local = state->local;
3638 +
3639 +   while (1) {
3640 +      remote_event_wait(&local->recycle);
3641 +
3642 +      vcos_mutex_lock(&state->slot_mutex);
3643 +
3644 +      process_free_queue(state);
3645 +
3646 +      vcos_mutex_unlock(&state->slot_mutex);
3647 +   }
3648 +   return NULL;
3649 +}
3650 +
3651 +/* Called by the lp thread */
3652 +static void *
3653 +lp_func(void *v)
3654 +{
3655 +   VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
3656 +
3657 +   while (1) {
3658 +      vcos_event_wait(&state->lp_evt);
3659 +      vcos_mutex_lock(&state->use_count_mutex);
3660 +      if (state->videocore_use_count == 0)
3661 +      {
3662 +         vchiq_platform_suspend(state);
3663 +      }
3664 +      vcos_mutex_unlock(&state->use_count_mutex);
3665 +   }
3666 +   return NULL;
3667 +}
3668 +
3669 +static void
3670 +init_bulk_queue(VCHIQ_BULK_QUEUE_T *queue)
3671 +{
3672 +   queue->local_insert = 0;
3673 +   queue->remote_insert = 0;
3674 +   queue->process = 0;
3675 +   queue->remote_notify = 0;
3676 +   queue->remove = 0;
3677 +}
3678 +
3679 +VCHIQ_SLOT_ZERO_T *
3680 +vchiq_init_slots(void *mem_base, int mem_size)
3681 +{
3682 +   int mem_align = (VCHIQ_SLOT_SIZE - (int)mem_base) & VCHIQ_SLOT_MASK;
3683 +   VCHIQ_SLOT_ZERO_T *slot_zero = (VCHIQ_SLOT_ZERO_T *)((char *)mem_base + mem_align);
3684 +   int num_slots = (mem_size - mem_align)/VCHIQ_SLOT_SIZE;
3685 +   int first_data_slot = VCHIQ_SLOT_ZERO_SLOTS;
3686 +
3687 +   /* Ensure there is enough memory to run an absolutely minimum system */
3688 +   num_slots -= first_data_slot;
3689 +
3690 +   if (num_slots < 4)
3691 +   {
3692 +      vcos_log_error("vchiq_init_slots - insufficient memory %x bytes", mem_size);
3693 +      return NULL;
3694 +   }
3695 +
3696 +   memset(slot_zero, 0, sizeof(VCHIQ_SLOT_ZERO_T));
3697 +
3698 +   slot_zero->magic = VCHIQ_MAGIC;
3699 +   slot_zero->version = VCHIQ_VERSION;
3700 +   slot_zero->version_min = VCHIQ_VERSION_MIN;
3701 +   slot_zero->slot_zero_size = sizeof(VCHIQ_SLOT_ZERO_T);
3702 +   slot_zero->slot_size = VCHIQ_SLOT_SIZE;
3703 +   slot_zero->max_slots = VCHIQ_MAX_SLOTS;
3704 +   slot_zero->max_slots_per_side = VCHIQ_MAX_SLOTS_PER_SIDE;
3705 +
3706 +   slot_zero->master.slot_first = first_data_slot;
3707 +   slot_zero->slave.slot_first = first_data_slot + (num_slots/2);
3708 +   slot_zero->master.slot_last = slot_zero->slave.slot_first - 1;
3709 +   slot_zero->slave.slot_last = first_data_slot + num_slots - 1;
3710 +
3711 +   return slot_zero;
3712 +}
3713 +
3714 +VCHIQ_STATUS_T
3715 +vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, int is_master)
3716 +{
3717 +   VCHIQ_SHARED_STATE_T *local;
3718 +   VCHIQ_SHARED_STATE_T *remote;
3719 +   VCOS_THREAD_ATTR_T attrs;
3720 +   char threadname[10];
3721 +   static int id = 0;
3722 +   int i;
3723 +
3724 +   vcos_log_set_level(&vchiq_core_log_category, vchiq_default_core_log_level);
3725 +   vcos_log_set_level(&vchiq_core_msg_log_category, vchiq_default_core_msg_log_level);
3726 +   vcos_log_register("vchiq_core", &vchiq_core_log_category);
3727 +   vcos_log_register("vchiq_core_msg", &vchiq_core_msg_log_category);
3728 +
3729 +   vcos_log_warn( "%s: slot_zero = 0x%08lx, is_master = %d\n", __func__, (unsigned long)slot_zero, is_master );
3730 +
3731 +   /* Check the input configuration */
3732 +
3733 +   if (slot_zero->magic != VCHIQ_MAGIC)
3734 +   {
3735 +      vcos_log_error("slot_zero=%x: magic=%x (expected %x)",
3736 +         (unsigned int)slot_zero, slot_zero->magic, VCHIQ_MAGIC);
3737 +      return VCHIQ_ERROR;
3738 +   }
3739 +
3740 +   if (slot_zero->version < VCHIQ_VERSION_MIN)
3741 +   {
3742 +      vcos_log_error("slot_zero=%x: peer_version=%x (minimum %x)",
3743 +         (unsigned int)slot_zero, slot_zero->version, VCHIQ_VERSION_MIN);
3744 +      return VCHIQ_ERROR;
3745 +   }
3746 +
3747 +   if (VCHIQ_VERSION < slot_zero->version_min)
3748 +   {
3749 +      vcos_log_error("slot_zero=%x: version=%x (peer minimum %x)",
3750 +         (unsigned int)slot_zero, VCHIQ_VERSION, slot_zero->version_min);
3751 +      return VCHIQ_ERROR;
3752 +   }
3753 +
3754 +   if (slot_zero->slot_zero_size != sizeof(VCHIQ_SLOT_ZERO_T))
3755 +   {
3756 +      vcos_log_error("slot_zero=%x: slot_zero_size=%x (expected %x)",
3757 +         (unsigned int)slot_zero, slot_zero->slot_zero_size, sizeof(VCHIQ_SLOT_ZERO_T));
3758 +      return VCHIQ_ERROR;
3759 +   }
3760 +
3761 +   if (slot_zero->slot_size != VCHIQ_SLOT_SIZE)
3762 +   {
3763 +      vcos_log_error("slot_zero=%x: slot_size=%d (expected %d",
3764 +         (unsigned int)slot_zero, slot_zero->slot_size, VCHIQ_SLOT_SIZE);
3765 +      return VCHIQ_ERROR;
3766 +   }
3767 +
3768 +   if (slot_zero->max_slots != VCHIQ_MAX_SLOTS)
3769 +   {
3770 +      vcos_log_error("slot_zero=%x: max_slots=%d (expected %d)",
3771 +         (unsigned int)slot_zero, slot_zero->max_slots, VCHIQ_MAX_SLOTS);
3772 +      return VCHIQ_ERROR;
3773 +   }
3774 +
3775 +   if (slot_zero->max_slots_per_side != VCHIQ_MAX_SLOTS_PER_SIDE)
3776 +   {
3777 +      vcos_log_error("slot_zero=%x: max_slots_per_side=%d (expected %d)",
3778 +         (unsigned int)slot_zero, slot_zero->max_slots_per_side,
3779 +         VCHIQ_MAX_SLOTS_PER_SIDE);
3780 +      return VCHIQ_ERROR;
3781 +   }
3782 +
3783 +   if (is_master)
3784 +   {
3785 +      local = &slot_zero->master;
3786 +      remote = &slot_zero->slave;
3787 +   }
3788 +   else
3789 +   {
3790 +      local = &slot_zero->slave;
3791 +      remote = &slot_zero->master;
3792 +   }
3793 +
3794 +   if (local->initialised)
3795 +   {
3796 +      if (remote->initialised)
3797 +         vcos_log_error("vchiq: FATAL: local state has already been initialised");
3798 +      else
3799 +         vcos_log_error("vchiq: FATAL: master/slave mismatch - two %ss", is_master ? "master" : "slave");
3800 +      return VCHIQ_ERROR;
3801 +   }
3802 +
3803 +   memset(state, 0, sizeof(VCHIQ_STATE_T));
3804 +   state->id = id++;
3805 +   state->is_master = is_master;
3806 +
3807 +   /*
3808 +      initialize shared state pointers
3809 +    */
3810 +
3811 +   state->local = local;
3812 +   state->remote = remote;
3813 +   state->slot_data = (VCHIQ_SLOT_T *)slot_zero;
3814 +
3815 +   /*
3816 +      initialize events and mutexes
3817 +    */
3818 +
3819 +   vcos_event_create(&state->connect, "v.connect");
3820 +   vcos_mutex_create(&state->mutex, "v.mutex");
3821 +   vcos_event_create(&state->trigger_event, "v.trigger_event");
3822 +   vcos_event_create(&state->recycle_event, "v.recycle_event");
3823 +
3824 +   vcos_mutex_create(&state->slot_mutex, "v.slot_mutex");
3825 +   vcos_mutex_create(&state->recycle_mutex, "v.recycle_mutex");
3826 +   vcos_mutex_create(&state->use_count_mutex, "v.use_count_mutex");
3827 +   vcos_mutex_create(&state->suspend_resume_mutex, "v.susp_res_mutex");
3828 +
3829 +   vcos_event_create(&state->slot_available_event, "v.slot_available_event");
3830 +   vcos_event_create(&state->slot_remove_event, "v.slot_remove_event");
3831 +
3832 +   state->slot_queue_available = 0;
3833 +
3834 +   for (i = 0; i < VCHIQ_MAX_SERVICES; i++)
3835 +   {
3836 +      VCHIQ_SERVICE_QUOTA_T *service_quota = &state->service_quotas[i];
3837 +      vcos_event_create(&service_quota->quota_event, "v.quota_event");
3838 +   }
3839 +
3840 +   for (i = local->slot_first; i <= local->slot_last; i++)
3841 +   {
3842 +      local->slot_queue[state->slot_queue_available++] = i;
3843 +   }
3844 +
3845 +   state->default_slot_quota = state->slot_queue_available/2;
3846 +
3847 +   local->trigger.event = &state->trigger_event;
3848 +   remote_event_create(&local->trigger);
3849 +   local->tx_pos = 0;
3850 +
3851 +   local->recycle.event = &state->recycle_event;
3852 +   remote_event_create(&local->recycle);
3853 +   local->slot_queue_recycle = state->slot_queue_available;
3854 +
3855 +   vcos_event_create(&state->lp_evt, "LP_EVT");
3856 +
3857 +   local->debug[DEBUG_ENTRIES] = DEBUG_MAX;
3858 +
3859 +   /*
3860 +      bring up slot handler thread
3861 +    */
3862 +
3863 +   vcos_thread_attr_init(&attrs);
3864 +   vcos_thread_attr_setstacksize(&attrs, VCHIQ_SLOT_HANDLER_STACK);
3865 +   vcos_thread_attr_setpriority(&attrs, VCOS_THREAD_PRI_REALTIME);
3866 +   vcos_snprintf(threadname, sizeof(threadname), "VCHIQ-%d", state->id);
3867 +   if (vcos_thread_create(&state->slot_handler_thread, threadname,
3868 +            &attrs, slot_handler_func, state) != VCOS_SUCCESS)
3869 +      return VCHIQ_ERROR;
3870 +
3871 +   vcos_thread_attr_init(&attrs);
3872 +   vcos_thread_attr_setstacksize(&attrs, VCHIQ_SLOT_HANDLER_STACK);
3873 +   vcos_thread_attr_setpriority(&attrs, VCOS_THREAD_PRI_REALTIME);
3874 +   vcos_snprintf(threadname, sizeof(threadname), "VCHIQr-%d", state->id);
3875 +   if (vcos_thread_create(&state->recycle_thread, threadname,
3876 +            &attrs, recycle_func, state) != VCOS_SUCCESS)
3877 +      return VCHIQ_ERROR;
3878 +
3879 +   vcos_thread_attr_init(&attrs);
3880 +   vcos_thread_attr_setstacksize(&attrs, VCHIQ_SLOT_HANDLER_STACK);
3881 +   vcos_thread_attr_setpriority(&attrs, VCOS_THREAD_PRI_LOWEST);
3882 +   vcos_snprintf(threadname, sizeof(threadname), "VCHIQl-%d", state->id);
3883 +   if (vcos_thread_create(&state->lp_thread, threadname,
3884 +            &attrs, lp_func, state) != VCOS_SUCCESS)
3885 +      return VCHIQ_ERROR;
3886 +
3887 +   /* Indicate readiness to the other side */
3888 +   local->initialised = 1;
3889 +
3890 +   return VCHIQ_SUCCESS;
3891 +}
3892 +
3893 +/* Called from application thread when a client or server service is created. */
3894 +VCHIQ_SERVICE_T *
3895 +vchiq_add_service_internal(VCHIQ_STATE_T *state,
3896 +   const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
3897 +   VCHIQ_INSTANCE_T instance)
3898 +{
3899 +   VCHIQ_SERVICE_T **pservice = NULL;
3900 +   VCHIQ_SERVICE_T *service = NULL;
3901 +   int i;
3902 +
3903 +   /* Prepare to use a previously unused service */
3904 +   if (state->unused_service < VCHIQ_MAX_SERVICES)
3905 +   {
3906 +      pservice = &state->services[state->unused_service];
3907 +   }
3908 +
3909 +   if (srvstate == VCHIQ_SRVSTATE_OPENING) {
3910 +      for (i = 0; i < state->unused_service; i++) {
3911 +         VCHIQ_SERVICE_T *srv = state->services[i];
3912 +         if (!srv)
3913 +         {
3914 +            pservice = &state->services[i];
3915 +            break;
3916 +         }
3917 +         if (srv->srvstate == VCHIQ_SRVSTATE_FREE) {
3918 +            service = srv;
3919 +            break;
3920 +         }
3921 +      }
3922 +   } else {
3923 +      for (i = (state->unused_service - 1); i >= 0; i--) {
3924 +         VCHIQ_SERVICE_T *srv = state->services[i];
3925 +         if (!srv)
3926 +            pservice = &state->services[i];
3927 +         else if (srv->srvstate == VCHIQ_SRVSTATE_FREE) {
3928 +            service = srv;
3929 +         } else if ((srv->public_fourcc == params->fourcc) &&
3930 +            ((srv->instance != instance)
3931 +            || (srv->base.callback != params->callback))) {
3932 +            /* There is another server using this fourcc which doesn't match */
3933 +            pservice = NULL;
3934 +            service = NULL;
3935 +         }
3936 +      }
3937 +   }
3938 +
3939 +   if (pservice && !service)
3940 +   {
3941 +      service = vcos_malloc(sizeof(VCHIQ_SERVICE_T), "VCHIQ service");
3942 +      if (service)
3943 +      {
3944 +         service->srvstate = VCHIQ_SRVSTATE_FREE;
3945 +         service->localport = (pservice - state->services);
3946 +         vcos_event_create(&service->remove_event, "v.remove_event");
3947 +         vcos_event_create(&service->bulk_remove_event, "v.bulk_remove_event");
3948 +         vcos_mutex_create(&service->bulk_mutex, "v.bulk_mutex");
3949 +         *pservice = service;
3950 +      }
3951 +      else
3952 +      {
3953 +         vcos_log_error("vchiq: Out of memory");
3954 +      }
3955 +   }
3956 +
3957 +   if (service) {
3958 +      VCHIQ_SERVICE_QUOTA_T *service_quota =
3959 +         &state->service_quotas[service->localport];
3960 +      if (vcos_is_log_enabled( &vchiq_core_msg_log_category, VCOS_LOG_INFO)) {
3961 +         vcos_log_impl( &vchiq_core_msg_log_category,
3962 +                     VCOS_LOG_INFO,
3963 +                     "%s Service %c%c%c%c SrcPort:%d",
3964 +                     ( srvstate == VCHIQ_SRVSTATE_OPENING )
3965 +                     ? "Open" : "Add",
3966 +                     VCHIQ_FOURCC_AS_4CHARS(params->fourcc),
3967 +                     service->localport );
3968 +      }
3969 +      service->state = state;
3970 +      service->base.fourcc   = params->fourcc;
3971 +      service->base.callback = params->callback;
3972 +      service->base.userdata = params->userdata;
3973 +      service->version       = params->version;
3974 +      service->version_min   = params->version_min;
3975 +      vchiq_set_service_state(service, srvstate);
3976 +      service->public_fourcc =
3977 +         (srvstate ==
3978 +         VCHIQ_SRVSTATE_OPENING) ? VCHIQ_FOURCC_INVALID : params->fourcc;
3979 +      service->instance = instance;
3980 +      service->remoteport = VCHIQ_PORT_FREE;
3981 +      service->client_id = 0;
3982 +      service->auto_close = 1;
3983 +      service->service_use_count = 0;
3984 +      init_bulk_queue(&service->bulk_tx);
3985 +      init_bulk_queue(&service->bulk_rx);
3986 +      service_quota->slot_quota = state->default_slot_quota;
3987 +      if (service_quota->slot_use_count == 0)
3988 +         service_quota->previous_tx_index =
3989 +            SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos) - 1;
3990 +      memset(&service->stats, 0, sizeof(service->stats));
3991 +      vcos_atomic_flags_create(&service->poll_flags);
3992 +
3993 +      /* Ensure the events are unsignalled */
3994 +      while (vcos_event_try(&service->remove_event) == VCOS_SUCCESS)
3995 +         continue;
3996 +      while (vcos_event_try(&service_quota->quota_event) == VCOS_SUCCESS)
3997 +         continue;
3998 +
3999 +      if (pservice == &state->services[state->unused_service])
4000 +         state->unused_service++;
4001 +   }
4002 +
4003 +   return service;
4004 +}
4005 +
4006 +VCHIQ_STATUS_T
4007 +vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id)
4008 +{
4009 +   VCHIQ_OPEN_PAYLOAD_T payload = {
4010 +      service->base.fourcc,
4011 +      client_id,
4012 +      service->version,
4013 +      service->version_min
4014 +   };
4015 +   VCHIQ_ELEMENT_T body = { &payload, sizeof(payload) };
4016 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4017 +
4018 +   service->client_id = client_id;
4019 +   vchiq_use_service(&service->base);
4020 +   status = queue_message(service->state, NULL,
4021 +                     VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0),
4022 +                     &body, 1, sizeof(payload), 1);
4023 +   if (status == VCHIQ_SUCCESS) {
4024 +      if (vcos_event_wait(&service->remove_event) != VCOS_SUCCESS) {
4025 +         status = VCHIQ_RETRY;
4026 +         vchiq_release_service(&service->base);
4027 +      } else if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
4028 +         vcos_log_info("%d: osi - srvstate = %d", service->state->id, service->srvstate);
4029 +         vcos_assert(service->srvstate == VCHIQ_SRVSTATE_CLOSEWAIT);
4030 +         status = VCHIQ_ERROR;
4031 +         VCHIQ_SERVICE_STATS_INC(service, error_count);
4032 +         vchiq_release_service(&service->base);
4033 +      }
4034 +   }
4035 +   return status;
4036 +}
4037 +
4038 +/* Called by the slot handler */
4039 +VCHIQ_STATUS_T
4040 +vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd)
4041 +{
4042 +   VCHIQ_STATE_T *state = service->state;
4043 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4044 +
4045 +   vcos_log_trace("%d: csi:%d (%s)",
4046 +      service->state->id, service->localport,
4047 +      srvstate_names[service->srvstate]);
4048 +
4049 +   switch (service->srvstate)
4050 +   {
4051 +   case VCHIQ_SRVSTATE_OPENING:
4052 +      if (close_recvd)
4053 +      {
4054 +         /* The open was rejected - tell the user */
4055 +         vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSEWAIT);
4056 +         vcos_event_signal(&service->remove_event);
4057 +      }
4058 +      else
4059 +      {
4060 +         /* Shutdown mid-open - let the other side know */
4061 +         status = queue_message(state, NULL,
4062 +            VCHIQ_MAKE_MSG
4063 +            (VCHIQ_MSG_CLOSE,
4064 +            service->localport,
4065 +            VCHIQ_MSG_DSTPORT(service->remoteport)),
4066 +            NULL, 0, 0, 0);
4067 +
4068 +         if (status == VCHIQ_SUCCESS)
4069 +            vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
4070 +      }
4071 +      break;
4072 +
4073 +   case VCHIQ_SRVSTATE_OPEN:
4074 +      if (state->is_master)
4075 +      {
4076 +         /* Abort any outstanding bulk transfers */
4077 +         vcos_mutex_lock(&service->bulk_mutex);
4078 +         abort_outstanding_bulks(service, &service->bulk_tx);
4079 +         abort_outstanding_bulks(service, &service->bulk_rx);
4080 +         status = notify_bulks(service, &service->bulk_tx);
4081 +         if (status == VCHIQ_SUCCESS)
4082 +            status = notify_bulks(service, &service->bulk_rx);
4083 +         vcos_mutex_unlock(&service->bulk_mutex);
4084 +      }
4085 +
4086 +      if (status == VCHIQ_SUCCESS)
4087 +         status = queue_message(state, NULL,
4088 +            VCHIQ_MAKE_MSG
4089 +            (VCHIQ_MSG_CLOSE,
4090 +            service->localport,
4091 +            VCHIQ_MSG_DSTPORT(service->remoteport)),
4092 +            NULL, 0, 0, 0);
4093 +
4094 +      if (status == VCHIQ_SUCCESS)
4095 +      {
4096 +         if (close_recvd)
4097 +            vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSING);
4098 +         else
4099 +            vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
4100 +      }
4101 +      break;
4102 +
4103 +   case VCHIQ_SRVSTATE_CLOSESENT:
4104 +      vcos_assert(close_recvd);
4105 +
4106 +      if (!state->is_master)
4107 +      {
4108 +         /* Abort any outstanding bulk transfers */
4109 +         vcos_mutex_lock(&service->bulk_mutex);
4110 +         abort_outstanding_bulks(service, &service->bulk_tx);
4111 +         abort_outstanding_bulks(service, &service->bulk_rx);
4112 +         status = notify_bulks(service, &service->bulk_tx);
4113 +         if (status == VCHIQ_SUCCESS)
4114 +            status = notify_bulks(service, &service->bulk_rx);
4115 +         vcos_mutex_unlock(&service->bulk_mutex);
4116 +      }
4117 +
4118 +      if (status == VCHIQ_SUCCESS)
4119 +         vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSING);
4120 +      break;
4121 +
4122 +   case VCHIQ_SRVSTATE_CLOSING:
4123 +      /* We may come here after a retry */
4124 +      vcos_assert(!close_recvd);
4125 +      break;
4126 +
4127 +   default:
4128 +      vcos_log_error("vchiq_close_service_internal(%d) called in state %s",
4129 +         close_recvd, srvstate_names[service->srvstate]);
4130 +      vcos_assert(0);
4131 +      break;
4132 +   }
4133 +
4134 +   if (service->srvstate == VCHIQ_SRVSTATE_CLOSING)
4135 +   {
4136 +      /* Complete the close process */
4137 +      vchiq_release_service(&service->base);
4138 +
4139 +      service->client_id = 0;
4140 +
4141 +      /* Now tell the client that the services is closed */
4142 +      if (service->instance)
4143 +      {
4144 +         int oldstate = service->srvstate;
4145 +
4146 +         /* Change the service state now for the benefit of the callback */
4147 +         vchiq_set_service_state(service,
4148 +            ((service->public_fourcc == VCHIQ_FOURCC_INVALID) ||
4149 +            !service->auto_close) ?
4150 +            VCHIQ_SRVSTATE_CLOSEWAIT :
4151 +            VCHIQ_SRVSTATE_LISTENING);
4152 +
4153 +         status = make_service_callback(service, VCHIQ_SERVICE_CLOSED, NULL, NULL);
4154 +
4155 +         if (status == VCHIQ_RETRY)
4156 +         {
4157 +            /* Restore the old state, to be retried later */
4158 +            vchiq_set_service_state(service, oldstate);
4159 +         }
4160 +         else
4161 +         {
4162 +            if (status == VCHIQ_ERROR) {
4163 +               /* Signal an error (fatal, since the other end will probably have closed) */
4164 +               vchiq_set_service_state(service, VCHIQ_SRVSTATE_OPEN);
4165 +            }
4166 +         }
4167 +      }
4168 +
4169 +      if (status != VCHIQ_RETRY)
4170 +      {
4171 +         if (service->srvstate == VCHIQ_SRVSTATE_CLOSING)
4172 +            vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSEWAIT);
4173 +         vcos_event_signal(&service->remove_event);
4174 +      }
4175 +   }
4176 +
4177 +   return status;
4178 +}
4179 +
4180 +/* Called from the application process upon process death */
4181 +void
4182 +vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service)
4183 +{
4184 +   VCHIQ_STATE_T *state = service->state;
4185 +
4186 +   vcos_log_info("%d: tsi - (%d<->%d)", state->id, service->localport, service->remoteport);
4187 +
4188 +   /* Disconnect from the instance, to prevent any callbacks */
4189 +   service->instance = NULL;
4190 +
4191 +   /* Mark the service for termination by the slot handler */
4192 +   request_poll(state, service, VCHIQ_POLL_TERMINATE);
4193 +}
4194 +
4195 +/* Called from the application process upon process death, and from
4196 +   vchiq_remove_service */
4197 +void
4198 +vchiq_free_service_internal(VCHIQ_SERVICE_T *service)
4199 +{
4200 +   VCHIQ_STATE_T *state = service->state;
4201 +   int slot_last = state->remote->slot_last;
4202 +   int i;
4203 +
4204 +   vcos_log_info("%d: fsi - (%d)", state->id, service->localport);
4205 +
4206 +   vcos_mutex_lock(&state->mutex);
4207 +
4208 +   /* Release any claimed messages */
4209 +   for (i = state->remote->slot_first; i <= slot_last; i++)
4210 +   {
4211 +      VCHIQ_SLOT_INFO_T *slot_info = SLOT_INFO_FROM_INDEX(state, i);
4212 +      if (slot_info->release_count != slot_info->use_count)
4213 +      {
4214 +         char *data = (char *)SLOT_DATA_FROM_INDEX(state, i);
4215 +         int pos, end;
4216 +
4217 +         end = VCHIQ_SLOT_SIZE;
4218 +         if (data == state->rx_data)
4219 +         {
4220 +            /* This buffer is still being read from - stop at the current read position */
4221 +            end = state->rx_pos & VCHIQ_SLOT_MASK;
4222 +         }
4223 +
4224 +         pos = 0;
4225 +
4226 +         while (pos < end)
4227 +         {
4228 +            VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)(data + pos);
4229 +            int msgid = header->msgid;
4230 +            int port = VCHIQ_MSG_DSTPORT(msgid);
4231 +            if (port == service->localport)
4232 +            {
4233 +               if (msgid & VCHIQ_MSGID_CLAIMED)
4234 +               {
4235 +                  header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
4236 +                  vcos_log_info("  fsi - hdr %x", (unsigned int)header);
4237 +                  release_slot(state, slot_info);
4238 +               }
4239 +            }
4240 +            pos += calc_stride(header->size);
4241 +         }
4242 +      }
4243 +   }
4244 +
4245 +   vcos_assert(state->services[service->localport] == service);
4246 +   vchiq_set_service_state(service, VCHIQ_SRVSTATE_FREE);
4247 +   state->services[service->localport] = NULL;
4248 +   vcos_free(service);
4249 +   vcos_mutex_unlock(&state->mutex);
4250 +}
4251 +
4252 +VCHIQ_STATUS_T
4253 +vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
4254 +{
4255 +   int i;
4256 +
4257 +   /* Find all services registered to this client and enable them. */
4258 +   for (i = 0; i < state->unused_service; i++)
4259 +   {
4260 +      VCHIQ_SERVICE_T *service = state->services[i];
4261 +      if (service && (service->instance == instance)) {
4262 +         if (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)
4263 +            vchiq_set_service_state(service,
4264 +               VCHIQ_SRVSTATE_LISTENING);
4265 +      }
4266 +   }
4267 +
4268 +   if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) {
4269 +      if (queue_message(state, NULL,
4270 +         VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0,
4271 +         0, 1) == VCHIQ_RETRY)
4272 +         return VCHIQ_RETRY;
4273 +      vcos_event_wait(&state->connect);
4274 +
4275 +      vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
4276 +   }
4277 +
4278 +   return VCHIQ_SUCCESS;
4279 +}
4280 +
4281 +VCHIQ_STATUS_T
4282 +vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance)
4283 +{
4284 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4285 +   int i;
4286 +
4287 +   /* Find all services registered to this client and close them. */
4288 +   for (i = 0; i < state->unused_service; i++)
4289 +   {
4290 +      VCHIQ_SERVICE_T *service = state->services[i];
4291 +      if (service && (service->instance == instance) &&
4292 +         ((service->srvstate == VCHIQ_SRVSTATE_OPEN) ||
4293 +         (service->srvstate == VCHIQ_SRVSTATE_LISTENING)))
4294 +      {
4295 +         status = vchiq_remove_service(&service->base);
4296 +         if (status != VCHIQ_SUCCESS)
4297 +            break;
4298 +      }
4299 +   }
4300 +
4301 +   return status;
4302 +}
4303 +
4304 +VCHIQ_STATUS_T
4305 +vchiq_pause_internal(VCHIQ_STATE_T *state)
4306 +{
4307 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4308 +
4309 +   switch (state->conn_state)
4310 +   {
4311 +   case VCHIQ_CONNSTATE_CONNECTED:
4312 +      /* Request a pause */
4313 +      vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSING);
4314 +      request_poll(state, NULL, 0);
4315 +      break;
4316 +   case VCHIQ_CONNSTATE_PAUSED:
4317 +      break;
4318 +   default:
4319 +      status = VCHIQ_ERROR;
4320 +      VCHIQ_STATS_INC(state, error_count);
4321 +      break;
4322 +   }
4323 +
4324 +   return status;
4325 +}
4326 +
4327 +VCHIQ_STATUS_T
4328 +vchiq_resume_internal(VCHIQ_STATE_T *state)
4329 +{
4330 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4331 +
4332 +   if (state->conn_state == VCHIQ_CONNSTATE_PAUSED)
4333 +   {
4334 +      vchiq_set_conn_state(state, VCHIQ_CONNSTATE_RESUMING);
4335 +      request_poll(state, NULL, 0);
4336 +   }
4337 +   else
4338 +   {
4339 +      status = VCHIQ_ERROR;
4340 +      VCHIQ_STATS_INC(state, error_count);
4341 +   }
4342 +
4343 +   return status;
4344 +}
4345 +
4346 +VCHIQ_STATUS_T
4347 +vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
4348 +{
4349 +   /* Unregister the service */
4350 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *) handle;
4351 +   VCHIQ_STATUS_T status = VCHIQ_ERROR;
4352 +
4353 +   if (service == NULL)
4354 +      return VCHIQ_ERROR;
4355 +
4356 +   vcos_log_info("%d: close_service:%d", service->state->id, service->localport);
4357 +
4358 +   if (service->public_fourcc != VCHIQ_FOURCC_INVALID)
4359 +   {
4360 +      if (service->srvstate == VCHIQ_SRVSTATE_CLOSEWAIT)
4361 +      {
4362 +         /* This is a non-auto-close server */
4363 +         vchiq_set_service_state(service, VCHIQ_SRVSTATE_LISTENING);
4364 +         status = VCHIQ_SUCCESS;
4365 +      }
4366 +   }
4367 +   else
4368 +   {
4369 +      /* For clients, make it an alias of vchiq_remove_service */
4370 +      status = vchiq_remove_service(handle);
4371 +   }
4372 +
4373 +   return status;
4374 +}
4375 +
4376 +VCHIQ_STATUS_T
4377 +vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
4378 +{
4379 +   /* Unregister the service */
4380 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *) handle;
4381 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
4382 +
4383 +   if (service == NULL)
4384 +      return VCHIQ_ERROR;
4385 +
4386 +   vcos_log_info("%d: remove_service:%d", service->state->id, service->localport);
4387 +
4388 +   switch (service->srvstate)
4389 +   {
4390 +   case VCHIQ_SRVSTATE_OPENING:
4391 +   case VCHIQ_SRVSTATE_OPEN:
4392 +      /* Mark the service for termination by the slot handler */
4393 +      request_poll(service->state, service, VCHIQ_POLL_TERMINATE);
4394 +
4395 +      /* Drop through... */
4396 +   case VCHIQ_SRVSTATE_CLOSESENT:
4397 +   case VCHIQ_SRVSTATE_CLOSING:
4398 +      while ((service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) &&
4399 +         (service->srvstate != VCHIQ_SRVSTATE_LISTENING))
4400 +      {
4401 +         if (vcos_event_wait(&service->remove_event) != VCOS_SUCCESS) {
4402 +            status = VCHIQ_RETRY;
4403 +            break;
4404 +         }
4405 +      }
4406 +      break;
4407 +
4408 +   default:
4409 +      break;
4410 +   }
4411 +
4412 +   if (status == VCHIQ_SUCCESS) {
4413 +      if (service->srvstate == VCHIQ_SRVSTATE_OPEN)
4414 +         status = VCHIQ_ERROR;
4415 +      else
4416 +      {
4417 +         service->instance = NULL;
4418 +         vchiq_free_service_internal(service);
4419 +      }
4420 +   }
4421 +
4422 +   return status;
4423 +}
4424 +
4425 +
4426 +VCHIQ_STATUS_T
4427 +vchiq_bulk_transfer(VCHIQ_SERVICE_T *service,
4428 +   VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
4429 +   VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir)
4430 +{
4431 +   VCHIQ_BULK_QUEUE_T *queue = (dir == VCHIQ_BULK_TRANSMIT) ?
4432 +      &service->bulk_tx : &service->bulk_rx;
4433 +   VCHIQ_BULK_T *bulk;
4434 +   VCHIQ_STATE_T *state;
4435 +   BULK_WAITER_T bulk_waiter;
4436 +   const char dir_char = (dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r';
4437 +   const int dir_msgtype = (dir == VCHIQ_BULK_TRANSMIT) ? VCHIQ_MSG_BULK_TX : VCHIQ_MSG_BULK_RX;
4438 +   VCHIQ_STATUS_T status = VCHIQ_ERROR;
4439 +
4440 +   if ((service == NULL) ||
4441 +       ((memhandle == VCHI_MEM_HANDLE_INVALID) && (offset == NULL)))
4442 +      return VCHIQ_ERROR;
4443 +
4444 +   state = service->state;
4445 +
4446 +   if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
4447 +      return VCHIQ_ERROR;  /* Must be connected */
4448 +
4449 +   if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
4450 +      return VCHIQ_RETRY;
4451 +
4452 +   if (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS)
4453 +   {
4454 +      VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
4455 +      do {
4456 +         vcos_mutex_unlock(&service->bulk_mutex);
4457 +         if (vcos_event_wait(&service->bulk_remove_event) != VCOS_SUCCESS)
4458 +            return VCHIQ_RETRY;
4459 +         if (vcos_mutex_lock(&service->bulk_mutex) != VCOS_SUCCESS)
4460 +            return VCHIQ_RETRY;
4461 +      } while (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS);
4462 +   }
4463 +
4464 +   bulk = &queue->bulks[BULK_INDEX(queue->local_insert)];
4465 +
4466 +   if (mode == VCHIQ_BULK_MODE_BLOCKING)
4467 +   {
4468 +      vcos_event_create(&bulk_waiter.event, "bulk_waiter");
4469 +      bulk_waiter.actual = 0;
4470 +      userdata = &bulk_waiter;
4471 +   }
4472 +
4473 +   bulk->mode = mode;
4474 +   bulk->dir = dir;
4475 +   bulk->userdata = userdata;
4476 +   bulk->size = size;
4477 +   bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
4478 +
4479 +   if (vchiq_prepare_bulk_data(bulk, memhandle, offset, size, dir) != VCHIQ_SUCCESS)
4480 +   {
4481 +      goto error_exit;
4482 +   }
4483 +
4484 +   vcos_log_info("%d: bt (%d->%d) %cx %x@%x %x", state->id,
4485 +      service->localport, service->remoteport, dir_char,
4486 +      size, (unsigned int)bulk->data, (unsigned int)userdata);
4487 +
4488 +   if (state->is_master)
4489 +   {
4490 +      queue->local_insert++;
4491 +      if (resolve_bulks(service, queue))
4492 +         request_poll(state, service, (dir == VCHIQ_BULK_TRANSMIT) ?
4493 +            VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
4494 +   }
4495 +   else
4496 +   {
4497 +      int payload[2] = { (int)bulk->data, bulk->size };
4498 +      VCHIQ_ELEMENT_T element = { payload, sizeof(payload) };
4499 +
4500 +      if (queue_message(state, NULL,
4501 +         VCHIQ_MAKE_MSG(dir_msgtype,
4502 +            service->localport, service->remoteport),
4503 +         &element, 1, sizeof(payload), 1) != VCHIQ_SUCCESS)
4504 +      {
4505 +         vchiq_complete_bulk(bulk);
4506 +         goto error_exit;
4507 +      }
4508 +      queue->local_insert++;
4509 +      queue->remote_insert++;
4510 +   }
4511 +
4512 +   vcos_mutex_unlock(&service->bulk_mutex);
4513
4514 +   vcos_log_trace("%d: bt:%d %cx li=%x ri=%x p=%x", state->id,
4515 +      service->localport, dir_char,
4516 +      queue->local_insert, queue->remote_insert, queue->process);
4517 +
4518 +   status = VCHIQ_SUCCESS;
4519 +
4520 +   if (mode == VCHIQ_BULK_MODE_BLOCKING)
4521 +   {
4522 +      if (vcos_event_wait(&bulk_waiter.event) != VCOS_SUCCESS)
4523 +      {
4524 +         vcos_log_info("bulk wait interrupted");
4525 +         /* Stop notify_bulks signalling a non-existent waiter */
4526 +         bulk->userdata = NULL;
4527 +         status = VCHIQ_ERROR;
4528 +      }
4529 +      else if (bulk_waiter.actual == VCHIQ_BULK_ACTUAL_ABORTED)
4530 +         status = VCHIQ_ERROR;
4531 +
4532 +      vcos_event_delete(&bulk_waiter.event);
4533 +   }
4534 +
4535 +   return status;
4536 +
4537 +error_exit:
4538 +   if (mode == VCHIQ_BULK_MODE_BLOCKING)
4539 +      vcos_event_delete(&bulk_waiter.event);
4540 +   vcos_mutex_unlock(&service->bulk_mutex);
4541 +
4542 +   return status;
4543 +}
4544 +
4545 +VCHIQ_STATUS_T
4546 +vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
4547 +   const void *data, int size, void *userdata)
4548 +{
4549 +   return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4550 +      VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
4551 +      VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
4552 +}
4553 +
4554 +VCHIQ_STATUS_T
4555 +vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, int size,
4556 +   void *userdata)
4557 +{
4558 +   return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4559 +      VCHI_MEM_HANDLE_INVALID, data, size, userdata,
4560 +      VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
4561 +}
4562 +
4563 +VCHIQ_STATUS_T
4564 +vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
4565 +   VCHI_MEM_HANDLE_T memhandle, const void *offset, int size, void *userdata)
4566 +{
4567 +   return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4568 +      memhandle, (void *)offset, size, userdata,
4569 +      VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
4570 +}
4571 +
4572 +VCHIQ_STATUS_T
4573 +vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
4574 +   VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata)
4575 +{
4576 +   return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4577 +      memhandle, offset, size, userdata,
4578 +      VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
4579 +}
4580 +
4581 +VCHIQ_STATUS_T
4582 +vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, int size,
4583 +   void *userdata, VCHIQ_BULK_MODE_T mode)
4584 +{
4585 +   return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4586 +      VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
4587 +      mode, VCHIQ_BULK_TRANSMIT);
4588 +}
4589 +
4590 +VCHIQ_STATUS_T
4591 +vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, int size,
4592 +   void *userdata, VCHIQ_BULK_MODE_T mode)
4593 +{
4594 +   return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4595 +      VCHI_MEM_HANDLE_INVALID, data, size, userdata,
4596 +      mode, VCHIQ_BULK_RECEIVE);
4597 +}
4598 +
4599 +VCHIQ_STATUS_T
4600 +vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
4601 +   VCHI_MEM_HANDLE_T memhandle, const void *offset, int size, void *userdata,
4602 +   VCHIQ_BULK_MODE_T mode)
4603 +{
4604 +   return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4605 +      memhandle, (void *)offset, size, userdata,
4606 +      mode, VCHIQ_BULK_TRANSMIT);
4607 +}
4608 +
4609 +VCHIQ_STATUS_T
4610 +vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
4611 +   VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
4612 +   VCHIQ_BULK_MODE_T mode)
4613 +{
4614 +   return vchiq_bulk_transfer((VCHIQ_SERVICE_T *)handle,
4615 +      memhandle, offset, size, userdata,
4616 +      mode, VCHIQ_BULK_RECEIVE);
4617 +}
4618 +
4619 +VCHIQ_STATUS_T
4620 +vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
4621 +   const VCHIQ_ELEMENT_T *elements, int count)
4622 +{
4623 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *) handle;
4624 +
4625 +   unsigned int size = 0;
4626 +   unsigned int i;
4627 +
4628 +   if ((service == NULL) ||
4629 +      (service->srvstate != VCHIQ_SRVSTATE_OPEN))
4630 +      return VCHIQ_ERROR;
4631 +
4632 +   for (i = 0; i < (unsigned int)count; i++)
4633 +   {
4634 +      if (elements[i].size)
4635 +      {
4636 +         if (elements[i].data == NULL)
4637 +         {
4638 +            VCHIQ_SERVICE_STATS_INC(service, error_count);
4639 +            return VCHIQ_ERROR;
4640 +         }
4641 +         size += elements[i].size;
4642 +      }
4643 +   }
4644 +
4645 +   if (size > VCHIQ_MAX_MSG_SIZE)
4646 +   {
4647 +      VCHIQ_SERVICE_STATS_INC(service, error_count);
4648 +      return VCHIQ_ERROR;
4649 +   }
4650 +
4651 +   return queue_message(service->state, service,
4652 +            VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA, service->localport,
4653 +               service->remoteport), elements, count, size, 1);
4654 +}
4655 +
4656 +void
4657 +vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle, VCHIQ_HEADER_T *header)
4658 +{
4659 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
4660 +   VCHIQ_STATE_T *state;
4661 +   int slot_index;
4662 +   int msgid;
4663 +
4664 +   if (service == NULL)
4665 +      return;
4666 +
4667 +   state = service->state;
4668 +
4669 +   slot_index = SLOT_INDEX_FROM_DATA(state, (void *)header);
4670 +
4671 +   if ((slot_index >= state->remote->slot_first) &&
4672 +      (slot_index <= state->remote->slot_last) &&
4673 +      ((msgid = header->msgid) & VCHIQ_MSGID_CLAIMED))
4674 +   {
4675 +      VCHIQ_SLOT_INFO_T *slot_info = SLOT_INFO_FROM_INDEX(state, slot_index);
4676 +
4677 +      /* Rewrite the message header to prevent a double release */
4678 +      header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
4679 +
4680 +      release_slot(state, slot_info);
4681 +   }
4682 +}
4683 +
4684 +int
4685 +vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
4686 +{
4687 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
4688 +   return service ? service->client_id : 0;
4689 +}
4690 +
4691 +VCHIQ_STATUS_T
4692 +vchiq_get_config(VCHIQ_INSTANCE_T instance,
4693 +   int config_size, VCHIQ_CONFIG_T *pconfig)
4694 +{
4695 +   VCHIQ_CONFIG_T config;
4696 +
4697 +   vcos_unused(instance);
4698 +
4699 +   config.max_msg_size           = VCHIQ_MAX_MSG_SIZE;
4700 +   config.bulk_threshold         = VCHIQ_MAX_MSG_SIZE;
4701 +   config.max_outstanding_bulks  = VCHIQ_NUM_SERVICE_BULKS;
4702 +   config.max_services           = VCHIQ_MAX_SERVICES;
4703 +   config.version                = VCHIQ_VERSION;
4704 +   config.version_min            = VCHIQ_VERSION_MIN;
4705 +
4706 +   if (config_size > sizeof(VCHIQ_CONFIG_T))
4707 +      return VCHIQ_ERROR;
4708 +
4709 +   memcpy(pconfig, &config, vcos_min(config_size, sizeof(VCHIQ_CONFIG_T)));
4710 +
4711 +   return VCHIQ_SUCCESS;
4712 +}
4713 +
4714 +VCHIQ_STATUS_T
4715 +vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
4716 +   VCHIQ_SERVICE_OPTION_T option, int value)
4717 +{
4718 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
4719 +   VCHIQ_STATUS_T status = VCHIQ_ERROR;
4720 +
4721 +   if (service)
4722 +   {
4723 +      switch (option)
4724 +      {
4725 +      case VCHIQ_SERVICE_OPTION_AUTOCLOSE:
4726 +         service->auto_close = value;
4727 +         status = VCHIQ_SUCCESS;
4728 +         break;
4729 +
4730 +      default:
4731 +         break;
4732 +      }
4733 +   }
4734 +
4735 +   return status;
4736 +}
4737 +
4738 +void
4739 +vchiq_dump_shared_state(void *dump_context, VCHIQ_STATE_T *state,
4740 +   VCHIQ_SHARED_STATE_T *shared, const char *label)
4741 +{
4742 +   static const char *const debug_names[] =
4743 +   {
4744 +      "<entries>",
4745 +      "SLOT_HANDLER_COUNT",
4746 +      "SLOT_HANDLER_LINE",
4747 +      "PARSE_LINE",
4748 +      "PARSE_HEADER",
4749 +      "PARSE_MSGID",
4750 +      "AWAIT_COMPLETION_LINE",
4751 +      "DEQUEUE_MESSAGE_LINE",
4752 +      "SERVICE_CALLBACK_LINE",
4753 +      "MSG_QUEUE_FULL_COUNT",
4754 +      "COMPLETION_QUEUE_FULL_COUNT"
4755 +   };
4756 +   int i;
4757 +
4758 +   char buf[80];
4759 +   int len;
4760 +   len = vcos_snprintf(buf, sizeof(buf),
4761 +      "  %s: slots %d-%d tx_pos=%x recycle=%x",
4762 +      label, shared->slot_first, shared->slot_last,
4763 +      shared->tx_pos, shared->slot_queue_recycle);
4764 +   vchiq_dump(dump_context, buf, len + 1);
4765 +
4766 +   len = vcos_snprintf(buf, sizeof(buf),
4767 +      "    Slots claimed:"); 
4768 +   vchiq_dump(dump_context, buf, len + 1);
4769 +
4770 +   for (i = shared->slot_first; i <= shared->slot_last; i++)
4771 +   {
4772 +      VCHIQ_SLOT_INFO_T slot_info = *SLOT_INFO_FROM_INDEX(state, i);
4773 +      if (slot_info.use_count != slot_info.release_count)
4774 +      {
4775 +         len = vcos_snprintf(buf, sizeof(buf),
4776 +            "      %d: %d/%d", i, slot_info.use_count, slot_info.release_count);
4777 +         vchiq_dump(dump_context, buf, len + 1);
4778 +      }
4779 +   }
4780 +
4781 +   for (i = 1; i < shared->debug[DEBUG_ENTRIES]; i++)
4782 +   {
4783 +      len = vcos_snprintf(buf, sizeof(buf), "    DEBUG: %s = %d(%x)",
4784 +         debug_names[i], shared->debug[i], shared->debug[i]);
4785 +      vchiq_dump(dump_context, buf, len + 1);
4786 +   }
4787 +}
4788 +
4789 +void
4790 +vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state)
4791 +{
4792 +   char buf[80];
4793 +   int len;
4794 +   int i;
4795 +
4796 +   len = vcos_snprintf(buf, sizeof(buf), "State %d: %s", state->id,
4797 +      conn_state_names[state->conn_state]);
4798 +   vchiq_dump(dump_context, buf, len + 1);
4799 +
4800 +   len = vcos_snprintf(buf, sizeof(buf),
4801 +      "  tx_pos=%x(@%x), rx_pos=%x(@%x)",
4802 +      state->id, state->local->tx_pos,
4803 +      (uint32_t)state->tx_data + (state->local_tx_pos & VCHIQ_SLOT_MASK),
4804 +      state->rx_pos,
4805 +      (uint32_t)state->rx_data + (state->rx_pos & VCHIQ_SLOT_MASK));
4806 +   vchiq_dump(dump_context, buf, len + 1);
4807 +
4808 +   len = vcos_snprintf(buf, sizeof(buf),
4809 +      "  Version: %d (min %d)",
4810 +      VCHIQ_VERSION, VCHIQ_VERSION_MIN);
4811 +   vchiq_dump(dump_context, buf, len + 1);
4812 +
4813 +   if (VCHIQ_ENABLE_STATS)
4814 +   {
4815 +      len = vcos_snprintf(buf, sizeof(buf),
4816 +         "  Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, error_count=%d",
4817 +         state->stats.ctrl_tx_count, state->stats.ctrl_rx_count,
4818 +         state->stats.slot_stalls);
4819 +      vchiq_dump(dump_context, buf, len + 1);
4820 +   }
4821 +
4822 +   len = vcos_snprintf(buf, sizeof(buf),
4823 +      "  Slots: %d available, %d recyclable, %d stalls",
4824 +      state->slot_queue_available - SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos),
4825 +      state->local->slot_queue_recycle - state->slot_queue_available,
4826 +      state->stats.slot_stalls);
4827 +   vchiq_dump(dump_context, buf, len + 1);
4828 +
4829 +   vchiq_dump_platform_state(dump_context);
4830 +
4831 +   vchiq_dump_shared_state(dump_context, state, state->local, "Local");
4832 +   vchiq_dump_shared_state(dump_context, state, state->remote, "Remote");
4833 +
4834 +   vchiq_dump_platform_instances(dump_context);
4835 +
4836 +   for (i = 0; i < state->unused_service; i++) {
4837 +      VCHIQ_SERVICE_T *service = state->services[i];
4838 +
4839 +      if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE))
4840 +         vchiq_dump_service_state(dump_context, service);
4841 +   }
4842 +}
4843 +
4844 +void
4845 +vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service)
4846 +{
4847 +   char buf[80];
4848 +   int len;
4849 +
4850 +   len = vcos_snprintf(buf, sizeof(buf), "Service %d: %s",
4851 +      service->localport, srvstate_names[service->srvstate]);
4852 +
4853 +   if (service->srvstate != VCHIQ_SRVSTATE_FREE)
4854 +   {
4855 +      char remoteport[30];
4856 +      VCHIQ_SERVICE_QUOTA_T *service_quota =
4857 +         &service->state->service_quotas[service->localport];
4858 +      int fourcc = service->base.fourcc;
4859 +      if (service->remoteport != VCHIQ_PORT_FREE)
4860 +      {
4861 +         int len2 = vcos_snprintf(remoteport, sizeof(remoteport), "%d",
4862 +            service->remoteport);
4863 +         if (service->public_fourcc != VCHIQ_FOURCC_INVALID)
4864 +            vcos_snprintf(remoteport + len2, sizeof(remoteport) - len2,
4865 +               " (client %x)", service->client_id);
4866 +      }
4867 +      else
4868 +         vcos_strcpy(remoteport, "n/a");
4869 +
4870 +      len += vcos_snprintf(buf + len, sizeof(buf) - len,
4871 +         " '%c%c%c%c' remote %s (slot use %d/%d)",
4872 +         VCHIQ_FOURCC_AS_4CHARS(fourcc),
4873 +         remoteport,
4874 +         service_quota->slot_use_count,
4875 +         service_quota->slot_quota);
4876 +
4877 +      if (VCHIQ_ENABLE_STATS)
4878 +      {
4879 +         vchiq_dump(dump_context, buf, len + 1);
4880 +
4881 +         len = vcos_snprintf(buf, sizeof(buf),
4882 +            "  Ctrl: tx_count=%d, tx_bytes=%" PRIu64 ", rx_count=%d, rx_bytes=%" PRIu64,
4883 +            service->stats.ctrl_tx_count, service->stats.ctrl_tx_bytes,
4884 +            service->stats.ctrl_rx_count, service->stats.ctrl_rx_bytes);
4885 +         vchiq_dump(dump_context, buf, len + 1);
4886 +
4887 +         len = vcos_snprintf(buf, sizeof(buf),
4888 +            "  Bulk: tx_count=%d, tx_bytes=%" PRIu64 ", rx_count=%d, rx_bytes=%" PRIu64,
4889 +            service->stats.bulk_tx_count, service->stats.bulk_tx_bytes,
4890 +            service->stats.bulk_rx_count, service->stats.bulk_rx_bytes);
4891 +         vchiq_dump(dump_context, buf, len + 1);
4892 +
4893 +         len = vcos_snprintf(buf, sizeof(buf),
4894 +            "  %d quota stalls, %d slot stalls, %d bulk stalls, %d aborted, %d errors",
4895 +            service->stats.quota_stalls, service->stats.slot_stalls,
4896 +            service->stats.bulk_stalls, service->stats.bulk_aborted_count,
4897 +            service->stats.error_count);
4898 +       }
4899 +   }
4900 +
4901 +   vchiq_dump(dump_context, buf, len + 1);
4902 +
4903 +   vchiq_dump_platform_service_state(dump_context, service);
4904 +}
4905 --- /dev/null
4906 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
4907 @@ -0,0 +1,480 @@
4908 +/*
4909 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
4910 + *
4911 + * This program is free software; you can redistribute it and/or modify
4912 + * it under the terms of the GNU General Public License as published by
4913 + * the Free Software Foundation; either version 2 of the License, or
4914 + * (at your option) any later version.
4915 + *
4916 + * This program is distributed in the hope that it will be useful,
4917 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4918 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4919 + * GNU General Public License for more details.
4920 + *
4921 + * You should have received a copy of the GNU General Public License
4922 + * along with this program; if not, write to the Free Software
4923 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
4924 + */
4925 +
4926 +#ifndef VCHIQ_CORE_H
4927 +#define VCHIQ_CORE_H
4928 +
4929 +#include "vchiq_cfg.h"
4930 +
4931 +#include "vchiq.h"
4932 +
4933 +#define IS_POW2(x) (x && ((x & (x - 1)) == 0))
4934 +
4935 +/* Ensure that the slot size and maximum number of slots are powers of 2 */
4936 +vcos_static_assert(IS_POW2(VCHIQ_SLOT_SIZE));
4937 +vcos_static_assert(IS_POW2(VCHIQ_MAX_SLOTS));
4938 +vcos_static_assert(IS_POW2(VCHIQ_MAX_SLOTS_PER_SIDE));
4939 +
4940 +#define VCHIQ_SLOT_MASK        (VCHIQ_SLOT_SIZE - 1)
4941 +#define VCHIQ_SLOT_QUEUE_MASK  (VCHIQ_MAX_SLOTS_PER_SIDE - 1)
4942 +#define VCHIQ_SLOT_ZERO_SLOTS  ((sizeof(VCHIQ_SLOT_ZERO_T) + \
4943 +   VCHIQ_SLOT_SIZE - 1) / VCHIQ_SLOT_SIZE)
4944 +
4945 +#define VCHIQ_MSG_PADDING              0  // -
4946 +#define VCHIQ_MSG_CONNECT              1  // -
4947 +#define VCHIQ_MSG_OPEN                 2  // + (srcport, -), fourcc, client_id
4948 +#define VCHIQ_MSG_OPENACK              3  // + (srcport, dstport)
4949 +#define VCHIQ_MSG_CLOSE                4  // + (srcport, dstport)
4950 +#define VCHIQ_MSG_DATA                 5  // + (srcport, dstport)
4951 +#define VCHIQ_MSG_BULK_RX              6  // + (srcport, dstport), data, size
4952 +#define VCHIQ_MSG_BULK_TX              7  // + (srcport, dstport), data, size
4953 +#define VCHIQ_MSG_BULK_RX_DONE         8  // + (srcport, dstport), actual
4954 +#define VCHIQ_MSG_BULK_TX_DONE         9  // + (srcport, dstport), actual
4955 +#define VCHIQ_MSG_PAUSE               10  // -
4956 +#define VCHIQ_MSG_RESUME              11  // -
4957 +
4958 +#define VCHIQ_PORT_MAX                 (VCHIQ_MAX_SERVICES - 1)
4959 +#define VCHIQ_PORT_FREE                0x1000
4960 +#define VCHIQ_PORT_IS_VALID(port)      (port < VCHIQ_PORT_FREE)
4961 +#define VCHIQ_MAKE_MSG(type,srcport,dstport)      ((type<<24) | (srcport<<12) | (dstport<<0))
4962 +#define VCHIQ_MSG_TYPE(msgid)          ((unsigned int)msgid >> 24)
4963 +#define VCHIQ_MSG_SRCPORT(msgid)       (unsigned short)(((unsigned int)msgid >> 12) & 0xfff)
4964 +#define VCHIQ_MSG_DSTPORT(msgid)       ((unsigned short)msgid & 0xfff)
4965 +
4966 +#define VCHIQ_FOURCC_AS_4CHARS(fourcc) \
4967 +   ((fourcc) >> 24) & 0xff, \
4968 +   ((fourcc) >> 16) & 0xff, \
4969 +   ((fourcc) >>  8) & 0xff, \
4970 +   ((fourcc)      ) & 0xff
4971 +
4972 +/* Ensure the fields are wide enough */
4973 +vcos_static_assert(VCHIQ_MSG_SRCPORT(VCHIQ_MAKE_MSG(0,0,VCHIQ_PORT_MAX)) == 0);
4974 +vcos_static_assert(VCHIQ_MSG_TYPE(VCHIQ_MAKE_MSG(0,VCHIQ_PORT_MAX,0)) == 0);
4975 +vcos_static_assert((unsigned int)VCHIQ_PORT_MAX < (unsigned int)VCHIQ_PORT_FREE);
4976 +
4977 +#define VCHIQ_MSGID_PADDING            VCHIQ_MAKE_MSG(VCHIQ_MSG_PADDING,0,0)
4978 +#define VCHIQ_MSGID_CLAIMED            0x40000000
4979 +
4980 +#define VCHIQ_FOURCC_INVALID           0x00000000
4981 +#define VCHIQ_FOURCC_IS_LEGAL(fourcc)  (fourcc != VCHIQ_FOURCC_INVALID)
4982 +
4983 +#define VCHIQ_BULK_ACTUAL_ABORTED -1
4984 +
4985 +typedef uint32_t BITSET_T;
4986 +
4987 +vcos_static_assert((sizeof(BITSET_T) * 8) == 32);
4988 +
4989 +#define BITSET_SIZE(b)        ((b + 31) >> 5)
4990 +#define BITSET_WORD(b)        (b >> 5)
4991 +#define BITSET_BIT(b)         (1 << (b & 31))
4992 +#define BITSET_ZERO(bs)       memset(bs, 0, sizeof(bs))
4993 +#define BITSET_IS_SET(bs, b)  (bs[BITSET_WORD(b)] & BITSET_BIT(b))
4994 +#define BITSET_SET(bs, b)     (bs[BITSET_WORD(b)] |= BITSET_BIT(b))
4995 +#define BITSET_CLR(bs, b)     (bs[BITSET_WORD(b)] &= ~BITSET_BIT(b))
4996 +
4997 +#if VCHIQ_ENABLE_STATS
4998 +#define VCHIQ_STATS_INC(state, stat) (state->stats. stat ++)
4999 +#define VCHIQ_SERVICE_STATS_INC(service, stat) (service->stats. stat ++)
5000 +#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) (service->stats. stat += addend)
5001 +#else
5002 +#define VCHIQ_STATS_INC(state, stat) ((void)0)
5003 +#define VCHIQ_SERVICE_STATS_INC(service, stat) ((void)0)
5004 +#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) ((void)0)
5005 +#endif
5006 +
5007 +enum
5008 +{
5009 +   DEBUG_ENTRIES,
5010 +#if VCHIQ_ENABLE_DEBUG
5011 +   DEBUG_SLOT_HANDLER_COUNT,
5012 +   DEBUG_SLOT_HANDLER_LINE,
5013 +   DEBUG_PARSE_LINE,
5014 +   DEBUG_PARSE_HEADER,
5015 +   DEBUG_PARSE_MSGID,
5016 +   DEBUG_AWAIT_COMPLETION_LINE,
5017 +   DEBUG_DEQUEUE_MESSAGE_LINE,
5018 +   DEBUG_SERVICE_CALLBACK_LINE,
5019 +   DEBUG_MSG_QUEUE_FULL_COUNT,
5020 +   DEBUG_COMPLETION_QUEUE_FULL_COUNT,
5021 +#endif
5022 +   DEBUG_MAX
5023 +};
5024 +
5025 +#if VCHIQ_ENABLE_DEBUG
5026 +
5027 +#define DEBUG_INITIALISE(local) volatile int *debug_ptr = (local)->debug;
5028 +#define DEBUG_TRACE(d) debug_ptr[DEBUG_ ## d] = __LINE__
5029 +#define DEBUG_VALUE(d,v) debug_ptr[DEBUG_ ## d] = (v)
5030 +#define DEBUG_COUNT(d) debug_ptr[DEBUG_ ## d]++
5031 +
5032 +#else /* VCHIQ_ENABLE_DEBUG */
5033 +
5034 +#define DEBUG_INITIALISE(local)
5035 +#define DEBUG_TRACE(d)
5036 +#define DEBUG_VALUE(d,v)
5037 +#define DEBUG_COUNT(d)
5038 +
5039 +#endif /* VCHIQ_ENABLE_DEBUG */
5040 +
5041 +typedef enum
5042 +{
5043 +   VCHIQ_CONNSTATE_DISCONNECTED,
5044 +   VCHIQ_CONNSTATE_CONNECTED,
5045 +   VCHIQ_CONNSTATE_PAUSING,
5046 +   VCHIQ_CONNSTATE_PAUSE_SENT,
5047 +   VCHIQ_CONNSTATE_PAUSED,
5048 +   VCHIQ_CONNSTATE_RESUMING
5049 +} VCHIQ_CONNSTATE_T;
5050 +
5051 +enum
5052 +{
5053 +   VCHIQ_SRVSTATE_FREE,
5054 +   VCHIQ_SRVSTATE_HIDDEN,
5055 +   VCHIQ_SRVSTATE_LISTENING,
5056 +   VCHIQ_SRVSTATE_OPENING,
5057 +   VCHIQ_SRVSTATE_OPEN,
5058 +   VCHIQ_SRVSTATE_CLOSESENT,
5059 +   VCHIQ_SRVSTATE_CLOSING,
5060 +   VCHIQ_SRVSTATE_CLOSEWAIT
5061 +};
5062 +
5063 +enum
5064 +{
5065 +   VCHIQ_POLL_TERMINATE,
5066 +   VCHIQ_POLL_TXNOTIFY,
5067 +   VCHIQ_POLL_RXNOTIFY,
5068 +   VCHIQ_POLL_COUNT
5069 +};
5070 +
5071 +typedef enum
5072 +{
5073 +   VCHIQ_BULK_TRANSMIT,
5074 +   VCHIQ_BULK_RECEIVE
5075 +} VCHIQ_BULK_DIR_T;
5076 +
5077 +typedef struct vchiq_bulk_struct {
5078 +   short mode;
5079 +   short dir;
5080 +   void *userdata;
5081 +   VCHI_MEM_HANDLE_T handle;
5082 +   void *data;
5083 +   int size;
5084 +   void *remote_data;
5085 +   int remote_size;
5086 +   int actual;
5087 +} VCHIQ_BULK_T;
5088 +
5089 +typedef struct vchiq_bulk_queue_struct {
5090 +   int local_insert;  /* Where to insert the next local bulk */
5091 +   int remote_insert; /* Where to insert the next remote bulk (master) */
5092 +   int process;       /* Bulk to transfer next */
5093 +   int remote_notify; /* Bulk to notify the remote client of next (master) */
5094 +   int remove;        /* Bulk to notify the local client of, and remove, next */
5095 +   VCHIQ_BULK_T bulks[VCHIQ_NUM_SERVICE_BULKS];
5096 +} VCHIQ_BULK_QUEUE_T;
5097 +
5098 +typedef struct remote_event_struct {
5099 +   volatile int armed;
5100 +   volatile int fired;
5101 +   VCOS_EVENT_T * event;
5102 +} REMOTE_EVENT_T;
5103 +
5104 +typedef struct vchiq_state_struct VCHIQ_STATE_T;
5105 +
5106 +typedef struct vchiq_slot_struct {
5107 +   char data[VCHIQ_SLOT_SIZE];
5108 +} VCHIQ_SLOT_T;
5109 +
5110 +typedef struct vchiq_slot_info_struct {
5111 +   /* Use two counters rather than one to avoid the need for a mutex. */
5112 +   volatile short use_count;
5113 +   volatile short release_count;
5114 +} VCHIQ_SLOT_INFO_T;
5115 +
5116 +typedef struct vchiq_service_struct {
5117 +   VCHIQ_SERVICE_BASE_T base;
5118 +   volatile int srvstate;
5119 +   unsigned int localport;
5120 +   unsigned int remoteport;
5121 +   int public_fourcc;
5122 +   int client_id;
5123 +   int auto_close;
5124 +   VCOS_ATOMIC_FLAGS_T poll_flags;
5125 +   short version;
5126 +   short version_min;
5127 +
5128 +   VCHIQ_STATE_T *state;
5129 +   VCHIQ_INSTANCE_T instance;
5130 +
5131 +   int service_use_count;
5132 +
5133 +   VCHIQ_BULK_QUEUE_T bulk_tx;
5134 +   VCHIQ_BULK_QUEUE_T bulk_rx;
5135 +
5136 +   VCOS_EVENT_T remove_event;
5137 +   VCOS_EVENT_T bulk_remove_event;
5138 +   VCOS_MUTEX_T bulk_mutex;
5139 +
5140 +   struct service_stats_struct
5141 +   {
5142 +      int quota_stalls;
5143 +      int slot_stalls;
5144 +      int bulk_stalls;
5145 +      int error_count;
5146 +      int ctrl_tx_count;
5147 +      int ctrl_rx_count;
5148 +      int bulk_tx_count;
5149 +      int bulk_rx_count;
5150 +      int bulk_aborted_count;
5151 +      uint64_t ctrl_tx_bytes;
5152 +      uint64_t ctrl_rx_bytes;
5153 +      uint64_t bulk_tx_bytes;
5154 +      uint64_t bulk_rx_bytes;
5155 +   } stats;
5156 +} VCHIQ_SERVICE_T;
5157 +
5158 +/* The quota information is outside VCHIQ_SERVICE_T so that it can be
5159 +   statically allocated, since for accounting reasons a service's slot
5160 +   usage is carried over between users of the same port number.
5161 + */
5162 +typedef struct vchiq_service_quota_struct {
5163 +   int slot_quota;
5164 +   int slot_use_count;
5165 +   VCOS_EVENT_T quota_event;
5166 +   int previous_tx_index;
5167 +} VCHIQ_SERVICE_QUOTA_T;
5168 +
5169 +typedef struct vchiq_shared_state_struct {
5170 +
5171 +   /* A non-zero value here indicates that the content is valid. */
5172 +   int initialised;
5173 +
5174 +   /* The first and last (inclusive) slots allocated to the owner. */
5175 +   int slot_first;
5176 +   int slot_last;
5177 +
5178 +   /* Signalling this event indicates that owner's slot handler thread should
5179 +      run. */
5180 +   REMOTE_EVENT_T trigger;
5181 +
5182 +   /* Indicates the byte position within the stream where the next message
5183 +      will be written. The least significant bits are an index into the slot.
5184 +      The next bits are the index of the slot in slot_queue. */
5185 +   volatile int tx_pos;
5186 +
5187 +   /* This event should be signalled when a slot is recycled. */
5188 +   REMOTE_EVENT_T recycle;
5189 +
5190 +   /* The slot_queue index where the next recycled slot will be written. */
5191 +   volatile int slot_queue_recycle;
5192 +
5193 +   /* A circular buffer of slot indexes. */
5194 +   int slot_queue[VCHIQ_MAX_SLOTS_PER_SIDE];
5195 +
5196 +   /* Debugging state */
5197 +   volatile int debug[DEBUG_MAX];
5198 +} VCHIQ_SHARED_STATE_T;
5199 +
5200 +typedef struct vchiq_slot_zero_struct {
5201 +   int magic;
5202 +   short version;
5203 +   short version_min;
5204 +   int slot_zero_size;
5205 +   int slot_size;
5206 +   int max_slots;
5207 +   int max_slots_per_side;
5208 +   int platform_data[2];
5209 +   VCHIQ_SHARED_STATE_T master;
5210 +   VCHIQ_SHARED_STATE_T slave;
5211 +   VCHIQ_SLOT_INFO_T slots[VCHIQ_MAX_SLOTS];
5212 +} VCHIQ_SLOT_ZERO_T;
5213 +
5214 +struct vchiq_state_struct {
5215 +   int id;
5216 +   int initialised;
5217 +   VCHIQ_CONNSTATE_T conn_state;
5218 +   int is_master;
5219 +
5220 +   VCHIQ_SHARED_STATE_T *local;
5221 +   VCHIQ_SHARED_STATE_T *remote;
5222 +   VCHIQ_SLOT_T *slot_data;
5223 +
5224 +   int default_slot_quota;
5225 +
5226 +   VCOS_EVENT_T connect;      // event indicating connect message received
5227 +   VCOS_MUTEX_T mutex;        // mutex protecting services
5228 +   VCHIQ_INSTANCE_T *instance;
5229 +
5230 +   VCOS_THREAD_T slot_handler_thread;  // processes incoming messages
5231 +   VCOS_THREAD_T recycle_thread;       // processes recycled slots
5232 +   VCOS_THREAD_T lp_thread;            // processes low priority messages (eg suspend)
5233 +
5234 +   /* Local implementation of the trigger remote event */
5235 +   VCOS_EVENT_T trigger_event;
5236 +
5237 +   /* Local implementation of the recycle remote event */
5238 +   VCOS_EVENT_T recycle_event;
5239 +
5240 +   VCOS_EVENT_T lp_evt;
5241 +
5242 +   char *tx_data;
5243 +   char *rx_data;
5244 +   VCHIQ_SLOT_INFO_T *rx_info;
5245 +
5246 +   VCOS_MUTEX_T slot_mutex;
5247 +
5248 +   VCOS_MUTEX_T recycle_mutex;
5249 +
5250 +   VCOS_MUTEX_T suspend_resume_mutex;
5251 +   VCOS_MUTEX_T use_count_mutex;
5252 +
5253 +   /* Global use count for videocore.
5254 +    * This is equal to the sum of the use counts for all services.  When this hits
5255 +    * zero the videocore suspend procedure will be initiated. */
5256 +   int videocore_use_count;
5257 +
5258 +   /* Flag to indicate whether videocore is currently suspended */
5259 +   int videocore_suspended;
5260 +
5261 +   /* Indicates the byte position within the stream from where the next message
5262 +      will be read. The least significant bits are an index into the slot.
5263 +      The next bits are the index of the slot in remote->slot_queue. */
5264 +   int rx_pos;
5265 +
5266 +   /* A cached copy of local->tx_pos. Only write to local->tx_pos, and read
5267 +      from remote->tx_pos. */
5268 +   int local_tx_pos;
5269 +
5270 +   /* The slot_queue index of the slot to become available next. */
5271 +   int slot_queue_available;
5272 +
5273 +   /* A flag to indicate if any poll has been requested */
5274 +   int poll_needed;
5275 +
5276 +   /* An array of bit sets indicating which services must be polled. */
5277 +   VCOS_ATOMIC_FLAGS_T poll_services[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
5278 +
5279 +   /* The number of the first unused service */
5280 +   int unused_service;
5281 +
5282 +   /* Signalled when a free slot becomes available. */
5283 +   VCOS_EVENT_T slot_available_event;
5284 +
5285 +   VCOS_EVENT_T slot_remove_event;
5286 +
5287 +   struct state_stats_struct
5288 +   {
5289 +      int slot_stalls;
5290 +      int ctrl_tx_count;
5291 +      int ctrl_rx_count;
5292 +      int error_count;
5293 +   } stats;
5294 +
5295 +   VCHIQ_SERVICE_T *services[VCHIQ_MAX_SERVICES];
5296 +   VCHIQ_SERVICE_QUOTA_T service_quotas[VCHIQ_MAX_SERVICES];
5297 +   VCHIQ_SLOT_INFO_T slot_info[VCHIQ_MAX_SLOTS];
5298 +};
5299 +
5300 +extern VCHIQ_SLOT_ZERO_T *
5301 +vchiq_init_slots(void *mem_base, int mem_size);
5302 +
5303 +extern VCHIQ_STATUS_T
5304 +vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, int is_master);
5305 +
5306 +extern VCHIQ_STATUS_T
5307 +vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
5308 +
5309 +extern VCHIQ_SERVICE_T *
5310 +vchiq_add_service_internal(VCHIQ_STATE_T *state,
5311 +   const VCHIQ_SERVICE_PARAMS_T *params, int srvstate,
5312 +   VCHIQ_INSTANCE_T instance);
5313 +
5314 +extern VCHIQ_STATUS_T
5315 +vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id);
5316 +
5317 +extern VCHIQ_STATUS_T
5318 +vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd);
5319 +
5320 +extern void
5321 +vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service);
5322 +
5323 +extern void
5324 +vchiq_free_service_internal(VCHIQ_SERVICE_T *service);
5325 +
5326 +extern VCHIQ_STATUS_T
5327 +vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance);
5328 +
5329 +extern VCHIQ_STATUS_T
5330 +vchiq_pause_internal(VCHIQ_STATE_T *state);
5331 +
5332 +extern VCHIQ_STATUS_T
5333 +vchiq_resume_internal(VCHIQ_STATE_T *state);
5334 +
5335 +extern void
5336 +remote_event_pollall(VCHIQ_STATE_T *state);
5337 +
5338 +extern VCHIQ_STATUS_T
5339 +vchiq_bulk_transfer(VCHIQ_SERVICE_T *service,
5340 +   VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata,
5341 +   VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir);
5342 +
5343 +extern void
5344 +vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state);
5345 +
5346 +extern void
5347 +vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service);
5348 +
5349 +/* The following functions are called from vchiq_core, and external
5350 +   implementations must be provided. */
5351 +
5352 +extern VCHIQ_STATUS_T
5353 +vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk,
5354 +   VCHI_MEM_HANDLE_T memhandle, void *offset, int size, int dir);
5355 +
5356 +extern void
5357 +vchiq_transfer_bulk(VCHIQ_BULK_T *bulk);
5358 +
5359 +extern void
5360 +vchiq_complete_bulk(VCHIQ_BULK_T *bulk);
5361 +
5362 +extern VCHIQ_STATUS_T
5363 +vchiq_copy_from_user(void *dst, const void *src, int size);
5364 +
5365 +extern void
5366 +remote_event_signal(REMOTE_EVENT_T *event);
5367 +
5368 +extern void
5369 +vchiq_platform_paused(VCHIQ_STATE_T *state);
5370 +
5371 +extern void
5372 +vchiq_platform_resumed(VCHIQ_STATE_T *state);
5373 +
5374 +extern void
5375 +vchiq_dump(void *dump_context, const char *str, int len);
5376 +
5377 +extern void
5378 +vchiq_dump_platform_state(void *dump_context);
5379 +
5380 +extern void
5381 +vchiq_dump_platform_instances(void *dump_context);
5382 +
5383 +extern void
5384 +vchiq_dump_platform_service_state(void *dump_context,
5385 +   VCHIQ_SERVICE_T *service);
5386 +
5387 +#endif
5388 --- /dev/null
5389 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_if.h
5390 @@ -0,0 +1,148 @@
5391 +/*
5392 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
5393 + *
5394 + * This program is free software; you can redistribute it and/or modify
5395 + * it under the terms of the GNU General Public License as published by
5396 + * the Free Software Foundation; either version 2 of the License, or
5397 + * (at your option) any later version.
5398 + *
5399 + * This program is distributed in the hope that it will be useful,
5400 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5401 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5402 + * GNU General Public License for more details.
5403 + *
5404 + * You should have received a copy of the GNU General Public License
5405 + * along with this program; if not, write to the Free Software
5406 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
5407 + */
5408 +
5409 +#ifndef VCHIQ_IF_H
5410 +#define VCHIQ_IF_H
5411 +
5412 +#include "interface/vchi/vchi_mh.h"
5413 +
5414 +#define VCHIQ_SLOT_SIZE          4096
5415 +#define VCHIQ_MAX_MSG_SIZE       (VCHIQ_SLOT_SIZE - sizeof(VCHIQ_HEADER_T))
5416 +#define VCHIQ_CHANNEL_SIZE       VCHIQ_MAX_MSG_SIZE /* For backwards compatibility */
5417 +
5418 +#define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3)     (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3))
5419 +#define VCHIQ_GET_SERVICE_USERDATA(service)   (service->userdata)
5420 +#define VCHIQ_GET_SERVICE_FOURCC(service)     (service->fourcc)
5421 +
5422 +typedef enum {
5423 +   VCHIQ_SERVICE_OPENED,         // service, -, -
5424 +   VCHIQ_SERVICE_CLOSED,         // service, -, -
5425 +   VCHIQ_MESSAGE_AVAILABLE,      // service, header, -
5426 +   VCHIQ_BULK_TRANSMIT_DONE,     // service, -, bulk_userdata
5427 +   VCHIQ_BULK_RECEIVE_DONE,      // service, -, bulk_userdata
5428 +   VCHIQ_BULK_TRANSMIT_ABORTED,  // service, -, bulk_userdata
5429 +   VCHIQ_BULK_RECEIVE_ABORTED    // service, -, bulk_userdata
5430 +} VCHIQ_REASON_T;
5431 +
5432 +typedef enum
5433 +{
5434 +   VCHIQ_ERROR   = -1,
5435 +   VCHIQ_SUCCESS = 0,
5436 +   VCHIQ_RETRY   = 1
5437 +} VCHIQ_STATUS_T;
5438 +
5439 +typedef enum
5440 +{
5441 +   VCHIQ_BULK_MODE_CALLBACK,
5442 +   VCHIQ_BULK_MODE_BLOCKING,
5443 +   VCHIQ_BULK_MODE_NOCALLBACK
5444 +} VCHIQ_BULK_MODE_T;
5445 +
5446 +typedef enum
5447 +{
5448 +   VCHIQ_SERVICE_OPTION_AUTOCLOSE
5449 +} VCHIQ_SERVICE_OPTION_T;
5450 +
5451 +#ifdef __HIGHC__
5452 +/* Allow zero-sized arrays without warnings */
5453 +#pragma warning (push)
5454 +#pragma warning (disable : 4200)
5455 +#endif
5456 +
5457 +typedef struct vchiq_header_struct {
5458 +   /* The message identifier - opaque to applications. */
5459 +   int msgid;
5460 +
5461 +   /* Size of message data. */
5462 +   unsigned int size;      
5463 +
5464 +   char data[0];           /* message */
5465 +} VCHIQ_HEADER_T;
5466 +
5467 +#ifdef __HIGHC__
5468 +#pragma warning (pop)
5469 +#endif
5470 +
5471 +typedef struct {
5472 +   const void *data;
5473 +   int size;
5474 +} VCHIQ_ELEMENT_T;
5475 +
5476 +typedef const struct vchiq_service_base_struct *VCHIQ_SERVICE_HANDLE_T;
5477 +
5478 +typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, VCHIQ_HEADER_T *, VCHIQ_SERVICE_HANDLE_T, void *);
5479 +
5480 +typedef struct vchiq_service_base_struct {
5481 +   int fourcc;
5482 +   VCHIQ_CALLBACK_T callback;
5483 +   void *userdata;
5484 +} VCHIQ_SERVICE_BASE_T;
5485 +
5486 +typedef struct vchiq_service_params_struct {
5487 +  int fourcc;
5488 +  VCHIQ_CALLBACK_T callback;
5489 +  void *userdata;
5490 +  short version;       /* Increment for non-trivial changes */
5491 +  short version_min;   /* Update for incompatible changes */
5492 +} VCHIQ_SERVICE_PARAMS_T;
5493 +
5494 +typedef struct vchiq_config_struct {
5495 +   int max_msg_size;
5496 +   int bulk_threshold; /* The message size aboce which it is better to use
5497 +                          a bulk transfer (<= max_msg_size) */
5498 +   int max_outstanding_bulks;
5499 +   int max_services;
5500 +   short version;      /* The version of VCHIQ */
5501 +   short version_min;  /* The minimum compatible version of VCHIQ */
5502 +} VCHIQ_CONFIG_T;
5503 +
5504 +typedef struct vchiq_instance_struct *VCHIQ_INSTANCE_T;
5505 +
5506 +extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance);
5507 +extern VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance);
5508 +extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance);
5509 +extern VCHIQ_STATUS_T vchiq_add_service(VCHIQ_INSTANCE_T instance, int fourcc, VCHIQ_CALLBACK_T callback, void *userdata, VCHIQ_SERVICE_HANDLE_T *pservice);
5510 +extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance, int fourcc, VCHIQ_CALLBACK_T callback, void *userdata, VCHIQ_SERVICE_HANDLE_T *pservice);
5511 +extern VCHIQ_STATUS_T vchiq_add_service_params(VCHIQ_INSTANCE_T instance,
5512 +   const VCHIQ_SERVICE_PARAMS_T *params,
5513 +   VCHIQ_SERVICE_HANDLE_T *pservice);
5514 +extern VCHIQ_STATUS_T vchiq_open_service_params(VCHIQ_INSTANCE_T instance,
5515 +   const VCHIQ_SERVICE_PARAMS_T *params,
5516 +   VCHIQ_SERVICE_HANDLE_T *pservice);
5517 +extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service);
5518 +extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service);
5519 +extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
5520 +extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
5521 +
5522 +extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service, const VCHIQ_ELEMENT_T *elements, int count);
5523 +extern void           vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service, VCHIQ_HEADER_T *header);
5524 +extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, const void *data, int size, void *userdata);
5525 +extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service, void *data, int size, void *userdata);
5526 +extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, const void *offset, int size, void *userdata);
5527 +extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, void *offset, int size, void *userdata);
5528 +extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, const void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
5529 +extern VCHIQ_STATUS_T vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T service, void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
5530 +extern VCHIQ_STATUS_T vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, const void *offset, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
5531 +extern VCHIQ_STATUS_T vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, void *offset, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
5532 +extern int            vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T service);
5533 +extern VCHIQ_STATUS_T vchiq_get_config(VCHIQ_INSTANCE_T instance, int config_size, VCHIQ_CONFIG_T *pconfig);
5534 +extern VCHIQ_STATUS_T vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T service, VCHIQ_SERVICE_OPTION_T option, int value);
5535 +
5536 +extern VCHIQ_STATUS_T vchiq_dump_phys_mem( VCHIQ_SERVICE_HANDLE_T service, void *ptr, size_t num_bytes );
5537 +
5538 +#endif /* VCHIQ_IF_H */
5539 --- /dev/null
5540 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
5541 @@ -0,0 +1,105 @@
5542 +/*
5543 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
5544 + *
5545 + * This program is free software; you can redistribute it and/or modify
5546 + * it under the terms of the GNU General Public License as published by
5547 + * the Free Software Foundation; either version 2 of the License, or
5548 + * (at your option) any later version.
5549 + *
5550 + * This program is distributed in the hope that it will be useful,
5551 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5552 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5553 + * GNU General Public License for more details.
5554 + *
5555 + * You should have received a copy of the GNU General Public License
5556 + * along with this program; if not, write to the Free Software
5557 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
5558 + */
5559 +
5560 +#ifndef VCHIQ_IOCTLS_H
5561 +#define VCHIQ_IOCTLS_H
5562 +
5563 +#include <linux/ioctl.h>
5564 +#include "vchiq_if.h"
5565 +
5566 +#define VCHIQ_IOC_MAGIC 0xc4
5567 +#define VCHIQ_INVALID_HANDLE -1
5568 +
5569 +typedef struct {
5570 +   VCHIQ_SERVICE_PARAMS_T params;
5571 +   int is_open;
5572 +   int is_vchi;
5573 +   int handle;       /* OUT */
5574 +} VCHIQ_CREATE_SERVICE_T;
5575 +
5576 +typedef struct {
5577 +   int handle;
5578 +   int count;
5579 +   const VCHIQ_ELEMENT_T *elements;
5580 +} VCHIQ_QUEUE_MESSAGE_T;
5581 +
5582 +typedef struct {
5583 +   int handle;
5584 +   void *data;
5585 +   int size;
5586 +   void *userdata;
5587 +   VCHIQ_BULK_MODE_T mode;
5588 +} VCHIQ_QUEUE_BULK_TRANSFER_T;
5589 +
5590 +typedef struct {
5591 +   VCHIQ_REASON_T reason;
5592 +   VCHIQ_HEADER_T *header;
5593 +   void *service_userdata;
5594 +   void *bulk_userdata;
5595 +} VCHIQ_COMPLETION_DATA_T;
5596 +
5597 +typedef struct {
5598 +   int count;
5599 +   VCHIQ_COMPLETION_DATA_T *buf;
5600 +   int msgbufsize;
5601 +   int msgbufcount; /* IN/OUT */
5602 +   void **msgbufs;
5603 +} VCHIQ_AWAIT_COMPLETION_T;
5604 +
5605 +typedef struct {
5606 +   int handle;
5607 +   int blocking;
5608 +   int bufsize;
5609 +   void *buf;
5610 +} VCHIQ_DEQUEUE_MESSAGE_T;
5611 +
5612 +typedef struct {
5613 +   int config_size;
5614 +   VCHIQ_CONFIG_T *pconfig;
5615 +} VCHIQ_GET_CONFIG_T;
5616 +
5617 +typedef struct {
5618 +   int handle;
5619 +   VCHIQ_SERVICE_OPTION_T option;
5620 +   int value;
5621 +} VCHIQ_SET_SERVICE_OPTION_T;
5622 +
5623 +typedef struct {
5624 +   void     *virt_addr;
5625 +   size_t    num_bytes;
5626 +} VCHIQ_DUMP_MEM_T;
5627 +
5628 +#define VCHIQ_IOC_CONNECT              _IO(VCHIQ_IOC_MAGIC,   0)
5629 +#define VCHIQ_IOC_SHUTDOWN             _IO(VCHIQ_IOC_MAGIC,   1)
5630 +#define VCHIQ_IOC_CREATE_SERVICE       _IOWR(VCHIQ_IOC_MAGIC, 2, VCHIQ_CREATE_SERVICE_T)
5631 +#define VCHIQ_IOC_REMOVE_SERVICE       _IO(VCHIQ_IOC_MAGIC,   3)
5632 +#define VCHIQ_IOC_QUEUE_MESSAGE        _IOW(VCHIQ_IOC_MAGIC,  4, VCHIQ_QUEUE_MESSAGE_T)
5633 +#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT  _IOW(VCHIQ_IOC_MAGIC,  5, VCHIQ_QUEUE_BULK_TRANSFER_T)
5634 +#define VCHIQ_IOC_QUEUE_BULK_RECEIVE   _IOW(VCHIQ_IOC_MAGIC,  6, VCHIQ_QUEUE_BULK_TRANSFER_T)
5635 +#define VCHIQ_IOC_AWAIT_COMPLETION     _IOW(VCHIQ_IOC_MAGIC,  7, VCHIQ_AWAIT_COMPLETION_T)
5636 +#define VCHIQ_IOC_DEQUEUE_MESSAGE      _IOW(VCHIQ_IOC_MAGIC,  8, VCHIQ_DEQUEUE_MESSAGE_T)
5637 +#define VCHIQ_IOC_GET_CLIENT_ID        _IO(VCHIQ_IOC_MAGIC,   9)
5638 +#define VCHIQ_IOC_GET_CONFIG           _IOW(VCHIQ_IOC_MAGIC, 10, VCHIQ_GET_CONFIG_T)
5639 +#define VCHIQ_IOC_CLOSE_SERVICE        _IO(VCHIQ_IOC_MAGIC,  11)
5640 +#define VCHIQ_IOC_USE_SERVICE          _IO(VCHIQ_IOC_MAGIC,  12)
5641 +#define VCHIQ_IOC_RELEASE_SERVICE      _IO(VCHIQ_IOC_MAGIC,  13)
5642 +#define VCHIQ_IOC_SET_SERVICE_OPTION   _IOW(VCHIQ_IOC_MAGIC, 14, VCHIQ_SET_SERVICE_OPTION_T)
5643 +#define VCHIQ_IOC_DUMP_PHYS_MEM        _IOW(VCHIQ_IOC_MAGIC, 15, VCHIQ_DUMP_MEM_T)
5644 +#define VCHIQ_IOC_MAX                  15
5645 +
5646 +#endif
5647 --- /dev/null
5648 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
5649 @@ -0,0 +1,297 @@
5650 +/*****************************************************************************
5651 +* Copyright 2001 - 2011 Broadcom Corporation.  All rights reserved.
5652 +*
5653 +* Unless you and Broadcom execute a separate written software license
5654 +* agreement governing use of this software, this software is licensed to you
5655 +* under the terms of the GNU General Public License version 2, available at
5656 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
5657 +*
5658 +* Notwithstanding the above, under no circumstances may you combine this
5659 +* software in any way with any other Broadcom software provided under a
5660 +* license other than the GPL, without Broadcom's express prior written
5661 +* consent.
5662 +*****************************************************************************/
5663 +
5664 +/* ---- Include Files ---------------------------------------------------- */
5665 +
5666 +#include <linux/kernel.h>
5667 +#include <linux/module.h>
5668 +
5669 +#include "vchiq_core.h"
5670 +#include "vchiq_arm.h"
5671 +#include "interface/vcos/vcos_logging.h"
5672 +
5673 +/* ---- Public Variables ------------------------------------------------- */
5674 +
5675 +extern VCOS_LOG_CAT_T vchiq_core_log_category;
5676 +#define  VCOS_LOG_CATEGORY (&vchiq_core_log_category)
5677 +
5678 +/* ---- Private Constants and Types -------------------------------------- */
5679 +
5680 +struct vchiq_instance_struct {
5681 +   VCHIQ_STATE_T *state;
5682 +
5683 +   int connected;
5684 +};
5685 +
5686 +/****************************************************************************
5687 +*
5688 +*   vchiq_initialise
5689 +*
5690 +***************************************************************************/
5691 +
5692 +VCHIQ_STATUS_T vchiq_initialise( VCHIQ_INSTANCE_T *instanceOut )
5693 +{
5694 +   VCHIQ_STATUS_T status = VCHIQ_ERROR;
5695 +   VCHIQ_STATE_T *state;
5696 +   VCHIQ_INSTANCE_T instance = NULL;
5697 +
5698 +   vcos_log_trace( "%s called", __func__ );
5699 +
5700 +   state = vchiq_get_state();
5701 +   if (!state)
5702 +   {
5703 +      printk( KERN_ERR "%s: videocore not initialized\n", __func__ );
5704 +      goto failed;
5705 +   }
5706 +
5707 +   instance = kzalloc( sizeof(*instance), GFP_KERNEL );
5708 +   if( !instance )
5709 +   {
5710 +      printk( KERN_ERR "%s: error allocating vchiq instance\n", __func__ );
5711 +      goto failed;
5712 +   }
5713 +
5714 +   instance->connected = 0;
5715 +   instance->state = state;
5716 +
5717 +   *instanceOut = instance;
5718 +   
5719 +   status = VCHIQ_SUCCESS;
5720 +
5721 +failed:
5722 +   vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5723 +
5724 +   return status;
5725 +}
5726 +
5727 +/****************************************************************************
5728 +*
5729 +*   vchiq_shutdown
5730 +*
5731 +***************************************************************************/
5732 +
5733 +VCHIQ_STATUS_T vchiq_shutdown( VCHIQ_INSTANCE_T instance )
5734 +{
5735 +   VCHIQ_STATUS_T status;
5736 +   VCHIQ_STATE_T *state = instance->state;
5737 +
5738 +   vcos_log_trace( "%s(%p) called", __func__, instance );
5739 +
5740 +   vcos_mutex_lock(&state->mutex);
5741 +
5742 +   /* Remove all services */
5743 +   status = vchiq_shutdown_internal(state, instance);
5744 +
5745 +   vcos_mutex_unlock(&state->mutex);
5746 +
5747 +   if (status == VCHIQ_SUCCESS)
5748 +      kfree(instance);
5749 +
5750 +   vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5751 +
5752 +   return status;
5753 +}
5754 +
5755 +/****************************************************************************
5756 +*
5757 +*   vchiq_is_connected
5758 +*
5759 +***************************************************************************/
5760 +
5761 +int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
5762 +{
5763 +   return instance->connected;
5764 +}
5765 +
5766 +/****************************************************************************
5767 +*
5768 +*   vchiq_connect
5769 +*
5770 +***************************************************************************/
5771 +
5772 +VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
5773 +{
5774 +   VCHIQ_STATUS_T status;
5775 +   VCHIQ_STATE_T *state = instance->state;
5776 +
5777 +   vcos_log_trace( "%s(%p) called", __func__, instance );
5778 +
5779 +   if (vcos_mutex_lock(&state->mutex) != VCOS_SUCCESS) {
5780 +      vcos_log_trace( "%s: call to vcos_mutex_lock failed", __func__ );
5781 +      status = VCHIQ_RETRY;
5782 +      goto failed;
5783 +   }
5784 +   status = vchiq_connect_internal(state, instance);
5785 +
5786 +   if (status == VCHIQ_SUCCESS)
5787 +      instance->connected = 1;
5788 +
5789 +   vcos_mutex_unlock(&state->mutex);
5790 +
5791 +failed:
5792 +   vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5793 +
5794 +   return status;
5795 +}
5796 +
5797 +/****************************************************************************
5798 +*
5799 +*   vchiq_add_service
5800 +*
5801 +***************************************************************************/
5802 +
5803 +VCHIQ_STATUS_T vchiq_add_service(
5804 +   VCHIQ_INSTANCE_T        instance,
5805 +   int                     fourcc,
5806 +   VCHIQ_CALLBACK_T        callback,
5807 +   void                   *userdata,
5808 +   VCHIQ_SERVICE_HANDLE_T *pservice)
5809 +{
5810 +   VCHIQ_SERVICE_PARAMS_T params;
5811 +
5812 +   params.fourcc        = fourcc;
5813 +   params.callback      = callback;
5814 +   params.userdata      = userdata;
5815 +   params.version       = 0;
5816 +   params.version_min   = 0;
5817 +
5818 +   return vchiq_add_service_params(instance, &params, pservice);
5819 +}
5820 +
5821 +/****************************************************************************
5822 +*
5823 +*   vchiq_open_service
5824 +*
5825 +***************************************************************************/
5826 +
5827 +VCHIQ_STATUS_T vchiq_open_service(
5828 +   VCHIQ_INSTANCE_T        instance,
5829 +   int                     fourcc,
5830 +   VCHIQ_CALLBACK_T        callback,
5831 +   void                   *userdata,
5832 +   VCHIQ_SERVICE_HANDLE_T *pservice)
5833 +{
5834 +   VCHIQ_SERVICE_PARAMS_T params;
5835 +
5836 +   params.fourcc        = fourcc;
5837 +   params.callback      = callback;
5838 +   params.userdata      = userdata;
5839 +   params.version       = 0;
5840 +   params.version_min   = 0;
5841 +
5842 +   return vchiq_open_service_params(instance, &params, pservice);
5843 +}
5844 +
5845 +/****************************************************************************
5846 +*
5847 +*   vchiq_add_service_params
5848 +*
5849 +***************************************************************************/
5850 +
5851 +VCHIQ_STATUS_T vchiq_add_service_params(
5852 +   VCHIQ_INSTANCE_T              instance,
5853 +   const VCHIQ_SERVICE_PARAMS_T *params,
5854 +   VCHIQ_SERVICE_HANDLE_T       *pservice)
5855 +{
5856 +   VCHIQ_STATUS_T status;
5857 +   VCHIQ_STATE_T *state = instance->state;
5858 +   VCHIQ_SERVICE_T *service;
5859 +   int srvstate;
5860 +
5861 +   vcos_log_trace( "%s(%p) called", __func__, instance );
5862 +
5863 +   *pservice = NULL;
5864 +
5865 +   srvstate = vchiq_is_connected( instance )
5866 +      ? VCHIQ_SRVSTATE_LISTENING
5867 +      : VCHIQ_SRVSTATE_HIDDEN;
5868 +
5869 +   vcos_mutex_lock(&state->mutex);
5870 +
5871 +   service = vchiq_add_service_internal(
5872 +      state,
5873 +      params,
5874 +      srvstate,
5875 +      instance);
5876 +
5877 +   vcos_mutex_unlock(&state->mutex);
5878 +
5879 +   if ( service  )
5880 +   {
5881 +      *pservice = &service->base;
5882 +      status = VCHIQ_SUCCESS;
5883 +   }
5884 +   else
5885 +   {
5886 +      status = VCHIQ_ERROR;
5887 +   }
5888 +
5889 +   vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5890 +
5891 +   return status;
5892 +}
5893 +
5894 +/****************************************************************************
5895 +*
5896 +*   vchiq_open_service_params
5897 +*
5898 +***************************************************************************/
5899 +
5900 +VCHIQ_STATUS_T vchiq_open_service_params(
5901 +   VCHIQ_INSTANCE_T              instance,
5902 +   const VCHIQ_SERVICE_PARAMS_T *params,
5903 +   VCHIQ_SERVICE_HANDLE_T       *pservice)
5904 +{
5905 +   VCHIQ_STATUS_T   status = VCHIQ_ERROR;
5906 +   VCHIQ_STATE_T   *state = instance->state;
5907 +   VCHIQ_SERVICE_T *service;
5908 +
5909 +   vcos_log_trace( "%s(%p) called", __func__, instance );
5910 +
5911 +   *pservice = NULL;
5912 +
5913 +   if (!vchiq_is_connected(instance))
5914 +      goto failed;
5915 +
5916 +   vcos_mutex_lock(&state->mutex);
5917 +
5918 +   service = vchiq_add_service_internal(state,
5919 +      params,
5920 +      VCHIQ_SRVSTATE_OPENING,
5921 +      instance);
5922 +
5923 +   vcos_mutex_unlock(&state->mutex);
5924 +
5925 +   if ( service  )
5926 +   {
5927 +      status = vchiq_open_service_internal(service, current->pid);
5928 +      if ( status == VCHIQ_SUCCESS )
5929 +         *pservice = &service->base;
5930 +      else
5931 +         vchiq_remove_service(&service->base);
5932 +   }
5933 +
5934 +failed:
5935 +   vcos_log_trace( "%s(%p): returning %d", __func__, instance, status );
5936 +
5937 +   return status;
5938 +}
5939 +
5940 +EXPORT_SYMBOL(vchiq_initialise);
5941 +EXPORT_SYMBOL(vchiq_shutdown);
5942 +EXPORT_SYMBOL(vchiq_connect);
5943 +EXPORT_SYMBOL(vchiq_add_service);
5944 +EXPORT_SYMBOL(vchiq_open_service);
5945 +EXPORT_SYMBOL(vchiq_add_service_params);
5946 +EXPORT_SYMBOL(vchiq_open_service_params);
5947 --- /dev/null
5948 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_lib.c
5949 @@ -0,0 +1,1518 @@
5950 +/*
5951 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
5952 + *
5953 + * This program is free software; you can redistribute it and/or modify
5954 + * it under the terms of the GNU General Public License as published by
5955 + * the Free Software Foundation; either version 2 of the License, or
5956 + * (at your option) any later version.
5957 + *
5958 + * This program is distributed in the hope that it will be useful,
5959 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5960 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5961 + * GNU General Public License for more details.
5962 + *
5963 + * You should have received a copy of the GNU General Public License
5964 + * along with this program; if not, write to the Free Software
5965 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
5966 + */
5967 +
5968 +#include <unistd.h>
5969 +#include <fcntl.h>
5970 +#include <sys/ioctl.h>
5971 +#include <stdio.h>
5972 +
5973 +#include "vchiq.h"
5974 +#include "vchiq_cfg.h"
5975 +#include "vchiq_ioctl.h"
5976 +#include "interface/vchi/vchi.h"
5977 +#include "interface/vchi/common/endian.h"
5978 +#include "interface/vcos/vcos.h"
5979 +
5980 +#define VCHIQ_MAX_INSTANCE_SERVICES 32
5981 +#define MSGBUF_SIZE (VCHIQ_MAX_MSG_SIZE + sizeof(VCHIQ_HEADER_T))
5982 +
5983 +#define RETRY(r,x) do { r = x; } while ((r == -1) && (errno == EINTR))
5984 +
5985 +#define VCOS_LOG_CATEGORY (&vchiq_lib_log_category)
5986 +
5987 +typedef struct vchiq_service_struct
5988 +{
5989 +   VCHIQ_SERVICE_BASE_T base;
5990 +   int handle;
5991 +   int fd;
5992 +   VCHI_CALLBACK_T vchi_callback;
5993 +   void *peek_buf;
5994 +   int peek_size;
5995 +   int client_id;
5996 +} VCHIQ_SERVICE_T;
5997 +
5998 +typedef struct vchiq_service_struct VCHI_SERVICE_T;
5999 +
6000 +struct vchiq_instance_struct
6001 +{
6002 +   int fd;
6003 +   int initialised;
6004 +   int connected;
6005 +   VCOS_THREAD_T completion_thread;
6006 +   VCOS_MUTEX_T mutex;
6007 +   int used_services;
6008 +   VCHIQ_SERVICE_T services[VCHIQ_MAX_INSTANCE_SERVICES];
6009 +} vchiq_instance;
6010 +
6011 +typedef struct vchiq_instance_struct VCHI_STATE_T;
6012 +
6013 +/* Local data */
6014 +static VCOS_LOG_LEVEL_T vchiq_default_lib_log_level = VCOS_LOG_WARN;
6015 +static VCOS_LOG_CAT_T vchiq_lib_log_category;
6016 +static VCOS_MUTEX_T vchiq_lib_mutex;
6017 +static void *free_msgbufs;
6018 +
6019 +
6020 +/* Local utility functions */
6021 +static VCHIQ_INSTANCE_T
6022 +vchiq_lib_init(void);
6023 +
6024 +static void *completion_thread(void *);
6025 +
6026 +static VCHIQ_STATUS_T
6027 +create_service(VCHIQ_INSTANCE_T instance,
6028 +   const VCHIQ_SERVICE_PARAMS_T *params,
6029 +   VCHI_CALLBACK_T vchi_callback,
6030 +   int is_open,
6031 +   VCHIQ_SERVICE_HANDLE_T *pservice);
6032 +
6033 +static int
6034 +fill_peek_buf(VCHI_SERVICE_T *service,
6035 +   VCHI_FLAGS_T flags);
6036 +
6037 +static void *
6038 +alloc_msgbuf(void);
6039 +
6040 +static void
6041 +free_msgbuf(void *buf);
6042 +
6043 +static __inline int
6044 +is_valid_instance(VCHIQ_INSTANCE_T instance)
6045 +{
6046 +   return (instance == &vchiq_instance) && (instance->initialised > 0);
6047 +}
6048 +
6049 +/*
6050 + * VCHIQ API
6051 + */
6052 +
6053 +VCHIQ_STATUS_T
6054 +vchiq_initialise(VCHIQ_INSTANCE_T *pinstance)
6055 +{
6056 +   VCHIQ_INSTANCE_T instance;
6057 +
6058 +   instance = vchiq_lib_init();
6059 +
6060 +   vcos_log_trace( "%s: returning instance handle %p", __func__, instance );
6061 +
6062 +   *pinstance = instance;
6063 +
6064 +   return (instance != NULL) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6065 +}
6066 +
6067 +VCHIQ_STATUS_T
6068 +vchiq_shutdown(VCHIQ_INSTANCE_T instance)
6069 +{
6070 +   vcos_log_trace( "%s called", __func__ );
6071 +
6072 +   if (!is_valid_instance(instance))
6073 +      return VCHIQ_ERROR;
6074 +
6075 +   vcos_mutex_lock(&instance->mutex);
6076 +
6077 +   if (instance->initialised == 1)
6078 +   {
6079 +      int i;
6080 +
6081 +      instance->initialised = -1; /* Enter limbo */
6082 +
6083 +      /* Remove all services */
6084 +
6085 +      for (i = 0; i < instance->used_services; i++)
6086 +      {
6087 +         if (instance->services[i].handle != VCHIQ_INVALID_HANDLE)
6088 +         {
6089 +            vchiq_remove_service(&instance->services[i].base);
6090 +            instance->services[i].handle = VCHIQ_INVALID_HANDLE;
6091 +         }
6092 +      }
6093 +
6094 +      if (instance->connected)
6095 +      {
6096 +         int ret;
6097 +         RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_SHUTDOWN, 0));
6098 +         vcos_assert(ret == 0);
6099 +         vcos_thread_join(&instance->completion_thread, NULL);
6100 +         instance->connected = 0;
6101 +      }
6102 +
6103 +      close(instance->fd);
6104 +      instance->fd = -1;
6105 +   }
6106 +   else if (instance->initialised > 1)
6107 +   {
6108 +      instance->initialised--;
6109 +   }
6110 +
6111 +   vcos_mutex_unlock(&instance->mutex);
6112 +
6113 +   vcos_global_lock();
6114 +
6115 +   if (instance->initialised == -1)
6116 +   {
6117 +      vcos_mutex_delete(&instance->mutex);
6118 +      instance->initialised = 0;
6119 +   }
6120 +
6121 +   vcos_global_unlock();
6122 +
6123 +   vcos_log_trace( "%s returning", __func__ );
6124 +
6125 +   return VCHIQ_SUCCESS;
6126 +}
6127 +
6128 +VCHIQ_STATUS_T
6129 +vchiq_connect(VCHIQ_INSTANCE_T instance)
6130 +{
6131 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
6132 +
6133 +   vcos_log_trace( "%s called", __func__ );
6134 +
6135 +   if (!is_valid_instance(instance))
6136 +      return VCHIQ_ERROR;
6137 +
6138 +   vcos_mutex_lock(&instance->mutex);
6139 +
6140 +   if (!instance->connected)
6141 +   {
6142 +      int ret = ioctl(instance->fd, VCHIQ_IOC_CONNECT, 0);
6143 +      if (ret == 0)
6144 +      {
6145 +         VCOS_THREAD_ATTR_T attrs;
6146 +         instance->connected = 1;
6147 +         vcos_thread_attr_init(&attrs);
6148 +         vcos_thread_create(&instance->completion_thread, "VCHIQ completion",
6149 +                            &attrs, completion_thread, instance);
6150 +      }
6151 +      else
6152 +      {
6153 +         status = VCHIQ_ERROR;
6154 +      }
6155 +   }
6156 +
6157 +   vcos_mutex_unlock(&instance->mutex);
6158 +
6159 +   return status;
6160 +}
6161 +
6162 +VCHIQ_STATUS_T
6163 +vchiq_add_service(VCHIQ_INSTANCE_T instance,
6164 +   int fourcc,
6165 +   VCHIQ_CALLBACK_T callback,
6166 +   void *userdata,
6167 +   VCHIQ_SERVICE_HANDLE_T *pservice)
6168 +{
6169 +   VCHIQ_SERVICE_PARAMS_T params;
6170 +
6171 +   params.fourcc        = fourcc;
6172 +   params.callback      = callback;
6173 +   params.userdata      = userdata;
6174 +   params.version       = 0;
6175 +   params.version_min   = 0;
6176 +
6177 +   return vchiq_add_service_params(instance, &params, pservice);
6178 +}
6179 +
6180 +VCHIQ_STATUS_T
6181 +vchiq_open_service(VCHIQ_INSTANCE_T instance,
6182 +   int fourcc,
6183 +   VCHIQ_CALLBACK_T callback,
6184 +   void *userdata,
6185 +   VCHIQ_SERVICE_HANDLE_T *pservice)
6186 +{
6187 +   VCHIQ_SERVICE_PARAMS_T params;
6188 +
6189 +   params.fourcc        = fourcc;
6190 +   params.callback      = callback;
6191 +   params.userdata      = userdata;
6192 +   params.version       = 0;
6193 +   params.version_min   = 0;
6194 +
6195 +   return vchiq_open_service_params(instance, &params, pservice);
6196 +}
6197 +
6198 +VCHIQ_STATUS_T
6199 +vchiq_add_service_params(VCHIQ_INSTANCE_T instance,
6200 +   const VCHIQ_SERVICE_PARAMS_T *params,
6201 +   VCHIQ_SERVICE_HANDLE_T *pservice)
6202 +{
6203 +   VCHIQ_STATUS_T status;
6204 +
6205 +   vcos_log_trace( "%s called fourcc = 0x%08x (%c%c%c%c)",
6206 +                   __func__,
6207 +                   params->fourcc,
6208 +                   (params->fourcc >> 24) & 0xff,
6209 +                   (params->fourcc >> 16) & 0xff,
6210 +                   (params->fourcc >>  8) & 0xff,
6211 +                   (params->fourcc      ) & 0xff );
6212 +
6213 +   if (!params->callback)
6214 +      return VCHIQ_ERROR;
6215 +
6216 +   if (!is_valid_instance(instance))
6217 +      return VCHIQ_ERROR;
6218 +
6219 +   status = create_service(instance,
6220 +      params,
6221 +      NULL/*vchi_callback*/,
6222 +      0/*!open*/,
6223 +      pservice);
6224 +
6225 +   vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*pservice );
6226 +
6227 +   return status;
6228 +}
6229 +
6230 +VCHIQ_STATUS_T
6231 +vchiq_open_service_params(VCHIQ_INSTANCE_T instance,
6232 +   const VCHIQ_SERVICE_PARAMS_T *params,
6233 +   VCHIQ_SERVICE_HANDLE_T *pservice)
6234 +{
6235 +   VCHIQ_STATUS_T status;
6236 +
6237 +   vcos_log_trace( "%s called fourcc = 0x%08x (%c%c%c%c)",
6238 +                   __func__,
6239 +                   params->fourcc,
6240 +                   (params->fourcc >> 24) & 0xff,
6241 +                   (params->fourcc >> 16) & 0xff,
6242 +                   (params->fourcc >>  8) & 0xff,
6243 +                   (params->fourcc      ) & 0xff );
6244 +
6245 +   if (!params->callback)
6246 +      return VCHIQ_ERROR;
6247 +
6248 +   if (!is_valid_instance(instance))
6249 +      return VCHIQ_ERROR;
6250 +
6251 +   status = create_service(instance,
6252 +      params,
6253 +      NULL/*vchi_callback*/,
6254 +      1/*open*/,
6255 +      pservice);
6256 +
6257 +   vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*pservice );
6258 +
6259 +   return status;
6260 +}
6261 +
6262 +VCHIQ_STATUS_T
6263 +vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
6264 +{
6265 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6266 +   int ret;
6267 +
6268 +   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6269 +
6270 +   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_CLOSE_SERVICE, service->handle));
6271 +
6272 +   if (ret != 0)
6273 +      return VCHIQ_ERROR;
6274 +
6275 +   service->handle = VCHIQ_INVALID_HANDLE;
6276 +   return VCHIQ_SUCCESS;
6277 +}
6278 +
6279 +VCHIQ_STATUS_T
6280 +vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
6281 +{
6282 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6283 +   int ret;
6284 +
6285 +   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6286 +
6287 +   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
6288 +
6289 +   if (ret != 0)
6290 +      return VCHIQ_ERROR;
6291 +
6292 +   service->handle = VCHIQ_INVALID_HANDLE;
6293 +   return VCHIQ_SUCCESS;
6294 +}
6295 +
6296 +VCHIQ_STATUS_T
6297 +vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
6298 +   const VCHIQ_ELEMENT_T *elements,
6299 +   int count)
6300 +{
6301 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6302 +   VCHIQ_QUEUE_MESSAGE_T args;
6303 +   int ret;
6304 +
6305 +   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6306 +
6307 +   args.handle = service->handle;
6308 +   args.elements = elements;
6309 +   args.count = count;
6310 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
6311 +
6312 +   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6313 +}
6314 +
6315 +void
6316 +vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle,
6317 +   VCHIQ_HEADER_T *header)
6318 +{
6319 +   vcos_log_trace( "%s handle=%08x, header=%x", __func__, (uint32_t)handle, (uint32_t)header );
6320 +
6321 +   free_msgbuf(header);
6322 +}
6323 +
6324 +VCHIQ_STATUS_T
6325 +vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
6326 +   const void *data,
6327 +   int size,
6328 +   void *userdata)
6329 +{
6330 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6331 +   VCHIQ_QUEUE_BULK_TRANSFER_T args;
6332 +   int ret;
6333 +
6334 +   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6335 +
6336 +   args.handle = service->handle;
6337 +   args.data = (void *)data;
6338 +   args.size = size;
6339 +   args.userdata = userdata;
6340 +   args.mode = VCHIQ_BULK_MODE_CALLBACK;
6341 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
6342 +
6343 +   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6344 +}
6345 +
6346 +VCHIQ_STATUS_T
6347 +vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
6348 +   void *data,
6349 +   int size,
6350 +   void *userdata)
6351 +{
6352 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6353 +   VCHIQ_QUEUE_BULK_TRANSFER_T args;
6354 +   int ret;
6355 +
6356 +   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6357 +
6358 +   args.handle = service->handle;
6359 +   args.data = data;
6360 +   args.size = size;
6361 +   args.userdata = userdata;
6362 +   args.mode = VCHIQ_BULK_MODE_CALLBACK;
6363 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
6364 +
6365 +   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6366 +}
6367 +
6368 +VCHIQ_STATUS_T
6369 +vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
6370 +   VCHI_MEM_HANDLE_T memhandle,
6371 +   const void *offset,
6372 +   int size,
6373 +   void *userdata)
6374 +{
6375 +   vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6376 +
6377 +   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6378 +
6379 +   return vchiq_queue_bulk_transmit(handle, offset, size, userdata);
6380 +}
6381 +
6382 +VCHIQ_STATUS_T
6383 +vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
6384 +   VCHI_MEM_HANDLE_T memhandle,
6385 +   void *offset,
6386 +   int size,
6387 +   void *userdata)
6388 +{
6389 +   vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6390 +
6391 +   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6392 +
6393 +   return vchiq_queue_bulk_receive(handle, offset, size, userdata);
6394 +}
6395 +
6396 +VCHIQ_STATUS_T
6397 +vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
6398 +   const void *data,
6399 +   int size,
6400 +   void *userdata,
6401 +   VCHIQ_BULK_MODE_T mode)
6402 +{
6403 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6404 +   VCHIQ_QUEUE_BULK_TRANSFER_T args;
6405 +   int ret;
6406 +
6407 +   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6408 +
6409 +   args.handle = service->handle;
6410 +   args.data = (void *)data;
6411 +   args.size = size;
6412 +   args.userdata = userdata;
6413 +   args.mode = mode;
6414 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
6415 +
6416 +   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6417 +}
6418 +
6419 +VCHIQ_STATUS_T
6420 +vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
6421 +   void *data,
6422 +   int size,
6423 +   void *userdata,
6424 +   VCHIQ_BULK_MODE_T mode)
6425 +{
6426 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6427 +   VCHIQ_QUEUE_BULK_TRANSFER_T args;
6428 +   int ret;
6429 +
6430 +   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
6431 +
6432 +   args.handle = service->handle;
6433 +   args.data = data;
6434 +   args.size = size;
6435 +   args.userdata = userdata;
6436 +   args.mode = mode;
6437 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
6438 +
6439 +   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6440 +}
6441 +
6442 +VCHIQ_STATUS_T
6443 +vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
6444 +   VCHI_MEM_HANDLE_T memhandle,
6445 +   const void *offset,
6446 +   int size,
6447 +   void *userdata,
6448 +   VCHIQ_BULK_MODE_T mode)
6449 +{
6450 +   vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6451 +
6452 +   return vchiq_bulk_transmit(handle, offset, size, userdata, mode);
6453 +}
6454 +
6455 +VCHIQ_STATUS_T
6456 +vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
6457 +   VCHI_MEM_HANDLE_T memhandle,
6458 +   void *offset,
6459 +   int size,
6460 +   void *userdata,
6461 +   VCHIQ_BULK_MODE_T mode)
6462 +{
6463 +   vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
6464 +
6465 +   return vchiq_bulk_receive(handle, offset, size, userdata, mode);
6466 +}
6467 +
6468 +int
6469 +vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
6470 +{
6471 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6472 +
6473 +   return ioctl(service->fd, VCHIQ_IOC_GET_CLIENT_ID, service->handle);
6474 +}
6475 +
6476 +VCHIQ_STATUS_T
6477 +vchiq_get_config(VCHIQ_INSTANCE_T instance,
6478 +   int config_size,
6479 +   VCHIQ_CONFIG_T *pconfig)
6480 +{
6481 +   VCHIQ_GET_CONFIG_T args;
6482 +   int ret;
6483 +
6484 +   if (!is_valid_instance(instance))
6485 +      return VCHIQ_ERROR;
6486 +
6487 +   args.config_size = config_size;
6488 +   args.pconfig = pconfig;
6489 +
6490 +   RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_GET_CONFIG, &args));
6491 +
6492 +   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6493 +}
6494 +
6495 +int32_t
6496 +vchiq_use_service( const VCHIQ_SERVICE_HANDLE_T handle )
6497 +{
6498 +    VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6499 +    int ret;
6500 +    RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
6501 +    return ret;
6502 +}
6503 +
6504 +int32_t
6505 +vchiq_release_service( const VCHIQ_SERVICE_HANDLE_T handle )
6506 +{
6507 +    VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6508 +    int ret;
6509 +    RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
6510 +    return ret;
6511 +}
6512 +
6513 +VCHIQ_STATUS_T
6514 +vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
6515 +   VCHIQ_SERVICE_OPTION_T option, int value)
6516 +{
6517 +   VCHIQ_SET_SERVICE_OPTION_T args;
6518 +   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
6519 +   int ret;
6520 +
6521 +   args.handle = service->handle;
6522 +   args.option = option;
6523 +   args.value  = value;
6524 +
6525 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_SET_SERVICE_OPTION, &args));
6526 +
6527 +   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
6528 +}
6529 +
6530 +/*
6531 + * VCHI API
6532 + */
6533 +
6534 +/* ----------------------------------------------------------------------
6535 + * return pointer to the mphi message driver function table
6536 + * -------------------------------------------------------------------- */
6537 +const VCHI_MESSAGE_DRIVER_T *
6538 +vchi_mphi_message_driver_func_table( void )
6539 +{
6540 +   return NULL;
6541 +}
6542 +
6543 +/* ----------------------------------------------------------------------
6544 + * return a pointer to the 'single' connection driver fops
6545 + * -------------------------------------------------------------------- */
6546 +const VCHI_CONNECTION_API_T *
6547 +single_get_func_table( void )
6548 +{
6549 +   return NULL;
6550 +}
6551 +
6552 +VCHI_CONNECTION_T *
6553 +vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
6554 +   const VCHI_MESSAGE_DRIVER_T * low_level )
6555 +{
6556 +   vcos_unused(function_table);
6557 +   vcos_unused(low_level);
6558 +
6559 +   return NULL;
6560 +}
6561 +
6562 +/***********************************************************
6563 + * Name: vchi_msg_peek
6564 + *
6565 + * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
6566 + *             void **data,
6567 + *             uint32_t *msg_size,
6568 + *             VCHI_FLAGS_T flags
6569 + *
6570 + * Description: Routine to return a pointer to the current message (to allow in place processing)
6571 + *              The message can be removed using vchi_msg_remove when you're finished
6572 + *
6573 + * Returns: int32_t - success == 0
6574 + *
6575 + ***********************************************************/
6576 +int32_t
6577 +vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
6578 +   void **data,
6579 +   uint32_t *msg_size,
6580 +   VCHI_FLAGS_T flags )
6581 +{
6582 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6583 +   int ret;
6584 +
6585 +   ret = fill_peek_buf(service, flags);
6586 +
6587 +   if (ret == 0)
6588 +   {
6589 +      *data = service->peek_buf;
6590 +      *msg_size = service->peek_size;
6591 +   }
6592 +
6593 +   return ret;
6594 +}
6595 +
6596 +/***********************************************************
6597 + * Name: vchi_msg_remove
6598 + *
6599 + * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
6600 + *
6601 + * Description: Routine to remove a message (after it has been read with vchi_msg_peek)
6602 + *
6603 + * Returns: int32_t - success == 0
6604 + *
6605 + ***********************************************************/
6606 +int32_t
6607 +vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle )
6608 +{
6609 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6610 +
6611 +   /* Why would you call vchi_msg_remove without calling vchi_msg_peek first? */
6612 +   vcos_assert(service->peek_size >= 0);
6613 +
6614 +   /* Invalidate the content but reuse the buffer */
6615 +   service->peek_size = -1;
6616 +
6617 +   return 0;
6618 +}
6619 +
6620 +/***********************************************************
6621 + * Name: vchi_msg_queue
6622 + *
6623 + * Arguments:  VCHI_SERVICE_HANDLE_T handle,
6624 + *             const void *data,
6625 + *             uint32_t data_size,
6626 + *             VCHI_FLAGS_T flags,
6627 + *             void *msg_handle,
6628 + *
6629 + * Description: Thin wrapper to queue a message onto a connection
6630 + *
6631 + * Returns: int32_t - success == 0
6632 + *
6633 + ***********************************************************/
6634 +int32_t
6635 +vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
6636 +   const void * data,
6637 +   uint32_t data_size,
6638 +   VCHI_FLAGS_T flags,
6639 +   void * msg_handle )
6640 +{
6641 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6642 +   VCHIQ_QUEUE_MESSAGE_T args;
6643 +   VCHIQ_ELEMENT_T element = {data, data_size};
6644 +   int ret;
6645 +
6646 +   vcos_unused(msg_handle);
6647 +   vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
6648 +
6649 +   args.handle = service->handle;
6650 +   args.elements = &element;
6651 +   args.count = 1;
6652 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
6653 +
6654 +   return ret;
6655 +}
6656 +
6657 +/***********************************************************
6658 + * Name: vchi_bulk_queue_receive
6659 + *
6660 + * Arguments:  VCHI_BULK_HANDLE_T handle,
6661 + *             void *data_dst,
6662 + *             const uint32_t data_size,
6663 + *             VCHI_FLAGS_T flags
6664 + *             void *bulk_handle
6665 + *
6666 + * Description: Routine to setup a rcv buffer
6667 + *
6668 + * Returns: int32_t - success == 0
6669 + *
6670 + ***********************************************************/
6671 +int32_t
6672 +vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
6673 +   void * data_dst,
6674 +   uint32_t data_size,
6675 +   VCHI_FLAGS_T flags,
6676 +   void * bulk_handle )
6677 +{
6678 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6679 +   VCHIQ_QUEUE_BULK_TRANSFER_T args;
6680 +   int ret;
6681 +
6682 +   switch ((int)flags) {
6683 +   case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6684 +      args.mode = VCHIQ_BULK_MODE_CALLBACK;
6685 +      break;
6686 +   case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
6687 +      args.mode = VCHIQ_BULK_MODE_BLOCKING;
6688 +      break;
6689 +   case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6690 +   case VCHI_FLAGS_NONE:
6691 +      args.mode = VCHIQ_BULK_MODE_NOCALLBACK;
6692 +      break;
6693 +   default:
6694 +      vcos_assert(0);
6695 +      break;
6696 +   }
6697 +
6698 +   args.handle = service->handle;
6699 +   args.data = data_dst;
6700 +   args.size = data_size;
6701 +   args.userdata = bulk_handle;
6702 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
6703 +
6704 +   return ret;
6705 +}
6706 +
6707 +/***********************************************************
6708 + * Name: vchi_bulk_queue_transmit
6709 + *
6710 + * Arguments:  VCHI_BULK_HANDLE_T handle,
6711 + *             const void *data_src,
6712 + *             uint32_t data_size,
6713 + *             VCHI_FLAGS_T flags,
6714 + *             void *bulk_handle
6715 + *
6716 + * Description: Routine to transmit some data
6717 + *
6718 + * Returns: int32_t - success == 0
6719 + *
6720 + ***********************************************************/
6721 +int32_t
6722 +vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
6723 +   const void * data_src,
6724 +   uint32_t data_size,
6725 +   VCHI_FLAGS_T flags,
6726 +   void * bulk_handle )
6727 +{
6728 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6729 +   VCHIQ_QUEUE_BULK_TRANSFER_T args;
6730 +   int ret;
6731 +
6732 +   switch ((int)flags) {
6733 +   case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6734 +      args.mode = VCHIQ_BULK_MODE_CALLBACK;
6735 +      break;
6736 +   case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
6737 +   case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
6738 +      args.mode = VCHIQ_BULK_MODE_BLOCKING;
6739 +      break;
6740 +   case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
6741 +   case VCHI_FLAGS_NONE:
6742 +      args.mode = VCHIQ_BULK_MODE_NOCALLBACK;
6743 +      break;
6744 +   default:
6745 +      vcos_assert(0);
6746 +      break;
6747 +   }
6748 +
6749 +   args.handle = service->handle;
6750 +   args.data = (void *)data_src;
6751 +   args.size = data_size;
6752 +   args.userdata = bulk_handle;
6753 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
6754 +
6755 +   return ret;
6756 +}
6757 +
6758 +/***********************************************************
6759 + * Name: vchi_msg_dequeue
6760 + *
6761 + * Arguments:  VCHI_SERVICE_HANDLE_T handle,
6762 + *             void *data,
6763 + *             uint32_t max_data_size_to_read,
6764 + *             uint32_t *actual_msg_size
6765 + *             VCHI_FLAGS_T flags
6766 + *
6767 + * Description: Routine to dequeue a message into the supplied buffer
6768 + *
6769 + * Returns: int32_t - success == 0
6770 + *
6771 + ***********************************************************/
6772 +int32_t
6773 +vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
6774 +   void *data,
6775 +   uint32_t max_data_size_to_read,
6776 +   uint32_t *actual_msg_size,
6777 +   VCHI_FLAGS_T flags )
6778 +{
6779 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6780 +   VCHIQ_DEQUEUE_MESSAGE_T args;
6781 +   int ret;
6782 +
6783 +   vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
6784 +
6785 +   if (service->peek_size >= 0)
6786 +   {
6787 +      fprintf(stderr, "vchi_msg_dequeue -> using peek buffer\n");
6788 +      if ((uint32_t)service->peek_size <= max_data_size_to_read)
6789 +      {
6790 +         memcpy(data, service->peek_buf, service->peek_size);
6791 +         *actual_msg_size = service->peek_size;
6792 +         /* Invalidate the peek data, but retain the buffer */
6793 +         service->peek_size = -1;
6794 +         ret = 0;
6795 +      }
6796 +      else
6797 +      {
6798 +         ret = -1;
6799 +      }
6800 +   }
6801 +   else
6802 +   {
6803 +      args.handle = service->handle;
6804 +      args.blocking = (flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
6805 +      args.bufsize = max_data_size_to_read;
6806 +      args.buf = data;
6807 +      RETRY(ret, ioctl(service->fd, VCHIQ_IOC_DEQUEUE_MESSAGE, &args));
6808 +      if (ret >= 0)
6809 +      {
6810 +         *actual_msg_size = ret;
6811 +         ret = 0;
6812 +      }
6813 +   }
6814 +
6815 +   if ((ret < 0) && (errno != EWOULDBLOCK))
6816 +      fprintf(stderr, "vchi_msg_dequeue -> %d(%d)\n", ret, errno);
6817 +
6818 +   return ret;
6819 +}
6820 +
6821 +/***********************************************************
6822 + * Name: vchi_msg_queuev
6823 + *
6824 + * Arguments:  VCHI_SERVICE_HANDLE_T handle,
6825 + *             const void *data,
6826 + *             uint32_t data_size,
6827 + *             VCHI_FLAGS_T flags,
6828 + *             void *msg_handle
6829 + *
6830 + * Description: Thin wrapper to queue a message onto a connection
6831 + *
6832 + * Returns: int32_t - success == 0
6833 + *
6834 + ***********************************************************/
6835 +
6836 +vcos_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
6837 +vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == offsetof(VCHIQ_ELEMENT_T, data));
6838 +vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == offsetof(VCHIQ_ELEMENT_T, size));
6839 +
6840 +int32_t
6841 +vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
6842 +   VCHI_MSG_VECTOR_T * vector,
6843 +   uint32_t count,
6844 +   VCHI_FLAGS_T flags,
6845 +   void *msg_handle )
6846 +{
6847 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6848 +   VCHIQ_QUEUE_MESSAGE_T args;
6849 +   int ret;
6850 +
6851 +   vcos_unused(msg_handle);
6852 +
6853 +   vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
6854 +
6855 +   args.handle = service->handle;
6856 +   args.elements = (const VCHIQ_ELEMENT_T *)vector;
6857 +   args.count = count;
6858 +   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
6859 +
6860 +   return ret;
6861 +}
6862 +
6863 +/***********************************************************
6864 + * Name: vchi_held_msg_release
6865 + *
6866 + * Arguments:  VCHI_HELD_MSG_T *message
6867 + *
6868 + * Description: Routine to release a held message (after it has been read with vchi_msg_hold)
6869 + *
6870 + * Returns: int32_t - success == 0
6871 + *
6872 + ***********************************************************/
6873 +int32_t
6874 +vchi_held_msg_release( VCHI_HELD_MSG_T *message )
6875 +{
6876 +   int ret = -1;
6877 +
6878 +   if (message && message->message && !message->service)
6879 +   {
6880 +      free_msgbuf(message->message);
6881 +      ret = 0;
6882 +   }
6883 +
6884 +   return ret;
6885 +}
6886 +
6887 +/***********************************************************
6888 + * Name: vchi_msg_hold
6889 + *
6890 + * Arguments:  VCHI_SERVICE_HANDLE_T handle,
6891 + *             void **data,
6892 + *             uint32_t *msg_size,
6893 + *             VCHI_FLAGS_T flags,
6894 + *             VCHI_HELD_MSG_T *message_handle
6895 + *
6896 + * Description: Routine to return a pointer to the current message (to allow in place processing)
6897 + *              The message is dequeued - don't forget to release the message using
6898 + *              vchi_held_msg_release when you're finished
6899 + *
6900 + * Returns: int32_t - success == 0
6901 + *
6902 + ***********************************************************/
6903 +int32_t
6904 +vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
6905 +   void **data,
6906 +   uint32_t *msg_size,
6907 +   VCHI_FLAGS_T flags,
6908 +   VCHI_HELD_MSG_T *message_handle )
6909 +{
6910 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
6911 +   int ret;
6912 +
6913 +   ret = fill_peek_buf(service, flags);
6914 +
6915 +   if (ret == 0)
6916 +   {
6917 +      *data = service->peek_buf;
6918 +      *msg_size = service->peek_size;
6919 +
6920 +      message_handle->message = service->peek_buf;
6921 +      message_handle->service = NULL;
6922 +
6923 +      service->peek_size = -1;
6924 +      service->peek_buf = NULL;
6925 +   }
6926 +
6927 +   return 0;
6928 +}
6929 +
6930 +/***********************************************************
6931 + * Name: vchi_initialise
6932 + *
6933 + * Arguments: VCHI_INSTANCE_T *instance_handle
6934 + *            VCHI_CONNECTION_T **connections
6935 + *            const uint32_t num_connections
6936 + *
6937 + * Description: Initialises the hardware but does not transmit anything
6938 + *              When run as a Host App this will be called twice hence the need
6939 + *              to malloc the state information
6940 + *
6941 + * Returns: 0 if successful, failure otherwise
6942 + *
6943 + ***********************************************************/
6944 +int32_t
6945 +vchi_initialise( VCHI_INSTANCE_T *instance_handle )
6946 +{
6947 +   VCHIQ_INSTANCE_T instance;
6948 +
6949 +   instance = vchiq_lib_init();
6950 +
6951 +   vcos_log_trace( "%s: returning instance handle %p", __func__, instance );
6952 +
6953 +   *instance_handle = (VCHI_INSTANCE_T)instance;
6954 +
6955 +   return (instance != NULL) ? 0 : -1;
6956 +}
6957 +
6958 +/***********************************************************
6959 + * Name: vchi_connect
6960 + *
6961 + * Arguments: VCHI_CONNECTION_T **connections
6962 + *            const uint32_t num_connections
6963 + *            VCHI_INSTANCE_T instance_handle )
6964 + *
6965 + * Description: Starts the command service on each connection,
6966 + *              causing INIT messages to be pinged back and forth
6967 + *
6968 + * Returns: 0 if successful, failure otherwise
6969 + *
6970 + ***********************************************************/
6971 +int32_t
6972 +vchi_connect( VCHI_CONNECTION_T **connections,
6973 +   const uint32_t num_connections,
6974 +   VCHI_INSTANCE_T instance_handle )
6975 +{
6976 +   VCHIQ_STATUS_T status;
6977 +
6978 +   vcos_unused(connections);
6979 +   vcos_unused(num_connections);
6980 +
6981 +   status = vchiq_connect((VCHIQ_INSTANCE_T)instance_handle);
6982 +
6983 +   return (status == VCHIQ_SUCCESS) ? 0 : -1;
6984 +}
6985 +
6986 +
6987 +/***********************************************************
6988 + * Name: vchi_disconnect
6989 + *
6990 + * Arguments: VCHI_INSTANCE_T instance_handle
6991 + *
6992 + * Description: Stops the command service on each connection,
6993 + *              causing DE-INIT messages to be pinged back and forth
6994 + *
6995 + * Returns: 0 if successful, failure otherwise
6996 + *
6997 + ***********************************************************/
6998 +int32_t
6999 +vchi_disconnect( VCHI_INSTANCE_T instance_handle )
7000 +{
7001 +   VCHIQ_STATUS_T status;
7002 +   
7003 +   status = vchiq_shutdown((VCHIQ_INSTANCE_T)instance_handle);
7004 +
7005 +   return (status == VCHIQ_SUCCESS) ? 0 : -1;
7006 +}
7007 +
7008 +
7009 +/***********************************************************
7010 + * Name: vchi_service_open
7011 + * Name: vchi_service_create
7012 + *
7013 + * Arguments: VCHI_INSTANCE_T *instance_handle
7014 + *            SERVICE_CREATION_T *setup,
7015 + *            VCHI_SERVICE_HANDLE_T *handle
7016 + *
7017 + * Description: Routine to open a service
7018 + *
7019 + * Returns: int32_t - success == 0
7020 + *
7021 + ***********************************************************/
7022 +int32_t
7023 +vchi_service_open( VCHI_INSTANCE_T instance_handle,
7024 +   SERVICE_CREATION_T *setup,
7025 +   VCHI_SERVICE_HANDLE_T *handle )
7026 +{
7027 +   VCHIQ_SERVICE_PARAMS_T params;
7028 +   VCHIQ_STATUS_T status;
7029 +
7030 +   memset(&params, 0, sizeof(params));
7031 +   params.fourcc = setup->service_id;
7032 +   params.userdata = setup->callback_param;
7033 +
7034 +   status = create_service((VCHIQ_INSTANCE_T)instance_handle,
7035 +      &params,
7036 +      setup->callback,
7037 +      1/*open*/,
7038 +      (VCHIQ_SERVICE_HANDLE_T *)handle);
7039 +
7040 +   return (status == VCHIQ_SUCCESS) ? 0 : -1;
7041 +}
7042 +
7043 +int32_t
7044 +vchi_service_create( VCHI_INSTANCE_T instance_handle,
7045 +   SERVICE_CREATION_T *setup, VCHI_SERVICE_HANDLE_T *handle )
7046 +{
7047 +   VCHIQ_SERVICE_PARAMS_T params;
7048 +   VCHIQ_STATUS_T status;
7049 +
7050 +   memset(&params, 0, sizeof(params));
7051 +   params.fourcc = setup->service_id;
7052 +   params.userdata = setup->callback_param;
7053 +
7054 +   status = create_service((VCHIQ_INSTANCE_T)instance_handle,
7055 +      &params,
7056 +      setup->callback,
7057 +      0/*!open*/,
7058 +      (VCHIQ_SERVICE_HANDLE_T *)handle);
7059 +
7060 +   return (status == VCHIQ_SUCCESS) ? 0 : -1;
7061 +}
7062 +
7063 +int32_t
7064 +vchi_service_close( const VCHI_SERVICE_HANDLE_T handle )
7065 +{
7066 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7067 +   int ret;
7068 +   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
7069 +
7070 +   if (ret == 0)
7071 +      service->handle = VCHIQ_INVALID_HANDLE;
7072 +
7073 +   return ret;
7074 +}
7075 +
7076 +int32_t
7077 +vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle )
7078 +{
7079 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7080 +   int ret;
7081 +   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
7082 +
7083 +   if (ret == 0)
7084 +      service->handle = VCHIQ_INVALID_HANDLE;
7085 +
7086 +   return ret;
7087 +}
7088 +
7089 +/* ----------------------------------------------------------------------
7090 + * read a uint32_t from buffer.
7091 + * network format is defined to be little endian
7092 + * -------------------------------------------------------------------- */
7093 +uint32_t
7094 +vchi_readbuf_uint32( const void *_ptr )
7095 +{
7096 +   const unsigned char *ptr = _ptr;
7097 +   return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
7098 +}
7099 +
7100 +/* ----------------------------------------------------------------------
7101 + * write a uint32_t to buffer.
7102 + * network format is defined to be little endian
7103 + * -------------------------------------------------------------------- */
7104 +void
7105 +vchi_writebuf_uint32( void *_ptr, uint32_t value )
7106 +{
7107 +   unsigned char *ptr = _ptr;
7108 +   ptr[0] = (unsigned char)((value >> 0)  & 0xFF);
7109 +   ptr[1] = (unsigned char)((value >> 8)  & 0xFF);
7110 +   ptr[2] = (unsigned char)((value >> 16) & 0xFF);
7111 +   ptr[3] = (unsigned char)((value >> 24) & 0xFF);
7112 +}
7113 +
7114 +/* ----------------------------------------------------------------------
7115 + * read a uint16_t from buffer.
7116 + * network format is defined to be little endian
7117 + * -------------------------------------------------------------------- */
7118 +uint16_t
7119 +vchi_readbuf_uint16( const void *_ptr )
7120 +{
7121 +   const unsigned char *ptr = _ptr;
7122 +   return ptr[0] | (ptr[1] << 8);
7123 +}
7124 +
7125 +/* ----------------------------------------------------------------------
7126 + * write a uint16_t into the buffer.
7127 + * network format is defined to be little endian
7128 + * -------------------------------------------------------------------- */
7129 +void
7130 +vchi_writebuf_uint16( void *_ptr, uint16_t value )
7131 +{
7132 +   unsigned char *ptr = _ptr;
7133 +   ptr[0] = (value >> 0)  & 0xFF;
7134 +   ptr[1] = (value >> 8)  & 0xFF;
7135 +}
7136 +
7137 +/***********************************************************
7138 + * Name: vchi_service_use
7139 + *
7140 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
7141 + *
7142 + * Description: Routine to increment refcount on a service
7143 + *
7144 + * Returns: void
7145 + *
7146 + ***********************************************************/
7147 +int32_t
7148 +vchi_service_use( const VCHI_SERVICE_HANDLE_T handle )
7149 +{
7150 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7151 +   int ret;
7152 +   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
7153 +   return ret;
7154 +}
7155 +
7156 +/***********************************************************
7157 + * Name: vchi_service_release
7158 + *
7159 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
7160 + *
7161 + * Description: Routine to decrement refcount on a service
7162 + *
7163 + * Returns: void
7164 + *
7165 + ***********************************************************/
7166 +int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle )
7167 +{
7168 +   VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
7169 +   int ret;
7170 +   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
7171 +   return ret;
7172 +}
7173 +
7174 +/*
7175 + * Support functions
7176 + */
7177 +
7178 +static VCHIQ_INSTANCE_T
7179 +vchiq_lib_init(void)
7180 +{
7181 +   static int mutex_initialised = 0;
7182 +   static VCOS_MUTEX_T vchiq_lib_mutex;
7183 +   VCHIQ_INSTANCE_T instance = &vchiq_instance;
7184 +
7185 +   vcos_global_lock();
7186 +   if (!mutex_initialised)
7187 +   {
7188 +      vcos_mutex_create(&vchiq_lib_mutex, "vchiq-init");
7189 +
7190 +      vcos_log_set_level( &vchiq_lib_log_category, vchiq_default_lib_log_level );
7191 +      vcos_log_register( "vchiq_lib", &vchiq_lib_log_category );
7192 +
7193 +      mutex_initialised = 1;
7194 +   }
7195 +   vcos_global_unlock();
7196 +
7197 +   vcos_mutex_lock(&vchiq_lib_mutex);
7198 +
7199 +   if (instance->initialised == 0)
7200 +   {
7201 +      instance->fd = open("/dev/vchiq", O_RDWR);
7202 +      if (instance->fd >= 0)
7203 +      {
7204 +         VCHIQ_GET_CONFIG_T args;
7205 +         VCHIQ_CONFIG_T config;
7206 +         int ret;
7207 +         args.config_size = sizeof(config);
7208 +         args.pconfig = &config;
7209 +         RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_GET_CONFIG, &args));
7210 +         if ((ret == 0) && (config.version >= VCHIQ_VERSION_MIN) && (config.version_min <= VCHIQ_VERSION))
7211 +         {
7212 +            instance->used_services = 0;
7213 +            vcos_mutex_create(&instance->mutex, "VCHIQ instance");
7214 +            instance->initialised = 1;
7215 +         }
7216 +         else
7217 +         {
7218 +            if (ret == 0)
7219 +            {
7220 +               vcos_log_error("Incompatible VCHIQ library - driver version %d (min %d), library version %d (min %d)",
7221 +                  config.version, config.version_min, VCHIQ_VERSION, VCHIQ_VERSION_MIN);
7222 +            }
7223 +            else
7224 +            {
7225 +               vcos_log_error("Very incompatible VCHIQ library - cannot retrieve driver version");
7226 +            }
7227 +            close(instance->fd);
7228 +            instance = NULL;
7229 +         }
7230 +      }
7231 +      else
7232 +      {
7233 +         instance = NULL;
7234 +      }
7235 +   }
7236 +   else if (instance->initialised > 0)
7237 +   {
7238 +      instance->initialised++;
7239 +   }
7240 +
7241 +   vcos_mutex_unlock(&vchiq_lib_mutex);
7242 +
7243 +   return instance;
7244 +}
7245 +
7246 +static void *
7247 +completion_thread(void *arg)
7248 +{
7249 +   VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)arg;
7250 +   VCHIQ_AWAIT_COMPLETION_T args;
7251 +   VCHIQ_COMPLETION_DATA_T completions[8];
7252 +   void *msgbufs[8];
7253 +
7254 +   static const VCHI_CALLBACK_REASON_T vchiq_reason_to_vchi[] =
7255 +   {
7256 +      VCHI_CALLBACK_SERVICE_OPENED,        // VCHIQ_SERVICE_OPENED
7257 +      VCHI_CALLBACK_SERVICE_CLOSED,        // VCHIQ_SERVICE_CLOSED
7258 +      VCHI_CALLBACK_MSG_AVAILABLE,         // VCHIQ_MESSAGE_AVAILABLE
7259 +      VCHI_CALLBACK_BULK_SENT,             // VCHIQ_BULK_TRANSMIT_DONE
7260 +      VCHI_CALLBACK_BULK_RECEIVED,         // VCHIQ_BULK_RECEIVE_DONE
7261 +      VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, // VCHIQ_BULK_TRANSMIT_ABORTED
7262 +      VCHI_CALLBACK_BULK_RECEIVE_ABORTED,  // VCHIQ_BULK_RECEIVE_ABORTED
7263 +   };
7264 +
7265 +   args.count = vcos_countof(completions);
7266 +   args.buf = completions;
7267 +   args.msgbufsize = MSGBUF_SIZE;
7268 +   args.msgbufcount = 0;
7269 +   args.msgbufs = msgbufs;
7270 +
7271 +   while (1)
7272 +   {
7273 +      int ret, i;
7274 +
7275 +      while ((unsigned int)args.msgbufcount < vcos_countof(msgbufs))
7276 +      {
7277 +         void *msgbuf = alloc_msgbuf();
7278 +         if (msgbuf)
7279 +         {
7280 +            msgbufs[args.msgbufcount++] = msgbuf;
7281 +         }
7282 +         else
7283 +         {
7284 +            fprintf(stderr, "vchiq_lib: failed to allocate a message buffer\n");
7285 +            vcos_demand(args.msgbufcount != 0);
7286 +         }
7287 +      }
7288 +
7289 +      RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_AWAIT_COMPLETION, &args));
7290 +
7291 +      if (ret <= 0)
7292 +         break;
7293 +
7294 +      for (i = 0; i < ret; i++)
7295 +      {
7296 +         VCHIQ_COMPLETION_DATA_T *completion = &completions[i];
7297 +         VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)completion->service_userdata;
7298 +         if (service->base.callback)
7299 +         {
7300 +            vcos_log_trace( "callback(%x, %x, %x, %x)",
7301 +               completion->reason, (uint32_t)completion->header,
7302 +               (uint32_t)&service->base, (uint32_t)completion->bulk_userdata );
7303 +            service->base.callback(completion->reason, completion->header,
7304 +               &service->base, completion->bulk_userdata);
7305 +         }
7306 +         else if (service->vchi_callback)
7307 +         {
7308 +            VCHI_CALLBACK_REASON_T vchi_reason =
7309 +               vchiq_reason_to_vchi[completion->reason];
7310 +            service->vchi_callback(service->base.userdata, vchi_reason, completion->bulk_userdata);
7311 +         }
7312 +      }
7313 +   }
7314 +   return NULL;
7315 +}
7316 +
7317 +static VCHIQ_STATUS_T
7318 +create_service(VCHIQ_INSTANCE_T instance,
7319 +   const VCHIQ_SERVICE_PARAMS_T *params,
7320 +   VCHI_CALLBACK_T vchi_callback,
7321 +   int is_open,
7322 +   VCHIQ_SERVICE_HANDLE_T *pservice)
7323 +{
7324 +   VCHIQ_SERVICE_T *service = NULL;
7325 +   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
7326 +   int i;
7327 +
7328 +   if (!is_valid_instance(instance))
7329 +      return VCHIQ_ERROR;
7330 +
7331 +   vcos_mutex_lock(&instance->mutex);
7332 +
7333 +   /* Find a free service */
7334 +   if (is_open)
7335 +   {
7336 +      /* Find a free service */
7337 +      for (i = 0; i < instance->used_services; i++)
7338 +      {
7339 +         if (instance->services[i].handle == VCHIQ_INVALID_HANDLE)
7340 +         {
7341 +            service = &instance->services[i];
7342 +            break;
7343 +         }
7344 +      }
7345 +   }
7346 +   else
7347 +   {
7348 +      for (i = (instance->used_services - 1); i >= 0; i--)
7349 +      {
7350 +         VCHIQ_SERVICE_T *srv = &instance->services[i];
7351 +         if (srv->handle == VCHIQ_INVALID_HANDLE)
7352 +         {
7353 +            service = srv;
7354 +         }
7355 +         else if (
7356 +            (srv->base.fourcc == params->fourcc) &&
7357 +            ((srv->base.callback != params->callback) ||
7358 +            (srv->vchi_callback != vchi_callback)))
7359 +         {
7360 +            /* There is another server using this fourcc which doesn't match */
7361 +            service = NULL;
7362 +            status = VCHIQ_ERROR;
7363 +            break;
7364 +         }
7365 +      }
7366 +   }
7367 +
7368 +   if (!service && (status == VCHIQ_SUCCESS) &&
7369 +      (instance->used_services < VCHIQ_MAX_INSTANCE_SERVICES))
7370 +      service = &instance->services[instance->used_services++];
7371 +
7372 +   if (service)
7373 +   {
7374 +      VCHIQ_CREATE_SERVICE_T args;
7375 +      int ret;
7376 +      service->base.fourcc = params->fourcc;
7377 +      service->base.callback = params->callback;
7378 +      service->vchi_callback = vchi_callback;
7379 +      service->base.userdata = params->userdata;
7380 +      service->fd = instance->fd;
7381 +      service->peek_size = -1;
7382 +      service->peek_buf = NULL;
7383 +
7384 +      args.params = *params;
7385 +      args.params.userdata = service;
7386 +      args.is_open = is_open;
7387 +      args.is_vchi = (params->callback == NULL);
7388 +      args.handle = -1; /* OUT parameter */
7389 +      RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_CREATE_SERVICE, &args));
7390 +      if (ret == 0)
7391 +         service->handle = args.handle;
7392 +      else
7393 +         status = VCHIQ_ERROR;
7394 +   }
7395 +
7396 +   *pservice = (status == VCHIQ_SUCCESS) ? &service->base : NULL;
7397 +
7398 +   vcos_mutex_unlock(&instance->mutex);
7399 +
7400 +   return status;
7401 +}
7402 +
7403 +static int
7404 +fill_peek_buf(VCHI_SERVICE_T *service,
7405 +   VCHI_FLAGS_T flags)
7406 +{
7407 +   VCHIQ_DEQUEUE_MESSAGE_T args;
7408 +   int ret = 0;
7409 +
7410 +   vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
7411 +
7412 +   if (service->peek_size < 0)
7413 +   {
7414 +      if (!service->peek_buf)
7415 +         service->peek_buf = alloc_msgbuf();
7416 +
7417 +      if (service->peek_buf)
7418 +      {
7419 +         args.handle = service->handle;
7420 +         args.blocking = (flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
7421 +         args.bufsize = MSGBUF_SIZE;
7422 +         args.buf = service->peek_buf;
7423 +
7424 +         RETRY(ret, ioctl(service->fd, VCHIQ_IOC_DEQUEUE_MESSAGE, &args));
7425 +
7426 +         if (ret >= 0)
7427 +         {
7428 +            service->peek_size = ret;
7429 +            ret = 0;
7430 +         }
7431 +         else
7432 +         {
7433 +            ret = -1;
7434 +         }
7435 +      }
7436 +      else
7437 +      {
7438 +         ret = -1;
7439 +      }
7440 +   }
7441 +
7442 +   return ret;
7443 +}
7444 +
7445 +
7446 +static void *
7447 +alloc_msgbuf(void)
7448 +{
7449 +   void *msgbuf;
7450 +   vcos_mutex_lock(&vchiq_lib_mutex);
7451 +   msgbuf = free_msgbufs;
7452 +   if (msgbuf)
7453 +      free_msgbufs = *(void **)msgbuf;
7454 +   vcos_mutex_unlock(&vchiq_lib_mutex);
7455 +   if (!msgbuf)
7456 +      msgbuf = malloc(MSGBUF_SIZE);
7457 +   return msgbuf;
7458 +}
7459 +
7460 +static void
7461 +free_msgbuf(void *buf)
7462 +{
7463 +   vcos_mutex_lock(&vchiq_lib_mutex);
7464 +   *(void **)buf = free_msgbufs;
7465 +   free_msgbufs = buf;
7466 +   vcos_mutex_unlock(&vchiq_lib_mutex);
7467 +}
7468 --- /dev/null
7469 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
7470 @@ -0,0 +1,45 @@
7471 +/*****************************************************************************
7472 +* Copyright 2001 - 2010 Broadcom Corporation.  All rights reserved.
7473 +*
7474 +* Unless you and Broadcom execute a separate written software license
7475 +* agreement governing use of this software, this software is licensed to you
7476 +* under the terms of the GNU General Public License version 2, available at
7477 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
7478 +*
7479 +* Notwithstanding the above, under no circumstances may you combine this
7480 +* software in any way with any other Broadcom software provided under a
7481 +* license other than the GPL, without Broadcom's express prior written
7482 +* consent.
7483 +*****************************************************************************/
7484 +
7485 +#ifndef VCHIQ_MEMDRV_H
7486 +#define VCHIQ_MEMDRV_H
7487 +
7488 +/* ---- Include Files ----------------------------------------------------- */
7489 +
7490 +#include <linux/kernel.h>
7491 +#include "vchiq_if.h"
7492 +
7493 +/* ---- Constants and Types ---------------------------------------------- */
7494 +
7495 +typedef struct
7496 +{
7497 +    void                   *armSharedMemVirt;
7498 +    dma_addr_t              armSharedMemPhys;
7499 +    size_t                  armSharedMemSize;
7500 +
7501 +    void                   *vcSharedMemVirt;
7502 +    dma_addr_t              vcSharedMemPhys;
7503 +    size_t                  vcSharedMemSize;
7504 +
7505 +} VCHIQ_SHARED_MEM_INFO_T;
7506 +
7507 +/* ---- Variable Externs ------------------------------------------------- */
7508 +
7509 +/* ---- Function Prototypes ---------------------------------------------- */
7510 +
7511 +void vchiq_get_shared_mem_info( VCHIQ_SHARED_MEM_INFO_T *info );
7512 +
7513 +VCHIQ_STATUS_T vchiq_memdrv_initialise(void);
7514 +
7515 +#endif
7516 --- /dev/null
7517 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
7518 @@ -0,0 +1,43 @@
7519 +/*
7520 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
7521 + *
7522 + * This program is free software; you can redistribute it and/or modify
7523 + * it under the terms of the GNU General Public License as published by
7524 + * the Free Software Foundation; either version 2 of the License, or
7525 + * (at your option) any later version.
7526 + *
7527 + * This program is distributed in the hope that it will be useful,
7528 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7529 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7530 + * GNU General Public License for more details.
7531 + *
7532 + * You should have received a copy of the GNU General Public License
7533 + * along with this program; if not, write to the Free Software
7534 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
7535 + */
7536 +
7537 +#ifndef VCHIQ_PAGELIST_H
7538 +#define VCHIQ_PAGELIST_H
7539 +
7540 +#ifndef PAGE_SIZE
7541 +#define PAGE_SIZE 4096
7542 +#endif
7543 +#define CACHE_LINE_SIZE 32
7544 +#define PAGELIST_WRITE 0
7545 +#define PAGELIST_READ 1
7546 +#define PAGELIST_READ_WITH_FRAGMENTS 2
7547 +
7548 +typedef struct pagelist_struct {
7549 +       unsigned long length;
7550 +       unsigned short type;
7551 +       unsigned short offset;
7552 +       unsigned long addrs[1]; /* N.B. 12 LSBs hold the number of following
7553 +                                  pages at consecutive addresses. */
7554 +} PAGELIST_T;
7555 +
7556 +typedef struct fragments_struct {
7557 +       char headbuf[CACHE_LINE_SIZE];
7558 +       char tailbuf[CACHE_LINE_SIZE];
7559 +} FRAGMENTS_T;
7560 +
7561 +#endif /* VCHIQ_PAGELIST_H */
7562 --- /dev/null
7563 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
7564 @@ -0,0 +1,970 @@
7565 +/*
7566 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
7567 + *
7568 + * This program is free software; you can redistribute it and/or modify
7569 + * it under the terms of the GNU General Public License as published by
7570 + * the Free Software Foundation; either version 2 of the License, or
7571 + * (at your option) any later version.
7572 + *
7573 + * This program is distributed in the hope that it will be useful,
7574 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7575 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7576 + * GNU General Public License for more details.
7577 + *
7578 + * You should have received a copy of the GNU General Public License
7579 + * along with this program; if not, write to the Free Software
7580 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
7581 + */
7582 +
7583 +#include "interface/vchi/vchi.h"
7584 +#include "vchiq.h"
7585 +#include "vchiq_core.h"
7586 +
7587 +#include "vchiq_util.h"
7588 +
7589 +#include <stddef.h>
7590 +
7591 +#if defined(__KERNEL__)
7592 +#include <linux/module.h>
7593 +#endif
7594 +
7595 +#define vchiq_status_to_vchi(status) ((int32_t)status)
7596 +
7597 +typedef struct {
7598 +   VCHIQ_SERVICE_HANDLE_T handle;
7599 +
7600 +   VCHIU_QUEUE_T queue;
7601 +
7602 +   VCHI_CALLBACK_T callback;
7603 +   void *callback_param;
7604 +} SHIM_SERVICE_T;
7605 +
7606 +/* ----------------------------------------------------------------------
7607 + * return pointer to the mphi message driver function table
7608 + * -------------------------------------------------------------------- */
7609 +#ifdef WIN32
7610 +const VCHI_MESSAGE_DRIVER_T *
7611 +mphi_get_func_table( void )
7612 +{
7613 +   return NULL;
7614 +}
7615 +#endif
7616 +
7617 +/* ----------------------------------------------------------------------
7618 + * return pointer to the mphi message driver function table
7619 + * -------------------------------------------------------------------- */
7620 +const VCHI_MESSAGE_DRIVER_T *
7621 +vchi_mphi_message_driver_func_table( void )
7622 +{
7623 +   return NULL;
7624 +}
7625 +
7626 +/* ----------------------------------------------------------------------
7627 + * return a pointer to the 'single' connection driver fops
7628 + * -------------------------------------------------------------------- */
7629 +const VCHI_CONNECTION_API_T *
7630 +single_get_func_table( void )
7631 +{
7632 +   return NULL;
7633 +}
7634 +
7635 +VCHI_CONNECTION_T * vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
7636 +                                            const VCHI_MESSAGE_DRIVER_T * low_level)
7637 +{
7638 +   vcos_unused(function_table);
7639 +   vcos_unused(low_level);
7640 +   return NULL;
7641 +}
7642 +
7643 +/***********************************************************
7644 + * Name: vchi_msg_peek
7645 + *
7646 + * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
7647 + *             void **data,
7648 + *             uint32_t *msg_size,
7649 + *             VCHI_FLAGS_T flags
7650 + *
7651 + * Description: Routine to return a pointer to the current message (to allow in place processing)
7652 + *              The message can be removed using vchi_msg_remove when you're finished
7653 + *
7654 + * Returns: int32_t - success == 0
7655 + *
7656 + ***********************************************************/
7657 +int32_t vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
7658 +                       void **data,
7659 +                       uint32_t *msg_size,
7660 +                       VCHI_FLAGS_T flags )
7661 +{
7662 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7663 +   VCHIQ_HEADER_T *header;
7664 +
7665 +   vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
7666 +
7667 +   if (flags == VCHI_FLAGS_NONE)
7668 +      if (vchiu_queue_is_empty(&service->queue))
7669 +         return -1;
7670 +
7671 +   header = vchiu_queue_peek(&service->queue);
7672 +
7673 +   *data = header->data;
7674 +   *msg_size = header->size;
7675 +
7676 +   return 0;
7677 +}
7678 +
7679 +/***********************************************************
7680 + * Name: vchi_msg_remove
7681 + *
7682 + * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
7683 + *
7684 + * Description: Routine to remove a message (after it has been read with vchi_msg_peek)
7685 + *
7686 + * Returns: int32_t - success == 0
7687 + *
7688 + ***********************************************************/
7689 +int32_t vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle )
7690 +{
7691 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7692 +   VCHIQ_HEADER_T *header;
7693 +
7694 +   header = vchiu_queue_pop(&service->queue);
7695 +
7696 +   vchiq_release_message(service->handle, header);
7697 +
7698 +   return 0;
7699 +}
7700 +
7701 +/***********************************************************
7702 + * Name: vchi_msg_queue
7703 + *
7704 + * Arguments:  VCHI_SERVICE_HANDLE_T handle,
7705 + *             const void *data,
7706 + *             uint32_t data_size,
7707 + *             VCHI_FLAGS_T flags,
7708 + *             void *msg_handle,
7709 + *
7710 + * Description: Thin wrapper to queue a message onto a connection
7711 + *
7712 + * Returns: int32_t - success == 0
7713 + *
7714 + ***********************************************************/
7715 +int32_t vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
7716 +                        const void * data,
7717 +                        uint32_t data_size,
7718 +                        VCHI_FLAGS_T flags,
7719 +                        void * msg_handle )
7720 +{
7721 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7722 +   VCHIQ_ELEMENT_T element = {data, data_size};
7723 +   VCHIQ_STATUS_T status;
7724 +
7725 +   vcos_unused(msg_handle);
7726 +
7727 +   vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
7728 +
7729 +   status = vchiq_queue_message(service->handle, &element, 1);
7730 +
7731 +   // On some platforms, like linux kernel, vchiq_queue_message() may return
7732 +   // VCHIQ_RETRY, so we need to implment a retry mechanism since this
7733 +   // function is supposed to block until queued
7734 +   while ( status == VCHIQ_RETRY )
7735 +   {
7736 +      vcos_sleep( 1 );
7737 +      status = vchiq_queue_message(service->handle, &element, 1);
7738 +   }
7739 +
7740 +   return vchiq_status_to_vchi(status);
7741 +}
7742 +
7743 +/***********************************************************
7744 + * Name: vchi_bulk_queue_receive
7745 + *
7746 + * Arguments:  VCHI_BULK_HANDLE_T handle,
7747 + *             void *data_dst,
7748 + *             const uint32_t data_size,
7749 + *             VCHI_FLAGS_T flags
7750 + *             void *bulk_handle
7751 + *
7752 + * Description: Routine to setup a rcv buffer
7753 + *
7754 + * Returns: int32_t - success == 0
7755 + *
7756 + ***********************************************************/
7757 +int32_t vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
7758 +                                 void * data_dst,
7759 +                                 uint32_t data_size,
7760 +                                 VCHI_FLAGS_T flags,
7761 +                                 void * bulk_handle )
7762 +{
7763 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7764 +   VCHIQ_BULK_MODE_T mode;
7765 +   VCHIQ_STATUS_T status;
7766 +
7767 +   switch ((int)flags) {
7768 +   case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7769 +      vcos_assert(service->callback);
7770 +      mode = VCHIQ_BULK_MODE_CALLBACK;
7771 +      break;
7772 +   case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7773 +      mode = VCHIQ_BULK_MODE_BLOCKING;
7774 +      break;
7775 +   case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7776 +   case VCHI_FLAGS_NONE:
7777 +      mode = VCHIQ_BULK_MODE_NOCALLBACK;
7778 +      break;
7779 +   default:
7780 +      vcos_assert(0);
7781 +      return vchiq_status_to_vchi(VCHIQ_ERROR);
7782 +   }
7783 +
7784 +   status = vchiq_bulk_receive(service->handle, data_dst, data_size,
7785 +      bulk_handle, mode);
7786 +
7787 +   // On some platforms, like linux kernel, vchiq_bulk_receive() may return
7788 +   // VCHIQ_RETRY, so we need to implment a retry mechanism since this
7789 +   // function is supposed to block until queued
7790 +   while ( status == VCHIQ_RETRY )
7791 +   {
7792 +      vcos_sleep( 1 );
7793 +      status = vchiq_bulk_receive(service->handle, data_dst, data_size,
7794 +         bulk_handle, mode);
7795 +   }
7796 +
7797 +   return vchiq_status_to_vchi(status);
7798 +}
7799 +
7800 +/***********************************************************
7801 + * Name: vchi_bulk_queue_receive_reloc
7802 + *
7803 + * Arguments:  VCHI_BULK_HANDLE_T handle,
7804 + *             VCHI_MEM_HANDLE_T h
7805 + *             uint32_t offset
7806 + *             const uint32_t data_size,
7807 + *             VCHI_FLAGS_T flags
7808 + *             void *bulk_handle
7809 + *
7810 + * Description: Routine to setup a relocatable rcv buffer
7811 + *
7812 + * Returns: int32_t - success == 0
7813 + *
7814 + ***********************************************************/
7815 +int32_t vchi_bulk_queue_receive_reloc( const VCHI_SERVICE_HANDLE_T handle,
7816 +                                       VCHI_MEM_HANDLE_T h,
7817 +                                       uint32_t offset,
7818 +                                       uint32_t data_size,
7819 +                                       const VCHI_FLAGS_T flags,
7820 +                                       void * const bulk_handle )
7821 +{
7822 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7823 +   VCHIQ_BULK_MODE_T mode;
7824 +   VCHIQ_STATUS_T status;
7825 +
7826 +   switch ((int)flags) {
7827 +   case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7828 +      vcos_assert(service->callback);
7829 +      mode = VCHIQ_BULK_MODE_CALLBACK;
7830 +      break;
7831 +   case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7832 +      mode = VCHIQ_BULK_MODE_BLOCKING;
7833 +      break;
7834 +   case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7835 +   case VCHI_FLAGS_NONE:
7836 +      mode = VCHIQ_BULK_MODE_NOCALLBACK;
7837 +      break;
7838 +   default:
7839 +      vcos_assert(0);
7840 +      return vchiq_status_to_vchi(VCHIQ_ERROR);
7841 +   }
7842 +
7843 +   status = vchiq_bulk_receive_handle(service->handle, h, (void*)offset,
7844 +      data_size, bulk_handle, mode);
7845 +
7846 +   // On some platforms, like linux kernel, vchiq_bulk_receive_handle() may
7847 +   // return VCHIQ_RETRY, so we need to implment a retry mechanism since
7848 +   // this function is supposed to block until queued
7849 +   while ( status == VCHIQ_RETRY )
7850 +   {
7851 +      vcos_sleep( 1 );
7852 +      status = vchiq_bulk_receive_handle(service->handle, h, (void*)offset,
7853 +         data_size, bulk_handle, mode);
7854 +   }
7855 +
7856 +   return vchiq_status_to_vchi(status);
7857 +}
7858 +
7859 +/***********************************************************
7860 + * Name: vchi_bulk_queue_transmit
7861 + *
7862 + * Arguments:  VCHI_BULK_HANDLE_T handle,
7863 + *             const void *data_src,
7864 + *             uint32_t data_size,
7865 + *             VCHI_FLAGS_T flags,
7866 + *             void *bulk_handle
7867 + *
7868 + * Description: Routine to transmit some data
7869 + *
7870 + * Returns: int32_t - success == 0
7871 + *
7872 + ***********************************************************/
7873 +int32_t vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
7874 +                                  const void * data_src,
7875 +                                  uint32_t data_size,
7876 +                                  VCHI_FLAGS_T flags,
7877 +                                  void * bulk_handle )
7878 +{
7879 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7880 +   VCHIQ_BULK_MODE_T mode;
7881 +   VCHIQ_STATUS_T status;
7882 +
7883 +   switch ((int)flags) {
7884 +   case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7885 +      vcos_assert(service->callback);
7886 +      mode = VCHIQ_BULK_MODE_CALLBACK;
7887 +      break;
7888 +   case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
7889 +   case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7890 +      mode = VCHIQ_BULK_MODE_BLOCKING;
7891 +      break;
7892 +   case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7893 +   case VCHI_FLAGS_NONE:
7894 +      mode = VCHIQ_BULK_MODE_NOCALLBACK;
7895 +      break;
7896 +   default:
7897 +      vcos_assert(0);
7898 +      return vchiq_status_to_vchi(VCHIQ_ERROR);
7899 +   }
7900 +
7901 +   status = vchiq_bulk_transmit(service->handle, data_src, data_size,
7902 +      bulk_handle, mode);
7903 +
7904 +   // On some platforms, like linux kernel, vchiq_bulk_transmit() may return
7905 +   // VCHIQ_RETRY, so we need to implment a retry mechanism since this
7906 +   // function is supposed to block until queued
7907 +   while ( status == VCHIQ_RETRY )
7908 +   {
7909 +      vcos_sleep( 1 );
7910 +      status = vchiq_bulk_transmit(service->handle, data_src, data_size,
7911 +         bulk_handle, mode);
7912 +   }
7913 +
7914 +   return vchiq_status_to_vchi(status);
7915 +}
7916 +
7917 +/***********************************************************
7918 + * Name: vchi_bulk_queue_transmit_reloc
7919 + *
7920 + * Arguments:  VCHI_BULK_HANDLE_T handle,
7921 + *             VCHI_MEM_HANDLE_T h_src,
7922 + *             uint32_t offset,
7923 + *             uint32_t data_size,
7924 + *             VCHI_FLAGS_T flags,
7925 + *             void *bulk_handle
7926 + *
7927 + * Description: Routine to transmit some data from a relocatable buffer
7928 + *
7929 + * Returns: int32_t - success == 0
7930 + *
7931 + ***********************************************************/
7932 +
7933 +int32_t vchi_bulk_queue_transmit_reloc( VCHI_SERVICE_HANDLE_T handle,
7934 +                                        VCHI_MEM_HANDLE_T h_src,
7935 +                                        uint32_t offset,
7936 +                                        uint32_t data_size,
7937 +                                        VCHI_FLAGS_T flags,
7938 +                                        void * const bulk_handle )
7939 +{
7940 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7941 +   VCHIQ_BULK_MODE_T mode;
7942 +   VCHIQ_STATUS_T status;
7943 +
7944 +   switch ((int)flags) {
7945 +   case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7946 +      vcos_assert(service->callback);
7947 +      mode = VCHIQ_BULK_MODE_CALLBACK;
7948 +      break;
7949 +   case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
7950 +   case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
7951 +      mode = VCHIQ_BULK_MODE_BLOCKING;
7952 +      break;
7953 +   case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
7954 +   case VCHI_FLAGS_NONE:
7955 +      mode = VCHIQ_BULK_MODE_NOCALLBACK;
7956 +      break;
7957 +   default:
7958 +      vcos_assert(0);
7959 +      return vchiq_status_to_vchi(VCHIQ_ERROR);
7960 +   }
7961 +
7962 +   status = vchiq_bulk_transmit_handle(service->handle, h_src, (void*)offset,
7963 +      data_size, bulk_handle, mode);
7964 +
7965 +   // On some platforms, like linux kernel, vchiq_bulk_transmit_handle() may
7966 +   // return VCHIQ_RETRY, so we need to implment a retry mechanism since this
7967 +   // function is supposed to block until queued
7968 +   while ( status == VCHIQ_RETRY )
7969 +   {
7970 +      vcos_sleep( 1 );
7971 +      status = vchiq_bulk_transmit_handle(service->handle, h_src, (void*)offset,
7972 +         data_size, bulk_handle, mode);
7973 +   }
7974 +
7975 +   return vchiq_status_to_vchi(status);
7976 +}
7977 +
7978 +/***********************************************************
7979 + * Name: vchi_msg_dequeue
7980 + *
7981 + * Arguments:  VCHI_SERVICE_HANDLE_T handle,
7982 + *             void *data,
7983 + *             uint32_t max_data_size_to_read,
7984 + *             uint32_t *actual_msg_size
7985 + *             VCHI_FLAGS_T flags
7986 + *
7987 + * Description: Routine to dequeue a message into the supplied buffer
7988 + *
7989 + * Returns: int32_t - success == 0
7990 + *
7991 + ***********************************************************/
7992 +int32_t vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
7993 +                          void *data,
7994 +                          uint32_t max_data_size_to_read,
7995 +                          uint32_t *actual_msg_size,
7996 +                          VCHI_FLAGS_T flags )
7997 +{
7998 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
7999 +   VCHIQ_HEADER_T *header;
8000 +
8001 +   vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
8002 +
8003 +   if (flags == VCHI_FLAGS_NONE)
8004 +      if (vchiu_queue_is_empty(&service->queue))
8005 +         return -1;
8006 +
8007 +   header = vchiu_queue_pop(&service->queue);
8008 +
8009 +   memcpy(data, header->data, header->size < max_data_size_to_read ? header->size : max_data_size_to_read);
8010 +
8011 +   *actual_msg_size = header->size;
8012 +
8013 +   vchiq_release_message(service->handle, header);
8014 +
8015 +   return 0;
8016 +}
8017 +
8018 +/***********************************************************
8019 + * Name: vchi_msg_queuev
8020 + *
8021 + * Arguments:  VCHI_SERVICE_HANDLE_T handle,
8022 + *             const void *data,
8023 + *             uint32_t data_size,
8024 + *             VCHI_FLAGS_T flags,
8025 + *             void *msg_handle
8026 + *
8027 + * Description: Thin wrapper to queue a message onto a connection
8028 + *
8029 + * Returns: int32_t - success == 0
8030 + *
8031 + ***********************************************************/
8032 +
8033 +vcos_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
8034 +vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == offsetof(VCHIQ_ELEMENT_T, data));
8035 +vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == offsetof(VCHIQ_ELEMENT_T, size));
8036 +
8037 +int32_t vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
8038 +                         VCHI_MSG_VECTOR_T * vector,
8039 +                         uint32_t count,
8040 +                         VCHI_FLAGS_T flags,
8041 +                         void *msg_handle )
8042 +{
8043 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8044 +
8045 +   vcos_unused(msg_handle);
8046 +
8047 +   vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
8048 +
8049 +   return vchiq_status_to_vchi(vchiq_queue_message(service->handle, (const VCHIQ_ELEMENT_T *)vector, count));
8050 +}
8051 +
8052 +#ifdef USE_MEMMGR
8053 +
8054 +/***********************************************************
8055 + * Name: vchi_msg_queuev_ex
8056 + *
8057 + * Arguments:  VCHI_SERVICE_HANDLE_T handle,
8058 + *             VCHI_MSG_VECTOR_EX_T *vector
8059 + *             uint32_t count
8060 + *             VCHI_FLAGS_T flags,
8061 + *             void *msg_handle
8062 + *
8063 + * Description: Thin wrapper to queue an array of messages onto a connection
8064 + * Supports resolving MEM_HANDLE's at last possible moment to avoid deadlocks.
8065 + *
8066 + * Currently just a shim, so deadlocks are still possible!
8067 + *
8068 + * Returns: int32_t - success == 0
8069 + *
8070 + ***********************************************************/
8071 +int32_t vchi_msg_queuev_ex( const VCHI_SERVICE_HANDLE_T handle,
8072 +                            VCHI_MSG_VECTOR_EX_T * const vector,
8073 +                            const uint32_t count,
8074 +                            const VCHI_FLAGS_T flags,
8075 +                            void * const msg_handle )
8076 +{
8077 +   int32_t success = -1;
8078 +   // For now, we don't actually support sending anything other than
8079 +   // a pointer, so handles have to be patched up; this is likely
8080 +   // to cause deadlocks. This code is not designed to be either
8081 +   // pretty, efficient, or deadlock-free.
8082 +
8083 +   #define max_vecs 16
8084 +   VCHI_MSG_VECTOR_T copy[max_vecs];
8085 +   const uint8_t *orig[max_vecs];
8086 +
8087 +   int i;
8088 +   vcos_unused(msg_handle);
8089 +
8090 +   if (count > sizeof(copy)/sizeof(copy[0]))
8091 +   {
8092 +      vcos_assert(0);
8093 +      return -1;
8094 +   }
8095 +
8096 +   for (i=0; i<count; i++)
8097 +   {
8098 +      VCHI_MSG_VECTOR_EX_T *v = vector+i;
8099 +
8100 +      switch (vector[i].type)
8101 +      {
8102 +      case VCHI_VEC_POINTER:
8103 +         copy[i].vec_base = v->u.ptr.vec_base;
8104 +         copy[i].vec_len =  v->u.ptr.vec_len;
8105 +         break;
8106 +      case VCHI_VEC_HANDLE:
8107 +         vcos_assert(v->u.handle.offset+v->u.handle.vec_len <= mem_get_size(v->u.handle.handle));
8108 +         copy[i].vec_base = (uint8_t*)mem_lock(v->u.handle.handle) + v->u.handle.offset;
8109 +         orig[i] = copy[i].vec_base;
8110 +         copy[i].vec_len = v->u.handle.vec_len;
8111 +         break;
8112 +      case VCHI_VEC_LIST:
8113 +         vcos_assert(0); // FIXME: implement this
8114 +         break;
8115 +      default:
8116 +         vcos_assert(0);
8117 +      }
8118 +   }
8119 +   success = vchi_msg_queuev( handle,
8120 +                              copy,
8121 +                              count,
8122 +                              flags &~ VCHI_FLAGS_INTERNAL,
8123 +                              msg_handle );
8124 +   if (vcos_verify(success == 0))
8125 +   {
8126 +      // now we need to patch up the vectors if any have been only partially consumed, and
8127 +      // unlock memory handles.
8128 +   
8129 +      for (i=0; i<count; i++)
8130 +      {
8131 +         VCHI_MSG_VECTOR_EX_T *v = vector+i;
8132 +
8133 +         switch (vector[i].type)
8134 +         {
8135 +         case VCHI_VEC_POINTER:
8136 +            if (flags & VCHI_FLAGS_ALLOW_PARTIAL)
8137 +            {
8138 +               v->u.ptr.vec_base = copy[i].vec_base;
8139 +               v->u.ptr.vec_len  = copy[i].vec_len;
8140 +            }
8141 +            break;
8142 +         case VCHI_VEC_HANDLE:
8143 +            mem_unlock(v->u.handle.handle);
8144 +            if (flags & VCHI_FLAGS_ALLOW_PARTIAL)
8145 +            {
8146 +               const uint8_t *old = orig[i];
8147 +               uint32_t change = (const uint8_t*)copy[i].vec_base-old;
8148 +               v->u.handle.offset += change;
8149 +               v->u.handle.vec_len -= change;
8150 +            }
8151 +            break;
8152 +         default:
8153 +            vcos_assert(0);
8154 +         }
8155 +      }
8156 +   }
8157 +
8158 +   return vchiq_status_to_vchi(success);
8159 +}
8160 +
8161 +#endif
8162 +
8163 +/***********************************************************
8164 + * Name: vchi_held_msg_release
8165 + *
8166 + * Arguments:  VCHI_HELD_MSG_T *message
8167 + *
8168 + * Description: Routine to release a held message (after it has been read with vchi_msg_hold)
8169 + *
8170 + * Returns: int32_t - success == 0
8171 + *
8172 + ***********************************************************/
8173 +int32_t vchi_held_msg_release( VCHI_HELD_MSG_T *message )
8174 +{
8175 +   vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service, (VCHIQ_HEADER_T *)message->message);
8176 +
8177 +   return 0;
8178 +}
8179 +
8180 +/***********************************************************
8181 + * Name: vchi_msg_hold
8182 + *
8183 + * Arguments:  VCHI_SERVICE_HANDLE_T handle,
8184 + *             void **data,
8185 + *             uint32_t *msg_size,
8186 + *             VCHI_FLAGS_T flags,
8187 + *             VCHI_HELD_MSG_T *message_handle
8188 + *
8189 + * Description: Routine to return a pointer to the current message (to allow in place processing)
8190 + *              The message is dequeued - don't forget to release the message using
8191 + *              vchi_held_msg_release when you're finished
8192 + *
8193 + * Returns: int32_t - success == 0
8194 + *
8195 + ***********************************************************/
8196 +int32_t vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
8197 +                       void **data,
8198 +                       uint32_t *msg_size,
8199 +                       VCHI_FLAGS_T flags,
8200 +                       VCHI_HELD_MSG_T *message_handle )
8201 +{
8202 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8203 +   VCHIQ_HEADER_T *header;
8204 +
8205 +   vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
8206 +
8207 +   if (flags == VCHI_FLAGS_NONE)
8208 +      if (vchiu_queue_is_empty(&service->queue))
8209 +         return -1;
8210 +
8211 +   header = vchiu_queue_pop(&service->queue);
8212 +
8213 +   *data = header->data;
8214 +   *msg_size = header->size;
8215 +
8216 +   message_handle->service = (struct opaque_vchi_service_t *)service->handle;
8217 +   message_handle->message = header;
8218 +
8219 +   return 0;
8220 +}
8221 +
8222 +/***********************************************************
8223 + * Name: vchi_initialise
8224 + *
8225 + * Arguments: VCHI_INSTANCE_T *instance_handle
8226 + *            VCHI_CONNECTION_T **connections
8227 + *            const uint32_t num_connections
8228 + *
8229 + * Description: Initialises the hardware but does not transmit anything
8230 + *              When run as a Host App this will be called twice hence the need
8231 + *              to malloc the state information
8232 + *
8233 + * Returns: 0 if successful, failure otherwise
8234 + *
8235 + ***********************************************************/
8236 +
8237 +int32_t vchi_initialise( VCHI_INSTANCE_T *instance_handle )
8238 +{
8239 +   VCHIQ_INSTANCE_T instance;
8240 +   VCHIQ_STATUS_T status;
8241 +
8242 +   status = vchiq_initialise(&instance);
8243 +
8244 +   *instance_handle = (VCHI_INSTANCE_T)instance;
8245 +
8246 +   return vchiq_status_to_vchi(status);
8247 +}
8248 +
8249 +/***********************************************************
8250 + * Name: vchi_connect
8251 + *
8252 + * Arguments: VCHI_CONNECTION_T **connections
8253 + *            const uint32_t num_connections
8254 + *            VCHI_INSTANCE_T instance_handle )
8255 + *
8256 + * Description: Starts the command service on each connection,
8257 + *              causing INIT messages to be pinged back and forth
8258 + *
8259 + * Returns: 0 if successful, failure otherwise
8260 + *
8261 + ***********************************************************/
8262 +int32_t vchi_connect( VCHI_CONNECTION_T **connections,
8263 +                      const uint32_t num_connections,
8264 +                      VCHI_INSTANCE_T instance_handle )
8265 +{
8266 +   VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8267 +
8268 +   vcos_unused(connections);
8269 +   vcos_unused(num_connections);
8270 +
8271 +   return vchiq_connect(instance);
8272 +}
8273 +
8274 +
8275 +/***********************************************************
8276 + * Name: vchi_disconnect
8277 + *
8278 + * Arguments: VCHI_INSTANCE_T instance_handle
8279 + *
8280 + * Description: Stops the command service on each connection,
8281 + *              causing DE-INIT messages to be pinged back and forth
8282 + *
8283 + * Returns: 0 if successful, failure otherwise
8284 + *
8285 + ***********************************************************/
8286 +int32_t vchi_disconnect( VCHI_INSTANCE_T instance_handle )
8287 +{
8288 +   VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8289 +   return vchiq_status_to_vchi(vchiq_shutdown(instance));
8290 +}
8291 +
8292 +
8293 +/***********************************************************
8294 + * Name: vchi_service_open
8295 + * Name: vchi_service_create
8296 + *
8297 + * Arguments: VCHI_INSTANCE_T *instance_handle
8298 + *            SERVICE_CREATION_T *setup,
8299 + *            VCHI_SERVICE_HANDLE_T *handle
8300 + *
8301 + * Description: Routine to open a service
8302 + *
8303 + * Returns: int32_t - success == 0
8304 + *
8305 + ***********************************************************/
8306 +
8307 +static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T handle, void *bulk_user)
8308 +{
8309 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
8310 +
8311 +   switch (reason) {
8312 +   case VCHIQ_MESSAGE_AVAILABLE:
8313 +      vchiu_queue_push(&service->queue, header);
8314 +
8315 +      if (service->callback)
8316 +         service->callback(service->callback_param, VCHI_CALLBACK_MSG_AVAILABLE, NULL);
8317 +      break;
8318 +   case VCHIQ_BULK_TRANSMIT_DONE:
8319 +      if (service->callback)
8320 +         service->callback(service->callback_param, VCHI_CALLBACK_BULK_SENT, bulk_user);
8321 +      break;
8322 +   case VCHIQ_BULK_RECEIVE_DONE:
8323 +      if (service->callback)
8324 +         service->callback(service->callback_param, VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
8325 +      break;
8326 +   case VCHIQ_SERVICE_CLOSED:
8327 +      if (service->callback)
8328 +         service->callback(service->callback_param, VCHI_CALLBACK_SERVICE_CLOSED, NULL);
8329 +      break;
8330 +   case VCHIQ_SERVICE_OPENED:
8331 +      /* No equivalent VCHI reason */
8332 +      break;
8333 +   case VCHIQ_BULK_TRANSMIT_ABORTED:
8334 +      if (service->callback)
8335 +         service->callback(service->callback_param, VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, bulk_user);
8336 +      break;
8337 +   case VCHIQ_BULK_RECEIVE_ABORTED:
8338 +      if (service->callback)
8339 +         service->callback(service->callback_param, VCHI_CALLBACK_BULK_RECEIVE_ABORTED, bulk_user);
8340 +      break;
8341 +   default:
8342 +      vcos_assert(0);
8343 +      break;
8344 +   }
8345 +
8346 +   return VCHIQ_SUCCESS;
8347 +}
8348 +
8349 +static SHIM_SERVICE_T *service_alloc(VCHIQ_INSTANCE_T instance,
8350 +                                     SERVICE_CREATION_T *setup)
8351 +{
8352 +   SHIM_SERVICE_T *service = vcos_calloc(1, sizeof(SHIM_SERVICE_T), "vchiq_shim");
8353 +
8354 +   vcos_unused(instance);
8355 +
8356 +   if (service)
8357 +   {
8358 +      if (vchiu_queue_init(&service->queue, 64))
8359 +      {
8360 +         service->callback = setup->callback;
8361 +         service->callback_param = setup->callback_param;
8362 +      }
8363 +      else
8364 +      {
8365 +         vcos_free(service);
8366 +         service = NULL;
8367 +      }
8368 +   }
8369 +
8370 +   return service;
8371 +}
8372 +
8373 +static void service_free(SHIM_SERVICE_T *service)
8374 +{
8375 +   if (service)
8376 +   {
8377 +      vchiu_queue_delete(&service->queue);
8378 +      vcos_free((void*)service);
8379 +   }
8380 +}
8381 +
8382 +int32_t vchi_service_open( VCHI_INSTANCE_T instance_handle,
8383 +                           SERVICE_CREATION_T *setup,
8384 +                           VCHI_SERVICE_HANDLE_T *handle)
8385 +{
8386 +   VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8387 +   SHIM_SERVICE_T *service = service_alloc(instance, setup);
8388 +   if (service)
8389 +   {
8390 +      VCHIQ_STATUS_T status = vchiq_open_service(instance, setup->service_id, shim_callback, service, &service->handle);
8391 +      if (status != VCHIQ_SUCCESS)
8392 +      {
8393 +         service_free(service);
8394 +         service = NULL;
8395 +      }
8396 +   }
8397 +
8398 +   *handle = (VCHI_SERVICE_HANDLE_T)service;
8399 +
8400 +   return (service != NULL) ? 0 : -1;
8401 +}
8402 +
8403 +int32_t vchi_service_create( VCHI_INSTANCE_T instance_handle,
8404 +                             SERVICE_CREATION_T *setup,
8405 +                             VCHI_SERVICE_HANDLE_T *handle )
8406 +{
8407 +   VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
8408 +   SHIM_SERVICE_T *service = service_alloc(instance, setup);
8409 +   if (service)
8410 +   {
8411 +      VCHIQ_STATUS_T status = vchiq_add_service(instance, setup->service_id, shim_callback, service, &service->handle);
8412 +      if (status != VCHIQ_SUCCESS)
8413 +      {
8414 +         service_free(service);
8415 +         service = NULL;
8416 +      }
8417 +   }
8418 +
8419 +   *handle = (VCHI_SERVICE_HANDLE_T)service;
8420 +
8421 +   return (service != NULL) ? 0 : -1;
8422 +}
8423 +
8424 +int32_t vchi_service_close( const VCHI_SERVICE_HANDLE_T handle )
8425 +{
8426 +   vcos_unused(handle);
8427 +
8428 +   // YTI??
8429 +   return 0;
8430 +}
8431 +
8432 +/* ----------------------------------------------------------------------
8433 + * read a uint32_t from buffer.
8434 + * network format is defined to be little endian
8435 + * -------------------------------------------------------------------- */
8436 +uint32_t
8437 +vchi_readbuf_uint32( const void *_ptr )
8438 +{
8439 +   const unsigned char *ptr = _ptr;
8440 +   return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
8441 +}
8442 +
8443 +/* ----------------------------------------------------------------------
8444 + * write a uint32_t to buffer.
8445 + * network format is defined to be little endian
8446 + * -------------------------------------------------------------------- */
8447 +void
8448 +vchi_writebuf_uint32( void *_ptr, uint32_t value )
8449 +{
8450 +   unsigned char *ptr = _ptr;
8451 +   ptr[0] = (unsigned char)((value >> 0)  & 0xFF);
8452 +   ptr[1] = (unsigned char)((value >> 8)  & 0xFF);
8453 +   ptr[2] = (unsigned char)((value >> 16) & 0xFF);
8454 +   ptr[3] = (unsigned char)((value >> 24) & 0xFF);
8455 +}
8456 +
8457 +/* ----------------------------------------------------------------------
8458 + * read a uint16_t from buffer.
8459 + * network format is defined to be little endian
8460 + * -------------------------------------------------------------------- */
8461 +uint16_t
8462 +vchi_readbuf_uint16( const void *_ptr )
8463 +{
8464 +   const unsigned char *ptr = _ptr;
8465 +   return ptr[0] | (ptr[1] << 8);
8466 +}
8467 +
8468 +/* ----------------------------------------------------------------------
8469 + * write a uint16_t into the buffer.
8470 + * network format is defined to be little endian
8471 + * -------------------------------------------------------------------- */
8472 +void
8473 +vchi_writebuf_uint16( void *_ptr, uint16_t value )
8474 +{
8475 +   unsigned char *ptr = _ptr;
8476 +   ptr[0] = (value >> 0)  & 0xFF;
8477 +   ptr[1] = (value >> 8)  & 0xFF;
8478 +}
8479 +
8480 +/***********************************************************
8481 + * Name: vchi_service_use
8482 + *
8483 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
8484 + *
8485 + * Description: Routine to increment refcount on a service
8486 + *
8487 + * Returns: void
8488 + *
8489 + ***********************************************************/
8490 +int32_t vchi_service_use( const VCHI_SERVICE_HANDLE_T handle )
8491 +{
8492 +   int32_t ret = -1;
8493 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8494 +   if(service)
8495 +   {
8496 +      ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
8497 +   }
8498 +   return ret;
8499 +}
8500 +
8501 +/***********************************************************
8502 + * Name: vchi_service_release
8503 + *
8504 + * Arguments: const VCHI_SERVICE_HANDLE_T handle
8505 + *
8506 + * Description: Routine to decrement refcount on a service
8507 + *
8508 + * Returns: void
8509 + *
8510 + ***********************************************************/
8511 +int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle )
8512 +{
8513 +   int32_t ret = -1;
8514 +   SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
8515 +   if(service)
8516 +   {
8517 +      ret = vchiq_status_to_vchi(vchiq_release_service(service->handle));
8518 +   }
8519 +   return ret;
8520 +}
8521 +
8522 +#if defined(__KERNEL__)
8523 +EXPORT_SYMBOL(vchi_initialise);
8524 +EXPORT_SYMBOL(vchi_connect);
8525 +EXPORT_SYMBOL(vchi_bulk_queue_transmit);
8526 +EXPORT_SYMBOL(vchi_msg_dequeue);
8527 +EXPORT_SYMBOL(vchi_msg_queue);
8528 +EXPORT_SYMBOL(vchi_msg_queuev);
8529 +EXPORT_SYMBOL(vchi_service_close);
8530 +EXPORT_SYMBOL(vchi_service_open);
8531 +EXPORT_SYMBOL(vchi_service_create);
8532 +EXPORT_SYMBOL(vchi_service_use);
8533 +EXPORT_SYMBOL(vchi_service_release);
8534 +#endif
8535 --- /dev/null
8536 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
8537 @@ -0,0 +1,97 @@
8538 +/*
8539 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
8540 + *
8541 + * This program is free software; you can redistribute it and/or modify
8542 + * it under the terms of the GNU General Public License as published by
8543 + * the Free Software Foundation; either version 2 of the License, or
8544 + * (at your option) any later version.
8545 + *
8546 + * This program is distributed in the hope that it will be useful,
8547 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8548 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8549 + * GNU General Public License for more details.
8550 + *
8551 + * You should have received a copy of the GNU General Public License
8552 + * along with this program; if not, write to the Free Software
8553 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
8554 + */
8555 +
8556 +#include "vchiq_util.h"
8557 +
8558 +#if !defined(__KERNEL__)
8559 +#include <stdlib.h>
8560 +#endif
8561 +
8562 +static __inline int is_pow2(int i)
8563 +{
8564 +  return i && !(i & (i - 1));
8565 +}
8566 +
8567 +int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size)
8568 +{
8569 +   vcos_assert(is_pow2(size));
8570 +
8571 +   queue->size = size;
8572 +   queue->read = 0;
8573 +   queue->write = 0;
8574 +
8575 +   vcos_event_create(&queue->pop, "vchiu");
8576 +   vcos_event_create(&queue->push, "vchiu");
8577 +
8578 +   queue->storage = vcos_malloc(size * sizeof(VCHIQ_HEADER_T *), VCOS_FUNCTION);
8579 +   if (queue->storage == NULL)
8580 +   {
8581 +      vchiu_queue_delete(queue);
8582 +      return 0;
8583 +   }
8584 +   return 1;
8585 +}
8586 +
8587 +void vchiu_queue_delete(VCHIU_QUEUE_T *queue)
8588 +{
8589 +   vcos_event_delete(&queue->pop);
8590 +   vcos_event_delete(&queue->push);
8591 +   if (queue->storage != NULL)
8592 +      vcos_free(queue->storage);
8593 +}
8594 +
8595 +int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue)
8596 +{
8597 +   return queue->read == queue->write;
8598 +}
8599 +
8600 +void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header)
8601 +{
8602 +   while (queue->write == queue->read + queue->size)
8603 +      vcos_event_wait(&queue->pop);
8604 +
8605 +   queue->storage[queue->write & (queue->size - 1)] = header;
8606 +
8607 +   queue->write++;
8608 +
8609 +   vcos_event_signal(&queue->push);
8610 +}
8611 +
8612 +VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue)
8613 +{
8614 +   while (queue->write == queue->read)
8615 +      vcos_event_wait(&queue->push);
8616 +
8617 +   return queue->storage[queue->read & (queue->size - 1)];
8618 +}
8619 +
8620 +VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue)
8621 +{
8622 +   VCHIQ_HEADER_T *header;
8623 +
8624 +   while (queue->write == queue->read)
8625 +      vcos_event_wait(&queue->push);
8626 +
8627 +   header = queue->storage[queue->read & (queue->size - 1)];
8628 +
8629 +   queue->read++;
8630 +
8631 +   vcos_event_signal(&queue->pop);
8632 +
8633 +   return header;
8634 +}
8635 --- /dev/null
8636 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.h
8637 @@ -0,0 +1,47 @@
8638 +/*
8639 + * Copyright (c) 2010-2011 Broadcom Corporation. All rights reserved.
8640 + *
8641 + * This program is free software; you can redistribute it and/or modify
8642 + * it under the terms of the GNU General Public License as published by
8643 + * the Free Software Foundation; either version 2 of the License, or
8644 + * (at your option) any later version.
8645 + *
8646 + * This program is distributed in the hope that it will be useful,
8647 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8648 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8649 + * GNU General Public License for more details.
8650 + *
8651 + * You should have received a copy of the GNU General Public License
8652 + * along with this program; if not, write to the Free Software
8653 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
8654 + */
8655 +
8656 +#ifndef VCHIQ_UTIL_H
8657 +#define VCHIQ_UTIL_H
8658 +
8659 +#include "vchiq_if.h"
8660 +#include "interface/vcos/vcos.h"
8661 +
8662 +typedef struct {
8663 +   int size;
8664 +   int read;
8665 +   int write;
8666 +
8667 +   VCOS_EVENT_T pop;
8668 +   VCOS_EVENT_T push;
8669 +
8670 +   VCHIQ_HEADER_T **storage;
8671 +} VCHIU_QUEUE_T;
8672 +
8673 +extern int  vchiu_queue_init(VCHIU_QUEUE_T *queue, int size);
8674 +extern void vchiu_queue_delete(VCHIU_QUEUE_T *queue);
8675 +
8676 +extern int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue);
8677 +
8678 +extern void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header);
8679 +
8680 +extern VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue);
8681 +extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue);
8682 +
8683 +#endif
8684 +
8685 --- /dev/null
8686 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_cmd.c
8687 @@ -0,0 +1,681 @@
8688 +/*****************************************************************************
8689 +* Copyright 2009 - 2011 Broadcom Corporation.  All rights reserved.
8690 +*
8691 +* Unless you and Broadcom execute a separate written software license
8692 +* agreement governing use of this software, this software is licensed to you
8693 +* under the terms of the GNU General Public License version 2, available at
8694 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
8695 +*
8696 +* Notwithstanding the above, under no circumstances may you combine this
8697 +* software in any way with any other Broadcom software provided under a
8698 +* license other than the GPL, without Broadcom's express prior written
8699 +* consent.
8700 +*****************************************************************************/
8701 +
8702 +/***************************************************************************** 
8703 +* 
8704 +*    This file provides a generic command line interface which allows
8705 +*    vcos internals to be manipulated and/or displayed.
8706 +*  
8707 +*****************************************************************************/
8708 +
8709 +/* ---- Include Files ---------------------------------------------------- */
8710 +
8711 +#include "interface/vcos/vcos.h"
8712 +
8713 +#ifdef HAVE_VCOS_VERSION
8714 +#include "interface/vcos/vcos_build_info.h"
8715 +#endif
8716 +
8717 +        #ifdef _VIDEOCORE
8718 +#include vcfw/logging/logging.h
8719 +#endif
8720 +
8721 +/* ---- Public Variables ------------------------------------------------- */
8722 +
8723 +/* ---- Private Constants and Types -------------------------------------- */
8724 +
8725 +#define  VCOS_LOG_CATEGORY (&vcos_cmd_log_category)
8726 +VCOS_LOG_CAT_T vcos_cmd_log_category;
8727 +
8728 +/* ---- Private Variables ------------------------------------------------ */
8729 +
8730 +static struct VCOS_CMD_GLOBALS_T
8731 +{
8732 +    VCOS_MUTEX_T    lock;
8733 +    VCOS_ONCE_T     initialized;
8734 +
8735 +    unsigned        num_cmd_entries;
8736 +    unsigned        num_cmd_alloc;
8737 +    VCOS_CMD_T     *cmd_entry;
8738 +
8739 +    VCOS_LOG_CAT_T *log_category;
8740 +} cmd_globals;
8741 +
8742 +/* ---- Private Function Prototypes -------------------------------------- */
8743 +
8744 +static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param );
8745 +
8746 +/* ---- Functions  ------------------------------------------------------- */
8747 +
8748 +/***************************************************************************** 
8749 +*
8750 +*   Walks through the commands looking for a particular command
8751 +*
8752 +*****************************************************************************/
8753 +
8754 +static VCOS_CMD_T *find_cmd( VCOS_CMD_T *cmd_entry, const char *name )
8755 +{
8756 +    VCOS_CMD_T   *scan_entry = cmd_entry;
8757 +
8758 +    while ( scan_entry->name != NULL )
8759 +    {
8760 +        if ( vcos_strcmp( scan_entry->name, name ) == 0 )
8761 +        {
8762 +            return scan_entry;
8763 +        }
8764 +        scan_entry++;
8765 +    }
8766 +
8767 +    return NULL;
8768 +}
8769 +
8770 +/***************************************************************************** 
8771 +*
8772 +*   Saves away 
8773 +*   each line individually.
8774 +*
8775 +*****************************************************************************/
8776 +
8777 +void vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category )
8778 +{
8779 +    cmd_globals.log_category = log_category;
8780 +}
8781 +
8782 +/***************************************************************************** 
8783 +*
8784 +*   Walks through a buffer containing newline separated lines, and logs
8785 +*   each line individually.
8786 +*
8787 +*****************************************************************************/
8788 +
8789 +static void cmd_log_results( VCOS_CMD_PARAM_T *param )
8790 +{
8791 +    char    *start;
8792 +    char    *end;
8793 +
8794 +    start = end = param->result_buf;
8795 +
8796 +    while ( *start != '\0' )
8797 +    {
8798 +        while (( *end != '\0' ) && ( *end != '\n' ))
8799 +            end++;
8800 +
8801 +        if ( *end == '\n' )
8802 +        {
8803 +            *end++ = '\0';
8804 +        }
8805 +
8806 +        if ( cmd_globals.log_category != NULL )
8807 +        {
8808 +            if ( vcos_is_log_enabled( cmd_globals.log_category, VCOS_LOG_INFO ))
8809 +            {
8810 +                vcos_log_impl( cmd_globals.log_category, VCOS_LOG_INFO, "%s", start );
8811 +            }
8812 +        }
8813 +        else
8814 +        {
8815 +            vcos_log_info( "%s", start );
8816 +        }
8817 +
8818 +        start = end;
8819 +    }
8820 +
8821 +    /* Since we logged the buffer, reset the pointer back to the beginning. */
8822 +
8823 +    param->result_ptr = param->result_buf;
8824 +    param->result_buf[0] = '\0';
8825 +}
8826 +
8827 +/***************************************************************************** 
8828 +*
8829 +*   Since we may have limited output space, we create a generic routine
8830 +*   which tries to use the result space, but will switch over to using
8831 +*   logging if the output is too large.
8832 +*
8833 +*****************************************************************************/
8834 +
8835 +void vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args )
8836 +{
8837 +    int     bytes_written;
8838 +    int     bytes_remaining;
8839 +
8840 +    bytes_remaining = (int)(param->result_size - ( param->result_ptr - param->result_buf ));
8841 +
8842 +    bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
8843 +
8844 +    if ( cmd_globals.log_category != NULL )
8845 +    {
8846 +        /* We're going to log each line as we encounter it. If the buffer
8847 +         * doesn't end in a newline, then we'll wait for one first.
8848 +         */
8849 +
8850 +        if ( (( bytes_written + 1 ) >= bytes_remaining ) 
8851 +        ||   ( param->result_ptr[ bytes_written - 1 ] == '\n' ))
8852 +        {
8853 +            cmd_log_results( param );
8854 +        }
8855 +        else
8856 +        {
8857 +            param->result_ptr += bytes_written;
8858 +        }
8859 +    }
8860 +    else
8861 +    {
8862 +        if (( bytes_written + 1 ) >= bytes_remaining )
8863 +        {
8864 +            /* Output doesn't fit - switch over to logging */
8865 +
8866 +            param->use_log = 1;
8867 +
8868 +            *param->result_ptr = '\0';  /* Zap the partial line that didn't fit above. */
8869 +
8870 +            cmd_log_results( param );   /* resets result_ptr */
8871 +
8872 +            bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
8873 +        }
8874 +        param->result_ptr += bytes_written;
8875 +    }
8876 +}
8877 +
8878 +/***************************************************************************** 
8879 +*
8880 +*   Prints the output.
8881 +*
8882 +*****************************************************************************/
8883 +
8884 +void vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
8885 +{
8886 +    va_list args;
8887 +
8888 +    va_start( args, fmt );
8889 +    vcos_cmd_vprintf( param, fmt, args );
8890 +    va_end( args );
8891 +}
8892 +
8893 +/***************************************************************************** 
8894 +*
8895 +*   Prints the arguments which were on the command line prior to ours.
8896 +*
8897 +*****************************************************************************/
8898 +
8899 +static void print_argument_prefix( VCOS_CMD_PARAM_T *param )
8900 +{
8901 +    int arg_idx;
8902 +
8903 +    for ( arg_idx = 0; &param->argv_orig[arg_idx] != param->argv; arg_idx++ )
8904 +    {
8905 +        vcos_cmd_printf( param, "%s ", param->argv_orig[arg_idx] );
8906 +    }
8907 +}
8908 +
8909 +/***************************************************************************** 
8910 +*
8911 +*   Prints an error message, prefixed by the command chain required to get
8912 +*   to where we're at.
8913 +*
8914 +*****************************************************************************/
8915 +
8916 +void vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
8917 +{
8918 +    va_list args;
8919 +
8920 +    print_argument_prefix( param );
8921 +
8922 +    va_start( args, fmt );
8923 +    vcos_cmd_vprintf( param, fmt, args );
8924 +    va_end( args );
8925 +    vcos_cmd_printf( param, "\n" );
8926 +}
8927 +
8928 +/****************************************************************************
8929 +*
8930 +*  usage - prints command usage for an array of commands.
8931 +*
8932 +***************************************************************************/
8933 +
8934 +static void usage( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
8935 +{
8936 +    int         cmd_idx;
8937 +    int         nameWidth = 0;
8938 +    int         argsWidth = 0;
8939 +    VCOS_CMD_T *scan_entry;
8940 +
8941 +    vcos_cmd_printf( param, "Usage: " );
8942 +    print_argument_prefix( param );
8943 +    vcos_cmd_printf( param, "command [args ...]\n" );
8944 +    vcos_cmd_printf( param, "\n" );
8945 +    vcos_cmd_printf( param, "Where command is one of the following:\n" );
8946 +
8947 +    for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
8948 +    {
8949 +        int aw;
8950 +        int nw;
8951 +
8952 +        scan_entry = &cmd_entry[cmd_idx];
8953 +
8954 +        nw = vcos_strlen( scan_entry->name );
8955 +        aw = vcos_strlen( scan_entry->args );
8956 +
8957 +        if ( nw > nameWidth )
8958 +        {
8959 +            nameWidth = nw;
8960 +        }
8961 +        if ( aw > argsWidth )
8962 +        {
8963 +            argsWidth = aw;
8964 +        }
8965 +    }
8966 +
8967 +    for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
8968 +    {
8969 +        scan_entry = &cmd_entry[cmd_idx];
8970 +
8971 +        vcos_cmd_printf( param, "  %-*s %-*s - %s\n", 
8972 +                    nameWidth, scan_entry->name,
8973 +                    argsWidth, scan_entry->args,
8974 +                    scan_entry->descr );
8975 +    }
8976 +}
8977 +
8978 +/****************************************************************************
8979 +*
8980 +*  Prints the usage for the current command.
8981 +*
8982 +***************************************************************************/
8983 +
8984 +void vcos_cmd_usage( VCOS_CMD_PARAM_T *param )
8985 +{
8986 +    VCOS_CMD_T *cmd_entry;
8987 +
8988 +    cmd_entry = param->cmd_entry;
8989 +
8990 +    if ( cmd_entry->sub_cmd_entry != NULL )
8991 +    {
8992 +        /* This command is command with sub-commands */
8993 +
8994 +        usage( param, param->cmd_entry->sub_cmd_entry );
8995 +    }
8996 +    else
8997 +    {
8998 +        vcos_cmd_printf( param, "Usage: " );
8999 +        print_argument_prefix( param );
9000 +        vcos_cmd_printf( param, "%s - %s\n",
9001 +                         param->cmd_entry->args,
9002 +                         param->cmd_entry->descr );
9003 +    }
9004 +}
9005 +
9006 +/***************************************************************************** 
9007 +*
9008 +*   Command to print out the help
9009 +* 
9010 +*   This help command is only called from the main menu.
9011 +* 
9012 +*****************************************************************************/
9013 +
9014 +static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param )
9015 +{
9016 +    VCOS_CMD_T  *found_entry;
9017 +
9018 +#if 0
9019 +    {
9020 +        int arg_idx;
9021 +
9022 +        vcos_log_trace( "%s: argc = %d", __func__, param->argc );
9023 +        for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
9024 +        {
9025 +            vcos_log_trace( "%s:  argv[%d] = '%s'", __func__, arg_idx, param->argv[arg_idx] );
9026 +        }
9027 +    }
9028 +#endif
9029 +
9030 +    /* If there is an argument after the word help, then we want to print
9031 +     * help for that command.
9032 +     */
9033 +
9034 +    if ( param->argc == 1 )
9035 +    {
9036 +        if ( param->cmd_parent_entry == cmd_globals.cmd_entry )
9037 +        {
9038 +            /* Bare help - print the command usage for the root */
9039 +
9040 +            usage( param, cmd_globals.cmd_entry );
9041 +            return VCOS_SUCCESS;
9042 +        }
9043 +
9044 +        /* For all other cases help requires an argument */
9045 +            
9046 +        vcos_cmd_error( param, "%s requires an argument", param->argv[0] );
9047 +        return VCOS_EINVAL;
9048 +    }
9049 +
9050 +    /* We were given an argument. */
9051 +
9052 +    if (( found_entry = find_cmd( param->cmd_parent_entry, param->argv[1] )) != NULL )
9053 +    {
9054 +        /* Make it look like the command that was specified is the one that's
9055 +         * currently running
9056 +         */
9057 +
9058 +        param->cmd_entry = found_entry;
9059 +        param->argv[0] = param->argv[1];
9060 +        param->argv++;
9061 +        param->argc--;
9062 +
9063 +        vcos_cmd_usage( param );
9064 +        return VCOS_SUCCESS;
9065 +    }
9066 +
9067 +    vcos_cmd_error( param, "- unrecognized command: '%s'", param->argv[1] );
9068 +    return VCOS_ENOENT;
9069 +}
9070 +
9071 +/***************************************************************************** 
9072 +*
9073 +*   Command to print out the version/build information.
9074 +*
9075 +*****************************************************************************/
9076 +
9077 +#ifdef HAVE_VCOS_VERSION
9078 +
9079 +static VCOS_STATUS_T version_cmd( VCOS_CMD_PARAM_T *param )
9080 +{
9081 +    static const char* copyright = "Copyright (c) 2011 Broadcom";
9082 +
9083 +    vcos_cmd_printf( param, "%s %s\n%s\nversion %s\n",
9084 +                     vcos_get_build_date(),
9085 +                     vcos_get_build_time(),
9086 +                     copyright,
9087 +                     vcos_get_build_version() );
9088 +
9089 +    return VCOS_SUCCESS;
9090 +}
9091 +
9092 +#endif
9093 +
9094 +/*****************************************************************************
9095 +*
9096 +*   Internal commands
9097 +*
9098 +*****************************************************************************/
9099 +
9100 +static VCOS_CMD_T cmd_help    = { "help",    "[command]", help_cmd,    NULL, "Prints command help information" };
9101 +
9102 +#ifdef HAVE_VCOS_VERSION
9103 +static VCOS_CMD_T cmd_version = { "version", "",          version_cmd, NULL, "Prints build/version information" };
9104 +#endif
9105 +
9106 +/***************************************************************************** 
9107 +*
9108 +*   Walks the command table and executes the commands
9109 +*
9110 +*****************************************************************************/
9111 +
9112 +static VCOS_STATUS_T execute_cmd( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
9113 +{
9114 +    const char     *cmdStr;
9115 +    VCOS_CMD_T     *found_entry;
9116 +
9117 +#if 0
9118 +    {
9119 +        int arg_idx;
9120 +
9121 +        vcos_cmd_printf( param, "%s: argc = %d", __func__, param->argc );
9122 +        for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
9123 +        {
9124 +            vcos_cmd_printf( param, " argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
9125 +        }
9126 +        vcos_cmd_printf( param, "\n" );
9127 +    }
9128 +#endif
9129 +
9130 +    if ( param->argc <= 1 )
9131 +    {
9132 +        /* No command specified */
9133 +
9134 +        vcos_cmd_error( param, "%s - no command specified", param->argv[0] );
9135 +        return VCOS_EINVAL;
9136 +    }
9137 +
9138 +    /* argv[0] is the command/program that caused us to get invoked, so we strip
9139 +     * it off.
9140 +     */
9141 +
9142 +    param->argc--;
9143 +    param->argv++;
9144 +    param->cmd_parent_entry = cmd_entry;
9145 +
9146 +    /* Not the help command, scan for the command and execute it. */
9147 +
9148 +    cmdStr = param->argv[0];
9149 +
9150 +    if (( found_entry = find_cmd( cmd_entry, cmdStr )) != NULL )
9151 +    {
9152 +        if ( found_entry->sub_cmd_entry != NULL )
9153 +        {
9154 +            return execute_cmd( param, found_entry->sub_cmd_entry );
9155 +        }
9156 +
9157 +        param->cmd_entry = found_entry;
9158 +        return found_entry->cmd_fn( param );
9159 +    }
9160 +
9161 +    /* Unrecognized command - check to see if it was the help command */
9162 +
9163 +    if ( vcos_strcmp( cmdStr, cmd_help.name ) == 0 )
9164 +    {
9165 +        return help_cmd( param );
9166 +    }
9167 +
9168 +    vcos_cmd_error( param, "- unrecognized command: '%s'", cmdStr );
9169 +    return VCOS_ENOENT;
9170 +}
9171 +
9172 +/***************************************************************************** 
9173 +*
9174 +*   Initializes the command line parser.
9175 +*
9176 +*****************************************************************************/
9177 +
9178 +static void vcos_cmd_init( void )
9179 +{
9180 +    vcos_mutex_create( &cmd_globals.lock, "vcos_cmd" );
9181 +
9182 +    cmd_globals.num_cmd_entries = 0;
9183 +    cmd_globals.num_cmd_alloc = 0;
9184 +    cmd_globals.cmd_entry = NULL;
9185 +}
9186 +
9187 +/***************************************************************************** 
9188 +*
9189 +*   Command line processor.
9190 +*
9191 +*****************************************************************************/
9192 +
9193 +VCOS_STATUS_T vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf )
9194 +{
9195 +    VCOS_STATUS_T       rc = VCOS_EINVAL;
9196 +    VCOS_CMD_PARAM_T    param;
9197 +
9198 +    vcos_once( &cmd_globals.initialized, vcos_cmd_init );
9199 +
9200 +    param.argc = argc;
9201 +    param.argv = param.argv_orig = argv;
9202 +
9203 +    param.use_log = 0;
9204 +    param.result_size = result_size;
9205 +    param.result_ptr = result_buf;
9206 +    param.result_buf = result_buf;
9207 +
9208 +       result_buf[0] = '\0';
9209 +
9210 +    vcos_mutex_lock( &cmd_globals.lock );
9211 +
9212 +    rc = execute_cmd( &param, cmd_globals.cmd_entry );
9213 +
9214 +    if ( param.use_log )
9215 +    {
9216 +        cmd_log_results( &param );
9217 +        vcos_snprintf( result_buf, result_size, "results logged" );
9218 +    }
9219 +    else
9220 +    if ( cmd_globals.log_category != NULL )
9221 +    {
9222 +        if ( result_buf[0] != '\0' )
9223 +        {
9224 +            /* There is a partial line still buffered. */
9225 +
9226 +            vcos_cmd_printf( &param, "\n" );
9227 +        }
9228 +    }
9229 +
9230 +    vcos_mutex_unlock( &cmd_globals.lock );
9231 +
9232 +    return rc;
9233 +}
9234 +
9235 +/***************************************************************************** 
9236 +*
9237 +*   Registers a command entry with the command line processor
9238 +*
9239 +*****************************************************************************/
9240 +
9241 +VCOS_STATUS_T vcos_cmd_register( VCOS_CMD_T *cmd_entry )
9242 +{
9243 +    VCOS_STATUS_T   rc;
9244 +    VCOS_UNSIGNED   new_num_cmd_alloc;
9245 +    VCOS_CMD_T     *new_cmd_entry;
9246 +    VCOS_CMD_T     *old_cmd_entry;
9247 +    VCOS_CMD_T     *scan_entry;
9248 +
9249 +    vcos_once( &cmd_globals.initialized, vcos_cmd_init );
9250 +
9251 +    vcos_assert( cmd_entry != NULL );
9252 +    vcos_assert( cmd_entry->name != NULL );
9253 +
9254 +    vcos_log_trace( "%s: cmd '%s'", __FUNCTION__, cmd_entry->name );
9255 +
9256 +    vcos_assert( cmd_entry->args != NULL );
9257 +    vcos_assert(( cmd_entry->cmd_fn != NULL ) || ( cmd_entry->sub_cmd_entry != NULL ));
9258 +    vcos_assert( cmd_entry->descr != NULL );
9259 +
9260 +    /* We expect vcos_cmd_init to be called before vcos_logging_init, so we
9261 +     * need to defer registering our logging category until someplace
9262 +     * like right here.
9263 +     */
9264 +
9265 +    if ( vcos_cmd_log_category.name == NULL )
9266 +    {
9267 +        /*
9268 +         * If you're using the command interface, you pretty much always want
9269 +         * log messages from this file to show up. So we change the default
9270 +         * from ERROR to be the more reasonable INFO level.
9271 +         */
9272 +
9273 +        vcos_log_set_level(&vcos_cmd_log_category, VCOS_LOG_INFO);
9274 +        vcos_log_register("vcos_cmd", &vcos_cmd_log_category);
9275 +
9276 +        /* We register a help command so that it shows up in the usage. */
9277 +
9278 +        vcos_cmd_register( &cmd_help );
9279 +#ifdef HAVE_VCOS_VERSION
9280 +        vcos_cmd_register( &cmd_version );
9281 +#endif
9282 +    }
9283 +
9284 +    vcos_mutex_lock( &cmd_globals.lock );
9285 +
9286 +    if ( cmd_globals.num_cmd_entries >= cmd_globals.num_cmd_alloc )
9287 +    {
9288 +        if ( cmd_globals.num_cmd_alloc == 0 )
9289 +        {
9290 +            /* We haven't allocated a table yet */
9291 +        }
9292 +
9293 +        /* The number 8 is rather arbitrary. */
9294 +
9295 +        new_num_cmd_alloc = cmd_globals.num_cmd_alloc + 8;
9296 +
9297 +        /* The + 1 is to ensure that we always have a NULL entry at the end. */
9298 +
9299 +        new_cmd_entry = (VCOS_CMD_T *)vcos_calloc( new_num_cmd_alloc + 1, sizeof( *cmd_entry ), "vcos_cmd_entries" );
9300 +        if ( new_cmd_entry == NULL )
9301 +        {
9302 +            rc = VCOS_ENOMEM;
9303 +            goto out;
9304 +        }
9305 +        memcpy( new_cmd_entry, cmd_globals.cmd_entry, cmd_globals.num_cmd_entries * sizeof( *cmd_entry ));
9306 +        cmd_globals.num_cmd_alloc = new_num_cmd_alloc;
9307 +        old_cmd_entry = cmd_globals.cmd_entry;
9308 +        cmd_globals.cmd_entry = new_cmd_entry;
9309 +        vcos_free( old_cmd_entry );
9310 +    }
9311 +
9312 +    if ( cmd_globals.num_cmd_entries == 0 )
9313 +    {
9314 +        /* This is the first command being registered */
9315 +
9316 +        cmd_globals.cmd_entry[0] = *cmd_entry;
9317 +    }
9318 +    else
9319 +    {
9320 +        /* Keep the list in alphabetical order. We start at the end and work backwards
9321 +         * shuffling entries up one until we find an insertion point.
9322 +         */
9323 +
9324 +        for ( scan_entry = &cmd_globals.cmd_entry[cmd_globals.num_cmd_entries - 1];
9325 +              scan_entry >= cmd_globals.cmd_entry; scan_entry-- )
9326 +        {
9327 +            if ( vcos_strcmp( cmd_entry->name, scan_entry->name ) > 0 )
9328 +            {
9329 +                /* We found an insertion point. */
9330 +
9331 +                break;
9332 +            }
9333 +
9334 +            scan_entry[1] = scan_entry[0];
9335 +        }
9336 +        scan_entry[1] = *cmd_entry;
9337 +    }
9338 +    cmd_globals.num_cmd_entries++;
9339 +
9340 +    rc = VCOS_SUCCESS;
9341 +
9342 +out:
9343 +
9344 +    vcos_mutex_unlock( &cmd_globals.lock );
9345 +    return rc;
9346 +}
9347 +
9348 +/***************************************************************************** 
9349 +*
9350 +*   Registers multiple commands.
9351 +*
9352 +*****************************************************************************/
9353 +
9354 +VCOS_STATUS_T vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry )
9355 +{
9356 +    VCOS_STATUS_T   status;
9357 +
9358 +    while ( cmd_entry->name != NULL )
9359 +    {
9360 +        if (( status = vcos_cmd_register( cmd_entry )) != VCOS_SUCCESS )
9361 +        {
9362 +            return status;
9363 +        }
9364 +        cmd_entry++;
9365 +    }
9366 +    return VCOS_SUCCESS;
9367 +}
9368 +
9369 --- /dev/null
9370 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_common.h
9371 @@ -0,0 +1,76 @@
9372 +/*=============================================================================
9373 +Copyright (c) 2009 Broadcom Europe Limited.
9374 +All rights reserved.
9375 +
9376 +Project  :  vcfw
9377 +Module   :  chip driver
9378 +
9379 +FILE DESCRIPTION
9380 +VideoCore OS Abstraction Layer - common postamble code
9381 +=============================================================================*/
9382 +
9383 +/** \file
9384 +  *
9385 +  * Postamble code included by the platform-specific header files
9386 +  */
9387 +
9388 +#define VCOS_THREAD_PRI_DEFAULT VCOS_THREAD_PRI_NORMAL
9389 +
9390 +#if !defined(VCOS_THREAD_PRI_INCREASE)
9391 +#error Which way to thread priorities go?
9392 +#endif
9393 +
9394 +#if VCOS_THREAD_PRI_INCREASE < 0
9395 +/* smaller numbers are higher priority */
9396 +#define VCOS_THREAD_PRI_LESS(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX)
9397 +#define VCOS_THREAD_PRI_MORE(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN)
9398 +#else
9399 +/* bigger numbers are lower priority */
9400 +#define VCOS_THREAD_PRI_MORE(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX)
9401 +#define VCOS_THREAD_PRI_LESS(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN)
9402 +#endif
9403 +
9404 +/* Convenience for Brits: */
9405 +#define VCOS_APPLICATION_INITIALISE VCOS_APPLICATION_INITIALIZE
9406 +
9407 +/*
9408 + * Check for constant definitions
9409 + */
9410 +#ifndef VCOS_TICKS_PER_SECOND
9411 +#error VCOS_TICKS_PER_SECOND not defined
9412 +#endif
9413 +
9414 +#if !defined(VCOS_THREAD_PRI_MIN) || !defined(VCOS_THREAD_PRI_MAX)
9415 +#error Priority range not defined
9416 +#endif
9417 +
9418 +#if !defined(VCOS_THREAD_PRI_HIGHEST) || !defined(VCOS_THREAD_PRI_LOWEST) || !defined(VCOS_THREAD_PRI_NORMAL)
9419 +#error Priority ordering not defined
9420 +#endif
9421 +
9422 +#if !defined(VCOS_CAN_SET_STACK_ADDR)
9423 +#error Can stack addresses be set on this platform? Please set this macro to either 0 or 1.
9424 +#endif
9425 +
9426 +#if (_VCOS_AFFINITY_CPU0|_VCOS_AFFINITY_CPU1) & (~_VCOS_AFFINITY_MASK) 
9427 +#error _VCOS_AFFINITY_CPUxxx values are not consistent with _VCOS_AFFINITY_MASK
9428 +#endif
9429 +
9430 +/** Append to the end of a singly-linked queue, O(1). Works with
9431 +  * any structure where list has members 'head' and 'tail' and
9432 +  * item has a 'next' pointer.
9433 +  */
9434 +#define VCOS_QUEUE_APPEND_TAIL(list, item) {\
9435 +   (item)->next = NULL;\
9436 +   if (!(list)->head) {\
9437 +      (list)->head = (list)->tail = (item); \
9438 +   } else {\
9439 +      (list)->tail->next = (item); \
9440 +      (list)->tail = (item); \
9441 +   } \
9442 +}
9443 +
9444 +#ifndef VCOS_HAVE_TIMER
9445 +VCOSPRE_ void VCOSPOST_ vcos_timer_init(void);
9446 +#endif
9447 +
9448 --- /dev/null
9449 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_blockpool.h
9450 @@ -0,0 +1,260 @@
9451 +/*=============================================================================
9452 +Copyright (c) 2011 Broadcom Europe Limited.
9453 +All rights reserved.
9454 +
9455 +Project  :  vcfw
9456 +Module   :  chip driver
9457 +
9458 +FILE DESCRIPTION
9459 +VideoCore OS Abstraction Layer - event flags implemented via a semaphore
9460 +=============================================================================*/
9461 +
9462 +#ifndef VCOS_GENERIC_BLOCKPOOL_H
9463 +#define VCOS_GENERIC_BLOCKPOOL_H
9464 +
9465 +/**
9466 +  * \file
9467 +  *
9468 +  * This provides a generic, thread safe implementation of a VCOS block pool
9469 +  * fixed size memory allocator.
9470 +  */
9471 +
9472 +#ifdef __cplusplus
9473 +extern "C" {
9474 +#endif
9475 +
9476 +#include "interface/vcos/vcos_types.h"
9477 +
9478 +/** Bits 0 to (VCOS_BLOCKPOOL_SUBPOOL_BITS - 1) are used to store the
9479 + * subpool id. */
9480 +#define VCOS_BLOCKPOOL_SUBPOOL_BITS 3
9481 +#define VCOS_BLOCKPOOL_MAX_SUBPOOLS (1 << VCOS_BLOCKPOOL_SUBPOOL_BITS)
9482 +
9483 +/* Make zero an invalid handle at the cost of decreasing the maximum
9484 + * number of blocks (2^28) by 1. Alternatively, a spare bit could be
9485 + * used to indicated valid blocks but there are likely to be better
9486 + * uses for spare bits. e.g. allowing more subpools
9487 + */
9488 +#define INDEX_OFFSET 1
9489 +
9490 +#define VCOS_BLOCKPOOL_HANDLE_GET_INDEX(h) \
9491 +   (((h) >> VCOS_BLOCKPOOL_SUBPOOL_BITS) - INDEX_OFFSET)
9492 +
9493 +#define VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(h) \
9494 +   ((h) & ((1 << VCOS_BLOCKPOOL_SUBPOOL_BITS) - 1))
9495 +
9496 +#define VCOS_BLOCKPOOL_HANDLE_CREATE(i,s) \
9497 +   ((((i) + INDEX_OFFSET) << VCOS_BLOCKPOOL_SUBPOOL_BITS) | (s))
9498 +
9499 +#define VCOS_BLOCKPOOL_INVALID_HANDLE 0
9500 +
9501 +typedef struct VCOS_BLOCKPOOL_HEADER_TAG
9502 +{
9503 +   /* Blocks either refer to to the pool if they are allocated
9504 +    * or the free list if they are available.
9505 +    */
9506 +   union {
9507 +   struct VCOS_BLOCKPOOL_HEADER_TAG *next;
9508 +   struct VCOS_BLOCKPOOL_SUBPOOL_TAG* subpool;
9509 +   } owner;
9510 +} VCOS_BLOCKPOOL_HEADER_T;
9511 +
9512 +typedef struct VCOS_BLOCKPOOL_SUBPOOL_TAG
9513 +{
9514 +   /** VCOS_BLOCKPOOL_SUBPOOL_MAGIC */
9515 +   uint32_t magic;
9516 +   VCOS_BLOCKPOOL_HEADER_T* free_list;
9517 +   /* The start of the pool memory */
9518 +   void *mem;
9519 +   /* Address of the first block header */
9520 +   void *start;
9521 +   /** The number of blocks in this sub-pool */
9522 +   VCOS_UNSIGNED num_blocks;
9523 +   /** Current number of available blocks in this sub-pool */
9524 +   VCOS_UNSIGNED available_blocks;
9525 +   /** Pointers to the pool that owns this sub-pool */
9526 +   struct VCOS_BLOCKPOOL_TAG* owner;
9527 +   /** Define properties such as memory ownership */
9528 +   uint32_t flags;
9529 +} VCOS_BLOCKPOOL_SUBPOOL_T;
9530 +
9531 +typedef struct VCOS_BLOCKPOOL_TAG
9532 +{
9533 +   /** VCOS_BLOCKPOOL_MAGIC */
9534 +   uint32_t magic;
9535 +   /** Thread safety for Alloc, Free, Delete, Stats */
9536 +   VCOS_MUTEX_T mutex;
9537 +   /** The size of the block data */
9538 +   size_t block_data_size;
9539 +   /** Block size inc overheads */
9540 +   size_t block_size;
9541 +   /** Name for debugging */
9542 +   const char *name;
9543 +   /* The number of subpools that may be used */
9544 +   VCOS_UNSIGNED num_subpools;
9545 +   /** Number of blocks in each dynamically allocated subpool */
9546 +   VCOS_UNSIGNED num_extension_blocks;
9547 +   /** Array of subpools. Subpool zero is is not deleted until the pool is
9548 +    * destroed. If the index of the pool is < num_subpools and
9549 +    * subpool[index.mem] is null then the subpool entry is valid but
9550 +    * "not currently allocated" */
9551 +   VCOS_BLOCKPOOL_SUBPOOL_T subpools[VCOS_BLOCKPOOL_MAX_SUBPOOLS];
9552 +} VCOS_BLOCKPOOL_T;
9553 +
9554 +#define VCOS_BLOCKPOOL_ROUND_UP(x,s)   (((x) + ((s) - 1)) & ~((s) - 1))
9555 +/**
9556 + * Calculates the size in bytes required for a block pool containing
9557 + * num_blocks of size block_size plus any overheads.
9558 + *
9559 + * The block pool header (VCOS_BLOCKPOOL_T) is allocated separately
9560 + *
9561 + * Overheads:
9562 + * block_size + header must be a multiple of sizeof(void*)
9563 + * The start of the first block may need to be up to wordsize - 1 bytes
9564 + * into the given buffer because statically allocated buffers within structures
9565 + * are not guaranteed to be word aligned.
9566 + */
9567 +#define VCOS_BLOCKPOOL_SIZE(num_blocks, block_size) \
9568 +   ((VCOS_BLOCKPOOL_ROUND_UP((block_size) + sizeof(VCOS_BLOCKPOOL_HEADER_T), \
9569 +                             sizeof(void*)) * (num_blocks)) + sizeof(void*))
9570 +
9571 +/**
9572 + * Sanity check to verify whether a handle is potentially a blockpool handle
9573 + * when the pool pointer is not available.
9574 + *
9575 + * If the pool pointer is availabe use vcos_blockpool_elem_to_handle instead.
9576 + *
9577 + * @param handle       the handle to verify
9578 + * @param max_blocks   the expected maximum number of block in the pool
9579 + *                     that the handle belongs to.
9580 + */
9581 +#define VCOS_BLOCKPOOL_IS_VALID_HANDLE_FORMAT(handle, max_blocks) \
9582 +    ((handle) != VCOS_BLOCKPOOL_INVALID_HANDLE \
9583 +     && VCOS_BLOCKPOOL_HANDLE_GET_INDEX((handle)) < (max_blocks))
9584 +
9585 +VCOSPRE_
9586 +   VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_init(VCOS_BLOCKPOOL_T *pool,
9587 +      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
9588 +      void *start, VCOS_UNSIGNED pool_size, const char *name);
9589 +
9590 +VCOSPRE_
9591 +   VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_create_on_heap(
9592 +         VCOS_BLOCKPOOL_T *pool, VCOS_UNSIGNED num_blocks,
9593 +         VCOS_UNSIGNED block_size, const char *name);
9594 +
9595 +VCOSPRE_
9596 +   VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
9597 +         VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks);
9598 +
9599 +VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool);
9600 +
9601 +VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool);
9602 +
9603 +VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_free(void *block);
9604 +
9605 +VCOSPRE_
9606 +   VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_available_count(
9607 +         VCOS_BLOCKPOOL_T *pool);
9608 +
9609 +VCOSPRE_
9610 +   VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_used_count(
9611 +         VCOS_BLOCKPOOL_T *pool);
9612 +
9613 +VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool);
9614 +
9615 +VCOSPRE_ uint32_t VCOSPOST_ vcos_generic_blockpool_elem_to_handle(void *block);
9616 +
9617 +VCOSPRE_ void VCOSPOST_
9618 +   *vcos_generic_blockpool_elem_from_handle(
9619 +         VCOS_BLOCKPOOL_T *pool, uint32_t handle);
9620 +
9621 +VCOSPRE_ uint32_t VCOSPOST_
9622 +   vcos_generic_blockpool_is_valid_elem(
9623 +         VCOS_BLOCKPOOL_T *pool, const void *block);
9624 +#if defined(VCOS_INLINE_BODIES)
9625 +
9626 +VCOS_INLINE_IMPL
9627 +VCOS_STATUS_T vcos_blockpool_init(VCOS_BLOCKPOOL_T *pool,
9628 +      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
9629 +      void *start, VCOS_UNSIGNED pool_size, const char *name)
9630 +{
9631 +   return vcos_generic_blockpool_init(pool, num_blocks, block_size,
9632 +         start, pool_size, name);
9633 +}
9634 +
9635 +VCOS_INLINE_IMPL
9636 +VCOS_STATUS_T vcos_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool,
9637 +      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, const char *name)
9638 +{
9639 +   return vcos_generic_blockpool_create_on_heap(
9640 +         pool, num_blocks, block_size, name);
9641 +}
9642 +
9643 +VCOS_INLINE_IMPL
9644 +   VCOS_STATUS_T VCOSPOST_ vcos_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
9645 +         VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks)
9646 +{
9647 +    return vcos_generic_blockpool_extend(pool, num_extensions, num_blocks);
9648 +}
9649 +
9650 +VCOS_INLINE_IMPL
9651 +void *vcos_blockpool_alloc(VCOS_BLOCKPOOL_T *pool)
9652 +{
9653 +   return vcos_generic_blockpool_alloc(pool);
9654 +}
9655 +
9656 +VCOS_INLINE_IMPL
9657 +void *vcos_blockpool_calloc(VCOS_BLOCKPOOL_T *pool)
9658 +{
9659 +   return vcos_generic_blockpool_calloc(pool);
9660 +}
9661 +
9662 +VCOS_INLINE_IMPL
9663 +void vcos_blockpool_free(void *block)
9664 +{
9665 +   vcos_generic_blockpool_free(block);
9666 +}
9667 +
9668 +VCOS_INLINE_IMPL
9669 +VCOS_UNSIGNED vcos_blockpool_available_count(VCOS_BLOCKPOOL_T *pool)
9670 +{
9671 +   return vcos_generic_blockpool_available_count(pool);
9672 +}
9673 +
9674 +VCOS_INLINE_IMPL
9675 +VCOS_UNSIGNED vcos_blockpool_used_count(VCOS_BLOCKPOOL_T *pool)
9676 +{
9677 +   return vcos_generic_blockpool_used_count(pool);
9678 +}
9679 +
9680 +VCOS_INLINE_IMPL
9681 +void vcos_blockpool_delete(VCOS_BLOCKPOOL_T *pool)
9682 +{
9683 +   vcos_generic_blockpool_delete(pool);
9684 +}
9685 +
9686 +VCOS_INLINE_IMPL
9687 +uint32_t vcos_blockpool_elem_to_handle(void *block)
9688 +{
9689 +   return vcos_generic_blockpool_elem_to_handle(block);
9690 +}
9691 +
9692 +VCOS_INLINE_IMPL
9693 +void *vcos_blockpool_elem_from_handle(VCOS_BLOCKPOOL_T *pool, uint32_t handle)
9694 +{
9695 +   return vcos_generic_blockpool_elem_from_handle(pool, handle);
9696 +}
9697 +
9698 +VCOS_INLINE_IMPL
9699 +uint32_t vcos_blockpool_is_valid_elem(VCOS_BLOCKPOOL_T *pool, const void *block)
9700 +{
9701 +   return vcos_generic_blockpool_is_valid_elem(pool, block);
9702 +}
9703 +#endif /* VCOS_INLINE_BODIES */
9704 +
9705 +
9706 +#ifdef __cplusplus
9707 +}
9708 +#endif
9709 +#endif /* VCOS_GENERIC_BLOCKPOOL_H */
9710 +
9711 --- /dev/null
9712 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.c
9713 @@ -0,0 +1,297 @@
9714 +/*=============================================================================
9715 +Copyright (c) 2009 Broadcom Europe Limited.
9716 +All rights reserved.
9717 +
9718 +FILE DESCRIPTION
9719 +VideoCore OS Abstraction Layer - event flags implemented via mutexes
9720 +=============================================================================*/
9721 +
9722 +#include "interface/vcos/vcos.h"
9723 +#include "interface/vcos/generic/vcos_generic_event_flags.h"
9724 +
9725 +#include <stddef.h>
9726 +
9727 +/** A structure created by a thread that waits on the event flags
9728 +  * for a particular combination of flags to arrive.
9729 +  */
9730 +typedef struct VCOS_EVENT_WAITER_T
9731 +{
9732 +   VCOS_UNSIGNED requested_events;  /**< The events wanted */
9733 +   VCOS_UNSIGNED actual_events;     /**< Actual events found */
9734 +   VCOS_UNSIGNED op;                /**< The event operation to be used */
9735 +   VCOS_STATUS_T return_status;     /**< The return status the waiter should pass back */
9736 +   VCOS_EVENT_FLAGS_T *flags;       /**< Pointer to the original 'flags' structure */
9737 +   VCOS_THREAD_T *thread;           /**< Thread waiting */
9738 +   struct VCOS_EVENT_WAITER_T *next;
9739 +} VCOS_EVENT_WAITER_T;
9740 +
9741 +#ifndef NDEBUG
9742 +static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags);
9743 +#endif
9744 +static void event_flags_timer_expired(void *cxt);
9745 +
9746 +VCOS_STATUS_T vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name)
9747 +{
9748 +   VCOS_STATUS_T rc;
9749 +   if ((rc=vcos_mutex_create(&flags->lock, name)) != VCOS_SUCCESS)
9750 +   {
9751 +      return rc;
9752 +   }
9753 +
9754 +   flags->events = 0;
9755 +   flags->waiters.head = flags->waiters.tail = 0;
9756 +   return rc;
9757 +}
9758 +
9759 +void vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
9760 +                                  VCOS_UNSIGNED bitmask,
9761 +                                  VCOS_OPTION op)
9762 +{
9763 +   vcos_assert(flags);
9764 +   vcos_mutex_lock(&flags->lock);
9765 +   if (op == VCOS_OR)
9766 +   {
9767 +      flags->events |= bitmask;
9768 +   }
9769 +   else if (op == VCOS_AND)
9770 +   {
9771 +      flags->events &= bitmask;
9772 +   }
9773 +   else
9774 +   {
9775 +      vcos_assert(0);
9776 +   }
9777 +
9778 +   /* Now wake up any threads that have now become signalled. */
9779 +   if (flags->waiters.head != NULL)
9780 +   {
9781 +      VCOS_UNSIGNED consumed_events = 0;
9782 +      VCOS_EVENT_WAITER_T **pcurrent_waiter = &flags->waiters.head;
9783 +      VCOS_EVENT_WAITER_T *prev_waiter = NULL;
9784 +
9785 +      /* Walk the chain of tasks suspend on this event flag group to determine
9786 +       * if any of their requests can be satisfied.
9787 +       */
9788 +      while ((*pcurrent_waiter) != NULL)
9789 +      {
9790 +         VCOS_EVENT_WAITER_T *curr_waiter = *pcurrent_waiter;
9791 +
9792 +         /* Determine if this request has been satisfied */
9793 +
9794 +         /* First, find the event flags in common. */
9795 +         VCOS_UNSIGNED waiter_satisfied = flags->events & curr_waiter->requested_events;
9796 +
9797 +         /* Second, determine if all the event flags must match */
9798 +         if (curr_waiter->op & VCOS_AND)
9799 +         {
9800 +            /* All requested events must be present */
9801 +            waiter_satisfied = (waiter_satisfied == curr_waiter->requested_events);
9802 +         }
9803 +
9804 +         /* Wake this one up? */
9805 +         if (waiter_satisfied)
9806 +         {
9807 +
9808 +            if (curr_waiter->op & VCOS_CONSUME)
9809 +            {
9810 +               consumed_events |= curr_waiter->requested_events;
9811 +            }
9812 +
9813 +            /* remove this block from the list, taking care at the end */
9814 +            *pcurrent_waiter = curr_waiter->next;
9815 +            if (curr_waiter->next == NULL)
9816 +               flags->waiters.tail = prev_waiter;
9817 +
9818 +            vcos_assert(waiter_list_valid(flags));
9819 +
9820 +            curr_waiter->return_status = VCOS_SUCCESS;
9821 +            curr_waiter->actual_events = flags->events;
9822 +
9823 +            _vcos_thread_sem_post(curr_waiter->thread);
9824 +         }
9825 +         else
9826 +         {
9827 +            /* move to next element in the list */
9828 +            prev_waiter = *pcurrent_waiter;
9829 +            pcurrent_waiter = &(curr_waiter->next);
9830 +         }
9831 +      }
9832 +
9833 +      flags->events &= ~consumed_events;
9834 +
9835 +   }
9836 +
9837 +   vcos_mutex_unlock(&flags->lock);
9838 +}
9839 +
9840 +void vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *flags)
9841 +{
9842 +   vcos_mutex_delete(&flags->lock);
9843 +}
9844 +
9845 +extern VCOS_STATUS_T vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
9846 +                                                  VCOS_UNSIGNED bitmask,
9847 +                                                  VCOS_OPTION op,
9848 +                                                  VCOS_UNSIGNED suspend,
9849 +                                                  VCOS_UNSIGNED *retrieved_bits)
9850 +{
9851 +   VCOS_EVENT_WAITER_T waitreq;
9852 +   VCOS_STATUS_T rc = VCOS_EAGAIN;
9853 +   int satisfied = 0;
9854 +
9855 +   vcos_assert(flags);
9856 +
9857 +   /* default retrieved bits to 0 */
9858 +   *retrieved_bits = 0;
9859 +
9860 +   vcos_mutex_lock(&flags->lock);
9861 +   switch (op & VCOS_EVENT_FLAG_OP_MASK)
9862 +   {
9863 +   case VCOS_AND:
9864 +      if ((flags->events & bitmask) == bitmask)
9865 +      {
9866 +         *retrieved_bits = flags->events;
9867 +         rc = VCOS_SUCCESS;
9868 +         satisfied = 1;
9869 +         if (op & VCOS_CONSUME)
9870 +            flags->events &= ~bitmask;
9871 +      }
9872 +      break;
9873 +
9874 +   case VCOS_OR:
9875 +      if (flags->events & bitmask)
9876 +      {
9877 +         *retrieved_bits = flags->events;
9878 +         rc = VCOS_SUCCESS;
9879 +         satisfied = 1;
9880 +         if (op & VCOS_CONSUME)
9881 +            flags->events &= ~bitmask;
9882 +      }
9883 +      break;
9884 +
9885 +   default:
9886 +      vcos_assert(0);
9887 +      rc = VCOS_EINVAL;
9888 +      break;
9889 +   }
9890 +
9891 +   if (!satisfied && suspend)
9892 +   {
9893 +      /* Have to go to sleep.
9894 +       *
9895 +       * Append to tail so we get FIFO ordering.
9896 +       */
9897 +      waitreq.requested_events = bitmask;
9898 +      waitreq.op = op;
9899 +      waitreq.return_status = VCOS_EAGAIN;
9900 +      waitreq.flags = flags;
9901 +      waitreq.actual_events = 0;
9902 +      waitreq.thread = vcos_thread_current();
9903 +      waitreq.next = 0;
9904 +      vcos_assert(waitreq.thread != (VCOS_THREAD_T*)-1);
9905 +      VCOS_QUEUE_APPEND_TAIL(&flags->waiters, &waitreq);
9906 +
9907 +      if (suspend != (VCOS_UNSIGNED)-1)
9908 +         _vcos_task_timer_set(event_flags_timer_expired, &waitreq, suspend);
9909 +
9910 +      vcos_mutex_unlock(&flags->lock);
9911 +      /* go to sleep and wait to be signalled or timeout */
9912 +
9913 +      _vcos_thread_sem_wait();
9914 +
9915 +      *retrieved_bits = waitreq.actual_events;
9916 +      rc = waitreq.return_status;
9917 +
9918 +      /* cancel the timer - do not do this while holding the mutex as it
9919 +       * might be waiting for the timeout function to complete, which will
9920 +       * try to take the mutex.
9921 +       */
9922 +      if (suspend != (VCOS_UNSIGNED)-1)
9923 +         _vcos_task_timer_cancel();
9924 +   }
9925 +   else
9926 +   {
9927 +      vcos_mutex_unlock(&flags->lock);
9928 +   }
9929 +
9930 +   return rc;
9931 +}
9932 +
9933 +
9934 +/** Called when a get call times out. Remove this thread's
9935 +  * entry from the waiting queue, then resume the thread.
9936 +  */
9937 +static void event_flags_timer_expired(void *cxt)
9938 +{
9939 +   VCOS_EVENT_WAITER_T *waitreq = (VCOS_EVENT_WAITER_T *)cxt;
9940 +   VCOS_EVENT_FLAGS_T *flags = waitreq->flags;
9941 +   VCOS_EVENT_WAITER_T **plist;
9942 +   VCOS_EVENT_WAITER_T *prev = NULL;
9943 +   VCOS_THREAD_T *thread = 0;
9944 +
9945 +   vcos_assert(flags);
9946 +
9947 +   vcos_mutex_lock(&flags->lock);
9948 +
9949 +   /* walk the list of waiting threads on this event group, and remove
9950 +    * the one that has expired.
9951 +    *
9952 +    * FIXME: could use doubly-linked list if lots of threads are found
9953 +    * to be waiting on a single event flag instance.
9954 +    */
9955 +   plist = &flags->waiters.head;
9956 +   while (*plist != NULL)
9957 +   {
9958 +      if (*plist == waitreq)
9959 +      {
9960 +         int at_end;
9961 +         /* found it */
9962 +         thread = (*plist)->thread;
9963 +         at_end = ((*plist)->next == NULL);
9964 +
9965 +         /* link past */
9966 +         *plist = (*plist)->next;
9967 +         if (at_end)
9968 +            flags->waiters.tail = prev;
9969 +
9970 +         break;
9971 +      }
9972 +      prev = *plist;
9973 +      plist = &(*plist)->next;
9974 +   }
9975 +   vcos_assert(waiter_list_valid(flags));
9976 +
9977 +   vcos_mutex_unlock(&flags->lock);
9978 +
9979 +   if (thread)
9980 +   {
9981 +      _vcos_thread_sem_post(thread);
9982 +   }
9983 +}
9984 +
9985 +#ifndef NDEBUG
9986 +
9987 +static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags)
9988 +{
9989 +   int valid;
9990 +   /* Either both head and tail are NULL, or neither are NULL */
9991 +   if (flags->waiters.head == NULL)
9992 +   {
9993 +      valid = (flags->waiters.tail == NULL);
9994 +   }
9995 +   else
9996 +   {
9997 +      valid = (flags->waiters.tail != NULL);
9998 +   }
9999 +
10000 +   /* If head and tail point at the same non-NULL element, then there
10001 +    * is only one element in the list.
10002 +    */
10003 +   if (flags->waiters.head && (flags->waiters.head == flags->waiters.tail))
10004 +   {
10005 +      valid = (flags->waiters.head->next == NULL);
10006 +   }
10007 +   return valid;
10008 +}
10009 +
10010 +#endif
10011 --- /dev/null
10012 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.h
10013 @@ -0,0 +1,104 @@
10014 +/*=============================================================================
10015 +Copyright (c) 2009 Broadcom Europe Limited.
10016 +All rights reserved.
10017 +
10018 +FILE DESCRIPTION
10019 +VideoCore OS Abstraction Layer - event flags implemented via a semaphore
10020 +=============================================================================*/
10021 +
10022 +#ifndef VCOS_GENERIC_EVENT_FLAGS_H
10023 +#define VCOS_GENERIC_EVENT_FLAGS_H
10024 +
10025 +#ifdef __cplusplus
10026 +extern "C" {
10027 +#endif
10028 +
10029 +#include "interface/vcos/vcos_types.h"
10030 +
10031 +/**
10032 +  * \file
10033 +  *
10034 +  * This provides event flags (as per Nucleus Event Groups) based on a
10035 +  * mutex, a semaphore (per waiting thread) and a timer (per waiting
10036 +  * thread).
10037 +  * 
10038 +  * The data structure is a 32 bit unsigned int (the current set of
10039 +  * flags) and a linked list of clients waiting to be 'satisfied'.
10040 +  *
10041 +  * The mutex merely locks access to the data structure. If a client
10042 +  * calls vcos_event_flags_get() and the requested bits are not already
10043 +  * present, it then sleeps on its per-thread semaphore after adding
10044 +  * this semaphore to the queue waiting. It also sets up a timer.
10045 +  *
10046 +  * The per-thread semaphore and timer are actually stored in the
10047 +  * thread context (joinable thread). In future it may become necessary
10048 +  * to support non-VCOS threads by using thread local storage to
10049 +  * create these objects and associate them with the thread.
10050 +  */
10051 +
10052 +struct VCOS_EVENT_WAITER_T;
10053 +
10054 +typedef struct VCOS_EVENT_FLAGS_T
10055 +{
10056 +   VCOS_UNSIGNED events;      /**< Events currently set */
10057 +   VCOS_MUTEX_T lock;         /**< Serialize access */
10058 +   struct
10059 +   {
10060 +      struct VCOS_EVENT_WAITER_T *head;   /**< List of threads waiting */
10061 +      struct VCOS_EVENT_WAITER_T *tail;   /**< List of threads waiting */
10062 +   } waiters;
10063 +} VCOS_EVENT_FLAGS_T;
10064 +
10065 +#define VCOS_OR      1
10066 +#define VCOS_AND     2
10067 +#define VCOS_CONSUME 4
10068 +#define VCOS_OR_CONSUME (VCOS_OR | VCOS_CONSUME)
10069 +#define VCOS_AND_CONSUME (VCOS_AND | VCOS_CONSUME)
10070 +#define VCOS_EVENT_FLAG_OP_MASK (VCOS_OR|VCOS_AND)
10071 +
10072 +VCOSPRE_  VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name);
10073 +VCOSPRE_  void VCOSPOST_ vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
10074 +                                                      VCOS_UNSIGNED events,
10075 +                                                      VCOS_OPTION op);
10076 +VCOSPRE_  void VCOSPOST_ vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *);
10077 +VCOSPRE_  VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
10078 +                                                               VCOS_UNSIGNED requested_events,
10079 +                                                               VCOS_OPTION op,
10080 +                                                               VCOS_UNSIGNED suspend,
10081 +                                                               VCOS_UNSIGNED *retrieved_events);
10082 +
10083 +#ifdef VCOS_INLINE_BODIES
10084 +
10085 +VCOS_INLINE_IMPL
10086 +VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name) {
10087 +   return vcos_generic_event_flags_create(flags, name);
10088 +}
10089 +
10090 +VCOS_INLINE_IMPL
10091 +void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
10092 +                          VCOS_UNSIGNED events,
10093 +                          VCOS_OPTION op) {
10094 +   vcos_generic_event_flags_set(flags, events, op);
10095 +}
10096 +
10097 +VCOS_INLINE_IMPL
10098 +void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *f) {
10099 +   vcos_generic_event_flags_delete(f);
10100 +}
10101 +
10102 +VCOS_INLINE_IMPL
10103 +VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
10104 +                                   VCOS_UNSIGNED requested_events,
10105 +                                   VCOS_OPTION op,
10106 +                                   VCOS_UNSIGNED suspend,
10107 +                                   VCOS_UNSIGNED *retrieved_events) {
10108 +   return vcos_generic_event_flags_get(flags, requested_events, op, suspend, retrieved_events);
10109 +}
10110 +
10111 +#endif /* VCOS_INLINE_BODIES */
10112 +
10113 +#ifdef __cplusplus
10114 +}
10115 +#endif
10116 +#endif
10117 +
10118 --- /dev/null
10119 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_named_sem.h
10120 @@ -0,0 +1,81 @@
10121 +/*=============================================================================
10122 +Copyright (c) 2009 Broadcom Europe Limited.
10123 +All rights reserved.
10124 +
10125 +Project  :  vcfw
10126 +Module   :  chip driver
10127 +
10128 +FILE DESCRIPTION
10129 +VideoCore OS Abstraction Layer - named semaphores
10130 +=============================================================================*/
10131 +
10132 +#ifndef VCOS_GENERIC_NAMED_SEM_H
10133 +#define VCOS_GENERIC_NAMED_SEM_H
10134 +
10135 +#ifdef __cplusplus
10136 +extern "C" {
10137 +#endif
10138 +
10139 +#include "interface/vcos/vcos_types.h"
10140 +
10141 +/**
10142 + * \file
10143 + *
10144 + * Generic support for named semaphores, using regular ones. This is only
10145 + * suitable for emulating them on an embedded MMUless system, since there is
10146 + * no support for opening semaphores across process boundaries.
10147 + *
10148 + */
10149 +
10150 +#define VCOS_NAMED_SEMAPHORE_NAMELEN   64
10151 +
10152 +/* In theory we could use the name facility provided within Nucleus. However, this
10153 + * is hard to do as semaphores are constantly being created and destroyed; we
10154 + * would need to stop everything while allocating the memory for the semaphore
10155 + * list and then walking it. So keep our own list.
10156 + */
10157 +typedef struct VCOS_NAMED_SEMAPHORE_T
10158 +{
10159 +   struct VCOS_NAMED_SEMAPHORE_IMPL_T *actual; /**< There are 'n' named semaphores per 1 actual semaphore  */
10160 +   VCOS_SEMAPHORE_T *sem;                      /**< Pointer to actual underlying semaphore */
10161 +} VCOS_NAMED_SEMAPHORE_T;
10162 +
10163 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_
10164 +vcos_generic_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
10165 +
10166 +VCOSPRE_ void VCOSPOST_ vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem);
10167 +
10168 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ _vcos_named_semaphore_init(void);
10169 +VCOSPRE_ void VCOSPOST_ _vcos_named_semaphore_deinit(void);
10170 +
10171 +#if defined(VCOS_INLINE_BODIES)
10172 +
10173 +VCOS_INLINE_IMPL
10174 +VCOS_STATUS_T vcos_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count) {
10175 +   return vcos_generic_named_semaphore_create(sem, name, count);
10176 +}
10177 +
10178 +VCOS_INLINE_IMPL
10179 +void vcos_named_semaphore_wait(VCOS_NAMED_SEMAPHORE_T *sem) {
10180 +   vcos_semaphore_wait(sem->sem);
10181 +}
10182 +
10183 +VCOS_INLINE_IMPL
10184 +VCOS_STATUS_T vcos_named_semaphore_trywait(VCOS_NAMED_SEMAPHORE_T *sem) {
10185 +   return vcos_semaphore_trywait(sem->sem);
10186 +}
10187 +
10188 +VCOS_INLINE_IMPL
10189 +void vcos_named_semaphore_post(VCOS_NAMED_SEMAPHORE_T *sem) {
10190 +   vcos_semaphore_post(sem->sem);
10191 +}
10192 +
10193 +
10194 +#endif
10195 +
10196 +#ifdef __cplusplus
10197 +}
10198 +#endif
10199 +#endif
10200 +
10201 +
10202 --- /dev/null
10203 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_quickslow_mutex.h
10204 @@ -0,0 +1,75 @@
10205 +/*=============================================================================
10206 +Copyright (c) 2009 Broadcom Europe Limited.
10207 +All rights reserved.
10208 +
10209 +Project  :  vcfw
10210 +Module   :  chip driver
10211 +
10212 +FILE DESCRIPTION
10213 +VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
10214 +=============================================================================*/
10215 +
10216 +#ifndef VCOS_GENERIC_QUICKSLOW_MUTEX_H
10217 +#define VCOS_GENERIC_QUICKSLOW_MUTEX_H
10218 +
10219 +#ifdef __cplusplus
10220 +extern "C" {
10221 +#endif
10222 +
10223 +#include "interface/vcos/vcos_types.h"
10224 +
10225 +/**
10226 + * \file
10227 + *
10228 + * Quickslow Mutexes implemented as regular ones (i.e. quick and slow modes are the same).
10229 + *
10230 + */
10231 +
10232 +typedef VCOS_MUTEX_T VCOS_QUICKSLOW_MUTEX_T;
10233 +
10234 +#if defined(VCOS_INLINE_BODIES)
10235 +VCOS_INLINE_IMPL
10236 +VCOS_STATUS_T vcos_quickslow_mutex_create(VCOS_QUICKSLOW_MUTEX_T *m, const char *name)
10237 +{
10238 +   return vcos_mutex_create(m, name);
10239 +}
10240 +
10241 +VCOS_INLINE_IMPL
10242 +void vcos_quickslow_mutex_delete(VCOS_QUICKSLOW_MUTEX_T *m)
10243 +{
10244 +   vcos_mutex_delete(m);
10245 +}
10246 +
10247 +VCOS_INLINE_IMPL
10248 +void vcos_quickslow_mutex_lock(VCOS_QUICKSLOW_MUTEX_T *m)
10249 +{
10250 +   while (vcos_mutex_lock(m) == VCOS_EAGAIN);
10251 +}
10252 +
10253 +VCOS_INLINE_IMPL
10254 +void vcos_quickslow_mutex_unlock(VCOS_QUICKSLOW_MUTEX_T *m)
10255 +{
10256 +   vcos_mutex_unlock(m);
10257 +}
10258 +
10259 +VCOS_INLINE_IMPL
10260 +void vcos_quickslow_mutex_lock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
10261 +{
10262 +   while (vcos_mutex_lock(m) == VCOS_EAGAIN);
10263 +}
10264 +
10265 +VCOS_INLINE_IMPL
10266 +void vcos_quickslow_mutex_unlock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
10267 +{
10268 +   vcos_mutex_unlock(m);
10269 +}
10270 +
10271 +#endif
10272 +
10273 +
10274 +#ifdef __cplusplus
10275 +}
10276 +#endif
10277 +#endif
10278 +
10279 +
10280 --- /dev/null
10281 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_reentrant_mtx.h
10282 @@ -0,0 +1,75 @@
10283 +/*=============================================================================
10284 +Copyright (c) 2009 Broadcom Europe Limited.
10285 +All rights reserved.
10286 +
10287 +Project  :  vcfw
10288 +Module   :  chip driver
10289 +
10290 +FILE DESCRIPTION
10291 +VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
10292 +=============================================================================*/
10293 +
10294 +#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
10295 +#define VCOS_GENERIC_REENTRANT_MUTEX_H
10296 +
10297 +#ifdef __cplusplus
10298 +extern "C" {
10299 +#endif
10300 +
10301 +#include "interface/vcos/vcos_types.h"
10302 +
10303 +/**
10304 + * \file
10305 + *
10306 + * Reentrant Mutexes from regular ones.
10307 + *
10308 + */
10309 +
10310 +typedef struct VCOS_REENTRANT_MUTEX_T
10311 +{
10312 +   VCOS_MUTEX_T mutex;
10313 +   VCOS_THREAD_T *owner;
10314 +   unsigned count;
10315 +} VCOS_REENTRANT_MUTEX_T;
10316 +
10317 +/* Extern definitions of functions that do the actual work */
10318 +
10319 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name);
10320 +
10321 +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m);
10322 +
10323 +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m);
10324 +
10325 +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m);
10326 +
10327 +/* Inline forwarding functions */
10328 +
10329 +#if defined(VCOS_INLINE_BODIES)
10330 +
10331 +VCOS_INLINE_IMPL
10332 +VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) {
10333 +   return vcos_generic_reentrant_mutex_create(m,name);
10334 +}
10335 +
10336 +VCOS_INLINE_IMPL
10337 +void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
10338 +   vcos_generic_reentrant_mutex_delete(m);
10339 +}
10340 +
10341 +VCOS_INLINE_IMPL
10342 +void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
10343 +   vcos_generic_reentrant_mutex_lock(m);
10344 +}
10345 +
10346 +VCOS_INLINE_IMPL
10347 +void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
10348 +   vcos_generic_reentrant_mutex_unlock(m);
10349 +}
10350 +#endif
10351 +
10352 +#ifdef __cplusplus
10353 +}
10354 +#endif
10355 +#endif
10356 +
10357 +
10358 --- /dev/null
10359 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_tls.h
10360 @@ -0,0 +1,144 @@
10361 +/*=============================================================================
10362 +Copyright (c) 2009 Broadcom Europe Limited.
10363 +All rights reserved.
10364 +
10365 +Project  :  vcfw
10366 +Module   :  chip driver
10367 +
10368 +FILE DESCRIPTION
10369 +VideoCore OS Abstraction Layer - generic thread local storage
10370 +=============================================================================*/
10371 +
10372 +#ifndef VCOS_GENERIC_TLS_H
10373 +#define VCOS_GENERIC_TLS_H
10374 +
10375 +#ifdef __cplusplus
10376 +extern "C" {
10377 +#endif
10378 +
10379 +#include "interface/vcos/vcos_types.h"
10380 +
10381 +/**
10382 +  * \file
10383 +  *
10384 +  * Do an emulation of Thread Local Storage. The platform needs to
10385 +  * provide a way to set and get a per-thread pointer which is
10386 +  * where the TLS data itself is stored.
10387 +  *
10388 +  *
10389 +  * Each thread that wants to join in this scheme needs to call
10390 +  * vcos_tls_thread_register().
10391 +  *
10392 +  * The platform needs to support the macros/functions
10393 +  * _vcos_tls_thread_ptr_set() and _vcos_tls_thread_ptr_get().
10394 +  */
10395 +
10396 +#ifndef VCOS_WANT_TLS_EMULATION
10397 +#error Should not be included unless TLS emulation is defined
10398 +#endif
10399 +
10400 +/** Number of slots to reserve per thread. This results in an overhead
10401 +  * of this many words per thread.
10402 +  */
10403 +#define VCOS_TLS_MAX_SLOTS 4
10404 +
10405 +/** TLS key. Allocating one of these reserves the client one of the 
10406 +  * available slots.
10407 +  */
10408 +typedef VCOS_UNSIGNED VCOS_TLS_KEY_T;
10409 +
10410 +/** TLS per-thread structure. Each thread gets one of these
10411 +  * if TLS emulation (rather than native TLS support) is
10412 +  * being used.
10413 +  */
10414 +typedef struct VCOS_TLS_THREAD_T
10415 +{
10416 +   void *slots[VCOS_TLS_MAX_SLOTS];
10417 +} VCOS_TLS_THREAD_T;
10418 +
10419 +/*
10420 + * Internal APIs 
10421 + */
10422 +
10423 +/** Register this thread's TLS storage area. */
10424 +VCOSPRE_ void VCOSPOST_ vcos_tls_thread_register(VCOS_TLS_THREAD_T *);
10425 +
10426 +/** Create a new TLS key */
10427 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_tls_create(VCOS_TLS_KEY_T *key);
10428 +
10429 +/** Delete a TLS key */
10430 +VCOSPRE_ void VCOSPOST_ vcos_generic_tls_delete(VCOS_TLS_KEY_T tls);
10431 +
10432 +/** Initialise the TLS library */
10433 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_tls_init(void);
10434 +
10435 +/** Deinitialise the TLS library */
10436 +VCOSPRE_ void VCOSPOST_ vcos_tls_deinit(void);
10437 +
10438 +#if defined(VCOS_INLINE_BODIES)
10439 +
10440 +#undef VCOS_ASSERT_LOGGING_DISABLE
10441 +#define VCOS_ASSERT_LOGGING_DISABLE 1
10442 +
10443 +/*
10444 + * Implementations of public API functions
10445 + */
10446 +
10447 +/** Set the given value. Since everything is per-thread, there is no need
10448 +  * for any locking.
10449 +  */
10450 +VCOS_INLINE_IMPL
10451 +VCOS_STATUS_T vcos_tls_set(VCOS_TLS_KEY_T tls, void *v) {
10452 +   VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get();
10453 +   vcos_assert(tlsdata); /* Fires if this thread has not been registered */
10454 +   if (tls<VCOS_TLS_MAX_SLOTS)
10455 +   {
10456 +      tlsdata->slots[tls] = v;
10457 +      return VCOS_SUCCESS;
10458 +   }
10459 +   else
10460 +   {
10461 +      vcos_assert(0);
10462 +      return VCOS_EINVAL;
10463 +   }
10464 +}
10465 +
10466 +/** Get the given value. No locking required.
10467 +  */
10468 +VCOS_INLINE_IMPL
10469 +void *vcos_tls_get(VCOS_TLS_KEY_T tls) {
10470 +   VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get();
10471 +   vcos_assert(tlsdata); /* Fires if this thread has not been registered */
10472 +   if (tls<VCOS_TLS_MAX_SLOTS)
10473 +   {
10474 +      return tlsdata->slots[tls];
10475 +   }
10476 +   else
10477 +   {
10478 +      vcos_assert(0);
10479 +      return NULL;
10480 +   }
10481 +}
10482 +
10483 +VCOS_INLINE_IMPL
10484 +VCOS_STATUS_T vcos_tls_create(VCOS_TLS_KEY_T *key) {
10485 +   return vcos_generic_tls_create(key);
10486 +}
10487 +
10488 +VCOS_INLINE_IMPL
10489 +void vcos_tls_delete(VCOS_TLS_KEY_T tls) {
10490 +   vcos_generic_tls_delete(tls);
10491 +}
10492 +
10493 +#undef VCOS_ASSERT_LOGGING_DISABLE
10494 +#define VCOS_ASSERT_LOGGING_DISABLE 0
10495 +
10496 +#endif /* VCOS_INLINE_BODIES */
10497 +
10498 +#ifdef __cplusplus
10499 +}
10500 +#endif
10501 +
10502 +#endif
10503 +
10504 +
10505 --- /dev/null
10506 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_joinable_thread_from_plain.h
10507 @@ -0,0 +1,202 @@
10508 +/*=============================================================================
10509 +Copyright (c) 2009 Broadcom Europe Limited.
10510 +All rights reserved.
10511 +
10512 +Module   :  vcos
10513 +
10514 +FILE DESCRIPTION
10515 +VideoCore OS Abstraction Layer - implementation: joinable thread from plain
10516 +=============================================================================*/
10517 +
10518 +/** \file
10519 +  *
10520 +  * Header file for platforms creating the joinable thread from a lowlevel
10521 +  * thread.
10522 +  *
10523 +  * In addition to the actual thread, the following are also created:
10524 +  *
10525 +  * - a semaphore to wait on when joining the thread
10526 +  * - a semaphore to support counted suspend/resume (used by event group)
10527 +  * - a per-thread timer (used by event group, but could be removed)
10528 +  */
10529 +
10530 +#ifndef VCOS_JOINABLE_THREAD_FROM_PLAIN_H
10531 +#define VCOS_JOINABLE_THREAD_FROM_PLAIN_H
10532 +
10533 +#ifdef __cplusplus
10534 +extern "C" {
10535 +#endif
10536 +
10537 +#include "interface/vcos/vcos_semaphore.h"
10538 +#include "interface/vcos/vcos_lowlevel_thread.h"
10539 +#include "interface/vcos/vcos_timer.h"
10540 +
10541 +#ifdef VCOS_WANT_TLS_EMULATION
10542 +#include "interface/vcos/generic/vcos_generic_tls.h"
10543 +#endif
10544 +
10545 +#define VCOS_THREAD_MAGIC 0x56436a74
10546 +
10547 +#define VCOS_THREAD_VALID(t) (t->magic == VCOS_THREAD_MAGIC)
10548 +#define VCOS_HAVE_THREAD_AT_EXIT        1
10549 +
10550 +/** Thread attribute structure. Clients should not manipulate this directly, but
10551 +  * should instead use the provided functions.
10552 +  */
10553 +typedef struct VCOS_THREAD_ATTR_T
10554 +{
10555 +   void *ta_stackaddr;
10556 +   VCOS_UNSIGNED ta_stacksz;
10557 +   VCOS_UNSIGNED ta_priority;
10558 +   VCOS_UNSIGNED ta_affinity;
10559 +   VCOS_UNSIGNED ta_timeslice;
10560 +   VCOS_UNSIGNED legacy;
10561 +   VCOS_UNSIGNED ta_autostart;
10562 +} VCOS_THREAD_ATTR_T;
10563 +
10564 +/** Each thread gets a timer, which is for internal VCOS use.
10565 +  */
10566 +typedef struct _VCOS_THREAD_TIMER_T
10567 +{
10568 +   VCOS_TIMER_T timer;
10569 +   void (*pfn)(void *);
10570 +   void *cxt;
10571 +} _VCOS_THREAD_TIMER_T;
10572 +
10573 +typedef void (*VCOS_THREAD_EXIT_HANDLER_T)(void *);
10574 +/** Called at thread exit.
10575 +  */
10576 +typedef struct VCOS_THREAD_EXIT_T
10577 +{
10578 +   VCOS_THREAD_EXIT_HANDLER_T pfn;
10579 +   void *cxt;
10580 +} VCOS_THREAD_EXIT_T;
10581 +#define VCOS_MAX_EXIT_HANDLERS  8
10582 +
10583 +/* The name field isn't used for anything, so we can just copy the
10584 + * the pointer. Nucleus makes its own copy.
10585 + */
10586 +typedef const char *          VCOS_LLTHREAD_T_NAME;
10587 +#define _VCOS_LLTHREAD_NAME(dst,src) (dst)=(src)
10588 +
10589 +/*
10590 + * Simulated TLS support
10591 + */
10592 +
10593 +
10594 +/** Thread structure.
10595 +  *
10596 +  * \warning Do not access the members of this structure directly!
10597 +  */
10598 +typedef struct VCOS_THREAD_T
10599 +{
10600 +   VCOS_LLTHREAD_T  thread;      /**< The underlying thread */
10601 +   char name[16];                /**< The name */
10602 +   unsigned int     magic;       /**< For debug */
10603 +   void            *exit_data;   /**< Exit data passed out in vcos_joinable_thread_exit() */
10604 +   void            *stack;       /**< Stack, if not supplied by caller */
10605 +   VCOS_SEMAPHORE_T wait;        /**< Semaphore to wait on at join */
10606 +   VCOS_SEMAPHORE_T suspend;     /**< Semaphore to wait on for counted suspend */
10607 +   int16_t          joined;      /**< Joined yet? For debug. */
10608 +   VCOS_UNSIGNED    legacy;      /**< Use (argc,argv) for entry point arguments */
10609 +   void *(*entry)(void*);        /**< Entry point */
10610 +   void             *arg;        /**< Argument passed to entry point */
10611 +   void *(*term)(void*);         /**< Termination function, used by reaper */
10612 +   void             *term_arg;   /**< Argument passed to termination function */
10613 +   _VCOS_THREAD_TIMER_T _timer;  /**< Internal timer, mainly for event groups */
10614 +#ifdef VCOS_WANT_TLS_EMULATION
10615 +   VCOS_TLS_THREAD_T   _tls;     /**< TLS data when native TLS not available, or NULL */
10616 +#endif
10617 +   /** Array of functions to call at thread exit */
10618 +   VCOS_THREAD_EXIT_T at_exit[VCOS_MAX_EXIT_HANDLERS];
10619 +
10620 +   struct VCOS_THREAD_T *next;   /**< For linked lists of threads */
10621 +} VCOS_THREAD_T;
10622 +
10623 +#if defined(VCOS_INLINE_BODIES)
10624 +
10625 +VCOS_INLINE_IMPL
10626 +void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED stacksz) {
10627 +   attrs->ta_stackaddr = addr;
10628 +   attrs->ta_stacksz = stacksz;
10629 +}
10630 +
10631 +VCOS_INLINE_IMPL
10632 +void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED stacksz) {
10633 +   attrs->ta_stacksz = stacksz;
10634 +}
10635 +
10636 +VCOS_INLINE_IMPL
10637 +void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri) {
10638 +   attrs->ta_priority = pri;
10639 +}
10640 +
10641 +VCOS_INLINE_IMPL
10642 +void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED affinity) {
10643 +   attrs->ta_affinity = affinity;
10644 +}
10645 +
10646 +VCOS_INLINE_IMPL
10647 +void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts) {
10648 +   attrs->ta_timeslice = ts;
10649 +}
10650 +
10651 +VCOS_INLINE_IMPL
10652 +void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy) {
10653 +   attrs->legacy = legacy;
10654 +}
10655 +
10656 +VCOS_INLINE_IMPL
10657 +void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart) {
10658 +   attrs->ta_autostart = autostart;
10659 +}
10660 +
10661 +VCOS_INLINE_IMPL
10662 +VCOS_THREAD_T *vcos_thread_current(void) {
10663 +   VCOS_THREAD_T *ret =  (VCOS_THREAD_T*)vcos_llthread_current();
10664 +   /*If we're called from a non-vcos thread, this assert will fail.
10665 +    *XXX FIXME why is this commented out?
10666 +    *vcos_assert(ret->magic == VCOS_THREAD_MAGIC);
10667 +    */
10668 +   return ret;
10669 +}
10670 +
10671 +VCOS_INLINE_IMPL
10672 +int vcos_thread_running(VCOS_THREAD_T *thread) {
10673 +   return vcos_llthread_running(&thread->thread);
10674 +}
10675 +
10676 +VCOS_INLINE_IMPL
10677 +void vcos_thread_resume(VCOS_THREAD_T *thread) {
10678 +   vcos_llthread_resume(&thread->thread);
10679 +}
10680 +
10681 +#endif /* VCOS_INLINE_BODIES */
10682 +
10683 +/**
10684 +  * \brief Create a VCOS_THREAD_T for the current thread. This is so we can have
10685 +  * VCOS_THREAD_Ts even for threads not originally created by VCOS (eg the
10686 +  * thread that calls vcos_init)
10687 +  */
10688 +extern VCOS_STATUS_T _vcos_thread_create_attach(VCOS_THREAD_T *thread,
10689 +                                                const char *name);
10690 +
10691 +/**
10692 +  * \brief Deletes the VCOS_THREAD_T, but does not wait for the underlying
10693 +  * thread to exit. This will cleanup everything created by
10694 +  * _vcos_thread_create_attach
10695 +  */
10696 +extern void _vcos_thread_delete(VCOS_THREAD_T *thread);
10697 +
10698 +/** Register a function to be called when the current thread exits.
10699 +  */
10700 +extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt);
10701 +
10702 +/** Deregister a previously registered at-exit function.
10703 +  */
10704 +extern void vcos_thread_deregister_at_exit(void (*pfn)(void*), void *cxt);
10705 +
10706 +#ifdef __cplusplus
10707 +}
10708 +#endif
10709 +#endif /* VCOS_JOINABLE_THREAD_FROM_PLAIN_H */
10710 --- /dev/null
10711 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_latch_from_sem.h
10712 @@ -0,0 +1,48 @@
10713 +/*=============================================================================
10714 +Copyright (c) 2009 Broadcom Europe Limited.
10715 +All rights reserved.
10716 +
10717 +Project  :  vcfw
10718 +Module   :  vcos
10719 +
10720 +FILE DESCRIPTION
10721 +VideoCore OS Abstraction Layer - Construct a latch from a semaphore
10722 +=============================================================================*/
10723 +
10724 +/** FIXME: rename to vcos_mutex_from_sem.c
10725 +  */
10726 +
10727 +typedef struct VCOS_MUTEX_T {
10728 +   VCOS_SEMAPHORE_T sem;
10729 +   struct VCOS_THREAD_T *owner;
10730 +} VCOS_MUTEX_T;
10731 +
10732 +extern VCOS_STATUS_T vcos_generic_mutex_create(VCOS_MUTEX_T *latch, const char *name);
10733 +extern void vcos_generic_mutex_delete(VCOS_MUTEX_T *latch);
10734 +extern VCOS_STATUS_T vcos_generic_mutex_lock(VCOS_MUTEX_T *latch);
10735 +extern void vcos_generic_mutex_unlock(VCOS_MUTEX_T *latch);
10736 +
10737 +#if defined(VCOS_INLINE_BODIES)
10738 +
10739 +VCOS_INLINE_IMPL
10740 +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *latch, const char *name) {
10741 +   return vcos_generic_mutex_create(latch,name);
10742 +}
10743 +
10744 +VCOS_INLINE_IMPL
10745 +void vcos_mutex_delete(VCOS_MUTEX_T *latch) {
10746 +   vcos_generic_mutex_delete(latch);
10747 +}
10748 +
10749 +VCOS_INLINE_IMPL
10750 +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *latch) {
10751 +   return vcos_generic_mutex_lock(latch);
10752 +}
10753 +
10754 +VCOS_INLINE_IMPL
10755 +void vcos_mutex_unlock(VCOS_MUTEX_T *latch) {
10756 +   vcos_generic_mutex_unlock(latch);
10757 +}
10758 +
10759 +#endif /* VCOS_INLINE_BODIES */
10760 +
10761 --- /dev/null
10762 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_logcat.c
10763 @@ -0,0 +1,549 @@
10764 +/*=============================================================================
10765 +Copyright (c) 2010 Broadcom Europe Limited.
10766 +All rights reserved.
10767 +
10768 +Project  :  vcfw
10769 +Module   :  vcos
10770 +
10771 +FILE DESCRIPTION
10772 +Categorized logging for VCOS - a generic implementation.
10773 +=============================================================================*/
10774 +
10775 +#include "interface/vcos/vcos.h"
10776 +#include "interface/vcos/vcos_ctype.h"
10777 +#include "interface/vcos/vcos_string.h"
10778 +
10779 +static VCOS_MUTEX_T lock;
10780 +static int warned_loglevel;             /* only warn about invalid log level once */
10781 +static VCOS_VLOG_IMPL_FUNC_T vcos_vlog_impl_func = vcos_vlog_default_impl;
10782 +
10783 +#define  VCOS_LOG_CATEGORY (&dflt_log_category)
10784 +static VCOS_LOG_CAT_T dflt_log_category;
10785 +VCOS_LOG_CAT_T *vcos_logging_categories = NULL;
10786 +static int inited;
10787 +
10788 +#if VCOS_HAVE_CMD
10789 +
10790 +/*
10791 + * For kernel or videocore purposes, we generally want the log command. For 
10792 + * user-space apps, they might want to provide their own log command, so we 
10793 + * don't include the built in on. 
10794 + *  
10795 + * So pthreads/vcos_platform.h defines VCOS_WANT_LOG_CMD to be 0. It is 
10796 + * undefined elsewhere. 
10797 + */
10798 +
10799 +#  if !defined( VCOS_WANT_LOG_CMD )
10800 +#     define  VCOS_WANT_LOG_CMD 1
10801 +#  endif
10802 +#else
10803 +#  define VCOS_WANT_LOG_CMD   0
10804 +#endif
10805 +
10806 +#if VCOS_WANT_LOG_CMD
10807 +
10808 +/*****************************************************************************
10809 +*
10810 +*   Does a vcos_assert(0), which is useful to test logging.
10811 +*
10812 +*****************************************************************************/
10813 +
10814 +VCOS_STATUS_T vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param )
10815 +{
10816 +   (void)param;
10817 +
10818 +#if defined( NDEBUG ) && !defined( VCOS_RELEASE_ASSERTS )
10819 +   vcos_log_error( "vcos_asserts have been compiled out" );
10820 +   vcos_cmd_printf( param, "vcos_asserts have been compiled out - did a vcos_log_error instead\n" );
10821 +#else
10822 +   vcos_assert(0);
10823 +   vcos_cmd_printf( param, "Executed vcos_assert(0)\n" );
10824 +#endif
10825 +
10826 +   return VCOS_SUCCESS;
10827 +}
10828 +
10829 +/*****************************************************************************
10830 +*
10831 +*   Sets a vcos logging level
10832 +*
10833 +*****************************************************************************/
10834 +
10835 +VCOS_STATUS_T vcos_log_set_cmd( VCOS_CMD_PARAM_T *param )
10836 +{
10837 +   VCOS_LOG_CAT_T   *cat;
10838 +   char             *name;
10839 +   char             *levelStr;
10840 +   VCOS_LOG_LEVEL_T  level;
10841 +   VCOS_STATUS_T     status;
10842 +
10843 +   if ( param->argc != 3 )
10844 +   {
10845 +      vcos_cmd_usage( param );
10846 +      return VCOS_EINVAL;
10847 +   }
10848 +
10849 +   name = param->argv[1];
10850 +   levelStr = param->argv[2];
10851 +
10852 +   if ( vcos_string_to_log_level( levelStr, &level ) != VCOS_SUCCESS )
10853 +   {
10854 +      vcos_cmd_printf( param, "Unrecognized logging level: '%s'\n", levelStr );
10855 +      return VCOS_EINVAL;
10856 +   }
10857 +
10858 +   vcos_mutex_lock(&lock);
10859 +
10860 +   status = VCOS_SUCCESS;
10861 +   for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10862 +   {
10863 +      if ( vcos_strcmp( name, cat->name ) == 0 )
10864 +      {
10865 +         cat->level = level;
10866 +         vcos_cmd_printf( param, "Category %s level set to %s\n", name, levelStr );
10867 +         break;
10868 +      }
10869 +   }
10870 +   if ( cat == NULL )
10871 +   {
10872 +      vcos_cmd_printf( param, "Unrecognized category: '%s'\n", name );
10873 +      status = VCOS_ENOENT;
10874 +   }
10875 +
10876 +   vcos_mutex_unlock(&lock);
10877 +
10878 +   return status;
10879 +}
10880 +
10881 +/*****************************************************************************
10882 +*
10883 +*   Prints out the current settings for a given category (or all cvategories)
10884 +*
10885 +*****************************************************************************/
10886 +
10887 +VCOS_STATUS_T vcos_log_status_cmd( VCOS_CMD_PARAM_T *param )
10888 +{
10889 +   VCOS_LOG_CAT_T   *cat;
10890 +   VCOS_STATUS_T     status;
10891 +
10892 +   vcos_mutex_lock(&lock);
10893 +
10894 +   if ( param->argc == 1)
10895 +   {
10896 +      int   nw;
10897 +      int   nameWidth = 0;
10898 +
10899 +      /* Print information about all of the categories. */
10900 +
10901 +      for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10902 +      {
10903 +         nw = (int)strlen( cat->name );
10904 +
10905 +         if ( nw > nameWidth )
10906 +         {
10907 +            nameWidth = nw;
10908 +         }
10909 +      }
10910 +
10911 +      for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10912 +      {
10913 +         vcos_cmd_printf( param, "%-*s - %s\n", nameWidth, cat->name, vcos_log_level_to_string( cat->level ));
10914 +      }
10915 +   }
10916 +   else
10917 +   {
10918 +      /* Print information about a particular category */
10919 +
10920 +      for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
10921 +      {
10922 +         if ( vcos_strcmp( cat->name, param->argv[1] ) == 0 )
10923 +         {
10924 +            vcos_cmd_printf( param, "%s - %s\n", cat->name, vcos_log_level_to_string( cat->level ));
10925 +            break;
10926 +         }
10927 +      }
10928 +      if ( cat == NULL )
10929 +      {
10930 +         vcos_cmd_printf( param, "Unrecognized logging category: '%s'\n", param->argv[1] );
10931 +         status = VCOS_ENOENT;
10932 +         goto out;
10933 +      }
10934 +   }
10935 +
10936 +   status = VCOS_SUCCESS;
10937 +out:
10938 +   vcos_mutex_unlock(&lock);
10939 +
10940 +   return status;
10941 +}
10942 +
10943 +/*****************************************************************************
10944 +*
10945 +*   Prints out the current settings for a given category (or all cvategories)
10946 +*
10947 +*****************************************************************************/
10948 +
10949 +VCOS_STATUS_T vcos_log_test_cmd( VCOS_CMD_PARAM_T *param )
10950 +{
10951 +   if ( param->argc == 1 )
10952 +   {
10953 +      static   int seq_num = 100;
10954 +
10955 +      /* No additional arguments - generate a message with an incrementing number */
10956 +
10957 +      vcos_log_error( "Test message %d", seq_num );
10958 +
10959 +      seq_num++;
10960 +      vcos_cmd_printf( param, "Logged 'Test message %d'\n", seq_num );
10961 +   }
10962 +   else
10963 +   {
10964 +      int   arg_idx;
10965 +
10966 +      /* Arguments supplied - log these */
10967 +
10968 +      for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
10969 +      {
10970 +         vcos_log_error( "argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
10971 +      }
10972 +      vcos_cmd_printf( param, "Logged %d line(s) of test data\n", param->argc );
10973 +   }
10974 +   return VCOS_SUCCESS;
10975 +}
10976 +
10977 +/*****************************************************************************
10978 +*
10979 +*   Internal commands
10980 +*
10981 +*****************************************************************************/
10982 +
10983 +static VCOS_CMD_T log_cmd_entry[] =
10984 +{
10985 +    { "assert",   "",                  vcos_log_assert_cmd, NULL,    "Does a vcos_assert(0) to test logging" },
10986 +    { "set",      "category level",    vcos_log_set_cmd,    NULL,    "Sets the vcos logging level for a category" },
10987 +    { "status",   "[category]",        vcos_log_status_cmd, NULL,    "Prints the vcos log status for a (or all) categories" },
10988 +    { "test",     "[arbitrary text]",  vcos_log_test_cmd,   NULL,    "Does a vcos_log to test logging" },
10989 +
10990 +    { NULL,       NULL,                NULL,                NULL,    NULL }
10991 +};
10992 +
10993 +static VCOS_CMD_T cmd_log =
10994 +    { "log",        "command [args]",  NULL,    log_cmd_entry, "Commands related to vcos logging" };
10995 +
10996 +#endif
10997 +
10998 +void vcos_logging_init(void)
10999 +{
11000 +   if (inited)
11001 +   {
11002 +      /* FIXME: should print a warning or something here */
11003 +      return;
11004 +   }
11005 +   vcos_mutex_create(&lock, "vcos_log");
11006 +
11007 +   vcos_log_platform_init();
11008 +
11009 +   vcos_log_register("default", &dflt_log_category);
11010 +
11011 +#if VCOS_WANT_LOG_CMD
11012 +   vcos_cmd_register( &cmd_log );
11013 +#endif
11014 +
11015 +   vcos_assert(!inited);
11016 +   inited = 1;
11017 +}
11018 +
11019 +/** Read an alphanumeric token, returning True if we succeeded.
11020 +  */
11021 +
11022 +static int read_tok(char *tok, size_t toklen, const char **pstr, char sep)
11023 +{
11024 +   const char *str = *pstr;
11025 +   size_t n = 0;
11026 +   char ch;
11027 +
11028 +   /* skip past any whitespace */
11029 +   while (str[0] && isspace((int)(str[0])))
11030 +      str++;
11031 +
11032 +   while ((ch = *str) != '\0' &&
11033 +          ch != sep &&
11034 +          (isalnum((int)ch) || (ch == '_')) &&
11035 +          n != toklen-1)
11036 +   {
11037 +      tok[n++] = ch;
11038 +      str++;
11039 +   }
11040 +
11041 +   /* did it work out? */
11042 +   if (ch == '\0' || ch == sep)
11043 +   {
11044 +      if (ch) str++; /* move to next token if not at end */
11045 +      /* yes */
11046 +      tok[n] = '\0';
11047 +      *pstr = str;
11048 +      return 1;
11049 +   }
11050 +   else
11051 +   {
11052 +      /* no */
11053 +      return 0;
11054 +   }
11055 +}
11056 +
11057 +const char *vcos_log_level_to_string( VCOS_LOG_LEVEL_T level )
11058 +{
11059 +   switch (level)
11060 +   {
11061 +      case VCOS_LOG_UNINITIALIZED:  return "uninit";
11062 +      case VCOS_LOG_NEVER:          return "never";
11063 +      case VCOS_LOG_ERROR:          return "error";
11064 +      case VCOS_LOG_WARN:           return "warn";
11065 +      case VCOS_LOG_INFO:           return "info";
11066 +      case VCOS_LOG_TRACE:          return "trace";
11067 +   }
11068 +   return "???";
11069 +}
11070 +
11071 +VCOS_STATUS_T vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level )
11072 +{
11073 +   if (strcmp(str,"error") == 0)
11074 +      *level = VCOS_LOG_ERROR;
11075 +   else if (strcmp(str,"never") == 0)
11076 +      *level = VCOS_LOG_NEVER;
11077 +   else if (strcmp(str,"warn") == 0)
11078 +      *level = VCOS_LOG_WARN;
11079 +   else if (strcmp(str,"warning") == 0)
11080 +      *level = VCOS_LOG_WARN;
11081 +   else if (strcmp(str,"info") == 0)
11082 +      *level = VCOS_LOG_INFO;
11083 +   else if (strcmp(str,"trace") == 0)
11084 +      *level = VCOS_LOG_TRACE;
11085 +   else
11086 +      return VCOS_EINVAL;
11087 +
11088 +   return VCOS_SUCCESS;
11089 +}
11090 +
11091 +static int read_level(VCOS_LOG_LEVEL_T *level, const char **pstr, char sep)
11092 +{
11093 +   char buf[16];
11094 +   int ret = 1;
11095 +   if (read_tok(buf,sizeof(buf),pstr,sep))
11096 +   {
11097 +      if (vcos_string_to_log_level(buf,level) != VCOS_SUCCESS)
11098 +      {
11099 +         vcos_log("Invalid trace level '%s'\n", buf);
11100 +         ret = 0;
11101 +      }
11102 +   }
11103 +   else
11104 +   {
11105 +      ret = 0;
11106 +   }
11107 +   return ret;
11108 +}
11109 +
11110 +void vcos_log_register(const char *name, VCOS_LOG_CAT_T *category)
11111 +{
11112 +   const char *env;
11113 +   VCOS_LOG_CAT_T *i;
11114 +
11115 +   category->name  = name;
11116 +   if ( category->level == VCOS_LOG_UNINITIALIZED )
11117 +   {
11118 +      category->level = VCOS_LOG_ERROR;
11119 +   }
11120 +   category->flags.want_prefix = (category != &dflt_log_category );
11121 +
11122 +   vcos_mutex_lock(&lock);
11123 +
11124 +   /* is it already registered? */
11125 +   for (i = vcos_logging_categories; i ; i = i->next )
11126 +   {
11127 +      if (i == category)
11128 +      {
11129 +         i->refcount++;
11130 +         break;
11131 +      }
11132 +   }
11133 +
11134 +   if (!i)
11135 +   {
11136 +      /* not yet registered */
11137 +      category->next = vcos_logging_categories;
11138 +      vcos_logging_categories = category;
11139 +      category->refcount++;
11140 +
11141 +      vcos_log_platform_register(category);
11142 +   }
11143 +
11144 +   vcos_mutex_unlock(&lock);
11145 +
11146 +   /* Check to see if this log level has been enabled. Look for
11147 +    * (<category:level>,)*
11148 +    *
11149 +    * VC_LOGLEVEL=ilcs:info,vchiq:warn
11150 +    */
11151 +
11152 +   env = _VCOS_LOG_LEVEL();
11153 +   if (env)
11154 +   {
11155 +      do
11156 +      {
11157 +         char env_name[64];
11158 +         VCOS_LOG_LEVEL_T level;
11159 +         if (read_tok(env_name, sizeof(env_name), &env, ':') &&
11160 +             read_level(&level, &env, ','))
11161 +         {
11162 +            if (strcmp(env_name, name) == 0)
11163 +            {
11164 +               category->level = level;
11165 +               break;
11166 +            }
11167 +         }
11168 +         else
11169 +         {
11170 +            if (!warned_loglevel)
11171 +            {
11172 +                vcos_log("VC_LOGLEVEL format invalid at %s\n", env);
11173 +                warned_loglevel = 1;
11174 +            }
11175 +            return;
11176 +         }
11177 +      } while (env[0] != '\0');
11178 +   }
11179 +
11180 +   vcos_log_info( "Registered log category '%s' with level %s",
11181 +                  category->name,
11182 +                  vcos_log_level_to_string( category->level ));
11183 +}
11184 +
11185 +void vcos_log_unregister(VCOS_LOG_CAT_T *category)
11186 +{
11187 +   VCOS_LOG_CAT_T **pcat;
11188 +   vcos_mutex_lock(&lock);
11189 +   category->refcount--;
11190 +   if (category->refcount == 0)
11191 +   {
11192 +      pcat = &vcos_logging_categories;
11193 +      while (*pcat != category)
11194 +      {
11195 +         if (!*pcat)
11196 +            break;   /* possibly deregistered twice? */
11197 +         if ((*pcat)->next == NULL)
11198 +         {
11199 +            vcos_assert(0); /* already removed! */
11200 +            vcos_mutex_unlock(&lock);
11201 +            return;
11202 +         }
11203 +         pcat = &(*pcat)->next;
11204 +      }
11205 +      if (*pcat)
11206 +         *pcat = category->next;
11207 +
11208 +      vcos_log_platform_unregister(category);
11209 +   }
11210 +   vcos_mutex_unlock(&lock);
11211 +}
11212 +
11213 +VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void)
11214 +{
11215 +   return &dflt_log_category;
11216 +}
11217 +
11218 +void vcos_set_log_options(const char *opt)
11219 +{
11220 +   (void)opt;
11221 +}
11222 +
11223 +void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
11224 +                             const char           *label,
11225 +                             uint32_t              addr,
11226 +                             const void           *voidMem,
11227 +                             size_t                numBytes )
11228 +{
11229 +   const uint8_t  *mem = (const uint8_t *)voidMem;
11230 +   size_t          offset;
11231 +   char            lineBuf[ 100 ];
11232 +   char           *s;
11233 +
11234 +   while ( numBytes > 0 )
11235 +   {
11236 +       s = lineBuf;
11237 +
11238 +       for ( offset = 0; offset < 16; offset++ )
11239 +       {
11240 +           if ( offset < numBytes )
11241 +           {
11242 +               s += vcos_snprintf( s, 4, "%02x ", mem[ offset ]);
11243 +           }
11244 +           else
11245 +           {
11246 +               s += vcos_snprintf( s, 4, "   " );
11247 +           }
11248 +       }
11249 +
11250 +       for ( offset = 0; offset < 16; offset++ )
11251 +       {
11252 +           if ( offset < numBytes )
11253 +           {
11254 +               uint8_t ch = mem[ offset ];
11255 +
11256 +               if (( ch < ' ' ) || ( ch > '~' ))
11257 +               {
11258 +                   ch = '.';
11259 +               }
11260 +               *s++ = (char)ch;
11261 +           }
11262 +       }
11263 +       *s++ = '\0';
11264 +
11265 +       if (( label != NULL ) && ( *label != '\0' ))
11266 +       {
11267 +          vcos_log_impl( cat, VCOS_LOG_INFO, "%s: %08x: %s", label, addr, lineBuf );
11268 +       }
11269 +       else
11270 +       {
11271 +          vcos_log_impl( cat, VCOS_LOG_INFO, "%08x: %s", addr, lineBuf );
11272 +       }
11273 +
11274 +       addr += 16;
11275 +       mem += 16;
11276 +       if ( numBytes > 16 )
11277 +       {
11278 +           numBytes -= 16;
11279 +       }
11280 +       else
11281 +       {
11282 +           numBytes = 0;
11283 +       }
11284 +   }
11285 +
11286 +}
11287 +
11288 +void vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...)
11289 +{
11290 +   va_list ap;
11291 +   va_start(ap,fmt);
11292 +   vcos_vlog_impl( cat, _level, fmt, ap );
11293 +   va_end(ap);
11294 +}
11295 +
11296 +void vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
11297 +{
11298 +   vcos_vlog_impl_func( cat, _level, fmt, args );
11299 +}
11300 +
11301 +void vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func )
11302 +{
11303 +   if ( vlog_impl_func == NULL )
11304 +   {
11305 +      vcos_vlog_impl_func = vcos_vlog_default_impl;
11306 +   }
11307 +   else
11308 +   {
11309 +      vcos_vlog_impl_func = vlog_impl_func;
11310 +   }
11311 +}
11312 +
11313 --- /dev/null
11314 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.c
11315 @@ -0,0 +1,73 @@
11316 +/*=============================================================================
11317 +Copyright (c) 2009 Broadcom Europe Limited.
11318 +All rights reserved.
11319 +
11320 +Project  :  vcfw
11321 +Module   :  vcos
11322 +
11323 +FILE DESCRIPTION
11324 +VideoCore OS Abstraction Layer - memory alloc implementation
11325 +=============================================================================*/
11326 +
11327 +#include "interface/vcos/vcos.h"
11328 +
11329 +#ifndef _vcos_platform_malloc
11330 +#include <stdlib.h>
11331 +#define _vcos_platform_malloc malloc
11332 +#define _vcos_platform_free   free
11333 +#endif
11334 +
11335 +typedef struct malloc_header_s {
11336 +   uint32_t guardword;
11337 +   uint32_t size;
11338 +   const char *description;
11339 +   void *ptr;
11340 +} MALLOC_HEADER_T;
11341 +
11342 +
11343 +#define MIN_ALIGN sizeof(MALLOC_HEADER_T)
11344 +
11345 +#define GUARDWORDHEAP  0xa55a5aa5
11346 +
11347 +void *vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *desc)
11348 +{
11349 +   int local_align = align == 0 ? 1 : align;
11350 +   int required_size = size + local_align + sizeof(MALLOC_HEADER_T);
11351 +   void *ptr = _vcos_platform_malloc(required_size);
11352 +   void *ret = (void *)VCOS_ALIGN_UP(((char *)ptr)+sizeof(MALLOC_HEADER_T), local_align);
11353 +   MALLOC_HEADER_T *h = ((MALLOC_HEADER_T *)ret)-1;
11354 +
11355 +   h->size = size;
11356 +   h->description = desc;
11357 +   h->guardword = GUARDWORDHEAP;
11358 +   h->ptr = ptr;
11359 +
11360 +   return ret;
11361 +}
11362 +
11363 +void *vcos_generic_mem_alloc(VCOS_UNSIGNED size, const char *desc)
11364 +{
11365 +   return vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
11366 +}
11367 +
11368 +void *vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *desc)
11369 +{
11370 +   uint32_t size = count*sz;
11371 +   void *ptr = vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
11372 +   if (ptr)
11373 +   {
11374 +      memset(ptr, 0, size);
11375 +   }
11376 +   return ptr;
11377 +}
11378 +
11379 +void vcos_generic_mem_free(void *ptr)
11380 +{
11381 +   MALLOC_HEADER_T *h;
11382 +   if (! ptr) return;
11383 +
11384 +   h = ((MALLOC_HEADER_T *)ptr)-1;
11385 +   vcos_assert(h->guardword == GUARDWORDHEAP);
11386 +   _vcos_platform_free(h->ptr);
11387 +}
11388 +
11389 --- /dev/null
11390 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.h
11391 @@ -0,0 +1,54 @@
11392 +/*=============================================================================
11393 +Copyright (c) 2009 Broadcom Europe Limited.
11394 +All rights reserved.
11395 +
11396 +Project  :  VMCS Host Apps
11397 +Module   :  Framework - VMCS
11398 +
11399 +FILE DESCRIPTION
11400 +Create the vcos_malloc API from the regular system malloc/free
11401 +=============================================================================*/
11402 +
11403 +/**
11404 +  * \file
11405 +  *
11406 +  * Create the vcos malloc API from a regular system malloc/free library.
11407 +  *
11408 +  * The API lets callers specify an alignment.
11409 +  *
11410 +  * Under VideoCore this is not needed, as we can simply use the rtos_malloc routines.
11411 +  * But on host platforms that won't be the case.
11412 +  *
11413 +  */
11414 +
11415 +VCOSPRE_ void * VCOSPOST_  vcos_generic_mem_alloc(VCOS_UNSIGNED sz, const char *desc);
11416 +VCOSPRE_  void * VCOSPOST_ vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *descr);
11417 +VCOSPRE_  void VCOSPOST_   vcos_generic_mem_free(void *ptr);
11418 +VCOSPRE_  void * VCOSPOST_ vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED sz, VCOS_UNSIGNED align, const char *desc);
11419 +
11420 +#ifdef VCOS_INLINE_BODIES
11421 +
11422 +VCOS_INLINE_IMPL
11423 +void *vcos_malloc(VCOS_UNSIGNED size, const char *description) {
11424 +   return vcos_generic_mem_alloc(size, description);
11425 +}
11426 +
11427 +VCOS_INLINE_IMPL
11428 +void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description) {
11429 +   return vcos_generic_mem_calloc(num, size, description);
11430 +}
11431 +
11432 +VCOS_INLINE_IMPL
11433 +void vcos_free(void *ptr) {
11434 +   vcos_generic_mem_free(ptr);
11435 +}
11436 +
11437 +VCOS_INLINE_IMPL
11438 +void * vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description) {
11439 +   return vcos_generic_mem_alloc_aligned(size, align, description);
11440 +}
11441 +
11442 +
11443 +#endif /* VCOS_INLINE_BODIES */
11444 +
11445 +
11446 --- /dev/null
11447 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mutexes_are_reentrant.h
11448 @@ -0,0 +1,68 @@
11449 +/*=============================================================================
11450 +Copyright (c) 2009 Broadcom Europe Limited.
11451 +All rights reserved.
11452 +
11453 +Project  :  vcfw
11454 +Module   :  chip driver
11455 +
11456 +FILE DESCRIPTION
11457 +VideoCore OS Abstraction Layer - reentrant mutexes mapped directly to regular ones
11458 +=============================================================================*/
11459 +
11460 +#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
11461 +#define VCOS_GENERIC_REENTRANT_MUTEX_H
11462 +
11463 +#ifdef __cplusplus
11464 +extern "C" {
11465 +#endif
11466 +
11467 +#include "interface/vcos/vcos_types.h"
11468 +#include "interface/vcos/vcos_mutex.h"
11469 +
11470 +/**
11471 + * \file
11472 + *
11473 + * Reentrant Mutexes directly using the native re-entrant mutex.
11474 + *
11475 + */
11476 +
11477 +typedef VCOS_MUTEX_T VCOS_REENTRANT_MUTEX_T;
11478 +
11479 +/* Inline forwarding functions */
11480 +
11481 +#if defined(VCOS_INLINE_BODIES)
11482 +
11483 +VCOS_INLINE_IMPL
11484 +VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) {
11485 +   return vcos_mutex_create(m,name);
11486 +}
11487 +
11488 +VCOS_INLINE_IMPL
11489 +void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
11490 +   vcos_mutex_delete(m);
11491 +}
11492 +
11493 +VCOS_INLINE_IMPL
11494 +void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
11495 +   vcos_mutex_lock(m);
11496 +}
11497 +
11498 +VCOS_INLINE_IMPL
11499 +void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
11500 +   vcos_mutex_unlock(m);
11501 +}
11502 +
11503 +VCOS_INLINE_IMPL
11504 +int vcos_reentrant_mutex_is_locked(VCOS_REENTRANT_MUTEX_T *m) {
11505 +   return vcos_mutex_is_locked(m);
11506 +}
11507 +
11508 +#endif
11509 +
11510 +#ifdef __cplusplus
11511 +}
11512 +#endif
11513 +#endif
11514 +
11515 +
11516 +
11517 --- /dev/null
11518 +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_thread_reaper.h
11519 @@ -0,0 +1,35 @@
11520 +/*=============================================================================
11521 +Copyright (c) 2010 Broadcom Europe Limited.
11522 +All rights reserved.
11523 +
11524 +Project  :  vcfw
11525 +Module   :  vcos
11526 +
11527 +FILE DESCRIPTION
11528 +VideoCore OS Abstraction Layer - thread reaping
11529 +=============================================================================*/
11530 +
11531 +#ifndef VCOS_THREAD_REAPER_H
11532 +#define VCOS_THREAD_REAPER_H
11533 +
11534 +#define VCOS_HAVE_THREAD_REAPER
11535 +
11536 +/** Initialise the thread reaper.
11537 +  */
11538 +VCOS_STATUS_T vcos_thread_reaper_init(void);
11539 +
11540 +/** Reap a thread. Arranges for the thread to be automatically
11541 +  * joined.
11542 +  *
11543 +  * @sa vcos_thread_join().
11544 +  *
11545 +  * @param thread           the thread to terminate
11546 +  * @param on_terminated    called after the thread has exited
11547 +  * @param cxt              pass back to the callback
11548 +  *
11549 +  */
11550 +void vcos_thread_reap(VCOS_THREAD_T *thread, void (*on_terminated)(void*), void *cxt);
11551 +
11552 +#endif
11553 +
11554 +
11555 --- /dev/null
11556 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/stdint.h
11557 @@ -0,0 +1,17 @@
11558 +/*=============================================================================
11559 +Copyright (c) 2010 Broadcom Europe Limited.
11560 +All rights reserved.
11561 +
11562 +FILE DESCRIPTION
11563 +VideoCore OS fAbstraction Layer - stdint.h C standard header
11564 +=============================================================================*/
11565 +
11566 +#ifndef _VCOS_PLATFORM_LINUX_STDINT_H
11567 +#define _VCOS_PLATFORM_LINUX_STDINT_H
11568 +
11569 +/* The Linux kernel does not have a <stdint.h> so we have to provide one of
11570 +   our own. */
11571 +
11572 +#include <linux/types.h> /* includes integer types */
11573 +
11574 +#endif /* _VCOS_PLATFORM_LINUX_STDINT_H */
11575 --- /dev/null
11576 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel.c
11577 @@ -0,0 +1,616 @@
11578 +/*=============================================================================
11579 +Copyright (c) 2009 Broadcom Europe Limited.
11580 +All rights reserved.
11581 +
11582 +Project  :  vcfw
11583 +Module   :  vcos
11584 +
11585 +FILE DESCRIPTION
11586 +VideoCore OS Abstraction Layer - pthreads types
11587 +=============================================================================*/
11588 +
11589 +#define  VCOS_INLINE_BODIES
11590 +#include <linux/module.h>
11591 +#include <linux/kernel.h>
11592 +#include <linux/time.h>
11593 +#include <linux/pid.h>
11594 +#include <linux/mm.h>
11595 +#include <linux/version.h>
11596 +
11597 +#if defined( CONFIG_BCM_KNLLOG_SUPPORT )
11598 +#include <linux/broadcom/knllog.h>
11599 +#endif
11600 +#include "interface/vcos/vcos.h"
11601 +#ifdef HAVE_VCOS_VERSION
11602 +#include "interface/vcos/vcos_build_info.h"
11603 +#endif
11604 +
11605 +VCOS_CFG_ENTRY_T  vcos_cfg_dir;
11606 +VCOS_CFG_ENTRY_T  vcos_logging_cfg_dir;
11607 +VCOS_CFG_ENTRY_T  vcos_version_cfg;
11608 +
11609 +#ifndef VCOS_DEFAULT_STACK_SIZE
11610 +#define VCOS_DEFAULT_STACK_SIZE 4096
11611 +#endif
11612 +
11613 +static VCOS_THREAD_ATTR_T default_attrs = {
11614 +   0,
11615 +   VCOS_DEFAULT_STACK_SIZE,
11616 +};
11617 +
11618 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
11619 +static DEFINE_SEMAPHORE(lock);
11620 +#else
11621 +static DECLARE_MUTEX(lock);
11622 +#endif
11623 +
11624 +typedef void (*LEGACY_ENTRY_FN_T)(int, void *);
11625 +
11626 +/** Wrapper function around the real thread function. Posts the semaphore
11627 +  * when completed.
11628 +  */
11629 +static int vcos_thread_wrapper(void *arg)
11630 +{
11631 +   void *ret;
11632 +   VCOS_THREAD_T *thread = arg;
11633 +
11634 +   vcos_assert(thread->magic == VCOS_THREAD_MAGIC);
11635 +
11636 +   thread->thread.thread = current;
11637 +
11638 +   vcos_add_thread(thread);
11639 +
11640 +#ifdef VCOS_WANT_TLS_EMULATION
11641 +   vcos_tls_thread_register(&thread->_tls);
11642 +#endif
11643 +
11644 +   if (thread->legacy)
11645 +   {
11646 +      LEGACY_ENTRY_FN_T fn = (LEGACY_ENTRY_FN_T)thread->entry;
11647 +      fn(0,thread->arg);
11648 +      ret = 0;
11649 +   }
11650 +   else
11651 +   {
11652 +      ret = thread->entry(thread->arg);
11653 +   }
11654 +
11655 +   thread->exit_data = ret;
11656 +
11657 +   vcos_remove_thread(current);
11658 +
11659 +   /* For join and cleanup */
11660 +   vcos_semaphore_post(&thread->wait);
11661 +
11662 +   return 0;
11663 +}
11664 +
11665 +VCOS_STATUS_T vcos_thread_create(VCOS_THREAD_T *thread,
11666 +                                 const char *name,
11667 +                                 VCOS_THREAD_ATTR_T *attrs,
11668 +                                 VCOS_THREAD_ENTRY_FN_T entry,
11669 +                                 void *arg)
11670 +{
11671 +   VCOS_STATUS_T st;
11672 +   struct task_struct *kthread;
11673 +
11674 +   memset(thread, 0, sizeof(*thread));
11675 +   thread->magic     = VCOS_THREAD_MAGIC;
11676 +   strlcpy( thread->name, name, sizeof( thread->name ));
11677 +   thread->legacy    = attrs ? attrs->legacy : 0;
11678 +   thread->entry = entry;
11679 +   thread->arg = arg;
11680 +
11681 +   if (!name)
11682 +   {
11683 +      vcos_assert(0);
11684 +      return VCOS_EINVAL;
11685 +   }
11686 +
11687 +   st = vcos_semaphore_create(&thread->wait, NULL, 0);
11688 +   if (st != VCOS_SUCCESS)
11689 +   {
11690 +      return st;
11691 +   }
11692 +
11693 +   st = vcos_semaphore_create(&thread->suspend, NULL, 0);
11694 +   if (st != VCOS_SUCCESS)
11695 +   {
11696 +      return st;
11697 +   }
11698 +
11699 +   /*required for event groups */
11700 +   vcos_timer_create(&thread->_timer.timer, thread->name, NULL, NULL);
11701 +
11702 +   kthread = kthread_create((int (*)(void *))vcos_thread_wrapper, (void*)thread, name);
11703 +   vcos_assert(kthread != NULL);
11704 +   set_user_nice(kthread, attrs->ta_priority);
11705 +   thread->thread.thread = kthread;
11706 +   wake_up_process(kthread);
11707 +   return VCOS_SUCCESS;
11708 +}
11709 +
11710 +void vcos_thread_join(VCOS_THREAD_T *thread,
11711 +                             void **pData)
11712 +{
11713 +   vcos_assert(thread);
11714 +   vcos_assert(thread->magic == VCOS_THREAD_MAGIC);
11715 +
11716 +   thread->joined = 1;
11717 +
11718 +   vcos_semaphore_wait(&thread->wait);
11719 +
11720 +   if (pData)
11721 +   {
11722 +      *pData = thread->exit_data;
11723 +   }
11724 +
11725 +   /* Clean up */
11726 +   if (thread->stack)
11727 +      vcos_free(thread->stack);
11728 +
11729 +   vcos_semaphore_delete(&thread->wait);
11730 +   vcos_semaphore_delete(&thread->suspend);
11731 +
11732 +}
11733 +
11734 +uint32_t vcos_getmicrosecs( void )
11735 +{
11736 +   struct timeval tv;
11737 +/*XXX FIX ME! switch to ktime_get_ts to use MONOTONIC clock */
11738 +   do_gettimeofday(&tv);
11739 +   return (tv.tv_sec*1000000) + tv.tv_usec;
11740 +}
11741 +
11742 +VCOS_STATUS_T vcos_timer_init(void)
11743 +{
11744 +    return VCOS_SUCCESS;
11745 +}
11746 +
11747 +static const char *log_prefix[] =
11748 +{
11749 +   "",            /* VCOS_LOG_UNINITIALIZED */
11750 +   "",            /* VCOS_LOG_NEVER */
11751 +   KERN_ERR,      /* VCOS_LOG_ERROR */
11752 +   KERN_WARNING,  /* VCOS_LOG_WARN */
11753 +   KERN_INFO,     /* VCOS_LOG_INFO */
11754 +   KERN_INFO      /* VCOS_LOG_TRACE */
11755 +};
11756 +
11757 +void vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
11758 +{
11759 +   char *newline = strchr( fmt, '\n' );
11760 +   const char  *prefix;
11761 +   const char  *real_fmt;
11762 +
11763 +   preempt_disable();
11764 +   {
11765 +       if ( *fmt == '<' )
11766 +       {
11767 +           prefix = fmt;
11768 +           real_fmt= &fmt[3];
11769 +       }
11770 +       else
11771 +       {
11772 +          prefix = log_prefix[_level];
11773 +          real_fmt = fmt;
11774 +       }
11775 +#if defined( CONFIG_BCM_KNLLOG_SUPPORT )
11776 +       knllog_ventry( "vcos", real_fmt, args );
11777 +#endif
11778 +       printk( "%.3svcos: [%d]: ", prefix, current->pid );
11779 +       vprintk( real_fmt, args );
11780 +
11781 +       if ( newline == NULL )
11782 +       {
11783 +          printk("\n");
11784 +       }
11785 +   }
11786 +   preempt_enable();
11787 +}
11788 +
11789 +
11790 +const char * _vcos_log_level(void)
11791 +{
11792 +   return NULL;
11793 +}
11794 +
11795 +/*****************************************************************************
11796 +*
11797 +*    Displays the version information in /proc/vcos/version
11798 +*
11799 +*****************************************************************************/
11800 +
11801 +#ifdef HAVE_VCOS_VERSION
11802 +
11803 +static void show_version( VCOS_CFG_BUF_T buf, void *data )
11804 +{
11805 +   static const char* copyright = "Copyright (c) 2011 Broadcom";
11806 +
11807 +   vcos_cfg_buf_printf( buf, "Built %s %s on %s\n%s\nversion %s\n",
11808 +                        vcos_get_build_date(),
11809 +                        vcos_get_build_time(),
11810 +                        vcos_get_build_hostname(),
11811 +                        copyright,
11812 +                        vcos_get_build_version() );
11813 +}
11814 +
11815 +#endif
11816 +
11817 +/*****************************************************************************
11818 +*
11819 +*    Initialises vcos
11820 +*
11821 +*****************************************************************************/
11822 +
11823 +VCOS_STATUS_T vcos_init(void)
11824 +{
11825 +   if ( vcos_cfg_mkdir( &vcos_cfg_dir, NULL, "vcos" ) != VCOS_SUCCESS )
11826 +   {
11827 +      printk( KERN_ERR "%s: Unable to create vcos cfg entry\n", __func__ );
11828 +   }
11829 +   vcos_logging_init();
11830 +
11831 +#ifdef HAVE_VCOS_VERSION
11832 +   if ( vcos_cfg_create_entry( &vcos_version_cfg, &vcos_cfg_dir, "version",
11833 +                               show_version, NULL, NULL ) != VCOS_SUCCESS )
11834 +   {
11835 +      printk( KERN_ERR "%s: Unable to create vcos cfg entry 'version'\n", __func__ );
11836 +   }
11837 +#endif
11838 +
11839 +   return VCOS_SUCCESS;
11840 +}
11841 +
11842 +/*****************************************************************************
11843 +*
11844 +*    Deinitializes vcos
11845 +*
11846 +*****************************************************************************/
11847 +
11848 +void vcos_deinit(void)
11849 +{
11850 +#ifdef HAVE_VCOS_VERSION
11851 +   vcos_cfg_remove_entry( &vcos_version_cfg );
11852 +#endif
11853 +   vcos_cfg_remove_entry( &vcos_cfg_dir );
11854 +}
11855 +
11856 +void vcos_global_lock(void)
11857 +{
11858 +   down(&lock);
11859 +}
11860 +
11861 +void vcos_global_unlock(void)
11862 +{
11863 +   up(&lock);
11864 +}
11865 +
11866 +/* vcos_thread_exit() doesn't really stop this thread here
11867 + *
11868 + * At the moment, call to do_exit() will leak task_struct for
11869 + * current thread, so we let the vcos_thread_wrapper() do the
11870 + * cleanup and exit job, and we return w/o actually stopping the thread.
11871 + *
11872 + * ToDo: Kernel v2.6.31 onwards, it is considered safe to call do_exit()
11873 + * from kthread, the implementation of which is combined in 2 patches
11874 + * with commit-ids "63706172" and "cdd140bd" in oss Linux kernel tree
11875 + */
11876 +
11877 +void vcos_thread_exit(void *arg)
11878 +{
11879 +   VCOS_THREAD_T *thread = vcos_thread_current();
11880 +
11881 +   vcos_assert(thread);
11882 +   vcos_assert(thread->magic == VCOS_THREAD_MAGIC);
11883 +
11884 +   thread->exit_data = arg;
11885 +}
11886 +
11887 +void vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs)
11888 +{
11889 +   *attrs = default_attrs;
11890 +}
11891 +
11892 +void _vcos_task_timer_set(void (*pfn)(void *), void *cxt, VCOS_UNSIGNED ms)
11893 +{
11894 +   VCOS_THREAD_T *self = vcos_thread_current();
11895 +   vcos_assert(self);
11896 +   vcos_assert(self->_timer.pfn == NULL);
11897 +
11898 +   vcos_timer_create( &self->_timer.timer, "TaskTimer", pfn, cxt );
11899 +   vcos_timer_set(&self->_timer.timer, ms);
11900 +}
11901 +
11902 +void _vcos_task_timer_cancel(void)
11903 +{
11904 +   VCOS_THREAD_T *self = vcos_thread_current();
11905 +   if (self->_timer.timer.linux_timer.function)
11906 +   {
11907 +      vcos_timer_cancel(&self->_timer.timer);
11908 +      vcos_timer_delete(&self->_timer.timer);
11909 +   }
11910 +}
11911 +
11912 +int vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap )
11913 +{
11914 +   return vsnprintf( buf, buflen, fmt, ap );
11915 +}
11916 +
11917 +int vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...)
11918 +{
11919 +   int ret;
11920 +   va_list ap;
11921 +   va_start(ap,fmt);
11922 +   ret = vsnprintf(buf, buflen, fmt, ap);
11923 +   va_end(ap);
11924 +   return ret;
11925 +}
11926 +
11927 +int vcos_llthread_running(VCOS_LLTHREAD_T *t) {
11928 +   vcos_assert(0);   /* this function only exists as a nasty hack for the video codecs! */
11929 +   return 1;
11930 +}
11931 +
11932 +static int vcos_verify_bkpts = 1;
11933 +
11934 +int vcos_verify_bkpts_enabled(void)
11935 +{
11936 +   return vcos_verify_bkpts;
11937 +}
11938 +
11939 +/*****************************************************************************
11940 +*
11941 +*    _vcos_log_platform_init is called from vcos_logging_init
11942 +*
11943 +*****************************************************************************/
11944 +
11945 +void _vcos_log_platform_init(void)
11946 +{
11947 +   if ( vcos_cfg_mkdir( &vcos_logging_cfg_dir, &vcos_cfg_dir, "logging" ) != VCOS_SUCCESS )
11948 +   {
11949 +      printk( KERN_ERR "%s: Unable to create logging cfg entry\n", __func__ );
11950 +   }
11951 +}
11952 +
11953 +/*****************************************************************************
11954 +*
11955 +*    Called to display the contents of a logging category.
11956 +*
11957 +*****************************************************************************/
11958 +
11959 +static void logging_show_category( VCOS_CFG_BUF_T buf, void *data )
11960 +{
11961 +   VCOS_LOG_CAT_T *category = data;
11962 +
11963 +   vcos_cfg_buf_printf( buf, "%s\n", vcos_log_level_to_string( category->level ));
11964 +}
11965 +
11966 +/*****************************************************************************
11967 +*
11968 +*    Called to parse content for a logging category.
11969 +*
11970 +*****************************************************************************/
11971 +
11972 +static void logging_parse_category( VCOS_CFG_BUF_T buf, void *data )
11973 +{
11974 +   VCOS_LOG_CAT_T *category = data;
11975 +   const char *str = vcos_cfg_buf_get_str( buf );
11976 +   VCOS_LOG_LEVEL_T  level;
11977 +
11978 +   if ( vcos_string_to_log_level( str, &level ) == VCOS_SUCCESS )
11979 +   {
11980 +      category->level = level;
11981 +   }
11982 +   else
11983 +   {
11984 +      printk( KERN_ERR "%s: Unrecognized logging level: '%s'\n",
11985 +              __func__, str );
11986 +   }
11987 +}
11988 +
11989 +/*****************************************************************************
11990 +*
11991 +*    _vcos_log_platform_register is called from vcos_log_register whenever
11992 +*    a new category is registered.
11993 +*
11994 +*****************************************************************************/
11995 +
11996 +void _vcos_log_platform_register(VCOS_LOG_CAT_T *category)
11997 +{
11998 +   VCOS_CFG_ENTRY_T  entry;
11999 +
12000 +   if ( vcos_cfg_create_entry( &entry, &vcos_logging_cfg_dir, category->name,
12001 +                               logging_show_category, logging_parse_category,
12002 +                               category ) != VCOS_SUCCESS )
12003 +   {
12004 +      printk( KERN_ERR "%s: Unable to create cfg entry for logging category '%s'\n",
12005 +              __func__, category->name );
12006 +      category->platform_data = NULL;
12007 +   }
12008 +   else
12009 +   {
12010 +      category->platform_data = entry;
12011 +   }
12012 +}
12013 +
12014 +/*****************************************************************************
12015 +*
12016 +*    _vcos_log_platform_unregister is called from vcos_log_unregister whenever
12017 +*    a new category is unregistered.
12018 +*
12019 +*****************************************************************************/
12020 +
12021 +void _vcos_log_platform_unregister(VCOS_LOG_CAT_T *category)
12022 +{
12023 +   VCOS_CFG_ENTRY_T  entry;
12024 +
12025 +   entry = category->platform_data;
12026 +   if ( entry != NULL )
12027 +   {
12028 +      if ( vcos_cfg_remove_entry( &entry ) != VCOS_SUCCESS )
12029 +      {
12030 +         printk( KERN_ERR "%s: Unable to remove cfg entry for logging category '%s'\n",
12031 +                 __func__, category->name );
12032 +      }
12033 +   }
12034 +}
12035 +
12036 +/*****************************************************************************
12037 +*
12038 +*    Allocate memory.
12039 +*
12040 +*****************************************************************************/
12041 +
12042 +void *vcos_platform_malloc( VCOS_UNSIGNED required_size )
12043 +{
12044 +   if ( required_size >= ( 2 * PAGE_SIZE ))
12045 +   {
12046 +      /* For larger allocations, use vmalloc, whose underlying allocator
12047 +       * returns pages
12048 +       */
12049 +
12050 +      return vmalloc( required_size );
12051 +   }
12052 +
12053 +   /* For smaller allocation, use kmalloc */
12054 +
12055 +   return kmalloc( required_size, GFP_KERNEL );
12056 +}
12057 +
12058 +/*****************************************************************************
12059 +*
12060 +*    Free previously allocated memory
12061 +*
12062 +*****************************************************************************/
12063 +
12064 +void  vcos_platform_free( void *ptr )
12065 +{
12066 +   if (((unsigned long)ptr >= VMALLOC_START )
12067 +   &&  ((unsigned long)ptr < VMALLOC_END ))
12068 +   {
12069 +      vfree( ptr );
12070 +   }
12071 +   else
12072 +   {
12073 +      kfree( ptr );
12074 +   }
12075 +}
12076 +
12077 +/*****************************************************************************
12078 +*
12079 +*    Execute a routine exactly once.
12080 +*
12081 +*****************************************************************************/
12082 +
12083 +VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
12084 +                        void (*init_routine)(void))
12085 +{
12086 +   /* In order to be thread-safe we need to re-test *once_control
12087 +    * inside the lock. The outer test is basically an optimization
12088 +    * so that once it is initialized we don't need to waste time
12089 +    * trying to acquire the lock.
12090 +    */
12091 +
12092 +   if ( *once_control == 0 )
12093 +   {
12094 +       vcos_global_lock();
12095 +       if ( *once_control == 0 )
12096 +       {
12097 +           init_routine();
12098 +           *once_control = 1;
12099 +       }
12100 +       vcos_global_unlock();
12101 +   }
12102 +
12103 +   return VCOS_SUCCESS;
12104 +}
12105 +
12106 +/*****************************************************************************
12107 +*
12108 +*    String duplication routine.
12109 +*
12110 +*****************************************************************************/
12111 +
12112 +char *vcos_strdup(const char *str)
12113 +{
12114 +    return kstrdup(str, GFP_KERNEL);
12115 +}
12116 +
12117 +
12118 +/* Export functions for modules to use */
12119 +EXPORT_SYMBOL( vcos_init );
12120 +
12121 +EXPORT_SYMBOL( vcos_semaphore_trywait );
12122 +EXPORT_SYMBOL( vcos_semaphore_post );
12123 +EXPORT_SYMBOL( vcos_semaphore_create );
12124 +EXPORT_SYMBOL( vcos_semaphore_wait );
12125 +EXPORT_SYMBOL( vcos_semaphore_delete );
12126 +
12127 +EXPORT_SYMBOL( vcos_log_impl );
12128 +EXPORT_SYMBOL( vcos_vlog_impl );
12129 +EXPORT_SYMBOL( vcos_vlog_default_impl );
12130 +EXPORT_SYMBOL( vcos_log_get_default_category );
12131 +EXPORT_SYMBOL( vcos_log_register );
12132 +EXPORT_SYMBOL( vcos_log_unregister );
12133 +EXPORT_SYMBOL( vcos_logging_init );
12134 +EXPORT_SYMBOL( vcos_log_level_to_string );
12135 +EXPORT_SYMBOL( vcos_string_to_log_level );
12136 +EXPORT_SYMBOL( vcos_log_dump_mem_impl );
12137 +
12138 +EXPORT_SYMBOL( vcos_event_create );
12139 +EXPORT_SYMBOL( vcos_event_delete );
12140 +EXPORT_SYMBOL( vcos_event_flags_set );
12141 +EXPORT_SYMBOL( vcos_event_signal );
12142 +EXPORT_SYMBOL( vcos_event_wait );
12143 +EXPORT_SYMBOL( vcos_event_try );
12144 +
12145 +EXPORT_SYMBOL( vcos_getmicrosecs );
12146 +
12147 +EXPORT_SYMBOL( vcos_strcasecmp );
12148 +EXPORT_SYMBOL( vcos_snprintf );
12149 +EXPORT_SYMBOL( vcos_vsnprintf );
12150 +
12151 +EXPORT_SYMBOL( vcos_thread_current );
12152 +EXPORT_SYMBOL( vcos_thread_join );
12153 +EXPORT_SYMBOL( vcos_thread_create );
12154 +EXPORT_SYMBOL( vcos_thread_set_priority );
12155 +EXPORT_SYMBOL( vcos_thread_exit );
12156 +EXPORT_SYMBOL( vcos_once );
12157 +
12158 +EXPORT_SYMBOL( vcos_thread_attr_init );
12159 +EXPORT_SYMBOL( vcos_thread_attr_setpriority );
12160 +EXPORT_SYMBOL( vcos_thread_attr_settimeslice );
12161 +EXPORT_SYMBOL( vcos_thread_attr_setstacksize );
12162 +EXPORT_SYMBOL( _vcos_thread_attr_setlegacyapi );
12163 +
12164 +EXPORT_SYMBOL( vcos_event_flags_create );
12165 +EXPORT_SYMBOL( vcos_event_flags_delete );
12166 +EXPORT_SYMBOL( vcos_event_flags_get );
12167 +
12168 +EXPORT_SYMBOL( vcos_sleep );
12169 +
12170 +EXPORT_SYMBOL( vcos_calloc );
12171 +EXPORT_SYMBOL( vcos_malloc );
12172 +EXPORT_SYMBOL( vcos_malloc_aligned );
12173 +EXPORT_SYMBOL( vcos_free );
12174 +
12175 +EXPORT_SYMBOL( vcos_mutex_create );
12176 +EXPORT_SYMBOL( vcos_mutex_delete );
12177 +EXPORT_SYMBOL( vcos_mutex_lock );
12178 +EXPORT_SYMBOL( vcos_mutex_unlock );
12179 +EXPORT_SYMBOL( vcos_mutex_trylock );
12180 +
12181 +EXPORT_SYMBOL( vcos_timer_cancel );
12182 +EXPORT_SYMBOL( vcos_timer_create );
12183 +EXPORT_SYMBOL( vcos_timer_delete );
12184 +EXPORT_SYMBOL( vcos_timer_set );
12185 +
12186 +EXPORT_SYMBOL( vcos_atomic_flags_create );
12187 +EXPORT_SYMBOL( vcos_atomic_flags_delete );
12188 +EXPORT_SYMBOL( vcos_atomic_flags_or );
12189 +EXPORT_SYMBOL( vcos_atomic_flags_get_and_clear );
12190 +
12191 +EXPORT_SYMBOL( vcos_verify_bkpts_enabled );
12192 +
12193 +EXPORT_SYMBOL( vcos_strdup );
12194 --- /dev/null
12195 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_cfg.c
12196 @@ -0,0 +1,332 @@
12197 +/*****************************************************************************
12198 +* Copyright 2009 - 2010 Broadcom Corporation.  All rights reserved.
12199 +*
12200 +* Unless you and Broadcom execute a separate written software license
12201 +* agreement governing use of this software, this software is licensed to you
12202 +* under the terms of the GNU General Public License version 2, available at
12203 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
12204 +*
12205 +* Notwithstanding the above, under no circumstances may you combine this
12206 +* software in any way with any other Broadcom software provided under a
12207 +* license other than the GPL, without Broadcom's express prior written
12208 +* consent.
12209 +*****************************************************************************/
12210 +
12211 +#include "interface/vcos/vcos.h"
12212 +#include <linux/module.h>
12213 +#include <linux/proc_fs.h>
12214 +#include <linux/seq_file.h>
12215 +#include <asm/uaccess.h>
12216 +
12217 +struct opaque_vcos_cfg_buf_t
12218 +{
12219 +    struct seq_file *seq;
12220 +    char            *charBuf;
12221 +};
12222 +
12223 +struct opaque_vcos_cfg_entry_t
12224 +{
12225 +    struct proc_dir_entry *pde;
12226 +    struct proc_dir_entry *parent_pde;
12227 +    VCOS_CFG_SHOW_FPTR     showFunc;
12228 +    VCOS_CFG_PARSE_FPTR    parseFunc;
12229 +    void                  *data;
12230 +    const char            *name;
12231 +};
12232 +
12233 +/***************************************************************************** 
12234 +* 
12235 +*    cfg_proc_show
12236 +*  
12237 +*****************************************************************************/
12238 +
12239 +static int cfg_proc_show( struct seq_file *s, void *v )
12240 +{
12241 +    VCOS_CFG_ENTRY_T                entry;
12242 +    struct opaque_vcos_cfg_buf_t    buf;
12243 +
12244 +    entry = s->private;
12245 +
12246 +    if ( entry->showFunc )
12247 +    {
12248 +        memset( &buf, 0, sizeof( buf ));
12249 +        buf.seq = s;
12250 +
12251 +        entry->showFunc( &buf, entry->data );
12252 +    }
12253 +
12254 +    return 0;
12255 +}
12256 +
12257 +/***************************************************************************** 
12258 +* 
12259 +*    cfg_proc_write
12260 +*  
12261 +*****************************************************************************/
12262 +
12263 +static ssize_t cfg_proc_write( struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
12264 +{
12265 +    VCOS_CFG_ENTRY_T                entry = PDE(file->f_path.dentry->d_inode)->data;
12266 +    char                           *charBuf;
12267 +    struct opaque_vcos_cfg_buf_t    buf;
12268 +    size_t                          len;
12269 +
12270 +    if ( entry->parseFunc != NULL )
12271 +    {
12272 +        /* The number 4000 is rather arbitrary. It just needs to be bigger than any input
12273 +         * string we expect to use.
12274 +         */
12275 +
12276 +        len = count;
12277 +        if ( count > 4000 )
12278 +        {
12279 +            len = 4000;
12280 +        }
12281 +
12282 +        /* Allocate a kernel buffer to contain the string being written. */
12283 +
12284 +        charBuf = kmalloc( len + 1, GFP_KERNEL );
12285 +        if ( copy_from_user( charBuf, buffer, len ))
12286 +        {
12287 +            kfree( charBuf );
12288 +            return -EFAULT;
12289 +        }
12290 +
12291 +        /* echo puts a trailing newline in the buffer - strip it out. */
12292 +
12293 +        if (( len > 0 ) && ( charBuf[ len - 1 ] == '\n' ))
12294 +        {
12295 +            len--;
12296 +        }
12297 +        charBuf[len] = '\0';
12298 +
12299 +        memset( &buf, 0, sizeof( buf ));
12300 +        buf.charBuf = charBuf;
12301 +
12302 +        entry->parseFunc( &buf, entry->data );
12303 +        kfree( charBuf );
12304 +    }
12305 +    return count;
12306 +}
12307 +
12308 +/***************************************************************************** 
12309 +* 
12310 +*    cfg_proc_open
12311 +*  
12312 +*****************************************************************************/
12313 +
12314 +static int cfg_proc_open( struct inode *inode, struct file *file )
12315 +{
12316 +    return single_open( file, cfg_proc_show, PDE(inode)->data );
12317 +}
12318 +
12319 +static const struct file_operations cfg_proc_fops = 
12320 +{
12321 +    .open       = cfg_proc_open,
12322 +    .read       = seq_read,
12323 +    .llseek     = seq_lseek,
12324 +    .release    = single_release,
12325 +    .write      = cfg_proc_write,
12326 +};
12327 +
12328 +/***************************************************************************** 
12329 +* 
12330 +*    vcos_cfg_mkdir
12331 +*  
12332 +*****************************************************************************/
12333 +
12334 +VCOS_STATUS_T vcos_cfg_mkdir( VCOS_CFG_ENTRY_T *entryp,
12335 +                              VCOS_CFG_ENTRY_T *parent,
12336 +                              const char *dirName )
12337 +{
12338 +    VCOS_CFG_ENTRY_T    entry;
12339 +
12340 +    if (( entry = kzalloc( sizeof( *entry ), GFP_KERNEL )) == NULL )
12341 +    {
12342 +        return VCOS_ENOMEM;
12343 +    }
12344 +
12345 +    if ( parent == NULL )
12346 +    {
12347 +        entry->pde = proc_mkdir( dirName, NULL );
12348 +    }
12349 +    else
12350 +    {
12351 +        entry->pde = proc_mkdir( dirName, (*parent)->pde );
12352 +        entry->parent_pde = (*parent)->pde;
12353 +    }
12354 +    if ( entry->pde == NULL )
12355 +    {
12356 +        kfree( entry );
12357 +        return VCOS_ENOMEM;
12358 +    }
12359 +
12360 +    entry->name = dirName;
12361 +
12362 +    *entryp = entry;
12363 +    return VCOS_SUCCESS;
12364 +}
12365 +
12366 +/***************************************************************************** 
12367 +* 
12368 +*    vcos_cfg_create_entry
12369 +*  
12370 +*****************************************************************************/
12371 +
12372 +VCOS_STATUS_T vcos_cfg_create_entry( VCOS_CFG_ENTRY_T *entryp,
12373 +                                     VCOS_CFG_ENTRY_T *parent,
12374 +                                     const char *entryName,
12375 +                                     VCOS_CFG_SHOW_FPTR showFunc,
12376 +                                     VCOS_CFG_PARSE_FPTR parseFunc,
12377 +                                     void *data )
12378 +{
12379 +    VCOS_CFG_ENTRY_T    entry;
12380 +    mode_t              mode;
12381 +
12382 +    *entryp = NULL;
12383 +
12384 +    if (( entry = kzalloc( sizeof( *entry ), GFP_KERNEL )) == NULL )
12385 +    {
12386 +        return VCOS_ENOMEM;
12387 +    }
12388 +
12389 +    mode = 0;
12390 +    if ( showFunc != NULL )
12391 +    {
12392 +        mode |= 0444;
12393 +    }
12394 +    if ( parseFunc != NULL )
12395 +    {
12396 +        mode |= 0200;
12397 +    }
12398 +    
12399 +    if ( parent == NULL )
12400 +    {
12401 +        entry->pde = create_proc_entry( entryName, mode, NULL );
12402 +    }
12403 +    else
12404 +    {
12405 +        entry->pde = create_proc_entry( entryName, mode, (*parent)->pde );
12406 +        entry->parent_pde = (*parent)->pde;
12407 +    }
12408 +    if ( entry->pde == NULL )
12409 +    {
12410 +        kfree( entry );
12411 +        return -ENOMEM;
12412 +    }
12413 +    entry->showFunc = showFunc;
12414 +    entry->parseFunc = parseFunc;
12415 +    entry->data = data;
12416 +    entry->name = entryName;
12417 +
12418 +    entry->pde->data = entry;
12419 +    entry->pde->proc_fops = &cfg_proc_fops;
12420 +    
12421 +    *entryp = entry;
12422 +    return VCOS_SUCCESS;    
12423 +}
12424 +
12425 +/***************************************************************************** 
12426 +* 
12427 +*    vcos_cfg_remove_entry
12428 +*  
12429 +*****************************************************************************/
12430 +
12431 +VCOS_STATUS_T vcos_cfg_remove_entry( VCOS_CFG_ENTRY_T *entryp )
12432 +{
12433 +    if (( entryp != NULL ) && ( *entryp != NULL ))
12434 +    {
12435 +        remove_proc_entry( (*entryp)->name, (*entryp)->parent_pde );
12436 +
12437 +        kfree( *entryp );
12438 +        *entryp = NULL;
12439 +    }
12440 +
12441 +    return VCOS_SUCCESS;
12442 +}
12443 +
12444 +/***************************************************************************** 
12445 +* 
12446 +*    vcos_cfg_is_entry_created
12447 +*  
12448 +*****************************************************************************/
12449 +
12450 +int vcos_cfg_is_entry_created( VCOS_CFG_ENTRY_T entry )
12451 +{
12452 +    return ( entry != NULL ) && ( entry->pde != NULL );
12453 +}
12454 +
12455 +/***************************************************************************** 
12456 +* 
12457 +*    vcos_cfg_buf_printf
12458 +*  
12459 +*****************************************************************************/
12460 +
12461 +void vcos_cfg_buf_printf( VCOS_CFG_BUF_T buf, const char *fmt, ... )
12462 +{
12463 +    struct seq_file *m = buf->seq;
12464 +
12465 +    /* Bah - there is no seq_vprintf */
12466 +
12467 +    va_list args;
12468 +    int len;
12469 +
12470 +    if (m->count < m->size) {
12471 +        va_start(args, fmt);
12472 +        len = vsnprintf(m->buf + m->count, m->size - m->count, fmt, args);
12473 +        va_end(args);
12474 +        if (m->count + len < m->size) {
12475 +            m->count += len;
12476 +            return;
12477 +        }
12478 +    }
12479 +    m->count = m->size;
12480 +}
12481 +
12482 +/***************************************************************************** 
12483 +* 
12484 +*    vcos_cfg_buf_get_str
12485 +*  
12486 +*****************************************************************************/
12487 +
12488 +char *vcos_cfg_buf_get_str( VCOS_CFG_BUF_T buf )
12489 +{
12490 +    return buf->charBuf;
12491 +}
12492 +
12493 +/***************************************************************************** 
12494 +* 
12495 +*    vcos_cfg_get_proc_entry
12496 +*  
12497 +*    This function is only created for a couple of backwards compatibility '
12498 +*    issues and shouldn't normally be used.
12499 +*  
12500 +*****************************************************************************/
12501 +
12502 +void *vcos_cfg_get_proc_entry( VCOS_CFG_ENTRY_T entry )
12503 +{
12504 +    return entry->pde;
12505 +}
12506 +
12507 +/***************************************************************************** 
12508 +* 
12509 +*    vcos_cfg_get_entry_name
12510 +*  
12511 +*****************************************************************************/
12512 +
12513 +const char *vcos_cfg_get_entry_name( VCOS_CFG_ENTRY_T entry )
12514 +{
12515 +   return entry->pde->name;
12516 +}
12517 +
12518 +
12519 +EXPORT_SYMBOL( vcos_cfg_mkdir );
12520 +EXPORT_SYMBOL( vcos_cfg_create_entry );
12521 +EXPORT_SYMBOL( vcos_cfg_remove_entry );
12522 +EXPORT_SYMBOL( vcos_cfg_get_entry_name );
12523 +EXPORT_SYMBOL( vcos_cfg_is_entry_created );
12524 +EXPORT_SYMBOL( vcos_cfg_buf_printf );
12525 +EXPORT_SYMBOL( vcos_cfg_buf_get_str );
12526 +
12527 +EXPORT_SYMBOL_GPL( vcos_cfg_get_proc_entry );
12528 +
12529 --- /dev/null
12530 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_misc.c
12531 @@ -0,0 +1,113 @@
12532 +// #############################################################################
12533 +// START #######################################################################
12534 +/*****************************************************************************
12535 +* Copyright 2009 - 2010 Broadcom Corporation.  All rights reserved.
12536 +*
12537 +* Unless you and Broadcom execute a separate written software license
12538 +* agreement governing use of this software, this software is licensed to you
12539 +* under the terms of the GNU General Public License version 2, available at
12540 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
12541 +*
12542 +* Notwithstanding the above, under no circumstances may you combine this
12543 +* software in any way with any other Broadcom software provided under a
12544 +* license other than the GPL, without Broadcom's express prior written
12545 +* consent.
12546 +*****************************************************************************/
12547 +
12548 +#include "interface/vcos/vcos.h"
12549 +#include <linux/sched.h>
12550 +#include <linux/module.h>
12551 +#include <linux/freezer.h>
12552 +#include <linux/string.h>
12553 +#include <linux/slab.h>
12554 +
12555 +/***************************************************************************** 
12556 +* 
12557 +*        vcos_semaphore_wait_freezable
12558 +*  
12559 +*****************************************************************************/
12560 +
12561 +VCOS_STATUS_T vcos_semaphore_wait_freezable(VCOS_SEMAPHORE_T *sem)
12562 +{
12563 +    int rval, sig_pended = 0;
12564 +    unsigned long flags;
12565 +    struct task_struct *task = current;
12566 +
12567 +    while (1) {
12568 +       rval = down_interruptible((struct semaphore *)sem);
12569 +       if (rval == 0) { /* down now */
12570 +          break;
12571 +       } else {
12572 +          if (freezing(current)) {
12573 +             try_to_freeze();
12574 +          } else {
12575 +             spin_lock_irqsave(&task->sighand->siglock, flags);
12576 +             if (test_tsk_thread_flag(task, TIF_SIGPENDING)) {
12577 +                clear_tsk_thread_flag(task, TIF_SIGPENDING);
12578 +                sig_pended = 1;
12579 +             }
12580 +             spin_unlock_irqrestore(&task->sighand->siglock, flags);
12581 +          }
12582 +       }
12583 +    }
12584 +
12585 +    if (sig_pended) {
12586 +       spin_lock_irqsave(&task->sighand->siglock, flags);
12587 +       set_tsk_thread_flag(task, TIF_SIGPENDING);
12588 +       spin_unlock_irqrestore(&task->sighand->siglock, flags);
12589 +    }
12590 +
12591 +    return 0;
12592 +}
12593 +
12594 +EXPORT_SYMBOL( vcos_semaphore_wait_freezable );
12595 +
12596 +/***************************************************************************** 
12597 +* 
12598 +*  vcos_kmalloc
12599 +*  
12600 +*  We really need to convert malloc to do kmalloc or vmalloc based on the
12601 +*  size, but for now we'll add a separate function.
12602 +*  
12603 +*****************************************************************************/
12604 +
12605 +void *vcos_kmalloc(VCOS_UNSIGNED size, const char *description)
12606 +{
12607 +   (void)description;
12608 +
12609 +   return kmalloc( size, GFP_KERNEL );
12610 +}
12611 +
12612 +/***************************************************************************** 
12613 +* 
12614 +*  vcos_kmalloc
12615 +*  
12616 +*  We really need to convert malloc to do kmalloc or vmalloc based on the
12617 +*  size, but for now we'll add a separate function.
12618 +*  
12619 +*****************************************************************************/
12620 +
12621 +void *vcos_kcalloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description)
12622 +{
12623 +   (void)description;
12624 +
12625 +   return kzalloc( num * size, GFP_KERNEL );
12626 +}
12627 +
12628 +/***************************************************************************** 
12629 +* 
12630 +*  vcos_kfree
12631 +*  
12632 +*****************************************************************************/
12633 +
12634 +void vcos_kfree(void *ptr)
12635 +{
12636 +   kfree( ptr );
12637 +}
12638 +
12639 +EXPORT_SYMBOL( vcos_kmalloc );
12640 +EXPORT_SYMBOL( vcos_kcalloc );
12641 +EXPORT_SYMBOL( vcos_kfree );
12642 +
12643 +// END #########################################################################
12644 +// #############################################################################
12645 --- /dev/null
12646 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_mod_init.c
12647 @@ -0,0 +1,64 @@
12648 +/*****************************************************************************
12649 +* Copyright 2006 - 2008 Broadcom Corporation.  All rights reserved.
12650 +*
12651 +* Unless you and Broadcom execute a separate written software license
12652 +* agreement governing use of this software, this software is licensed to you
12653 +* under the terms of the GNU General Public License version 2, available at
12654 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). 
12655 +*
12656 +* Notwithstanding the above, under no circumstances may you combine this
12657 +* software in any way with any other Broadcom software provided under a
12658 +* license other than the GPL, without Broadcom's express prior written
12659 +* consent.
12660 +****************************************************************************/
12661 +
12662 +/* ---- Include Files ---------------------------------------------------- */
12663 +
12664 +#include "interface/vcos/vcos.h"
12665 +#include <linux/module.h>
12666 +
12667 +/* ---- Public Variables ------------------------------------------------- */
12668 +
12669 +/* ---- Private Constants and Types -------------------------------------- */
12670 +
12671 +/* ---- Private Variables ------------------------------------------------ */
12672 +
12673 +/* ---- Private Function Prototypes -------------------------------------- */
12674 +
12675 +/* ---- Functions -------------------------------------------------------- */
12676 +
12677 +/****************************************************************************
12678 +*
12679 +*   Called to perform module initialization when the module is loaded
12680 +*
12681 +***************************************************************************/
12682 +
12683 +static int __init vcos_mod_init( void )
12684 +{
12685 +    printk( KERN_INFO "VCOS Module\n" );
12686 +
12687 +    vcos_init();
12688 +    return 0;
12689 +}
12690 +
12691 +/****************************************************************************
12692 +*
12693 +*   Called to perform module cleanup when the module is unloaded.
12694 +*
12695 +***************************************************************************/
12696 +
12697 +static void __exit vcos_mod_exit( void )
12698 +{
12699 +    vcos_deinit();
12700 +}
12701 +
12702 +/****************************************************************************/
12703 +
12704 +module_init( vcos_mod_init );
12705 +module_exit( vcos_mod_exit );
12706 +
12707 +MODULE_AUTHOR("Broadcom");
12708 +MODULE_DESCRIPTION( "VCOS Module Functions" );
12709 +MODULE_LICENSE( "GPL" );
12710 +MODULE_VERSION( "1.0" );
12711 +
12712 --- /dev/null
12713 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform.h
12714 @@ -0,0 +1,496 @@
12715 +/*=============================================================================
12716 +Copyright (c) 2009 Broadcom Europe Limited.
12717 +All rights reserved.
12718 +
12719 +Project  :  vcfw
12720 +Module   :  vcos
12721 +
12722 +FILE DESCRIPTION
12723 +VideoCore OS Abstraction Layer - Linux kernel (partial) implementation.
12724 +=============================================================================*/
12725 +
12726 +/* Do not include this file directly - instead include it via vcos.h */
12727 +
12728 +/** @file
12729 +  *
12730 +  * Linux kernel (partial) implementation of VCOS.
12731 +  *
12732 +  */
12733 +
12734 +#ifndef VCOS_PLATFORM_H
12735 +#define VCOS_PLATFORM_H
12736 +
12737 +#include <linux/types.h>
12738 +#include <linux/semaphore.h>
12739 +#include <linux/mutex.h>
12740 +#include <asm/bitops.h>
12741 +#include <linux/kthread.h>
12742 +#include <linux/wait.h>
12743 +#include <linux/vmalloc.h>
12744 +#include <linux/jiffies.h>
12745 +#include <linux/delay.h>
12746 +#include <linux/string.h>
12747 +#include <linux/types.h>
12748 +#include <linux/interrupt.h>
12749 +#include <linux/random.h>
12750 +#include <linux/sched.h>
12751 +#include <linux/ctype.h>
12752 +#include <linux/uaccess.h>
12753 +#include <linux/time.h>  /* for time_t */
12754 +#include <linux/slab.h>
12755 +#include <linux/vmalloc.h>
12756 +
12757 +#define VCOS_HAVE_RTOS         1
12758 +#define VCOS_HAVE_SEMAPHORE    1
12759 +#define VCOS_HAVE_EVENT        1
12760 +#define VCOS_HAVE_QUEUE        0
12761 +#define VCOS_HAVE_LEGACY_ISR   0
12762 +#define VCOS_HAVE_TIMER        1
12763 +#define VCOS_HAVE_CANCELLATION_SAFE_TIMER 0
12764 +#define VCOS_HAVE_MEMPOOL      0
12765 +#define VCOS_HAVE_ISR          0
12766 +#define VCOS_HAVE_ATOMIC_FLAGS 1
12767 +#define VCOS_HAVE_BLOCK_POOL   0
12768 +#define VCOS_HAVE_ONCE         1
12769 +#define VCOS_HAVE_FILE         0
12770 +#define VCOS_HAVE_USER_BUF     0
12771 +#define VCOS_HAVE_CFG          1
12772 +#define VCOS_HAVE_SPINLOCK     0
12773 +#define VCOS_HAVE_CMD          1
12774 +#define VCOS_HAVE_EVENT_FLAGS  1
12775 +
12776 +/* Exclude many VCOS classes which don't have predicates */
12777 +#define VCOS_TLS_H
12778 +#define VCOS_NAMED_MUTEX_H
12779 +#define VCOS_REENTRANT_MUTEX_H
12780 +#define VCOS_NAMED_SEMAPHORE_H
12781 +#define VCOS_QUICKSLOW_MUTEX_H
12782 +/*#define VCOS_INIT_H */
12783 +/*#define VCOS_MEM_H */
12784 +/*#define VCOS_STRING_H */
12785 +
12786 +typedef struct semaphore      VCOS_SEMAPHORE_T;
12787 +typedef struct semaphore      VCOS_EVENT_T;
12788 +typedef struct mutex          VCOS_MUTEX_T;
12789 +typedef volatile int          VCOS_ONCE_T;
12790 +
12791 +typedef unsigned int          VCOS_UNSIGNED;
12792 +typedef unsigned int          VCOS_OPTION;
12793 +typedef atomic_t              VCOS_ATOMIC_FLAGS_T;
12794 +
12795 +typedef struct
12796 +{
12797 +    struct  timer_list      linux_timer;
12798 +    void                   *context;
12799 +    void                  (*expiration_routine)(void *context);
12800 +
12801 +} VCOS_TIMER_T;
12802 +
12803 +typedef struct VCOS_LLTHREAD_T
12804 +{
12805 +   struct task_struct *thread;             /**< The thread itself */
12806 +   VCOS_SEMAPHORE_T suspend;     /**< For support event groups and similar - a per thread semaphore */
12807 +} VCOS_LLTHREAD_T;
12808 +
12809 +typedef enum
12810 +{
12811 +    VCOS_O_RDONLY   = 00000000,
12812 +    VCOS_O_WRONLY   = 00000001,
12813 +    VCOS_O_RDWR     = 00000002,
12814 +    VCOS_O_TRUNC    = 00001000,
12815 +} VCOS_FILE_FLAGS_T;
12816 +
12817 +typedef struct file *VCOS_FILE_T;
12818 +
12819 +#define VCOS_SUSPEND          -1
12820 +#define VCOS_NO_SUSPEND       0
12821 +
12822 +#define VCOS_START 1
12823 +#define VCOS_NO_START 0
12824 +
12825 +#define VCOS_THREAD_PRI_MIN   -20
12826 +#define VCOS_THREAD_PRI_MAX   19
12827 +
12828 +#define VCOS_THREAD_PRI_INCREASE -1
12829 +#define VCOS_THREAD_PRI_HIGHEST  VCOS_THREAD_PRI_MIN
12830 +#define VCOS_THREAD_PRI_LOWEST   VCOS_THREAD_PRI_MAX
12831 +#define VCOS_THREAD_PRI_NORMAL ((VCOS_THREAD_PRI_MAX+VCOS_THREAD_PRI_MIN)/2)
12832 +#define VCOS_THREAD_PRI_ABOVE_NORMAL (VCOS_THREAD_PRI_NORMAL + VCOS_THREAD_PRI_INCREASE)
12833 +#define VCOS_THREAD_PRI_REALTIME VCOS_THREAD_PRI_HIGHEST
12834 +
12835 +#define _VCOS_AFFINITY_DEFAULT 0
12836 +#define _VCOS_AFFINITY_CPU0 0
12837 +#define _VCOS_AFFINITY_CPU1 0
12838 +#define _VCOS_AFFINITY_MASK 0
12839 +#define VCOS_CAN_SET_STACK_ADDR  0
12840 +
12841 +#define VCOS_TICKS_PER_SECOND HZ
12842 +
12843 +#include "interface/vcos/generic/vcos_generic_event_flags.h"
12844 +#include "interface/vcos/generic/vcos_mem_from_malloc.h"
12845 +#include "interface/vcos/generic/vcos_joinable_thread_from_plain.h"
12846 +
12847 +/***********************************************************
12848 + *
12849 + * Memory allcoation
12850 + *
12851 + ***********************************************************/
12852 +
12853 +#define  _vcos_platform_malloc   vcos_platform_malloc
12854 +#define  _vcos_platform_free     vcos_platform_free
12855 +
12856 +void *vcos_platform_malloc( VCOS_UNSIGNED required_size );
12857 +void  vcos_platform_free( void *ptr );
12858 +
12859 +#if defined(VCOS_INLINE_BODIES)
12860 +
12861 +#undef VCOS_ASSERT_LOGGING_DISABLE
12862 +#define VCOS_ASSERT_LOGGING_DISABLE 1
12863 +
12864 +/***********************************************************
12865 + *
12866 + * Counted Semaphores
12867 + *
12868 + ***********************************************************/
12869 +
12870 +VCOS_INLINE_IMPL
12871 +VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem) {
12872 +   int ret = down_interruptible(sem);
12873 +   if ( ret == 0 )
12874 +      /* Success */
12875 +      return VCOS_SUCCESS;
12876 +   else if ( ret == -EINTR )
12877 +      /* Interrupted */
12878 +      return VCOS_EINTR;
12879 +   else
12880 +      /* Default (timeout) */
12881 +      return VCOS_EAGAIN;
12882 +}
12883 +
12884 +VCOS_INLINE_IMPL
12885 +VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem) {
12886 +   if (down_trylock(sem) != 0)
12887 +      return VCOS_EAGAIN;
12888 +   return VCOS_SUCCESS;
12889 +}
12890 +
12891 +VCOS_INLINE_IMPL
12892 +VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem,
12893 +                                    const char *name,
12894 +                                    VCOS_UNSIGNED initial_count) {
12895 +   sema_init(sem, initial_count);
12896 +   return VCOS_SUCCESS;
12897 +}
12898 +
12899 +VCOS_INLINE_IMPL
12900 +void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem) {
12901 +}
12902 +
12903 +VCOS_INLINE_IMPL
12904 +VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem) {
12905 +   up(sem);
12906 +   return VCOS_SUCCESS;
12907 +}
12908 +
12909 +/***********************************************************
12910 + *
12911 + * Threads
12912 + *
12913 + ***********************************************************/
12914 +
12915 +#include "vcos_thread_map.h"
12916 +
12917 +VCOS_INLINE_IMPL
12918 +VCOS_LLTHREAD_T *vcos_llthread_current(void) {
12919 +        return &vcos_kthread_current()->thread;
12920 +}
12921 +
12922 +VCOS_INLINE_IMPL
12923 +void vcos_llthread_resume(VCOS_LLTHREAD_T *thread) {
12924 +   vcos_assert(0);
12925 +}
12926 +
12927 +VCOS_INLINE_IMPL
12928 +void vcos_sleep(uint32_t ms) {
12929 +   msleep(ms);
12930 +}
12931 +
12932 +VCOS_INLINE_IMPL
12933 +void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED p) {
12934 +   /* not implemented */
12935 +}
12936 +VCOS_INLINE_IMPL
12937 +VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread) {
12938 +   /* not implemented */
12939 +   return 0;
12940 +}
12941 +
12942 +/***********************************************************
12943 + *
12944 + * Miscellaneous
12945 + *
12946 + ***********************************************************/
12947 +
12948 +VCOS_INLINE_IMPL
12949 +int vcos_strcasecmp(const char *s1, const char *s2) {
12950 +   return strcasecmp(s1,s2);
12951 +}
12952 +
12953 +
12954 +/***********************************************************
12955 + *
12956 + * Mutexes
12957 + *
12958 + ***********************************************************/
12959 +
12960 +VCOS_INLINE_IMPL
12961 +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *m, const char *name) {
12962 +   mutex_init(m);
12963 +   return VCOS_SUCCESS;
12964 +}
12965 +
12966 +VCOS_INLINE_IMPL
12967 +void vcos_mutex_delete(VCOS_MUTEX_T *m) {
12968 +}
12969 +
12970 +VCOS_INLINE_IMPL
12971 +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *m) {
12972 +   int ret = mutex_lock_interruptible(m);
12973 +   if ( ret == 0 )
12974 +      /* Success */
12975 +      return VCOS_SUCCESS;
12976 +   else if ( ret == -EINTR )
12977 +      /* Interrupted */
12978 +      return VCOS_EINTR;
12979 +   else
12980 +      /* Default */
12981 +      return VCOS_EAGAIN;
12982 +}
12983 +
12984 +VCOS_INLINE_IMPL
12985 +void vcos_mutex_unlock(VCOS_MUTEX_T *m) {
12986 +   mutex_unlock(m);
12987 +}
12988 +
12989 +VCOS_INLINE_IMPL
12990 +int vcos_mutex_is_locked(VCOS_MUTEX_T *m) {
12991 +   if (mutex_trylock(m) != 0)
12992 +      return 1; /* it was locked */
12993 +   mutex_unlock(m);
12994 +   /* it wasn't locked */
12995 +   return 0;
12996 +}
12997 +
12998 +VCOS_INLINE_IMPL
12999 +VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m) {
13000 +   if (mutex_trylock(m) == 0)
13001 +      return VCOS_SUCCESS;
13002 +   else
13003 +      return VCOS_EAGAIN;
13004 +}
13005 +
13006 +/* For supporting event groups - per thread semaphore */
13007 +VCOS_INLINE_IMPL
13008 +void _vcos_thread_sem_wait(void) {
13009 +   VCOS_THREAD_T *t = vcos_thread_current();
13010 +   vcos_semaphore_wait(&t->suspend);
13011 +}
13012 +
13013 +VCOS_INLINE_IMPL
13014 +void _vcos_thread_sem_post(VCOS_THREAD_T *target) {
13015 +   vcos_semaphore_post(&target->suspend);
13016 +}
13017 +
13018 +/***********************************************************
13019 + *
13020 + * Events
13021 + *
13022 + ***********************************************************/
13023 +
13024 +VCOS_INLINE_IMPL
13025 +VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *debug_name)
13026 +{
13027 +   sema_init(event, 0);
13028 +   return VCOS_SUCCESS;
13029 +}
13030 +
13031 +VCOS_INLINE_IMPL
13032 +void vcos_event_signal(VCOS_EVENT_T *event)
13033 +{
13034 +   up(event);
13035 +}
13036 +
13037 +VCOS_INLINE_IMPL
13038 +VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event)
13039 +{
13040 +   int ret = down_interruptible(event);
13041 +   if ( ret == -EINTR )
13042 +      /* Interrupted */
13043 +      return VCOS_EINTR;
13044 +   else if (ret != 0)
13045 +      /* Default (timeout) */
13046 +      return VCOS_EAGAIN;
13047 +   /* Emulate a maximum count of 1 by removing any extra upness */
13048 +   while (down_trylock(event) == 0) continue;
13049 +   return VCOS_SUCCESS;
13050 +}
13051 +
13052 +VCOS_INLINE_DECL
13053 +VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event)
13054 +{
13055 +   return (down_trylock(event) == 0) ? VCOS_SUCCESS : VCOS_EAGAIN;
13056 +}
13057 +
13058 +VCOS_INLINE_IMPL
13059 +void vcos_event_delete(VCOS_EVENT_T *event)
13060 +{
13061 +}
13062 +
13063 +/***********************************************************
13064 + *
13065 + * Timers
13066 + *
13067 + ***********************************************************/
13068 +
13069 +VCOS_INLINE_DECL
13070 +void vcos_timer_linux_func(unsigned long data)
13071 +{
13072 +    VCOS_TIMER_T    *vcos_timer = (VCOS_TIMER_T *)data;
13073 +
13074 +    vcos_timer->expiration_routine( vcos_timer->context );
13075 +}
13076 +
13077 +VCOS_INLINE_DECL
13078 +VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
13079 +                                const char *name,
13080 +                                void (*expiration_routine)(void *context),
13081 +                                void *context) {
13082 +       init_timer(&timer->linux_timer);
13083 +       timer->linux_timer.data = (unsigned long)timer;
13084 +       timer->linux_timer.function = vcos_timer_linux_func;
13085 +
13086 +    timer->context = context;
13087 +    timer->expiration_routine = expiration_routine;
13088 +
13089 +    return VCOS_SUCCESS;
13090 +}
13091 +
13092 +VCOS_INLINE_IMPL
13093 +void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms) {
13094 +       timer->linux_timer.expires = jiffies + msecs_to_jiffies(delay_ms);
13095 +       add_timer(&timer->linux_timer);
13096 +}
13097 +
13098 +VCOS_INLINE_IMPL
13099 +void vcos_timer_cancel(VCOS_TIMER_T *timer) {
13100 +     del_timer(&timer->linux_timer);
13101 +}
13102 +
13103 +VCOS_INLINE_IMPL
13104 +void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms) {
13105 +    del_timer_sync(&timer->linux_timer);
13106 +    timer->linux_timer.expires = jiffies + msecs_to_jiffies(delay_ms);
13107 +    add_timer(&timer->linux_timer);
13108 +}
13109 +
13110 +VCOS_INLINE_IMPL
13111 +void vcos_timer_delete(VCOS_TIMER_T *timer) {
13112 +    timer->context = NULL;
13113 +    timer->expiration_routine = NULL;
13114 +    timer->linux_timer.function = NULL;
13115 +    timer->linux_timer.data = 0;
13116 +    return;
13117 +}
13118 +
13119 +VCOS_INLINE_IMPL
13120 +VCOS_UNSIGNED vcos_process_id_current(void) {
13121 +   return (VCOS_UNSIGNED)current->pid;
13122 +}
13123 +
13124 +
13125 +VCOS_INLINE_IMPL
13126 +int vcos_in_interrupt(void) {
13127 +   return in_interrupt();
13128 +}
13129 +
13130 +/***********************************************************
13131 + *
13132 + * Atomic flags
13133 + *
13134 + ***********************************************************/
13135 +
13136 +VCOS_INLINE_IMPL
13137 +VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags)
13138 +{
13139 +   atomic_set(atomic_flags, 0);
13140 +   return VCOS_SUCCESS;
13141 +}
13142 +
13143 +VCOS_INLINE_IMPL
13144 +void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags)
13145 +{
13146 +   uint32_t value;
13147 +   do {
13148 +      value = atomic_read(atomic_flags);
13149 +   } while (atomic_cmpxchg(atomic_flags, value, value | flags) != value);
13150 +}
13151 +
13152 +VCOS_INLINE_IMPL
13153 +uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags)
13154 +{
13155 +   return atomic_xchg(atomic_flags, 0);
13156 +}
13157 +
13158 +VCOS_INLINE_IMPL
13159 +void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags)
13160 +{
13161 +}
13162 +
13163 +#undef VCOS_ASSERT_LOGGING_DISABLE
13164 +#define VCOS_ASSERT_LOGGING_DISABLE 0
13165 +
13166 +#endif /* VCOS_INLINE_BODIES */
13167 +
13168 +VCOS_INLINE_DECL void _vcos_thread_sem_wait(void);
13169 +VCOS_INLINE_DECL void _vcos_thread_sem_post(VCOS_THREAD_T *);
13170 +
13171 +/***********************************************************
13172 + *
13173 + * Misc
13174 + *
13175 + ***********************************************************/
13176 +VCOS_INLINE_DECL char *vcos_strdup(const char *str);
13177 +
13178 +/***********************************************************
13179 + *
13180 + * Logging
13181 + *
13182 + ***********************************************************/
13183 +
13184 +VCOSPRE_ const char * VCOSPOST_ _vcos_log_level(void);
13185 +#define _VCOS_LOG_LEVEL() _vcos_log_level()
13186 +
13187 +#define  vcos_log_platform_init()               _vcos_log_platform_init()
13188 +#define  vcos_log_platform_register(category)   _vcos_log_platform_register(category)
13189 +#define  vcos_log_platform_unregister(category) _vcos_log_platform_unregister(category)
13190 +
13191 +struct VCOS_LOG_CAT_T;  /* Forward declaration since vcos_logging.h hasn't been included yet */
13192 +
13193 +void _vcos_log_platform_init(void);
13194 +void _vcos_log_platform_register(struct VCOS_LOG_CAT_T *category);
13195 +void _vcos_log_platform_unregister(struct VCOS_LOG_CAT_T *category);
13196 +
13197 +/***********************************************************
13198 + *
13199 + * Memory barriers
13200 + *
13201 + ***********************************************************/
13202 +
13203 +#define vcos_wmb(x) wmb()
13204 +#define vcos_rmb() rmb()
13205 +
13206 +#include "interface/vcos/generic/vcos_common.h"
13207 +/*#include "interface/vcos/generic/vcos_generic_quickslow_mutex.h" */
13208 +
13209 +#endif /* VCOS_PLATFORM_H */
13210 +
13211 --- /dev/null
13212 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform_types.h
13213 @@ -0,0 +1,47 @@
13214 +/*=============================================================================
13215 +Copyright (c) 2009 Broadcom Europe Limited.
13216 +All rights reserved.
13217 +
13218 +Project  :  vcfw
13219 +Module   :  osal
13220 +
13221 +FILE DESCRIPTION
13222 +VideoCore OS Abstraction Layer - platform-specific types and defines
13223 +=============================================================================*/
13224 +
13225 +#ifndef VCOS_PLATFORM_TYPES_H
13226 +#define VCOS_PLATFORM_TYPES_H
13227 +
13228 +#include <stddef.h>
13229 +#include <linux/types.h>
13230 +#include <linux/bug.h>
13231 +
13232 +#define VCOSPRE_ extern
13233 +#define VCOSPOST_
13234 +
13235 +#if defined(__GNUC__) && (( __GNUC__ > 2 ) || (( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 3 )))
13236 +#define VCOS_FORMAT_ATTR_(ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK)  __attribute__ ((format (ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK)))
13237 +#else
13238 +#define VCOS_FORMAT_ATTR_(ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK)
13239 +#endif
13240 +
13241 +#if !defined( __STDC_VERSION__ )
13242 +#define __STDC_VERSION__ 199901L
13243 +#endif
13244 +
13245 +#if !defined( __STDC_VERSION )
13246 +#define __STDC_VERSION   __STDC_VERSION__
13247 +#endif
13248 +
13249 +static inline void __vcos_bkpt( void ) { BUG(); }
13250 +#define VCOS_BKPT __vcos_bkpt()
13251 +
13252 +#define VCOS_ASSERT_MSG(...) printk( KERN_ERR "vcos_assert: " __VA_ARGS__ )
13253 +
13254 +#define PRId64 "lld"
13255 +#define PRIi64 "lli"
13256 +#define PRIo64 "llo"
13257 +#define PRIu64 "llu"
13258 +#define PRIx64 "llx"
13259 +
13260 +#endif
13261 --- /dev/null
13262 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.c
13263 @@ -0,0 +1,129 @@
13264 +/*****************************************************************************
13265 +* Copyright 2009 - 2010 Broadcom Corporation.  All rights reserved.
13266 +*
13267 +* Unless you and Broadcom execute a separate written software license
13268 +* agreement governing use of this software, this software is licensed to you
13269 +* under the terms of the GNU General Public License version 2, available at
13270 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
13271 +*
13272 +* Notwithstanding the above, under no circumstances may you combine this
13273 +* software in any way with any other Broadcom software provided under a
13274 +* license other than the GPL, without Broadcom's express prior written
13275 +* consent.
13276 +*****************************************************************************/
13277 +
13278 +/** Support to allow VCOS thread-related functions to be called from
13279 +  * threads that were not created by VCOS.
13280 +  */
13281 +
13282 +#include <linux/semaphore.h>
13283 +#include <linux/vmalloc.h>
13284 +#include <linux/list.h>
13285 +#include <linux/sched.h>
13286 +
13287 +#include "vcos_thread_map.h"
13288 +#include "interface/vcos/vcos_logging.h"
13289 +
13290 +/*
13291 + * Store the vcos_thread pointer at the end of
13292 + * current kthread stack, right after the thread_info
13293 + * structure.
13294 + *
13295 + * I belive we should be safe here to steal these 4 bytes
13296 + * from the stack, as long as the vcos thread does not use up
13297 + * all the stack available
13298 + *
13299 + * NOTE: This scheme will not work on architectures with stack growing up
13300 + */
13301 +
13302 +/* Shout, if we are not being compiled for ARM kernel */
13303 +
13304 +#ifndef CONFIG_ARM
13305 +#error " **** The vcos kthread implementation may not work for non-ARM kernel ****"
13306 +#endif
13307 +
13308 +static inline void *to_current_vcos_thread(void)
13309 +{
13310 +   unsigned long *vcos_data;
13311 +
13312 +   vcos_data = (unsigned long *)((char *)current_thread_info() + sizeof(struct thread_info));
13313 +
13314 +   return (void *)vcos_data;
13315 +}
13316 +
13317 +
13318 +static inline void *to_vcos_thread(struct task_struct *tsk)
13319 +{
13320 +   unsigned long *vcos_data;
13321 +
13322 +   vcos_data = (unsigned long *)((char *)tsk->stack + sizeof(struct thread_info));
13323 +
13324 +   return (void *)vcos_data;
13325 +}
13326 +
13327 +/**
13328 +   @fn uint32_t vcos_add_thread(THREAD_MAP_T *vcos_thread);
13329 +*/
13330 +uint32_t vcos_add_thread(VCOS_THREAD_T *vcos_thread)
13331 +{
13332 +   VCOS_THREAD_T **vcos_thread_storage = (VCOS_THREAD_T **)to_current_vcos_thread();
13333 +
13334 +   *vcos_thread_storage = vcos_thread;
13335 +
13336 +   return(0);
13337 +}
13338 +
13339 +
13340 +/**
13341 +   @fn uint32_t vcos_remove_thread(struct task_struct * thread_id);
13342 +*/
13343 +uint32_t vcos_remove_thread(struct task_struct *thread_id)
13344 +{
13345 +   /* Remove thread_id -> VCOS_THREAD_T relationship */
13346 +   VCOS_THREAD_T **vcos_thread_storage;
13347 +
13348 +   /*
13349 +    * We want to be able to build vcos as a loadable module, which
13350 +    * means that we can't call get_task_struct. So we assert if we're
13351 +    * ever called with thread_id != current.
13352 +    */
13353 +
13354 +   BUG_ON( thread_id != current );
13355 +
13356 +   vcos_thread_storage = (VCOS_THREAD_T **)to_vcos_thread(thread_id);
13357 +
13358 +   *(unsigned long *)vcos_thread_storage = 0xCAFEBABE;
13359 +
13360 +   return(0);
13361 +}
13362 +
13363 +
13364 +VCOS_THREAD_T *vcos_kthread_current(void)
13365 +{
13366 +   VCOS_THREAD_T **vcos_thread_storage = (VCOS_THREAD_T **)to_current_vcos_thread();
13367 +
13368 +   /* If we find this, either the thread is already dead or stack pages of a
13369 +    * dead vcos thread are re-allocated to this one.
13370 +    *
13371 +    * Since there's no way to differentiate between these 2 cases, we just dump
13372 +    * the current task name to the log.
13373 +    *
13374 +    * If the current thread is created using VCOS API, you should *never* see this
13375 +    * print.
13376 +    * 
13377 +    * If its a non-VCOS thread, just let it go ...
13378 +    *
13379 +    * To debug VCOS, uncomment printk's under the "if" condition below
13380 +    *
13381 +    */
13382 +   if (*vcos_thread_storage == (void *)0xCAFEBABE)
13383 +   {
13384 +     #if 0
13385 +      printk(KERN_DEBUG"****************************************************\n");
13386 +      printk(KERN_DEBUG"%s : You have a problem, if \"%s\" is a VCOS thread\n",__func__, current->comm);
13387 +      printk(KERN_DEBUG"****************************************************\n");
13388 +     #endif
13389 +   }
13390 +
13391 +   return *vcos_thread_storage;
13392 +}
13393 --- /dev/null
13394 +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.h
13395 @@ -0,0 +1,39 @@
13396 +/*****************************************************************************
13397 +* Copyright 2009 - 2010 Broadcom Corporation.  All rights reserved.
13398 +*
13399 +* Unless you and Broadcom execute a separate written software license
13400 +* agreement governing use of this software, this software is licensed to you
13401 +* under the terms of the GNU General Public License version 2, available at
13402 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
13403 +*
13404 +* Notwithstanding the above, under no circumstances may you combine this
13405 +* software in any way with any other Broadcom software provided under a
13406 +* license other than the GPL, without Broadcom's express prior written
13407 +* consent.
13408 +*****************************************************************************/
13409 +
13410 +
13411 +#ifndef VCOS_THREAD_MAP_H
13412 +#define VCOS_THREAD_MAP_H
13413 +
13414 +#include <linux/string.h>
13415 +
13416 +#include "vcos_platform.h"
13417 +
13418 +static inline void vcos_thread_map_init(void)
13419 +{
13420 +   return;
13421 +}
13422 +
13423 +static inline void vcos_thread_map_cleanup(void)
13424 +{
13425 +   return;
13426 +}
13427 +
13428 +uint32_t vcos_add_thread(VCOS_THREAD_T *vcos_thread);
13429 +
13430 +uint32_t vcos_remove_thread(struct task_struct *thread_id);
13431 +
13432 +VCOS_THREAD_T *vcos_kthread_current(void);
13433 +
13434 +#endif /*VCOS_THREAD_MAP_H */
13435 --- /dev/null
13436 +++ b/drivers/misc/vc04_services/interface/vcos/vcos.h
13437 @@ -0,0 +1,201 @@
13438 +/*=============================================================================
13439 +Copyright (c) 2009 Broadcom Europe Limited.
13440 +All rights reserved.
13441 +
13442 +Project  :  vcfw
13443 +Module   :  chip driver
13444 +
13445 +FILE DESCRIPTION
13446 +VideoCore OS Abstraction Layer - public header file
13447 +=============================================================================*/
13448 +
13449 +/**
13450 +  * \mainpage OS Abstraction Layer
13451 +  *
13452 +  * \section intro Introduction
13453 +  *
13454 +  * This abstraction layer is here to allow the underlying OS to be easily changed (e.g. from
13455 +  * Nucleus to ThreadX) and to aid in porting host applications to new targets.
13456 +  *
13457 +  * \subsection error Error handling
13458 +  *
13459 +  * Wherever possible, VCOS functions assert internally and return void. The only exceptions
13460 +  * are creation functions (which might fail due to lack of resources) and functions that
13461 +  * might timeout or fail due to lack of space. Errors that might be reported by the underlying
13462 +  * OS API (e.g. invalid mutex) are treated as a programming error, and are merely asserted on.
13463 +  *
13464 +  * \section thread_synch Threads and synchronisation
13465 +  *
13466 +  * \subsection thread Threads
13467 +  *
13468 +  * The thread API is somewhat different to that found in Nucleus. In particular, threads
13469 +  * cannot just be destroyed at arbitrary times and nor can they merely exit. This is so
13470 +  * that the same API can be implemented across all interesting platforms without too much
13471 +  * difficulty. See vcos_thread.h for details. Thread attributes are configured via
13472 +  * the VCOS_THREAD_ATTR_T structure, found in vcos_thread_attr.h.
13473 +  *
13474 +  * \subsection sema Semaphores
13475 +  *
13476 +  * Counted semaphores (c.f. Nucleus NU_SEMAPHORE) are created with VCOS_SEMAPHORE_T.
13477 +  * Under ThreadX on VideoCore, semaphores are implemented using VideoCore spinlocks, and
13478 +  * so are quite a lot faster than ordinary ThreadX semaphores. See vcos_semaphore.h.
13479 +  *
13480 +  * \subsection mtx Mutexes
13481 +  *
13482 +  * Mutexes are used for locking. Attempts to take a mutex twice, or to unlock it
13483 +  * in a different thread to the one in which it was locked should be expected to fail.
13484 +  * Mutexes are not re-entrant (see vcos_reentrant_mutex.h for a slightly slower
13485 +  * re-entrant mutex).
13486 +  *
13487 +  * \subsection evflags Event flags
13488 +  *
13489 +  * Event flags (the ThreadX name - also known as event groups under Nucleus) provide
13490 +  * 32 flags which can be waited on by multiple clients, and signalled by multiple clients.
13491 +  * A timeout can be specified. See vcos_event_flags.h. An alternative to this is the
13492 +  * VCOS_EVENT_T (see vcos_event.h) which is akin to the Win32 auto-reset event, or a
13493 +  * saturating counted semaphore.
13494 +  *
13495 +  * \subsection event Events
13496 +  *
13497 +  * A VCOS_EVENT_T is a bit like a saturating semaphore. No matter how many times it
13498 +  * is signalled, the waiter will only wake up once. See vcos_event.h. You might think this
13499 +  * is useful if you suspect that the cost of reading the semaphore count (perhaps via a
13500 +  * system call) is expensive on your platform.
13501 +  *
13502 +  * \subsection tls Thread local storage
13503 +  *
13504 +  * Thread local storage is supported using vcos_tls.h. This is emulated on Nucleus
13505 +  * and ThreadX.
13506 +  *
13507 +  * \section int Interrupts
13508 +  *
13509 +  * The legacy LISR/HISR scheme found in Nucleus is supported via the legacy ISR API,
13510 +  * which is also supported on ThreadX. New code should avoid this, and old code should
13511 +  * be migrated away from it, since it is slow. See vcos_legacy_isr.h.
13512 +  *
13513 +  * Registering an interrupt handler, and disabling/restoring interrupts, is handled
13514 +  * using the functions in vcos_isr.h.
13515 +  *
13516 +  */
13517 +
13518 +/**
13519 +  * \file vcos.h
13520 +  *
13521 +  * This is the top level header file. Clients include this. It pulls in the platform-specific
13522 +  * header file (vcos_platform.h) together with header files defining the expected APIs, such
13523 +  * as vcos_mutex.h, vcos_semaphore.h, etc. It is also possible to include these header files
13524 +  * directly.
13525 +  *
13526 +  */
13527 +
13528 +#ifndef VCOS_H
13529 +#define VCOS_H
13530 +
13531 +#include "interface/vcos/vcos_assert.h"
13532 +#include "vcos_types.h"
13533 +#include "vcos_platform.h"
13534 +
13535 +#ifndef VCOS_INIT_H
13536 +#include "interface/vcos/vcos_init.h"
13537 +#endif
13538 +
13539 +#ifndef VCOS_SEMAPHORE_H
13540 +#include "interface/vcos/vcos_semaphore.h"
13541 +#endif
13542 +
13543 +#ifndef VCOS_THREAD_H
13544 +#include "interface/vcos/vcos_thread.h"
13545 +#endif
13546 +
13547 +#ifndef VCOS_MUTEX_H
13548 +#include "interface/vcos/vcos_mutex.h"
13549 +#endif
13550 +
13551 +#ifndef VCOS_MEM_H
13552 +#include "interface/vcos/vcos_mem.h"
13553 +#endif
13554 +
13555 +#ifndef VCOS_LOGGING_H
13556 +#include "interface/vcos/vcos_logging.h"
13557 +#endif
13558 +
13559 +#ifndef VCOS_STRING_H
13560 +#include "interface/vcos/vcos_string.h"
13561 +#endif
13562 +
13563 +#ifndef VCOS_EVENT_H
13564 +#include "interface/vcos/vcos_event.h"
13565 +#endif
13566 +
13567 +#ifndef VCOS_THREAD_ATTR_H
13568 +#include "interface/vcos/vcos_thread_attr.h"
13569 +#endif
13570 +
13571 +#ifndef VCOS_TLS_H
13572 +#include "interface/vcos/vcos_tls.h"
13573 +#endif
13574 +
13575 +#ifndef VCOS_REENTRANT_MUTEX_H
13576 +#include "interface/vcos/vcos_reentrant_mutex.h"
13577 +#endif
13578 +
13579 +#ifndef VCOS_NAMED_SEMAPHORE_H
13580 +#include "interface/vcos/vcos_named_semaphore.h"
13581 +#endif
13582 +
13583 +#ifndef VCOS_QUICKSLOW_MUTEX_H
13584 +#include "interface/vcos/vcos_quickslow_mutex.h"
13585 +#endif
13586 +
13587 +/* Headers with predicates */
13588 +
13589 +#if VCOS_HAVE_EVENT_FLAGS
13590 +#include "interface/vcos/vcos_event_flags.h"
13591 +#endif
13592 +
13593 +#if VCOS_HAVE_QUEUE
13594 +#include "interface/vcos/vcos_queue.h"
13595 +#endif
13596 +
13597 +#if VCOS_HAVE_LEGACY_ISR
13598 +#include "interface/vcos/vcos_legacy_isr.h"
13599 +#endif
13600 +
13601 +#if VCOS_HAVE_TIMER
13602 +#include "interface/vcos/vcos_timer.h"
13603 +#endif
13604 +
13605 +#if VCOS_HAVE_MEMPOOL
13606 +#include "interface/vcos/vcos_mempool.h"
13607 +#endif
13608 +
13609 +#if VCOS_HAVE_ISR
13610 +#include "interface/vcos/vcos_isr.h"
13611 +#endif
13612 +
13613 +#if VCOS_HAVE_ATOMIC_FLAGS
13614 +#include "interface/vcos/vcos_atomic_flags.h"
13615 +#endif
13616 +
13617 +#if VCOS_HAVE_ONCE
13618 +#include "interface/vcos/vcos_once.h"
13619 +#endif
13620 +
13621 +#if VCOS_HAVE_BLOCK_POOL
13622 +#include "interface/vcos/vcos_blockpool.h"
13623 +#endif
13624 +
13625 +#if VCOS_HAVE_FILE
13626 +#include "interface/vcos/vcos_file.h"
13627 +#endif
13628 +
13629 +#if VCOS_HAVE_CFG
13630 +#include "interface/vcos/vcos_cfg.h"
13631 +#endif
13632 +
13633 +#if VCOS_HAVE_CMD
13634 +#include "interface/vcos/vcos_cmd.h"
13635 +#endif
13636 +
13637 +#endif /* VCOS_H */
13638 +
13639 --- /dev/null
13640 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_assert.h
13641 @@ -0,0 +1,269 @@
13642 +/*=============================================================================
13643 +Copyright (c) 2009 Broadcom Europe Limited.
13644 +All rights reserved.
13645 +
13646 +Project  :  vcfw
13647 +Module   :  osal
13648 +
13649 +FILE DESCRIPTION
13650 +VideoCore OS Abstraction Layer - Assertion and error-handling macros.
13651 +=============================================================================*/
13652 +
13653 +
13654 +#ifndef VCOS_ASSERT_H
13655 +#define VCOS_ASSERT_H
13656 +
13657 +/*
13658 + * Macro:
13659 + *    vcos_assert(cond)
13660 + *    vcos_assert_msg(cond, fmt, ...)
13661 + * Use:
13662 + *    Detecting programming errors by ensuring that assumptions are correct.
13663 + * On failure:
13664 + *    Performs a platform-dependent "breakpoint", usually with an assert-style
13665 + *    message. The '_msg' variant expects a printf-style format string and
13666 + *    parameters.
13667 + *    If a failure is detected, the code should be fixed and rebuilt.
13668 + * In release builds:
13669 + *    Generates no code, i.e. does not evaluate 'cond'.
13670 + * Returns:
13671 + *    Nothing.
13672 + *
13673 + * Macro:
13674 + *    vcos_demand(cond)
13675 + *    vcos_demand_msg(cond, fmt, ...)
13676 + * Use:
13677 + *    Detecting fatal system errors that require a reboot.
13678 + * On failure:
13679 + *    Performs a platform-dependent "breakpoint", usually with an assert-style
13680 + *    message, then calls vcos_abort (see below).
13681 + * In release builds:
13682 + *    Calls vcos_abort() if 'cond' is false.
13683 + * Returns:
13684 + *    Nothing (never, on failure).
13685 + *
13686 + * Macro:
13687 + *    vcos_verify(cond)
13688 + *    vcos_verify_msg(cond, fmt, ...)
13689 + * Use:
13690 + *    Detecting run-time errors and interesting conditions, normally within an
13691 + *    'if' statement to catch the failures, i.e.
13692 + *       if (!vcos_verify(cond)) handle_error();
13693 + * On failure:
13694 + *    Generates a message and optionally stops at a platform-dependent
13695 + *    "breakpoint" (usually disabled). See vcos_verify_bkpts_enable below.
13696 + * In release builds:
13697 + *    Just evaluates and returns 'cond'.
13698 + * Returns:
13699 + *    Non-zero if 'cond' is true, otherwise zero.
13700 + *
13701 + * Macro:
13702 + *    vcos_static_assert(cond)
13703 + * Use:
13704 + *    Detecting compile-time errors.
13705 + * On failure:
13706 + *    Generates a compiler error.
13707 + * In release builds:
13708 + *    Generates a compiler error.
13709 + *
13710 + * Function:
13711 + *    void vcos_abort(void)
13712 + * Use:
13713 + *    Invokes the fatal error handling mechanism, alerting the host where
13714 + *    applicable.
13715 + * Returns:
13716 + *    Never.
13717 + *
13718 + * Macro:
13719 + *    VCOS_VERIFY_BKPTS
13720 + * Use:
13721 + *    Define in a module (before including vcos.h) to specify an alternative
13722 + *    flag to control breakpoints on vcos_verify() failures.
13723 + * Returns:
13724 + *    Non-zero values enable breakpoints.
13725 + *
13726 + * Function:
13727 + *    int vcos_verify_bkpts_enable(int enable);
13728 + * Use:
13729 + *    Sets the global flag controlling breakpoints on vcos_verify failures,
13730 + *    enabling the breakpoints iff 'enable' is non-zero.
13731 + * Returns:
13732 + *    The previous state of the flag.
13733 + *
13734 + * Function:
13735 + *    int vcos_verify_bkpts_enabled(void);
13736 + * Use:
13737 + *    Queries the state of the global flag enabling breakpoints on vcos_verify
13738 + *    failures.
13739 + * Returns:
13740 + *    The current state of the flag.
13741 + *
13742 + * Examples:
13743 + *
13744 + * int my_breakpoint_enable_flag = 1;
13745 + *
13746 + * #define VCOS_VERIFY_BKPTS my_breakpoint_enable_flag
13747 + *
13748 + * #include "interface/vcos/vcos.h"
13749 + *
13750 + * vcos_static_assert((sizeof(object) % 32) == 0);
13751 + *
13752 + * // ...
13753 + *
13754 + *    vcos_assert_msg(postcondition_is_true, "Coding error");
13755 + *
13756 + *    if (!vcos_verify_msg(buf, "Buffer allocation failed (%d bytes)", size))
13757 + *    {
13758 + *       // Tidy up
13759 + *       // ...
13760 + *       return OUT_OF_MEMORY;
13761 + *    }
13762 + *
13763 + *    vcos_demand(*p++==GUARDWORDHEAP);
13764 + */
13765 +
13766 +#ifdef __cplusplus
13767 +extern "C" {
13768 +#endif
13769 +
13770 +#include "interface/vcos/vcos_types.h"
13771 +
13772 +#ifdef __COVERITY__
13773 +#undef VCOS_ASSERT_BKPT
13774 +#define VCOS_ASSERT_BKPT __coverity_panic__()
13775 +#endif
13776 +
13777 +#ifndef VCOS_VERIFY_BKPTS
13778 +#define VCOS_VERIFY_BKPTS vcos_verify_bkpts_enabled()
13779 +#endif
13780 +
13781 +#ifndef VCOS_BKPT
13782 +#if defined(__VIDEOCORE__) && !defined(VCOS_ASSERT_NO_BKPTS)
13783 +#define VCOS_BKPT _bkpt()
13784 +#else
13785 +#define VCOS_BKPT (void )0
13786 +#endif
13787 +#endif
13788 +
13789 +#ifndef VCOS_ASSERT_BKPT
13790 +#define VCOS_ASSERT_BKPT VCOS_BKPT
13791 +#endif
13792 +
13793 +#ifndef VCOS_VERIFY_BKPT
13794 +#define VCOS_VERIFY_BKPT (VCOS_VERIFY_BKPTS ? VCOS_BKPT : (void)0)
13795 +#endif
13796 +
13797 +VCOSPRE_ int VCOSPOST_ vcos_verify_bkpts_enabled(void);
13798 +VCOSPRE_ int VCOSPOST_ vcos_verify_bkpts_enable(int enable);
13799 +VCOSPRE_ void VCOSPOST_ vcos_abort(void);
13800 +
13801 +#ifndef VCOS_ASSERT_MSG
13802 +#ifdef LOGGING
13803 +extern void logging_assert(const char *file, const char *func, int line, const char *format, ...);
13804 +#define VCOS_ASSERT_MSG(...) ((VCOS_ASSERT_LOGGING && !VCOS_ASSERT_LOGGING_DISABLE) ? logging_assert(__FILE__, __func__, __LINE__, __VA_ARGS__) : (void)0)
13805 +#else
13806 +#define VCOS_ASSERT_MSG(...) ((void)0)
13807 +#endif
13808 +#endif
13809 +
13810 +#ifndef VCOS_VERIFY_MSG
13811 +#define VCOS_VERIFY_MSG(...) VCOS_ASSERT_MSG(__VA_ARGS__)
13812 +#endif
13813 +
13814 +#ifndef VCOS_ASSERT_LOGGING
13815 +#define VCOS_ASSERT_LOGGING 0
13816 +#endif
13817 +
13818 +#ifndef VCOS_ASSERT_LOGGING_DISABLE
13819 +#define VCOS_ASSERT_LOGGING_DISABLE 0
13820 +#endif
13821 +
13822 +#if !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS)
13823 +
13824 +#ifndef vcos_assert
13825 +#define vcos_assert(cond) \
13826 +   ( (cond) ? (void)0 : (VCOS_ASSERT_MSG("%s", #cond), VCOS_ASSERT_BKPT) )
13827 +#endif
13828 +
13829 +#ifndef vcos_assert_msg
13830 +#define vcos_assert_msg(cond, ...) \
13831 +   ( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT) )
13832 +#endif
13833 +
13834 +#else  /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */
13835 +
13836 +#ifndef vcos_assert
13837 +#define vcos_assert(cond) (void)0
13838 +#endif
13839 +
13840 +#ifndef vcos_assert_msg
13841 +#define vcos_assert_msg(cond, ...) (void)0
13842 +#endif
13843 +
13844 +#endif /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */
13845 +
13846 +#if !defined(NDEBUG)
13847 +
13848 +#ifndef vcos_demand
13849 +#define vcos_demand(cond) \
13850 +   ( (cond) ? (void)0 : (VCOS_ASSERT_MSG("%s", #cond), VCOS_ASSERT_BKPT, vcos_abort()) )
13851 +#endif
13852 +
13853 +#ifndef vcos_demand_msg
13854 +#define vcos_demand_msg(cond, ...) \
13855 +   ( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT, vcos_abort()) )
13856 +#endif
13857 +
13858 +#ifndef vcos_verify
13859 +#define vcos_verify(cond) \
13860 +   ( (cond) ? 1 : (VCOS_VERIFY_MSG("%s", #cond), VCOS_VERIFY_BKPT, 0) )
13861 +#endif
13862 +
13863 +#ifndef vcos_verify_msg
13864 +#define vcos_verify_msg(cond, ...) \
13865 +   ( (cond) ? 1 : (VCOS_VERIFY_MSG(__VA_ARGS__), VCOS_VERIFY_BKPT, 0) )
13866 +#endif
13867 +
13868 +#else  /* !defined(NDEBUG) */
13869 +
13870 +#ifndef vcos_demand
13871 +#define vcos_demand(cond) \
13872 +   ( (cond) ? (void)0 : vcos_abort() )
13873 +#endif
13874 +
13875 +#ifndef vcos_demand_msg
13876 +#define vcos_demand_msg(cond, ...) \
13877 +   ( (cond) ? (void)0 : vcos_abort() )
13878 +#endif
13879 +
13880 +#ifndef vcos_verify
13881 +#define vcos_verify(cond) (cond)
13882 +#endif
13883 +
13884 +#ifndef vcos_verify_msg
13885 +#define vcos_verify_msg(cond, ...) (cond)
13886 +#endif
13887 +
13888 +#endif /* !defined(NDEBUG) */
13889 +
13890 +#ifndef vcos_static_assert
13891 +#if defined(__GNUC__)
13892 +#define vcos_static_assert(cond) __attribute__((unused)) extern int vcos_static_assert[(cond)?1:-1]
13893 +#else
13894 +#define vcos_static_assert(cond) extern int vcos_static_assert[(cond)?1:-1]
13895 +#endif
13896 +#endif
13897 +
13898 +#ifndef vc_assert
13899 +#define vc_assert(cond) vcos_assert(cond)
13900 +#endif
13901 +
13902 +/** Print out a backtrace, on supported platforms.
13903 +  */
13904 +extern void vcos_backtrace_self(void);
13905 +
13906 +#ifdef __cplusplus
13907 +}
13908 +#endif
13909 +
13910 +#endif /* VCOS_ASSERT_H */
13911 --- /dev/null
13912 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_atomic_flags.h
13913 @@ -0,0 +1,72 @@
13914 +/*=============================================================================
13915 +Copyright (c) 2009 Broadcom Europe Limited.
13916 +All rights reserved.
13917 +
13918 +Project  :  vcfw
13919 +Module   :  chip driver (just for consistency with the rest of vcos ;)
13920 +
13921 +FILE DESCRIPTION
13922 +VideoCore OS Abstraction Layer - public header file
13923 +=============================================================================*/
13924 +
13925 +#ifndef VCOS_ATOMIC_FLAGS_H
13926 +#define VCOS_ATOMIC_FLAGS_H
13927 +
13928 +#ifdef __cplusplus
13929 +extern "C" {
13930 +#endif
13931 +
13932 +#include "interface/vcos/vcos_types.h"
13933 +#include "vcos_platform.h"
13934 +
13935 +/**
13936 + * \file vcos_atomic_flags.h
13937 + *
13938 + * Defines atomic flags API.
13939 + *
13940 + * 32 flags. Atomic "or" and "get and clear" operations
13941 + */
13942 +
13943 +/**
13944 + * Create an atomic flags instance.
13945 + *
13946 + * @param atomic_flags Pointer to atomic flags instance, filled in on return
13947 + *
13948 + * @return VCOS_SUCCESS if succeeded.
13949 + */
13950 +VCOS_INLINE_DECL
13951 +VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags);
13952 +
13953 +/**
13954 + * Atomically set the specified flags.
13955 + *
13956 + * @param atomic_flags Instance to set flags on
13957 + * @param flags        Mask of flags to set
13958 + */
13959 +VCOS_INLINE_DECL
13960 +void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags);
13961 +
13962 +/**
13963 + * Retrieve the current flags and then clear them. The entire operation is
13964 + * atomic.
13965 + *
13966 + * @param atomic_flags Instance to get/clear flags from/on
13967 + *
13968 + * @return Mask of flags which were set (and we cleared)
13969 + */
13970 +VCOS_INLINE_DECL
13971 +uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags);
13972 +
13973 +/**
13974 + * Delete an atomic flags instance.
13975 + *
13976 + * @param atomic_flags Instance to delete
13977 + */
13978 +VCOS_INLINE_DECL
13979 +void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags);
13980 +
13981 +#ifdef __cplusplus
13982 +}
13983 +#endif
13984 +
13985 +#endif
13986 --- /dev/null
13987 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_build_info.h
13988 @@ -0,0 +1,5 @@
13989 +const char *vcos_get_build_hostname( void );
13990 +const char *vcos_get_build_version( void );
13991 +const char *vcos_get_build_time( void );
13992 +const char *vcos_get_build_date( void );
13993 +
13994 --- /dev/null
13995 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_cfg.h
13996 @@ -0,0 +1,113 @@
13997 +/*****************************************************************************
13998 +* Copyright 2009 - 2011 Broadcom Corporation.  All rights reserved.
13999 +*
14000 +* Unless you and Broadcom execute a separate written software license
14001 +* agreement governing use of this software, this software is licensed to you
14002 +* under the terms of the GNU General Public License version 2, available at
14003 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
14004 +*
14005 +* Notwithstanding the above, under no circumstances may you combine this
14006 +* software in any way with any other Broadcom software provided under a
14007 +* license other than the GPL, without Broadcom's express prior written
14008 +* consent.
14009 +*****************************************************************************/
14010 +
14011 +#if !defined( VCOS_CFG_H )
14012 +#define VCOS_CFG_H
14013 +
14014 +#ifdef __cplusplus
14015 +extern "C" {
14016 +#endif
14017 +
14018 +#include "interface/vcos/vcos_types.h"
14019 +#include "vcos_platform.h"
14020 +
14021 +typedef struct opaque_vcos_cfg_buf_t    *VCOS_CFG_BUF_T;
14022 +typedef struct opaque_vcos_cfg_entry_t  *VCOS_CFG_ENTRY_T;
14023 +
14024 +/** \file vcos_file.h
14025 +  *
14026 +  * API for accessing configuration/statistics information. This
14027 +  * is loosely modelled on the linux proc entries.
14028 +  */
14029 +
14030 +typedef void (*VCOS_CFG_SHOW_FPTR)( VCOS_CFG_BUF_T buf, void *data );
14031 +typedef void (*VCOS_CFG_PARSE_FPTR)( VCOS_CFG_BUF_T buf, void *data );
14032 +
14033 +/** Create a configuration directory.
14034 +  *
14035 +  * @param entry        Place to store the created config entry.
14036 +  * @param parent       Parent entry (for directory like config 
14037 +  *                     options).
14038 +  * @param entryName    Name of the directory.
14039 +  */
14040 +
14041 +VCOS_STATUS_T vcos_cfg_mkdir( VCOS_CFG_ENTRY_T *entry,
14042 +                              VCOS_CFG_ENTRY_T *parent,
14043 +                              const char *dirName );           
14044 +
14045 +/** Create a configuration entry.
14046 +  *
14047 +  * @param entry        Place to store the created config entry.
14048 +  * @param parent       Parent entry (for directory like config 
14049 +  *                     options).
14050 +  * @param entryName    Name of the configuration entry.
14051 +  * @param showFunc     Function pointer to show configuration 
14052 +  *                     data.
14053 +  * @param parseFunc    Function pointer to parse new data. 
14054 +  */
14055 +
14056 +VCOS_STATUS_T vcos_cfg_create_entry( VCOS_CFG_ENTRY_T *entry,
14057 +                                     VCOS_CFG_ENTRY_T *parent,
14058 +                                     const char *entryName,
14059 +                                     VCOS_CFG_SHOW_FPTR showFunc,
14060 +                                     VCOS_CFG_PARSE_FPTR parseFunc,
14061 +                                     void *data );
14062 +
14063 +/** Determines if a configuration entry has been created or not.
14064 +  *
14065 +  * @param entry        Configuration entry to query.
14066 +  */
14067 +
14068 +int vcos_cfg_is_entry_created( VCOS_CFG_ENTRY_T entry );
14069 +
14070 +/** Returns the name of a configuration entry.
14071 +  *
14072 +  * @param entry        Configuration entry to query.
14073 +  */
14074 +
14075 +const char *vcos_cfg_get_entry_name( VCOS_CFG_ENTRY_T entry );
14076 +
14077 +/** Removes a configuration entry.
14078 +  *
14079 +  * @param entry        Configuration entry to remove.
14080 +  */
14081 +
14082 +VCOS_STATUS_T vcos_cfg_remove_entry( VCOS_CFG_ENTRY_T *entry );
14083 +
14084 +
14085 +/** Writes data into a configuration buffer. Only valid inside
14086 +  * the show function. 
14087 +  *
14088 +  * @param buf      Buffer to write data into.
14089 +  * @param fmt      printf style format string. 
14090 +  */
14091 +
14092 +void vcos_cfg_buf_printf( VCOS_CFG_BUF_T buf, const char *fmt, ... );
14093 +
14094 +/** Retrieves a null terminated string of the data associated
14095 +  * with the buffer. Only valid inside the parse function.
14096 +  *
14097 +  * @param buf      Buffer to get data from.
14098 +  * @param fmt      printf style format string. 
14099 +  */
14100 +
14101 +char *vcos_cfg_buf_get_str( VCOS_CFG_BUF_T buf );
14102 +
14103 +void *vcos_cfg_get_proc_entry( VCOS_CFG_ENTRY_T entry );
14104 +
14105 +#ifdef __cplusplus
14106 +}
14107 +#endif
14108 +#endif
14109 +
14110 --- /dev/null
14111 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_cmd.h
14112 @@ -0,0 +1,98 @@
14113 +/*****************************************************************************
14114 +* Copyright 2009 - 2011 Broadcom Corporation.  All rights reserved.
14115 +*
14116 +* Unless you and Broadcom execute a separate written software license
14117 +* agreement governing use of this software, this software is licensed to you
14118 +* under the terms of the GNU General Public License version 2, available at
14119 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
14120 +*
14121 +* Notwithstanding the above, under no circumstances may you combine this
14122 +* software in any way with any other Broadcom software provided under a
14123 +* license other than the GPL, without Broadcom's express prior written
14124 +* consent.
14125 +*****************************************************************************/
14126 +
14127 +#if !defined( VCOS_CMD_H )
14128 +#define VCOS_CMD_H
14129 +
14130 +/* ---- Include Files ----------------------------------------------------- */
14131 +
14132 +#include "interface/vcos/vcos.h"
14133 +#include "interface/vcos/vcos_stdint.h"
14134 +
14135 +
14136 +/* ---- Constants and Types ---------------------------------------------- */
14137 +
14138 +struct VCOS_CMD_S;
14139 +typedef struct VCOS_CMD_S VCOS_CMD_T;
14140 +
14141 +typedef struct
14142 +{
14143 +    int         argc;           /* Number of arguments (includes the command/sub-command) */
14144 +    char      **argv;           /* Array of arguments */
14145 +    char      **argv_orig;      /* Original array of arguments */
14146 +
14147 +    VCOS_CMD_T *cmd_entry;
14148 +    VCOS_CMD_T *cmd_parent_entry;
14149 +
14150 +    int         use_log;        /* Output being logged? */
14151 +    size_t      result_size;    /* Size of result buffer. */
14152 +    char       *result_ptr;     /* Next place to put output. */
14153 +    char       *result_buf;     /* Start of the buffer. */
14154 +
14155 +} VCOS_CMD_PARAM_T;
14156 +
14157 +typedef VCOS_STATUS_T (*VCOS_CMD_FUNC_T)( VCOS_CMD_PARAM_T *param );
14158 +
14159 +struct VCOS_CMD_S
14160 +{
14161 +    const char         *name;
14162 +    const char         *args;
14163 +    VCOS_CMD_FUNC_T     cmd_fn;
14164 +    VCOS_CMD_T         *sub_cmd_entry;
14165 +    const char         *descr;
14166 +
14167 +};
14168 +
14169 +/* ---- Variable Externs ------------------------------------------------- */
14170 +
14171 +/* ---- Function Prototypes ---------------------------------------------- */
14172 +
14173 +/*
14174 + * Common printing routine for generating command output.
14175 + */
14176 +VCOSPRE_ void VCOSPOST_ vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) VCOS_FORMAT_ATTR_(printf, 2, 3);
14177 +VCOSPRE_ void VCOSPOST_ vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) VCOS_FORMAT_ATTR_(printf, 2, 3);
14178 +VCOSPRE_ void VCOSPOST_ vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args ) VCOS_FORMAT_ATTR_(printf, 2, 0);
14179 +
14180 +/*
14181 + * Cause vcos_cmd_error, printf and vprintf to always log to the provided
14182 + * category. When this call is made, the results buffer passed into
14183 + * vcos_cmd_execute is used as a line buffer and does not need to be
14184 + * output by the caller.
14185 + */
14186 +VCOSPRE_ void VCOSPOST_ vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category );
14187 +
14188 +/*
14189 + * Prints command usage for the current command.
14190 + */
14191 +VCOSPRE_ void VCOSPOST_ vcos_cmd_usage( VCOS_CMD_PARAM_T *param );
14192 +
14193 +/*
14194 + * Register commands to be processed
14195 + */
14196 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register( VCOS_CMD_T *cmd_entry );
14197 +
14198 +/*
14199 + * Registers multiple commands to be processed. The array should
14200 + * be terminated by an entry with all zeros.
14201 + */
14202 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry );
14203 +
14204 +/*
14205 + * Executes a command based on a command line.
14206 + */
14207 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf );
14208 +
14209 +#endif /* VCOS_CMD_H */
14210 +
14211 --- /dev/null
14212 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_ctype.h
14213 @@ -0,0 +1,29 @@
14214 +/*=============================================================================
14215 +Copyright (c) 2009 Broadcom Europe Limited.
14216 +All rights reserved.
14217 +
14218 +Project  :  vcfw
14219 +Module   :  chip driver
14220 +
14221 +FILE DESCRIPTION
14222 +VideoCore OS Abstraction Layer - public header file
14223 +=============================================================================*/
14224 +
14225 +#ifndef VCOS_CTYPE_H
14226 +#define VCOS_CTYPE_H
14227 +
14228 +/**
14229 +  * \file
14230 +  *
14231 +  * ctype functions.
14232 +  *
14233 +  */
14234 +
14235 +#ifdef __KERNEL__
14236 +#include <linux/ctype.h>
14237 +#else
14238 +#include <ctype.h>
14239 +#endif
14240 +
14241 +#endif
14242 +
14243 --- /dev/null
14244 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_dlfcn.h
14245 @@ -0,0 +1,69 @@
14246 +/*=============================================================================
14247 +Copyright (c) 2010 Broadcom Europe Limited.
14248 +All rights reserved.
14249 +
14250 +Project  :  vcfw
14251 +Module   :  chip driver
14252 +
14253 +FILE DESCRIPTION
14254 +VCOS - abstraction over dynamic library opening
14255 +=============================================================================*/
14256 +
14257 +#ifndef VCOS_DLFCN_H
14258 +#define VCOS_DLFCN_H
14259 +
14260 +#include "interface/vcos/vcos_types.h"
14261 +#include "vcos_platform.h"
14262 +
14263 +#ifdef __cplusplus
14264 +extern "C" {
14265 +#endif
14266 +
14267 +#define VCOS_DL_LAZY 1
14268 +#define VCOS_DL_NOW  2
14269 +
14270 +/**
14271 + * \file
14272 + *
14273 + * Loading dynamic libraries. See also dlfcn.h.
14274 + */
14275 +
14276 +/** Open a dynamic library.
14277 +  *
14278 +  * @param name  name of the library
14279 +  * @param mode  Load lazily or immediately (VCOS_DL_LAZY, VCOS_DL_NOW).
14280 +  *
14281 +  * @return A handle for use in subsequent calls.
14282 +  */
14283 +VCOSPRE_ void * VCOSPOST_ vcos_dlopen(const char *name, int mode);
14284 +
14285 +/** Look up a symbol.
14286 +  *
14287 +  * @param handle Handle to open
14288 +  * @param name   Name of function
14289 +  *
14290 +  * @return Function pointer, or NULL.
14291 +  */
14292 +VCOSPRE_ void VCOSPOST_ (*vcos_dlsym(void *handle, const char *name))(void);
14293 +
14294 +/** Close a library
14295 +  *
14296 +  * @param handle Handle to close
14297 +  */
14298 +VCOSPRE_ int VCOSPOST_ vcos_dlclose (void *handle);
14299 +
14300 +/** Return error message from library.
14301 +  *
14302 +  * @param err  On return, set to non-zero if an error has occurred
14303 +  * @param buf  Buffer to write error to
14304 +  * @param len  Size of buffer (including terminating NUL).
14305 +  */
14306 +VCOSPRE_ int VCOSPOST_ vcos_dlerror(int *err, char *buf, size_t buflen);
14307 +
14308 +
14309 +#ifdef __cplusplus
14310 +}
14311 +#endif
14312 +#endif
14313 +
14314 +
14315 --- /dev/null
14316 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_event.h
14317 @@ -0,0 +1,97 @@
14318 +/*=============================================================================
14319 +Copyright (c) 2009 Broadcom Europe Limited.
14320 +All rights reserved.
14321 +
14322 +Project  :  vcfw
14323 +Module   :  chip driver
14324 +
14325 +FILE DESCRIPTION
14326 +VideoCore OS Abstraction Layer - public header file for events
14327 +=============================================================================*/
14328 +
14329 +#ifndef VCOS_EVENT_H
14330 +#define VCOS_EVENT_H
14331 +
14332 +#ifdef __cplusplus
14333 +extern "C" {
14334 +#endif
14335 +
14336 +#include "interface/vcos/vcos_types.h"
14337 +#include "vcos_platform.h"
14338 +
14339 +/** 
14340 +  * \file
14341 +  *
14342 +  * An event is akin to the Win32 auto-reset event.
14343 +  *
14344 +  *
14345 +  * Signalling an event will wake up one waiting thread only. Once one
14346 +  * thread has been woken the event atomically returns to the unsignalled
14347 +  * state.
14348 +  * 
14349 +  * If no threads are waiting on the event when it is signalled it remains
14350 +  * signalled.
14351 +  *
14352 +  * This is almost, but not quite, completely unlike the "event flags"
14353 +  * object based on Nucleus event groups and ThreadX event flags.
14354 +  *
14355 +  * In particular, it should be similar in speed to a semaphore, unlike
14356 +  * the event flags.
14357 +  */
14358 +
14359 +/**
14360 +  * Create an event instance.
14361 +  *
14362 +  * @param event  Filled in with constructed event.
14363 +  * @param name   Name of the event (for debugging)
14364 +  *
14365 +  * @return VCOS_SUCCESS on success, or error code.
14366 +  */
14367 +VCOS_INLINE_DECL
14368 +VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *name);
14369 +
14370 +#ifndef vcos_event_signal
14371 +
14372 +/**
14373 +  * Signal the event. The event will return to being unsignalled
14374 +  * after exactly one waiting thread has been woken up. If no
14375 +  * threads are waiting it remains signalled.
14376 +  *
14377 +  * @param event The event to signal
14378 +  */
14379 +VCOS_INLINE_DECL
14380 +void vcos_event_signal(VCOS_EVENT_T *event);
14381 +
14382 +/**
14383 +  * Wait for the event.
14384 +  *
14385 +  * @param event The event to wait for
14386 +  * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the wait was interrupted.
14387 +  */
14388 +VCOS_INLINE_DECL
14389 +VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event);
14390 +
14391 +/**
14392 +  * Try event, but don't block.
14393 +  *
14394 +  * @param event The event to try
14395 +  * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the event is not currently signalled
14396 +  */
14397 +VCOS_INLINE_DECL
14398 +VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event);
14399 +
14400 +#endif
14401 +
14402 +/*
14403 + * Destroy an event.
14404 + */
14405 +VCOS_INLINE_DECL
14406 +void vcos_event_delete(VCOS_EVENT_T *event);
14407 +
14408 +#ifdef __cplusplus
14409 +}
14410 +#endif
14411 +
14412 +#endif
14413 +
14414 +
14415 --- /dev/null
14416 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_event_flags.h
14417 @@ -0,0 +1,98 @@
14418 +/*=============================================================================
14419 +Copyright (c) 2009 Broadcom Europe Limited.
14420 +All rights reserved.
14421 +
14422 +Project  :  vcfw
14423 +Module   :  chip driver
14424 +
14425 +FILE DESCRIPTION
14426 +VideoCore OS Abstraction Layer - public header file
14427 +=============================================================================*/
14428 +
14429 +#ifndef VCOS_EVENT_FLAGS_H
14430 +#define VCOS_EVENT_FLAGS_H
14431 +
14432 +
14433 +#ifdef __cplusplus
14434 +extern "C" {
14435 +#endif
14436 +
14437 +#include "interface/vcos/vcos_types.h"
14438 +#include "vcos_platform.h"
14439 +
14440 +#define VCOS_EVENT_FLAGS_SUSPEND    VCOS_SUSPEND
14441 +#define VCOS_EVENT_FLAGS_NO_SUSPEND VCOS_NO_SUSPEND
14442 +typedef VCOS_OPTION VCOS_EVENTGROUP_OPERATION_T;
14443 +
14444 +/**
14445 + * \file vcos_event_flags.h
14446 + *
14447 + * Defines event flags API.
14448 + *
14449 + * Similar to Nucleus event groups.
14450 + *
14451 + * These have the same semantics as Nucleus event groups and ThreadX event
14452 + * flags. As such, they are quite complex internally; if speed is important
14453 + * they might not be your best choice.
14454 + *
14455 + */
14456 +
14457 +/**
14458 + * Create an event flags instance.
14459 + *
14460 + * @param flags   Pointer to event flags instance, filled in on return.
14461 + * @param name    Name for the event flags, used for debug.
14462 + *
14463 + * @return VCOS_SUCCESS if succeeded.
14464 + */
14465 +
14466 +VCOS_INLINE_DECL
14467 +VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name);
14468 +
14469 +/**
14470 +  * Set some events.
14471 +  *
14472 +  * @param flags   Instance to set flags on
14473 +  * @param events  Bitmask of the flags to actually set
14474 +  * @param op      How the flags should be set. VCOS_OR will OR in the flags; VCOS_AND
14475 +  *                will AND them in, possibly clearing existing flags.
14476 +  */
14477 +VCOS_INLINE_DECL
14478 +void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
14479 +                          VCOS_UNSIGNED events,
14480 +                          VCOS_OPTION op);
14481 +
14482 +/**
14483 + * Retrieve some events.
14484 + *
14485 + * Waits until the specified events have been set.
14486 + *
14487 + * @param flags            Instance to wait on
14488 + * @param requested_events The bitmask to wait for
14489 + * @param op               VCOS_OR - get any; VCOS_AND - get all.
14490 + * @param ms_suspend       How long to wait, in milliseconds
14491 + * @param retrieved_events the events actually retrieved.
14492 + *
14493 + * @return VCOS_SUCCESS if events were retrieved. VCOS_EAGAIN if the
14494 + * timeout expired.
14495 + */
14496 +VCOS_INLINE_DECL
14497 +VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
14498 +                                                     VCOS_UNSIGNED requested_events,
14499 +                                                     VCOS_OPTION op,
14500 +                                                     VCOS_UNSIGNED ms_suspend,
14501 +                                                     VCOS_UNSIGNED *retrieved_events);
14502 +
14503 +
14504 +/**
14505 + * Delete an event flags instance.
14506 + */
14507 +VCOS_INLINE_DECL
14508 +void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *);
14509 +
14510 +#ifdef __cplusplus
14511 +}
14512 +#endif
14513 +
14514 +#endif
14515 +
14516 --- /dev/null
14517 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_init.h
14518 @@ -0,0 +1,43 @@
14519 +/*=============================================================================
14520 +Copyright (c) 2009 Broadcom Europe Limited.
14521 +All rights reserved.
14522 +
14523 +Project  :  vcfw
14524 +Module   :  chip driver
14525 +
14526 +FILE DESCRIPTION
14527 +VideoCore OS Abstraction Layer - initialization routines
14528 +=============================================================================*/
14529 +
14530 +
14531 +#include "interface/vcos/vcos_types.h"
14532 +#include "vcos_platform.h"
14533 +
14534 +#ifdef __cplusplus
14535 +extern "C" {
14536 +#endif
14537 +
14538 +/** \file
14539 +  *
14540 +  * Some OS support libraries need some initialization. To support this, call this
14541 +  * function at the start of day.
14542 +  */
14543 +
14544 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_init(void);
14545 +VCOSPRE_ void VCOSPOST_ vcos_deinit(void);
14546 +VCOSPRE_ void VCOSPOST_ vcos_global_lock(void);
14547 +VCOSPRE_ void VCOSPOST_ vcos_global_unlock(void);
14548 +
14549 +/** Pass in the argv/argc arguments passed to main() */
14550 +VCOSPRE_ void VCOSPOST_ vcos_set_args(int argc, const char **argv);
14551 +
14552 +/** Return argc. */
14553 +VCOSPRE_ int VCOSPOST_ vcos_get_argc(void);
14554 +
14555 +/** Return argv. */
14556 +VCOSPRE_ const char ** VCOSPOST_ vcos_get_argv(void);
14557 +
14558 +#ifdef __cplusplus
14559 +}
14560 +#endif
14561 +
14562 --- /dev/null
14563 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_logging.h
14564 @@ -0,0 +1,279 @@
14565 +/*=============================================================================
14566 +Copyright (c) 2009-2011 Broadcom Europe Limited.
14567 +All rights reserved.
14568 +
14569 +Project  :  vcfw
14570 +Module   :  chip driver
14571 +
14572 +FILE DESCRIPTION
14573 +VideoCore OS Abstraction Layer - logging support
14574 +=============================================================================*/
14575 +
14576 +#ifndef VCOS_LOGGING_H
14577 +#define VCOS_LOGGING_H
14578 +
14579 +#ifdef __cplusplus
14580 +extern "C" {
14581 +#endif
14582 +
14583 +#include <stdarg.h>
14584 +
14585 +#include "interface/vcos/vcos_types.h"
14586 +#include "vcos_platform.h"
14587 +
14588 +/**
14589 + * \file
14590 + *
14591 + * Logging support
14592 + *
14593 + * This provides categorised logging. Clients register
14594 + * a category, and then get a number of logging levels for
14595 + * that category.
14596 + *
14597 + * The logging level flag is tested using a flag *before* the
14598 + * function call, which makes logging very fast when disabled - there
14599 + * is no function call overhead just to find out that this log
14600 + * message is disabled.
14601 + *
14602 + * \section VCOS_LOG_CATEGORY
14603 + *
14604 + * As a convenience, clients define VCOS_LOG_CATEGORY to point to
14605 + * their category; the various vcos_log_xxx() macros then expand to
14606 + * use this.
14607 + *
14608 + * e.g.
14609 + *
14610 + *     #define VCOS_LOG_CATEGORY (&my_category)
14611 + *
14612 + *     #include <interface/vcos/vcos.h>
14613 + *
14614 + *     VCOS_LOG_CAT_T my_category;
14615 + *
14616 + *     ....
14617 + *
14618 + *     vcos_log_trace("Stuff happened: %d", n_stuff);
14619 + *
14620 + */
14621 +
14622 +/** Logging levels */
14623 +typedef enum VCOS_LOG_LEVEL_T
14624 +{
14625 +   VCOS_LOG_UNINITIALIZED   = 0,
14626 +   VCOS_LOG_NEVER,
14627 +   VCOS_LOG_ERROR,
14628 +   VCOS_LOG_WARN,
14629 +   VCOS_LOG_INFO,
14630 +   VCOS_LOG_TRACE,
14631 +} VCOS_LOG_LEVEL_T;
14632 +
14633 +
14634 +/** Initialize a logging category without going through vcos_log_register().
14635 + *
14636 + * This is useful for the case where there is no obvious point to do the
14637 + * registration (no initialization function for the module). However, it
14638 + * means that your logging category is not registered, so cannot be easily
14639 + * changed at run-time.
14640 + */
14641 +#define VCOS_LOG_INIT(n,l) { l, n, 0, {0}, 0, 0 }
14642 +
14643 +/** A registered logging category.
14644 +  */
14645 +typedef struct VCOS_LOG_CAT_T
14646 +{
14647 +   VCOS_LOG_LEVEL_T level;      /** Which levels are enabled for this category */
14648 +   const char *name;            /** Name for this category. */
14649 +   struct VCOS_LOG_CAT_T *next;
14650 +   struct {
14651 +      unsigned int want_prefix:1;
14652 +   } flags;
14653 +   unsigned int refcount;
14654 +   void *platform_data;         /** platform specific data */
14655 +} VCOS_LOG_CAT_T;
14656 +
14657 +typedef void (*VCOS_VLOG_IMPL_FUNC_T)(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args);
14658 +
14659 +/** Convert a VCOS_LOG_LEVEL_T into a printable string.
14660 +  * The platform needs to implement this function.
14661 +  */
14662 +VCOSPRE_ const char * VCOSPOST_ vcos_log_level_to_string( VCOS_LOG_LEVEL_T level );
14663 +
14664 +/** Convert a string into a VCOS_LOG_LEVEL_T
14665 +  * The platform needs to implement this function.
14666 +  */
14667 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level );
14668 +
14669 +/** Log a message. Basic API. Normal code should not use this.
14670 +  * The platform needs to implement this function.
14671 +  */
14672 +VCOSPRE_ void VCOSPOST_ vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...) VCOS_FORMAT_ATTR_(printf, 3, 4);
14673 +
14674 +/** Log a message using a varargs parameter list. Normal code should
14675 +  * not use this.
14676 +  */
14677 +VCOSPRE_ void VCOSPOST_ vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) VCOS_FORMAT_ATTR_(printf, 3, 0);
14678 +
14679 +/** Set the function which does the actual logging output.
14680 + *  Passing in NULL causes the default logging function to be
14681 + *  used.
14682 +  */
14683 +VCOSPRE_ void VCOSPOST_ vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func );
14684 +
14685 +/** The default logging function, which is provided by each
14686 +  * platform.
14687 +  */
14688 +
14689 +VCOSPRE_ void VCOSPOST_ vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) VCOS_FORMAT_ATTR_(printf, 3, 0);
14690 +
14691 +/*
14692 + * Initialise the logging subsystem. This is called from
14693 + * vcos_init() so you don't normally need to call it.
14694 + */
14695 +VCOSPRE_ void VCOSPOST_ vcos_logging_init(void);
14696 +
14697 +/** Register a logging category.
14698 +  *
14699 +  * @param name the name of this category.
14700 +  * @param category the category to register.
14701 +  */
14702 +VCOSPRE_ void VCOSPOST_ vcos_log_register(const char *name, VCOS_LOG_CAT_T *category);
14703 +
14704 +/** Unregister a logging category.
14705 +  */
14706 +VCOSPRE_ void VCOSPOST_ vcos_log_unregister(VCOS_LOG_CAT_T *category);
14707 +
14708 +/** Return a default logging category, for people too lazy to create their own.
14709 +  *
14710 +  * Using the default category will be slow (there's an extra function
14711 +  * call overhead). Don't do this in normal code.
14712 +  */
14713 +VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void);
14714 +
14715 +VCOSPRE_ void VCOSPOST_ vcos_set_log_options(const char *opt);
14716 +
14717 +/** Set the logging level for a category at run time. Without this, the level
14718 +  * will be that set by vcos_log_register from a platform-specific source.
14719 +  *
14720 +  * @param category the category to modify.
14721 +  * @param level the new logging level for this category.
14722 +  */
14723 +VCOS_STATIC_INLINE void vcos_log_set_level(VCOS_LOG_CAT_T *category, VCOS_LOG_LEVEL_T level)
14724 +{
14725 +   category->level = level;
14726 +}
14727 +
14728 +#define vcos_log_dump_mem(cat,label,addr,voidMem,numBytes)  do { if (vcos_is_log_enabled(cat,VCOS_LOG_TRACE)) vcos_log_dump_mem_impl(cat,label,addr,voidMem,numBytes); } while (0)
14729 +
14730 +void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
14731 +                             const char           *label,
14732 +                             uint32_t              addr,
14733 +                             const void           *voidMem,
14734 +                             size_t                numBytes );
14735 +
14736 +/*
14737 + * Platform specific hooks (optional).
14738 + */
14739 +#ifndef vcos_log_platform_init
14740 +#define vcos_log_platform_init()                (void)0
14741 +#endif
14742 +
14743 +#ifndef vcos_log_platform_register
14744 +#define vcos_log_platform_register(category)    (void)0
14745 +#endif
14746 +
14747 +#ifndef vcos_log_platform_unregister
14748 +#define vcos_log_platform_unregister(category)  (void)0
14749 +#endif
14750 +
14751 +/* VCOS_TRACE() - deprecated macro which just outputs in a debug build and
14752 + * is a no-op in a release build.
14753 + *
14754 + * _VCOS_LOG_X() - internal macro which outputs if the current level for the
14755 + * particular category is higher than the supplied message level.
14756 + */
14757 +
14758 +#define VCOS_LOG_DFLT_CATEGORY vcos_log_get_default_category()
14759 +
14760 +#define _VCOS_LEVEL(x) (x)
14761 +
14762 +#define vcos_is_log_enabled(cat,_level)  (_VCOS_LEVEL((cat)->level) >= _VCOS_LEVEL(_level))
14763 +
14764 +#if defined(_VCOS_METAWARE) || defined(__GNUC__)
14765 +
14766 +# if !defined(NDEBUG) || defined(VCOS_ALWAYS_WANT_LOGGING)
14767 +#  define VCOS_LOGGING_ENABLED
14768 +#  define _VCOS_LOG_X(cat, _level, fmt...)   do { if (vcos_is_log_enabled(cat,_level)) vcos_log_impl(cat,_level,fmt); } while (0)
14769 +#  define _VCOS_VLOG_X(cat, _level, fmt, ap) do { if (vcos_is_log_enabled(cat,_level)) vcos_vlog_impl(cat,_level,fmt,ap); } while (0)
14770 +# else
14771 +#  define _VCOS_LOG_X(cat, _level, fmt...) (void)0
14772 +#  define _VCOS_VLOG_X(cat, _level, fmt, ap) (void)0
14773 +# endif
14774 +
14775 +
14776 +
14777 +# define vcos_log_error(...)   _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, __VA_ARGS__)
14778 +# define vcos_log_warn(...)    _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, __VA_ARGS__)
14779 +# define vcos_log_info(...)    _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
14780 +# define vcos_log_trace(...)   _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, __VA_ARGS__)
14781 +
14782 +# define vcos_vlog_error(fmt,ap)  _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, fmt, ap)
14783 +# define vcos_vlog_warn(fmt,ap)   _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, fmt, ap)
14784 +# define vcos_vlog_info(fmt,ap)   _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, fmt, ap)
14785 +# define vcos_vlog_trace(fmt,ap)  _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, fmt, ap)
14786 +
14787 +# define vcos_log(...)   _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
14788 +# define vcos_vlog(fmt,ap)  _VCOS_VLOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt, ap)
14789 +# define VCOS_ALERT(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_ERROR, __VA_ARGS__)
14790 +# define VCOS_TRACE(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
14791 +
14792 +/*
14793 + * MS Visual Studio - pre 2005 does not grok variadic macros
14794 + */
14795 +#elif defined(_MSC_VER)
14796 +
14797 +# if _MSC_VER >= 1400
14798 +
14799 +#  if !defined(NDEBUG) || defined(VCOS_ALWAYS_WANT_LOGGING)
14800 +#   define VCOS_LOGGING_ENABLED
14801 +#   define _VCOS_LOG_X(cat, _level, fmt,...) do { if (vcos_is_log_enabled(cat,_level)) vcos_log_impl(cat, _level, fmt, __VA_ARGS__); } while (0)
14802 +#  else
14803 +#   define _VCOS_LOG_X(cat, _level, fmt,...) (void)0
14804 +#  endif
14805 +
14806 +# define vcos_log_error(fmt,...)   _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, fmt, __VA_ARGS__)
14807 +# define vcos_log_warn(fmt,...)    _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, fmt, __VA_ARGS__)
14808 +# define vcos_log_info(fmt,...)    _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, fmt, __VA_ARGS__)
14809 +# define vcos_log_trace(fmt,...)   _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, fmt, __VA_ARGS__)
14810 +
14811 +# define vcos_log(fmt,...)   _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt)
14812 +# define VCOS_ALERT(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_ERROR, fmt)
14813 +# define VCOS_TRACE(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt)
14814 +
14815 +# else /* _MSC_VER >= 1400 */
14816 +
14817 +/* do not define these */
14818 +
14819 +# endif /* _MSC_VER >= 1400 */
14820 +
14821 +#endif
14822 +
14823 +#if VCOS_HAVE_CMD
14824 +
14825 +#include "interface/vcos/vcos_cmd.h"
14826 +
14827 +/*
14828 + * These are the log sub-commands. They're exported here for user-mode apps which 
14829 + * may want to call these, since the "log" command isn't registered for user-mode 
14830 + * apps (vcdbg for example, has its own log command). 
14831 + */
14832 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param );
14833 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_set_cmd( VCOS_CMD_PARAM_T *param );
14834 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_status_cmd( VCOS_CMD_PARAM_T *param );
14835 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_test_cmd( VCOS_CMD_PARAM_T *param );
14836 +#endif
14837 +
14838 +#ifdef __cplusplus
14839 +}
14840 +#endif
14841 +#endif /* VCOS_LOGGING_H */
14842 +
14843 +
14844 --- /dev/null
14845 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_lowlevel_thread.h
14846 @@ -0,0 +1,107 @@
14847 +/*=============================================================================
14848 +Copyright (c) 2009 Broadcom Europe Limited.
14849 +All rights reserved.
14850 +
14851 +Project  :  vcfw
14852 +Module   :  chip driver
14853 +
14854 +FILE DESCRIPTION
14855 +VideoCore OS Abstraction Layer - low level thread support
14856 +=============================================================================*/
14857 +
14858 +#ifndef VCOS_LOWLEVEL_THREAD_H
14859 +#define VCOS_LOWLEVEL_THREAD_H
14860 +
14861 +#ifdef __cplusplus
14862 +extern "C" {
14863 +#endif
14864 +
14865 +#include "interface/vcos/vcos_types.h"
14866 +#include "vcos_platform.h"
14867 +
14868 +/**
14869 + * \file
14870 + *
14871 + * This defines a low level thread API that is supported by *some* operating systems
14872 + * and can be used to construct the regular "joinable thread" API on those operating
14873 + * systems.
14874 + *
14875 + * Most clients will not need to use this code.
14876 + *
14877 + * \sa vcos_joinable_thread.h
14878 + */
14879 +
14880 +/**
14881 +  * \brief Create a thread.
14882 +  *
14883 +  * This creates a thread which can be stopped either by returning from the
14884 +  * entry point function or by calling vcos_llthread_exit from within the entry
14885 +  * point function. The thread must be cleaned up by calling
14886 +  * vcos_llthread_delete. vcos_llthread_delete may or may not terminate the
14887 +  * thread.
14888 +  *
14889 +  * The preemptible parameter familiar from Nucleus is removed, as it is unused in
14890 +  *  VideoCore code. Affinity is added, since we do use this.
14891 +  *
14892 +  * @param thread       Filled in with thread instance
14893 +  * @param name         An optional name for the thread. "" may be used (but
14894 +  *                     a name will aid in debugging).
14895 +  * @param entry        Entry point
14896 +  * @param arg          A single argument passed to the entry point function
14897 +  * @param stack        Pointer to stack address
14898 +  * @param stacksz      Size of stack in bytes
14899 +  * @param priority     Priority of task, between VCOS_PRI_LOW and VCOS_PRI_HIGH
14900 +  * @param affinity     CPU affinity
14901 +  *
14902 +  * @sa vcos_llthread_terminate vcos_llthread_delete
14903 +  */
14904 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_llthread_create(VCOS_LLTHREAD_T *thread,
14905 +                                                      const char *name,
14906 +                                                      VCOS_LLTHREAD_ENTRY_FN_T entry,
14907 +                                                      void *arg,
14908 +                                                      void *stack,
14909 +                                                      VCOS_UNSIGNED stacksz,
14910 +                                                      VCOS_UNSIGNED priority,
14911 +                                                      VCOS_UNSIGNED affinity,
14912 +                                                      VCOS_UNSIGNED timeslice,
14913 +                                                      VCOS_UNSIGNED autostart);
14914 +
14915 +/**
14916 +  * \brief Exits the current thread.
14917 +  */
14918 +VCOSPRE_ void VCOSPOST_ vcos_llthread_exit(void);
14919 +
14920 +/**
14921 +  * \brief Delete a thread. This must be called to cleanup after
14922 +  * vcos_llthread_create. This may or may not terminate the thread.
14923 +  * It does not clean up any resources that may have been
14924 +  * allocated by the thread.
14925 +  */
14926 +VCOSPRE_ void VCOSPOST_ vcos_llthread_delete(VCOS_LLTHREAD_T *thread);
14927 +
14928 +/**
14929 +  * \brief Return current lowlevel thread pointer.
14930 +  */
14931 +VCOS_INLINE_DECL
14932 +VCOS_LLTHREAD_T *vcos_llthread_current(void);
14933 +
14934 +/**
14935 +  * Resume a thread.
14936 +  */
14937 +VCOS_INLINE_DECL
14938 +void vcos_llthread_resume(VCOS_LLTHREAD_T *thread);
14939 +
14940 +VCOSPRE_ int VCOSPOST_ vcos_llthread_running(VCOS_LLTHREAD_T *thread);
14941 +
14942 +/**
14943 +  * \brief Create a VCOS_LLTHREAD_T for the current thread. This is so we can
14944 +  * have VCOS_LLTHREAD_Ts even for threads not originally created by VCOS (eg
14945 +  * the thread that calls vcos_init).
14946 +  */
14947 +extern VCOS_STATUS_T _vcos_llthread_create_attach(VCOS_LLTHREAD_T *thread);
14948 +
14949 +#ifdef __cplusplus
14950 +}
14951 +#endif
14952 +#endif
14953 +
14954 --- /dev/null
14955 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_mem.h
14956 @@ -0,0 +1,81 @@
14957 +/*=============================================================================
14958 +Copyright (c) 2009 Broadcom Europe Limited.
14959 +All rights reserved.
14960 +
14961 +Project  :  vcfw
14962 +Module   :  chip driver
14963 +
14964 +FILE DESCRIPTION
14965 +VideoCore OS Abstraction Layer - memory support
14966 +=============================================================================*/
14967 +
14968 +#ifndef VCOS_MEM_H
14969 +#define VCOS_MEM_H
14970 +
14971 +#ifdef __cplusplus
14972 +extern "C" {
14973 +#endif
14974 +
14975 +#include "interface/vcos/vcos_types.h"
14976 +#include "vcos_platform.h"
14977 +
14978 +/** \file
14979 +  *
14980 +  * Memory allocation api (malloc/free equivalents) is for benefit of host
14981 +  * applications. VideoCore code should use rtos_XXX functions.
14982 +  *
14983 +  */
14984 +
14985 +
14986 +/** Allocate memory
14987 +  *
14988 +  * @param size Size of memory to allocate
14989 +  * @param description Description, to aid in debugging. May be ignored internally on some platforms.
14990 +  */
14991 +VCOS_INLINE_DECL
14992 +void *vcos_malloc(VCOS_UNSIGNED size, const char *description);
14993 +
14994 +void *vcos_kmalloc(VCOS_UNSIGNED size, const char *description);
14995 +void *vcos_kcalloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description);
14996 +
14997 +/** Allocate cleared memory
14998 +  *
14999 +  * @param num Number of items to allocate.
15000 +  * @param size Size of each item in bytes.
15001 +  * @param description Description, to aid in debugging. May be ignored internally on some platforms.
15002 +  */
15003 +VCOS_INLINE_DECL
15004 +void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description);
15005 +
15006 +/** Free memory
15007 +  *
15008 +  * Free memory that has been allocated.
15009 +  */
15010 +VCOS_INLINE_DECL
15011 +void vcos_free(void *ptr);
15012 +
15013 +void vcos_kfree(void *ptr);
15014 +
15015 +/** Allocate aligned memory
15016 +  *
15017 +  * Allocate memory aligned on the specified boundary.
15018 +  *
15019 +  * @param size Size of memory to allocate
15020 +  * @param description Description, to aid in debugging. May be ignored internally on some platforms.
15021 +  */
15022 +VCOS_INLINE_DECL
15023 +void *vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description);
15024 +
15025 +/** Return the amount of free heap memory
15026 +  *
15027 +  */
15028 +VCOS_INLINE_DECL
15029 +unsigned long vcos_get_free_mem(void);
15030 +
15031 +#ifdef __cplusplus
15032 +}
15033 +#endif
15034 +
15035 +#endif
15036 +
15037 +
15038 --- /dev/null
15039 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_msgqueue.h
15040 @@ -0,0 +1,157 @@
15041 +/*=============================================================================
15042 +Copyright (c) 2009 Broadcom Europe Limited.
15043 +All rights reserved.
15044 +
15045 +Project  :  vcfw
15046 +Module   :  chip driver
15047 +
15048 +FILE DESCRIPTION
15049 +VCOS - packet-like messages, based loosely on those found in TRIPOS.
15050 +=============================================================================*/
15051 +
15052 +#ifndef VCOS_MSGQUEUE_H
15053 +#define VCOS_MSGQUEUE_H
15054 +
15055 +#ifdef __cplusplus
15056 +extern "C" {
15057 +#endif
15058 +
15059 +#include "interface/vcos/vcos_types.h"
15060 +#include "vcos_platform.h"
15061 +
15062 +/**
15063 + * \file
15064 + *
15065 + * Packet-like messages, based loosely on those found in TRIPOS and
15066 + * derivatives thereof.
15067 + *
15068 + * A task can send a message *pointer* to another task, where it is
15069 + * queued on a linked list and the task woken up. The receiving task
15070 + * consumes all of the messages on its input queue, and optionally
15071 + * sends back replies using the original message memory.
15072 + *
15073 + * A caller can wait for the reply to a specific message - any other
15074 + * messages that arrive in the meantime are queued separately.
15075 + *
15076 + *
15077 + * All messages have a standard common layout, but the payload area can
15078 + * be used freely to extend this.
15079 + */
15080 +
15081 +/** Map the payload portion of a message to a structure pointer.
15082 +  */
15083 +#define VCOS_MSG_DATA(_msg) (void*)((_msg)->data)
15084 +
15085 +/** Standard message ids - FIXME - these need to be done properly! */
15086 +#define VCOS_MSG_N_QUIT            1
15087 +#define VCOS_MSG_N_OPEN            2
15088 +#define VCOS_MSG_N_CLOSE           3
15089 +#define VCOS_MSG_N_PRIVATE         (1<<20)
15090 +
15091 +#define VCOS_MSG_REPLY_BIT         (1<<31)
15092 +
15093 +/** Make gnuc compiler be happy about pointer punning */
15094 +#ifdef __GNUC__
15095 +#define __VCOS_MAY_ALIAS __attribute__((__may_alias__))
15096 +#else
15097 +#define __VCOS_MAY_ALIAS
15098 +#endif
15099 +
15100 +/** A single message queue.
15101 +  */
15102 +typedef struct VCOS_MSGQUEUE_T
15103 +{
15104 +   struct VCOS_MSG_T *head;            /**< head of linked list of messages waiting on this queue */
15105 +   struct VCOS_MSG_T *tail;            /**< tail of message queue */
15106 +   VCOS_SEMAPHORE_T sem;               /**< thread waits on this for new messages */
15107 +   VCOS_MUTEX_T lock;                  /**< locks the messages list */
15108 +} VCOS_MSGQUEUE_T;
15109 +
15110 +/** A single message
15111 +  */
15112 +typedef struct VCOS_MSG_T
15113 +{
15114 +   uint32_t code;                      /**< message code */
15115 +   int error;                          /**< error status signalled back to caller */
15116 +   VCOS_MSGQUEUE_T *dst;               /**< destination queue */
15117 +   VCOS_MSGQUEUE_T *src;               /**< source; replies go back to here */
15118 +   struct VCOS_MSG_T *next;            /**< next in queue */
15119 +   VCOS_THREAD_T *src_thread;          /**< for debug */
15120 +   uint32_t data[25];                  /**< payload area */
15121 +} VCOS_MSG_T;
15122 +   
15123 +/** An endpoint
15124 +  */
15125 +typedef struct VCOS_MSG_ENDPOINT_T
15126 +{
15127 +   VCOS_MSGQUEUE_T primary;            /**< incoming messages */
15128 +   VCOS_MSGQUEUE_T secondary;          /**< this is used for waitspecific */
15129 +   char name[32];                      /**< name of this endpoint, for find() */
15130 +   struct VCOS_MSG_ENDPOINT_T *next;   /**< next in global list of endpoints */
15131 +} VCOS_MSG_ENDPOINT_T;
15132 +#define MSG_REPLY_BIT (1<<31)
15133 +
15134 +/** Initalise the library. Normally called from vcos_init().
15135 +  */
15136 +extern VCOS_STATUS_T vcos_msgq_init(void);
15137 +
15138 +/** Find a message queue by name and get a handle to it.
15139 +  *
15140 +  * @param name  the name of the queue to find
15141 +  *
15142 +  * @return The message queue, or NULL if not found.
15143 +  */
15144 +VCOSPRE_ VCOS_MSGQUEUE_T VCOSPOST_ *vcos_msgq_find(const char *name);
15145 +
15146 +/** Wait for a message queue to come into existence. If it already exists,
15147 +  * return immediately, otherwise block.
15148 +  *
15149 +  * On the whole, if you find yourself using this, it is probably a sign
15150 +  * of poor design, since you should create all the server threads first,
15151 +  * and then the client threads. But it is sometimes useful.
15152 +  *
15153 +  * @param name  the name of the queue to find
15154 +  * @return The message queue
15155 +  */
15156 +VCOSPRE_ VCOS_MSGQUEUE_T VCOSPOST_ *vcos_msgq_wait(const char *name);
15157 +
15158 +/** Send a message.
15159 +  */
15160 +VCOSPRE_ void VCOSPOST_ vcos_msg_send(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg);
15161 +
15162 +/** Send a message and wait for a reply.
15163 +  */
15164 +VCOSPRE_ void VCOSPOST_ vcos_msg_sendwait(VCOS_MSGQUEUE_T *queue, uint32_t code, VCOS_MSG_T *msg);
15165 +
15166 +/** Wait for a message on this thread's endpoint.
15167 +  */
15168 +VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_wait(void);
15169 +
15170 +/** Wait for a specific message.
15171 +  */
15172 +VCOS_MSG_T * vcos_msg_wait_specific(VCOS_MSGQUEUE_T *queue, VCOS_MSG_T *msg);
15173 +
15174 +/** Peek for a message on this thread's endpoint, if a message is not available, NULL is 
15175 +    returned. If a message is available it will be removed from the endpoint and returned.
15176 +  */
15177 +VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_peek(void);
15178 +
15179 +/** Send a reply to a message
15180 +  */
15181 +VCOSPRE_ void VCOSPOST_ vcos_msg_reply(VCOS_MSG_T *msg);
15182 +
15183 +/** Create an endpoint. Each thread should need no more than one of these - if you 
15184 +  * find yourself needing a second one, you've done something wrong.
15185 +  */
15186 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_endpoint_create(VCOS_MSG_ENDPOINT_T *ep, const char *name);
15187 +
15188 +/** Destroy an endpoint.
15189 +  */
15190 +VCOSPRE_ void  VCOSPOST_ vcos_msgq_endpoint_delete(VCOS_MSG_ENDPOINT_T *ep);
15191 +
15192 +#ifdef __cplusplus
15193 +}
15194 +#endif
15195 +#endif
15196 +
15197 +
15198 --- /dev/null
15199 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_mutex.h
15200 @@ -0,0 +1,92 @@
15201 +/*=============================================================================
15202 +Copyright (c) 2009 Broadcom Europe Limited.
15203 +All rights reserved.
15204 +
15205 +Project  :  vcfw
15206 +Module   :  chip driver
15207 +
15208 +FILE DESCRIPTION
15209 +VideoCore OS Abstraction Layer - mutex public header file
15210 +=============================================================================*/
15211 +
15212 +#ifndef VCOS_MUTEX_H
15213 +#define VCOS_MUTEX_H
15214 +
15215 +#ifdef __cplusplus
15216 +extern "C" {
15217 +#endif
15218 +
15219 +#include "interface/vcos/vcos_types.h"
15220 +#include "vcos_platform.h"
15221 +
15222 +/**
15223 + * \file vcos_mutex.h
15224 + *
15225 + * Mutex API. Mutexes are not re-entrant, as supporting this adds extra code
15226 + * that slows down clients which have been written sensibly.
15227 + *
15228 + * \sa vcos_reentrant_mutex.h
15229 + *
15230 + */
15231 +
15232 +/** Create a mutex.
15233 +  *
15234 +  * @param m      Filled in with mutex on return
15235 +  * @param name   A non-null name for the mutex, used for diagnostics.
15236 +  *
15237 +  * @return VCOS_SUCCESS if mutex was created, or error code.
15238 +  */
15239 +VCOS_INLINE_DECL
15240 +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *m, const char *name);
15241 +
15242 +/** Delete the mutex.
15243 +  */
15244 +VCOS_INLINE_DECL
15245 +void vcos_mutex_delete(VCOS_MUTEX_T *m);
15246 +
15247 +/**
15248 +  * \brief Wait to claim the mutex.
15249 +  *
15250 +  * On most platforms this always returns VCOS_SUCCESS, and so would ideally be
15251 +  * a void function, however some platforms allow a wait to be interrupted so
15252 +  * it remains non-void.
15253 +  *
15254 +  * Try to obtain the mutex.
15255 +  * @param m   Mutex to wait on
15256 +  * @return VCOS_SUCCESS - mutex was taken.
15257 +  *         VCOS_EAGAIN  - could not take mutex.
15258 +  */
15259 +#ifndef vcos_mutex_lock
15260 +VCOS_INLINE_DECL
15261 +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *m);
15262 +
15263 +/** Release the mutex.
15264 +  */
15265 +VCOS_INLINE_DECL
15266 +void vcos_mutex_unlock(VCOS_MUTEX_T *m);
15267 +#endif
15268 +
15269 +/** Test if the mutex is already locked.
15270 +  *
15271 +  * @return 1 if mutex is locked, 0 if it is unlocked.
15272 +  */
15273 +VCOS_INLINE_DECL
15274 +int vcos_mutex_is_locked(VCOS_MUTEX_T *m);
15275 +
15276 +/** Obtain the mutex if possible.
15277 +  *
15278 +  * @param m  the mutex to try to obtain
15279 +  *
15280 +  * @return VCOS_SUCCESS if mutex is succesfully obtained, or VCOS_EAGAIN
15281 +  * if it is already in use by another thread.
15282 +  */
15283 +#ifndef vcos_mutex_trylock
15284 +VCOS_INLINE_DECL
15285 +VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m);
15286 +#endif
15287 +
15288 +
15289 +#ifdef __cplusplus
15290 +}
15291 +#endif
15292 +#endif
15293 --- /dev/null
15294 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_once.h
15295 @@ -0,0 +1,42 @@
15296 +/*=============================================================================
15297 +Copyright (c) 2011 Broadcom Europe Limited.
15298 +All rights reserved.
15299 +
15300 +Project  :  vcfw
15301 +Module   :  chip driver
15302 +
15303 +FILE DESCRIPTION
15304 +VideoCore OS Abstraction Layer - 'once'
15305 +=============================================================================*/
15306 +
15307 +#ifndef VCOS_ONCE_H
15308 +#define VCOS_ONCE_H
15309 +
15310 +#ifdef __cplusplus
15311 +extern "C" {
15312 +#endif
15313 +
15314 +#include "interface/vcos/vcos_types.h"
15315 +#include "vcos_platform.h"
15316 +
15317 +/**
15318 + * \file vcos_once.h
15319 + *
15320 + * Ensure something is called only once.
15321 + *
15322 + * Initialize once_control to VCOS_ONCE_INIT. The first
15323 + * time this is called, the init_routine will be called. Thereafter
15324 + * it won't.
15325 + *
15326 + * \sa pthread_once()
15327 + *
15328 + */
15329 +
15330 +VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
15331 +                        void (*init_routine)(void));
15332 +
15333 +#ifdef __cplusplus
15334 +}
15335 +#endif
15336 +#endif
15337 +
15338 --- /dev/null
15339 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_semaphore.h
15340 @@ -0,0 +1,115 @@
15341 +/*=============================================================================
15342 +Copyright (c) 2009 Broadcom Europe Limited.
15343 +All rights reserved.
15344 +
15345 +Project  :  vcfw
15346 +Module   :  chip driver
15347 +
15348 +FILE DESCRIPTION
15349 +VideoCore OS Abstraction Layer - public header file
15350 +=============================================================================*/
15351 +
15352 +#ifndef VCOS_SEMAPHORE_H
15353 +#define VCOS_SEMAPHORE_H
15354 +
15355 +#ifdef __cplusplus
15356 +extern "C" {
15357 +#endif
15358 +
15359 +#include "interface/vcos/vcos_types.h"
15360 +#include "vcos_platform.h"
15361 +
15362 +/**
15363 + * \file vcos_semaphore.h
15364 + *
15365 + * \section sem Semaphores
15366 + *
15367 + * This provides counting semaphores. Semaphores are not re-entrant. On sensible
15368 + * operating systems a semaphore can always be posted but can only be taken in 
15369 + * thread (not interrupt) context. Under Nucleus, a LISR cannot post a semaphore,
15370 + * although it would not be hard to lift this restriction.
15371 + *
15372 + * \subsection timeout Timeout
15373 + *
15374 + * On both Nucleus and ThreadX a semaphore can be taken with a timeout. This is
15375 + * not supported by VCOS because it makes the non-timeout code considerably more
15376 + * complicated (and hence slower). In the unlikely event that you need a timeout
15377 + * with a semaphore, and you cannot simply redesign your code to avoid it, use
15378 + * an event flag (vcos_event_flags.h).
15379 + *
15380 + * \subsection sem_nucleus Changes from Nucleus:
15381 + *
15382 + *  Semaphores are always "FIFO" - i.e. sleeping threads are woken in FIFO order. That's
15383 + *  because:
15384 + *  \arg there's no support for NU_PRIORITY in threadx (though it can be emulated, slowly)
15385 + *  \arg we don't appear to actually consciously use it - for example, Dispmanx uses
15386 + *  it, but all threads waiting are the same priority.
15387 + *         
15388 + */
15389 +
15390 +/** 
15391 +  * \brief Create a semaphore.
15392 +  *
15393 +  * Create a semaphore.
15394 +  *
15395 +  * @param sem   Pointer to memory to be initialized
15396 +  * @param name  A name for this semaphore. The name may be truncated internally.
15397 +  * @param count The initial count for the semaphore.
15398 +  *
15399 +  * @return VCOS_SUCCESS if the semaphore was created.
15400 +  * 
15401 +  */
15402 +VCOS_INLINE_DECL
15403 +VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
15404 +
15405 +/**
15406 +  * \brief Wait on a semaphore.
15407 +  *
15408 +  * There is no timeout option on a semaphore, as adding this will slow down
15409 +  * implementations on some platforms. If you need that kind of behaviour, use
15410 +  * an event group.
15411 +  *
15412 +  * On most platforms this always returns VCOS_SUCCESS, and so would ideally be
15413 +  * a void function, however some platforms allow a wait to be interrupted so
15414 +  * it remains non-void.
15415 +  *
15416 +  * @param sem Semaphore to wait on
15417 +  * @return VCOS_SUCCESS - semaphore was taken.
15418 +  *         VCOS_EAGAIN  - could not take semaphore
15419 +  *
15420 +  */
15421 +VCOS_INLINE_DECL
15422 +VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem);
15423 +
15424 +/**
15425 +  * \brief Try to wait for a semaphore.
15426 +  *
15427 +  * Try to obtain the semaphore. If it is already taken, return VCOS_TIMEOUT.
15428 +  * @param sem Semaphore to wait on
15429 +  * @return VCOS_SUCCESS - semaphore was taken.
15430 +  *         VCOS_EAGAIN - could not take semaphore
15431 +  */
15432 +VCOS_INLINE_DECL
15433 +VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem);
15434 +
15435 +/**
15436 +  * \brief Post a semaphore.
15437 +  *
15438 +  * @param sem Semaphore to wait on
15439 +  */
15440 +VCOS_INLINE_DECL
15441 +VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem);
15442 +
15443 +/**
15444 +  * \brief Delete a semaphore, releasing any resources consumed by it.
15445 +  *
15446 +  * @param sem Semaphore to wait on
15447 +  */
15448 +VCOS_INLINE_DECL
15449 +void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem);
15450 +
15451 +#ifdef __cplusplus
15452 +}
15453 +#endif
15454 +#endif
15455 +
15456 --- /dev/null
15457 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_stdbool.h
15458 @@ -0,0 +1,17 @@
15459 +#ifndef VCOS_STDBOOL_H
15460 +#define VCOS_STDBOOL_H
15461 +
15462 +#ifndef __cplusplus
15463 +
15464 +#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
15465 +#include <stdbool.h>
15466 +#else
15467 +typedef enum {
15468 +   false,
15469 +   true
15470 +} bool;
15471 +#endif
15472 +
15473 +#endif /* __cplusplus */
15474 +
15475 +#endif
15476 --- /dev/null
15477 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_stdint.h
15478 @@ -0,0 +1,193 @@
15479 +/*=============================================================================
15480 +Copyright (c) 2011 Broadcom Europe Limited.
15481 +All rights reserved.
15482 +
15483 +FILE DESCRIPTION
15484 +
15485 +=============================================================================*/
15486 +
15487 +#ifndef VCOS_STDINT_H
15488 +#define VCOS_STDINT_H
15489 +
15490 +/* Attempt to provide the types defined in stdint.h.
15491 + *
15492 + * Ideally this would either call out to a platform-specific
15493 + * header file (e.g. stdint.h) or define the types on a
15494 + * per-architecture/compiler basis. But for now we just
15495 + * use #ifdefs.
15496 + */
15497 +
15498 +#ifdef __cplusplus
15499 +extern "C" {
15500 +#endif
15501 +
15502 +#ifdef __SYMBIAN32__
15503 +
15504 +typedef signed   char      int8_t;
15505 +typedef unsigned char      uint8_t;
15506 +
15507 +typedef signed   short     int16_t;
15508 +typedef unsigned short     uint16_t;
15509 +
15510 +typedef int16_t            int_least16_t;
15511 +
15512 +typedef signed   long      int32_t;
15513 +typedef unsigned long      uint32_t;
15514 +
15515 +typedef signed long long   int64_t;
15516 +typedef unsigned long long uint64_t;
15517 +
15518 +typedef int32_t            intptr_t;
15519 +typedef uint32_t           uintptr_t;
15520 +
15521 +typedef int64_t            intmax_t;
15522 +typedef uint64_t           uintmax_t;
15523 +
15524 +#define INT8_MIN SCHAR_MIN
15525 +#define INT8_MAX SCHAR_MAX
15526 +#define UINT8_MAX UCHAR_MAX
15527 +#define INT16_MIN SHRT_MIN
15528 +#define INT16_MAX SHRT_MAX
15529 +#define UINT16_MAX USHRT_MAX
15530 +#define INT32_MIN LONG_MIN
15531 +#define INT32_MAX LONG_MAX
15532 +#define UINT32_MAX ULONG_MAX
15533 +#define INT64_MIN LLONG_MIN
15534 +#define INT64_MAX LLONG_MAX
15535 +#define UINT64_MAX ULLONG_MAX
15536 +
15537 +#define INTPTR_MIN INT32_MIN
15538 +#define INTPTR_MAX INT32_MAX
15539 +#define UINTPTR_MAX UINT32_MAX
15540 +#define INTMAX_MIN INT64_MIN
15541 +#define INTMAX_MAX INT64_MAX
15542 +#define INT_LEAST16_MAX INT16_MAX
15543 +#define INT_LEAST16_MAX INT16_MAX
15544 +
15545 +/*{{{ C99 types  - THIS WHOLE SECTION IS INCOMPATIBLE WITH C99. IT SHOULD RESIDE IN A STDINT.H SINCE THIS FILE GETS USED ON HOST SIDE */
15546 +
15547 +#elif defined( __STDC__ ) && __STDC_VERSION__ >= 199901L
15548 +
15549 +#include <stdint.h>
15550 +
15551 +#elif defined( __GNUC__ )
15552 +
15553 +#include <stdint.h>
15554 +
15555 +#elif defined(_MSC_VER)                     /* Visual C define equivalent types */
15556 +
15557 +#include <stddef.h> /* Avoids intptr_t being defined in vadefs.h */
15558 +
15559 +typedef          __int8    int8_t;
15560 +typedef unsigned __int8    uint8_t;
15561 +
15562 +typedef          __int16   int16_t;
15563 +typedef unsigned __int16   uint16_t;
15564 +
15565 +typedef          __int32   int32_t;
15566 +typedef unsigned __int32   uint32_t;
15567 +
15568 +typedef          __int64   int64_t;
15569 +typedef unsigned __int64   uint64_t;
15570 +typedef uint32_t           uintptr_t;
15571 +typedef int64_t            intmax_t;
15572 +typedef uint64_t           uintmax_t;
15573 +typedef int16_t            int_least16_t;
15574 +
15575 +#elif defined (VCMODS_LCC)
15576 +#include <limits.h>
15577 +
15578 +typedef signed   char      int8_t;
15579 +typedef unsigned char      uint8_t;
15580 +
15581 +typedef signed   short     int16_t;
15582 +typedef unsigned short     uint16_t;
15583 +
15584 +typedef signed   long      int32_t;
15585 +typedef unsigned long      uint32_t;
15586 +
15587 +typedef signed   long      int64_t; /*!!!! PFCD, this means code using 64bit numbers will be broken on the VCE */
15588 +typedef unsigned long      uint64_t; /* !!!! PFCD */
15589 +
15590 +typedef int32_t            intptr_t;
15591 +typedef uint32_t           uintptr_t;
15592 +typedef int64_t            intmax_t;
15593 +typedef uint64_t           uintmax_t;
15594 +typedef int16_t            int_least16_t;
15595 +
15596 +#define INT8_MIN SCHAR_MIN
15597 +#define INT8_MAX SCHAR_MAX
15598 +#define UINT8_MAX UCHAR_MAX
15599 +#define INT16_MIN SHRT_MIN
15600 +#define INT16_MAX SHRT_MAX
15601 +#define UINT16_MAX USHRT_MAX
15602 +#define INT32_MIN LONG_MIN
15603 +#define INT32_MAX LONG_MAX
15604 +#define UINT32_MAX ULONG_MAX
15605 +#define INT64_MIN LONG_MIN /* !!!! PFCD */
15606 +#define INT64_MAX LONG_MAX /* !!!! PFCD */
15607 +#define UINT64_MAX ULONG_MAX /* !!!! PFCD */
15608 +
15609 +#define INTPTR_MIN INT32_MIN
15610 +#define INTPTR_MAX INT32_MAX
15611 +#define UINTPTR_MAX UINT32_MAX
15612 +#define INTMAX_MIN INT64_MIN
15613 +#define INTMAX_MIN INT64_MIN
15614 +#define INT_LEAST16_MAX INT16_MAX
15615 +#define INT_LEAST16_MAX INT16_MAX
15616 +
15617 +#elif defined(__VIDEOCORE__)
15618 +
15619 +typedef signed   char      int8_t;
15620 +typedef unsigned char      uint8_t;
15621 +
15622 +typedef signed   short     int16_t;
15623 +typedef unsigned short     uint16_t;
15624 +
15625 +typedef signed   long      int32_t;
15626 +typedef unsigned long      uint32_t;
15627 +
15628 +typedef signed   long long int64_t;
15629 +typedef unsigned long long uint64_t;
15630 +
15631 +typedef int32_t            intptr_t;
15632 +typedef uint32_t           uintptr_t;
15633 +typedef int64_t            intmax_t;
15634 +typedef uint64_t           uintmax_t;
15635 +typedef int16_t            int_least16_t;
15636 +
15637 +#define INT8_MIN SCHAR_MIN
15638 +#define INT8_MAX SCHAR_MAX
15639 +#define UINT8_MAX UCHAR_MAX
15640 +#define INT16_MIN SHRT_MIN
15641 +#define INT16_MAX SHRT_MAX
15642 +#define UINT16_MAX USHRT_MAX
15643 +#define INT32_MIN LONG_MIN
15644 +#define INT32_MAX LONG_MAX
15645 +#define UINT32_MAX ULONG_MAX
15646 +#define INT64_MIN LLONG_MIN
15647 +#define INT64_MAX LLONG_MAX
15648 +#define UINT64_MAX ULLONG_MAX
15649 +
15650 +#define INTPTR_MIN INT32_MIN
15651 +#define INTPTR_MAX INT32_MAX
15652 +#define UINTPTR_MAX UINT32_MAX
15653 +#define INTMAX_MIN INT64_MIN
15654 +#define INTMAX_MAX INT64_MAX
15655 +#define INT_LEAST16_MAX INT16_MAX
15656 +#define INT_LEAST16_MAX INT16_MAX
15657 +
15658 +#elif defined (__HIGHC__) && defined(_I386)
15659 +
15660 +#include <stdint.h>
15661 +
15662 +#else
15663 +#error Unknown platform
15664 +#endif
15665 +
15666 +#ifdef __cplusplus
15667 +}
15668 +#endif
15669 +#endif /* VCOS_STDINT_H */
15670 +
15671 +
15672 --- /dev/null
15673 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_string.h
15674 @@ -0,0 +1,73 @@
15675 +/*=============================================================================
15676 +Copyright (c) 2009 Broadcom Europe Limited.
15677 +All rights reserved.
15678 +
15679 +Project  :  vcfw
15680 +Module   :  chip driver
15681 +
15682 +FILE DESCRIPTION
15683 +VideoCore OS Abstraction Layer - public header file
15684 +=============================================================================*/
15685 +
15686 +#ifndef VCOS_STRING_H
15687 +#define VCOS_STRING_H
15688 +
15689 +/**
15690 +  * \file
15691 +  *
15692 +  * String functions.
15693 +  *
15694 +  */
15695 +
15696 +#ifdef __cplusplus
15697 +extern "C" {
15698 +#endif
15699 +
15700 +#include "interface/vcos/vcos_types.h"
15701 +#include "vcos_platform.h"
15702 +
15703 +#ifdef __KERNEL__
15704 +#include <linux/string.h>
15705 +#else
15706 +#include <string.h>
15707 +#endif
15708 +
15709 +/** Case insensitive string comparison.
15710 +  *
15711 +  */
15712 +
15713 +VCOS_INLINE_DECL
15714 +int vcos_strcasecmp(const char *s1, const char *s2);
15715 +
15716 +VCOS_INLINE_DECL
15717 +int vcos_strncasecmp(const char *s1, const char *s2, size_t n);
15718 +
15719 +VCOSPRE_ int VCOSPOST_ vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap );
15720 +
15721 +VCOSPRE_ int VCOSPOST_ vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...);
15722 +
15723 +VCOS_STATIC_INLINE
15724 +int vcos_strlen(const char *s) { return (int)strlen(s); }
15725 +
15726 +VCOS_STATIC_INLINE
15727 +int vcos_strcmp(const char *s1, const char *s2) { return strcmp(s1,s2); }
15728 +
15729 +VCOS_STATIC_INLINE
15730 +int vcos_strncmp(const char *cs, const char *ct, size_t count) { return strncmp(cs, ct, count); }
15731 +
15732 +VCOS_STATIC_INLINE
15733 +char *vcos_strcpy(char *dst, const char *src) { return strcpy(dst, src); }
15734 +
15735 +VCOS_STATIC_INLINE
15736 +char *vcos_strncpy(char *dst, const char *src, size_t count) { return strncpy(dst, src, count); }
15737 +
15738 +VCOS_STATIC_INLINE
15739 +void *vcos_memcpy(void *dst, const void *src, size_t n) {  memcpy(dst, src, n);  return dst;  }
15740 +
15741 +VCOS_STATIC_INLINE
15742 +void *vcos_memset(void *p, int c, size_t n) { return memset(p, c, n); }
15743 +
15744 +#ifdef __cplusplus
15745 +}
15746 +#endif
15747 +#endif
15748 --- /dev/null
15749 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_thread.h
15750 @@ -0,0 +1,259 @@
15751 +/*=============================================================================
15752 +Copyright (c) 2009 Broadcom Europe Limited.
15753 +All rights reserved.
15754 +
15755 +Project  :  vcfw
15756 +Module   :  chip driver
15757 +
15758 +FILE DESCRIPTION
15759 +VideoCore OS Abstraction Layer - public header file
15760 +=============================================================================*/
15761 +
15762 +#ifndef VCOS_THREAD_H
15763 +#define VCOS_THREAD_H
15764 +
15765 +#ifdef __cplusplus
15766 +extern "C" {
15767 +#endif
15768 +
15769 +#include "interface/vcos/vcos_types.h"
15770 +#include "vcos_platform.h"
15771 +
15772 +/**
15773 + * \file vcos_thread.h
15774 + *
15775 + * \section thread Threads
15776 + *
15777 + * Under Nucleus, a thread is created by NU_Create_Task, passing in the stack
15778 + * and various other parameters. To stop the thread, NU_Terminate_Thread() and
15779 + * NU_Delete_Thread() are called.
15780 + *
15781 + * Unfortunately it's not possible to emulate this API under some fairly common
15782 + * operating systems. Under Windows you can't pass in the stack, and you can't
15783 + * safely terminate a thread.
15784 + *
15785 + * Therefore, an API which is similar to the pthreads API is used instead. This
15786 + * API can (mostly) be emulated under all interesting operating systems.
15787 + *
15788 + * Obviously this makes the code somewhat more complicated on VideoCore than it
15789 + * would otherwise be - we end up with an extra mutex per thread, and some code
15790 + * that waits for it. The benefit is that we have a single way of creating
15791 + * threads that works consistently on all platforms (apart from stack supplying).
15792 + *
15793 + * \subsection stack Stack
15794 + *
15795 + * It's still not possible to pass in the stack address, but this can be made
15796 + * much more obvious in the API: the relevant function is missing and the
15797 + * CPP symbol VCOS_CAN_SET_STACK_ADDR is zero rather than one.
15798 + *
15799 + * \subsection thr_create Creating a thread
15800 + *
15801 + * The simplest way to create a thread is with vcos_thread_create() passing in a
15802 + * NULL thread parameter argument. To wait for the thread to exit, call
15803 + * vcos_thread_join().
15804 + *
15805 + * \subsection back Backward compatibility
15806 + *
15807 + * To ease migration, a "classic" thread creation API is provided for code
15808 + * that used to make use of Nucleus, vcos_thread_create_classic(). The
15809 + * arguments are not exactly the same, as the PREEMPT parameter is dropped.
15810 + *
15811 + */
15812 +
15813 +#define VCOS_AFFINITY_CPU0    _VCOS_AFFINITY_CPU0
15814 +#define VCOS_AFFINITY_CPU1    _VCOS_AFFINITY_CPU1
15815 +#define VCOS_AFFINITY_MASK    _VCOS_AFFINITY_MASK
15816 +#define VCOS_AFFINITY_DEFAULT _VCOS_AFFINITY_DEFAULT
15817 +#define VCOS_AFFINITY_THISCPU _VCOS_AFFINITY_THISCPU
15818 +
15819 +/** Report whether or not we have an RTOS at all, and hence the ability to
15820 +  * create threads.
15821 +  */
15822 +VCOSPRE_ int VCOSPOST_ vcos_have_rtos(void);
15823 +
15824 +/** Create a thread. It must be cleaned up by calling vcos_thread_join().
15825 +  *
15826 +  * @param thread   Filled in on return with thread
15827 +  * @param name     A name for the thread. May be the empty string.
15828 +  * @param attrs    Attributes; default attributes will be used if this is NULL.
15829 +  * @param entry    Entry point.
15830 +  * @param arg      Argument passed to the entry point.
15831 +  */
15832 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create(VCOS_THREAD_T *thread,
15833 +                                                    const char *name,
15834 +                                                    VCOS_THREAD_ATTR_T *attrs,
15835 +                                                    VCOS_THREAD_ENTRY_FN_T entry,
15836 +                                                    void *arg);
15837 +
15838 +/** Exit the thread from within the thread function itself.
15839 +  * Resources must still be cleaned up via a call to thread_join().
15840 +  *
15841 +  * The thread can also be terminated by simply exiting the thread function.
15842 +  *
15843 +  * @param data Data passed to thread_join. May be NULL.
15844 +  */
15845 +VCOSPRE_ void VCOSPOST_ vcos_thread_exit(void *data);
15846 +
15847 +/** Wait for a thread to terminate and then clean up its resources.
15848 +  *
15849 +  * @param thread Thread to wait for
15850 +  * @param pData  Updated to point at data provided in vcos_thread_exit or exit
15851 +  * code of thread function.
15852 +  */
15853 +VCOSPRE_ void VCOSPOST_ vcos_thread_join(VCOS_THREAD_T *thread,
15854 +                             void **pData);
15855 +
15856 +
15857 +/**
15858 +  * \brief Create a thread using an API similar to the one "traditionally"
15859 +  * used under Nucleus.
15860 +  *
15861 +  * This creates a thread which must be cleaned up by calling vcos_thread_join().
15862 +  * The thread cannot be simply terminated (as in Nucleus and ThreadX) as thread
15863 +  * termination is not universally supported.
15864 +  *
15865 +  * @param thread       Filled in with thread instance
15866 +  * @param name         An optional name for the thread. NULL or "" may be used (but
15867 +  *                     a name will aid in debugging).
15868 +  * @param entry        Entry point
15869 +  * @param arg          A single argument passed to the entry point function
15870 +  * @param stack        Pointer to stack address
15871 +  * @param stacksz      Size of stack in bytes
15872 +  * @param priaff       Priority of task, between VCOS_PRI_LOW and VCOS_PRI_HIGH, ORed with the CPU affinity
15873 +  * @param autostart    If non-zero the thread will start immediately.
15874 +  * @param timeslice    Timeslice (system ticks) for this thread.
15875 +  *
15876 +  * @sa vcos_thread_terminate vcos_thread_delete
15877 +  */
15878 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create_classic(VCOS_THREAD_T *thread,
15879 +                                                            const char *name,
15880 +                                                            void *(*entry)(void *arg),
15881 +                                                            void *arg,
15882 +                                                            void *stack,
15883 +                                                            VCOS_UNSIGNED stacksz,
15884 +                                                            VCOS_UNSIGNED priaff,
15885 +                                                            VCOS_UNSIGNED timeslice,
15886 +                                                            VCOS_UNSIGNED autostart);
15887 +
15888 +/**
15889 +  * \brief Set a thread's priority
15890 +  *
15891 +  * Set the priority for a thread.
15892 +  *
15893 +  * @param thread  The thread
15894 +  * @param pri     Thread priority in VCOS_PRI_MASK bits; affinity in VCOS_AFFINITY_MASK bits.
15895 +  */
15896 +VCOS_INLINE_DECL
15897 +void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED pri);
15898 +
15899 +/**
15900 +  * \brief Return the currently executing thread.
15901 +  *
15902 +  */
15903 +VCOS_INLINE_DECL
15904 +VCOS_THREAD_T *vcos_thread_current(void);
15905 +
15906 +/**
15907 +  * \brief Return the thread's priority.
15908 +  */
15909 +VCOS_INLINE_DECL
15910 +VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread);
15911 +
15912 +/**
15913 +  * \brief Return the thread's cpu affinity.
15914 +  */
15915 +VCOS_INLINE_DECL
15916 +VCOS_UNSIGNED vcos_thread_get_affinity(VCOS_THREAD_T *thread);
15917 +
15918 +/**
15919 +  * \brief Set the thread's cpu affinity.
15920 +  */
15921 +
15922 +VCOS_INLINE_DECL
15923 +void vcos_thread_set_affinity(VCOS_THREAD_T *thread, VCOS_UNSIGNED affinity);
15924 +
15925 +/**
15926 +  * \brief Query whether we are in an interrupt.
15927 +  *
15928 +  * @return 1 if in interrupt context.
15929 +  */
15930 +VCOS_INLINE_DECL
15931 +int vcos_in_interrupt(void);
15932 +
15933 +/**
15934 +  * \brief Sleep a while.
15935 +  *
15936 +  * @param ms Number of milliseconds to sleep for
15937 +  *
15938 +  * This may actually sleep a whole number of ticks.
15939 +  */
15940 +VCOS_INLINE_DECL
15941 +void vcos_sleep(uint32_t ms);
15942 +
15943 +/**
15944 +  * \brief Return the value of the hardware microsecond counter.
15945 +  *
15946 +  */
15947 +VCOS_INLINE_DECL
15948 +uint32_t vcos_getmicrosecs(void);
15949 +
15950 +#define vcos_get_ms() (vcos_getmicrosecs()/1000)
15951 +
15952 +/**
15953 +  * \brief Return a unique identifier for the current process
15954 +  *
15955 +  */
15956 +VCOS_INLINE_DECL
15957 +VCOS_UNSIGNED vcos_process_id_current(void);
15958 +
15959 +/** Relinquish this time slice. */
15960 +VCOS_INLINE_DECL
15961 +void vcos_thread_relinquish(void);
15962 +
15963 +/** Return the name of the given thread.
15964 +  */
15965 +VCOSPRE_ const char * VCOSPOST_ vcos_thread_get_name(const VCOS_THREAD_T *thread);
15966 +
15967 +/** Change preemption. This is almost certainly not what you want, as it won't
15968 +  * work reliably in a multicore system: although you can affect the preemption
15969 +  * on *this* core, you won't affect what's happening on the other core(s).
15970 +  *
15971 +  * It's mainly here to ease migration. If you're using it in new code, you
15972 +  * probably need to think again.
15973 +  *
15974 +  * @param pe New preemption, VCOS_PREEMPT or VCOS_NO_PREEMPT
15975 +  * @return Old value of preemption.
15976 +  */
15977 +VCOS_INLINE_DECL
15978 +VCOS_UNSIGNED vcos_change_preemption(VCOS_UNSIGNED pe);
15979 +
15980 +/** Is a thread still running, or has it exited?
15981 +  *
15982 +  * Note: this exists for some fairly scary code in the video codec tests. Don't
15983 +  * try to use it for anything else, as it may well not do what you expect.
15984 +  *
15985 +  * @param thread   thread to query
15986 +  * @return non-zero if thread is running, or zero if it has exited.
15987 +  */
15988 +VCOS_INLINE_DECL
15989 +int vcos_thread_running(VCOS_THREAD_T *thread);
15990 +
15991 +/** Resume a thread.
15992 +  *
15993 +  * @param thread thread to resume
15994 +  */
15995 +VCOS_INLINE_DECL
15996 +void vcos_thread_resume(VCOS_THREAD_T *thread);
15997 +
15998 +/*
15999 + * Internal APIs - may not always be present and should not be used in
16000 + * client code.
16001 + */
16002 +
16003 +extern void _vcos_task_timer_set(void (*pfn)(void*), void *, VCOS_UNSIGNED ms);
16004 +extern void _vcos_task_timer_cancel(void);
16005 +
16006 +#ifdef __cplusplus
16007 +}
16008 +#endif
16009 +#endif
16010 --- /dev/null
16011 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_thread_attr.h
16012 @@ -0,0 +1,73 @@
16013 +/*=============================================================================
16014 +Copyright (c) 2009 Broadcom Europe Limited.
16015 +All rights reserved.
16016 +
16017 +FILE DESCRIPTION
16018 +VideoCore OS Abstraction Layer - thread attributes
16019 +=============================================================================*/
16020 +
16021 +#ifndef VCOS_THREAD_ATTR_H
16022 +#define VCOS_THREAD_ATTR_H
16023 +
16024 +#ifdef __cplusplus
16025 +extern "C" {
16026 +#endif
16027 +
16028 +/**
16029 + * \file
16030 + *
16031 + * Attributes for thread creation.
16032 + *
16033 + */
16034 +
16035 +/** Initialize thread attribute struct. This call does not allocate memory,
16036 +  * and so cannot fail.
16037 +  *
16038 +  */
16039 +VCOSPRE_ void VCOSPOST_ vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs);
16040 +
16041 +/** Set the stack address and size. If not set, a stack will be allocated automatically.
16042 +  *
16043 +  * This can only be set on some platforms. It will always be possible to set the stack
16044 +  * address on VideoCore, but on host platforms, support may well not be available.
16045 +  */
16046 +#if VCOS_CAN_SET_STACK_ADDR
16047 +VCOS_INLINE_DECL
16048 +void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED sz);
16049 +#endif
16050 +
16051 +/** Set the stack size. If not set, a default size will be used. Attempting to call this after having
16052 +  * set the stack location with vcos_thread_attr_setstack() will result in undefined behaviour.
16053 +  */
16054 +VCOS_INLINE_DECL
16055 +void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED sz);
16056 +
16057 +/** Set the task priority. If not set, a default value will be used.
16058 +  */
16059 +VCOS_INLINE_DECL
16060 +void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri);
16061 +
16062 +/** Set the task cpu affinity. If not set, the default will be used.
16063 +  */
16064 +VCOS_INLINE_DECL
16065 +void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED aff);
16066 +
16067 +/** Set the timeslice. If not set the default will be used.
16068 +  */
16069 +VCOS_INLINE_DECL
16070 +void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts);
16071 +
16072 +/** The thread entry function takes (argc,argv), as per Nucleus, with
16073 +  * argc being 0. This may be withdrawn in a future release and should not
16074 +  * be used in new code.
16075 +  */
16076 +VCOS_INLINE_DECL
16077 +void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy);
16078 +
16079 +VCOS_INLINE_DECL
16080 +void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart);
16081 +
16082 +#ifdef __cplusplus
16083 +}
16084 +#endif
16085 +#endif
16086 --- /dev/null
16087 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_timer.h
16088 @@ -0,0 +1,95 @@
16089 +/*=============================================================================
16090 +Copyright (c) 2009 Broadcom Europe Limited.
16091 +All rights reserved.
16092 +
16093 +Project  :  vcfw
16094 +Module   :  chip driver
16095 +
16096 +FILE DESCRIPTION
16097 +VideoCore OS Abstraction Layer - timer support
16098 +=============================================================================*/
16099 +
16100 +#ifndef VCOS_TIMER_H
16101 +#define VCOS_TIMER_H
16102 +
16103 +#ifdef __cplusplus
16104 +extern "C" {
16105 +#endif
16106 +
16107 +#include "interface/vcos/vcos_types.h"
16108 +#include "vcos_platform.h"
16109 +
16110 +/** \file vcos_timer.h
16111 +  *
16112 +  * Timers are single shot.
16113 +  *
16114 +  * Timer times are in milliseconds.
16115 +  *
16116 +  * \note that timer callback functions are called from an arbitrary thread
16117 +  * context. The expiration function should do its work as quickly as possible;
16118 +  * blocking should be avoided.
16119 +  *
16120 +  * \note On Windows, the separate function vcos_timer_init() must be called
16121 +  * as timer initialization from DllMain is not possible.
16122 +  */
16123 +
16124 +/** Perform timer subsystem initialization. This function is not needed
16125 +  * on non-Windows platforms but is still present so that it can be
16126 +  * called. On Windows it is needed because vcos_init() gets called
16127 +  * from DLL initialization where it is not possible to create a
16128 +  * time queue (deadlock occurs if you try).
16129 +  *
16130 +  * @return VCOS_SUCCESS on success. VCOS_EEXIST if this has already been called
16131 +  * once. VCOS_ENOMEM if resource allocation failed.
16132 +  */
16133 +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_timer_init(void);
16134 +
16135 +/** Create a timer in a disabled state.
16136 +  *
16137 +  * The timer is initially disabled.
16138 +  *
16139 +  * @param timer     timer handle
16140 +  * @param name      name for timer
16141 +  * @param expiration_routine function to call when timer expires
16142 +  * @param context   context passed to expiration routine
16143 +  *
16144 +  */
16145 +VCOS_INLINE_DECL
16146 +VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
16147 +                                const char *name,
16148 +                                void (*expiration_routine)(void *context),
16149 +                                void *context);
16150 +
16151 +
16152 +
16153 +/** Start a timer running.
16154 +  *
16155 +  * Timer must be stopped.
16156 +  *
16157 +  * @param timer     timer handle
16158 +  * @param delay     Delay to wait for, in ms
16159 +  */
16160 +VCOS_INLINE_DECL
16161 +void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay);
16162 +
16163 +/** Stop an already running timer.
16164 +  *
16165 +  * @param timer     timer handle
16166 +  */
16167 +VCOS_INLINE_DECL
16168 +void vcos_timer_cancel(VCOS_TIMER_T *timer);
16169 +
16170 +/** Stop a timer and restart it.
16171 +  * @param timer     timer handle
16172 +  * @param delay     delay in ms
16173 +  */
16174 +VCOS_INLINE_DECL
16175 +void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay);
16176 +
16177 +VCOS_INLINE_DECL
16178 +void vcos_timer_delete(VCOS_TIMER_T *timer);
16179 +
16180 +#ifdef __cplusplus
16181 +}
16182 +#endif
16183 +#endif
16184 --- /dev/null
16185 +++ b/drivers/misc/vc04_services/interface/vcos/vcos_types.h
16186 @@ -0,0 +1,197 @@
16187 +/*=============================================================================
16188 +Copyright (c) 2009 Broadcom Europe Limited.
16189 +All rights reserved.
16190 +
16191 +FILE DESCRIPTION
16192 +VideoCore OS Abstraction Layer - basic types
16193 +=============================================================================*/
16194 +
16195 +#ifndef VCOS_TYPES_H
16196 +#define VCOS_TYPES_H
16197 +
16198 +#define VCOS_VERSION   1
16199 +
16200 +#include "vcos_platform_types.h"
16201 +
16202 +#if !defined(VCOSPRE_) || !defined(VCOSPOST_)
16203 +#error VCOSPRE_ and VCOSPOST_ not defined!
16204 +#endif
16205 +
16206 +/* Redefine these here; this means that existing header files can carry on
16207 + * using the VCHPOST/VCHPRE macros rather than having huge changes, which
16208 + * could cause nasty merge problems.
16209 + */
16210 +#ifndef VCHPOST_
16211 +#define VCHPOST_ VCOSPOST_
16212 +#endif
16213 +#ifndef VCHPRE_
16214 +#define VCHPRE_  VCOSPRE_
16215 +#endif
16216 +
16217 +/** Entry function for a lowlevel thread.
16218 +  *
16219 +  * Returns void for consistency with Nucleus/ThreadX.
16220 +  */
16221 +typedef void (*VCOS_LLTHREAD_ENTRY_FN_T)(void *);
16222 +
16223 +/** Thread entry point. Returns a void* for consistency
16224 +  * with pthreads.
16225 +  */
16226 +typedef void *(*VCOS_THREAD_ENTRY_FN_T)(void*);
16227 +
16228 +
16229 +/* Error return codes - chosen to be similar to errno values */
16230 +typedef enum
16231 +{
16232 +   VCOS_SUCCESS,
16233 +   VCOS_EAGAIN,
16234 +   VCOS_ENOENT,
16235 +   VCOS_ENOSPC,
16236 +   VCOS_EINVAL,
16237 +   VCOS_EACCESS,
16238 +   VCOS_ENOMEM,
16239 +   VCOS_ENOSYS,
16240 +   VCOS_EEXIST,
16241 +   VCOS_ENXIO,
16242 +   VCOS_EINTR
16243 +} VCOS_STATUS_T;
16244 +
16245 +/* Some compilers (MetaWare) won't inline with -g turned on, which then results
16246 + * in a lot of code bloat. To overcome this, inline functions are forward declared
16247 + * with the prefix VCOS_INLINE_DECL, and implemented with the prefix VCOS_INLINE_IMPL.
16248 + *
16249 + * That then means that in a release build, "static inline" can be used in the obvious
16250 + * way, but in a debug build the implementations can be skipped in all but one file,
16251 + * by using VCOS_INLINE_BODIES.
16252 + *
16253 + * VCOS_INLINE_DECL - put this at the start of an inline forward declaration of a VCOS
16254 + * function.
16255 + *
16256 + * VCOS_INLINE_IMPL - put this at the start of an inlined implementation of a VCOS
16257 + * function.
16258 + *
16259 + */
16260 +
16261 +/* VCOS_EXPORT - it turns out that in some circumstances we need the implementation of
16262 + * a function even if it is usually inlined.
16263 + *
16264 + * In particular, if we have a codec that is usually provided in object form, if it
16265 + * was built for a debug build it will be full of calls to vcos_XXX(). If this is used
16266 + * in a *release* build, then there won't be any of these calls around in the main image
16267 + * as they will all have been inlined. The problem also exists for vcos functions called
16268 + * from assembler.
16269 + *
16270 + * VCOS_EXPORT ensures that the named function will be emitted as a regular (not static-inline)
16271 + * function inside vcos_<platform>.c so that it can be linked against. Doing this for every
16272 + * VCOS function would be a bit code-bloat-tastic, so it is only done for those that need it.
16273 + *
16274 + */
16275 +
16276 +#ifdef __cplusplus
16277 +#define _VCOS_INLINE inline
16278 +#else
16279 +#define _VCOS_INLINE __inline
16280 +#endif
16281 +
16282 +#if defined(NDEBUG)
16283 +
16284 +#ifdef __GNUC__
16285 +# define VCOS_INLINE_DECL extern __inline__
16286 +# define VCOS_INLINE_IMPL static __inline__
16287 +#else
16288 +# define VCOS_INLINE_DECL static _VCOS_INLINE   /* declare a func */
16289 +# define VCOS_INLINE_IMPL static _VCOS_INLINE   /* implement a func inline */
16290 +#endif
16291 +
16292 +# if defined(VCOS_WANT_IMPL)
16293 +#  define VCOS_EXPORT
16294 +# else
16295 +#  define VCOS_EXPORT VCOS_INLINE_IMPL
16296 +# endif /* VCOS_WANT_IMPL */
16297 +
16298 +#define VCOS_INLINE_BODIES
16299 +
16300 +#else /* NDEBUG */
16301 +
16302 +#if !defined(VCOS_INLINE_DECL)
16303 +   #define VCOS_INLINE_DECL extern
16304 +#endif
16305 +#if !defined(VCOS_INLINE_IMPL)
16306 +   #define VCOS_INLINE_IMPL
16307 +#endif
16308 +#define VCOS_EXPORT VCOS_INLINE_IMPL
16309 +#endif
16310 +
16311 +#define VCOS_STATIC_INLINE static _VCOS_INLINE
16312 +
16313 +#if defined(__HIGHC__) || defined(__HIGHC_ANSI__)
16314 +#define _VCOS_METAWARE
16315 +#endif
16316 +
16317 +/** It seems that __FUNCTION__ isn't standard!
16318 +  */
16319 +#if __STDC_VERSION__ < 199901L
16320 +# if __GNUC__ >= 2 || defined(__VIDEOCORE__)
16321 +#  define VCOS_FUNCTION __FUNCTION__
16322 +# else
16323 +#  define VCOS_FUNCTION "<unknown>"
16324 +# endif
16325 +#else
16326 +# define VCOS_FUNCTION __func__
16327 +#endif
16328 +
16329 +#define _VCOS_MS_PER_TICK (1000/VCOS_TICKS_PER_SECOND)
16330 +
16331 +/* Convert a number of milliseconds to a tick count. Internal use only - fails to
16332 + * convert VCOS_SUSPEND correctly.
16333 + */
16334 +#define _VCOS_MS_TO_TICKS(ms) (((ms)+_VCOS_MS_PER_TICK-1)/_VCOS_MS_PER_TICK)
16335 +
16336 +#define VCOS_TICKS_TO_MS(ticks) ((ticks) * _VCOS_MS_PER_TICK)
16337 +
16338 +/** VCOS version of DATESTR, from pcdisk.h. Used by the hostreq service.
16339 + */ 
16340 +typedef struct vcos_datestr
16341 +{
16342 +   uint8_t       cmsec;              /**< Centesimal mili second */
16343 +   uint16_t      date;               /**< Date */
16344 +   uint16_t      time;               /**< Time */
16345 +
16346 +} VCOS_DATESTR;
16347 +
16348 +/* Compile-time assert - declares invalid array length if condition
16349 + * not met, or array of length one if OK.
16350 + */
16351 +#define VCOS_CASSERT(e) extern char vcos_compile_time_check[1/(e)]
16352 +
16353 +#define vcos_min(x,y) ((x) < (y) ? (x) : (y))
16354 +#define vcos_max(x,y) ((x) > (y) ? (x) : (y))
16355 +
16356 +/** Return the count of an array. FIXME: under gcc we could make
16357 + * this report an error for pointers using __builtin_types_compatible().
16358 + */
16359 +#define vcos_countof(x) (sizeof((x)) / sizeof((x)[0]))
16360 +
16361 +/* for backward compatibility */
16362 +#define countof(x) (sizeof((x)) / sizeof((x)[0]))
16363 +
16364 +#define VCOS_ALIGN_DOWN(p,n) (((ptrdiff_t)(p)) & ~((n)-1))
16365 +#define VCOS_ALIGN_UP(p,n) VCOS_ALIGN_DOWN((ptrdiff_t)(p)+(n)-1,(n))
16366 +
16367 +/** bool_t is not a POSIX type so cannot rely on it. Define it here.
16368 +  * It's not even defined in stdbool.h.
16369 +  */
16370 +typedef int32_t vcos_bool_t;
16371 +typedef int32_t vcos_fourcc_t;
16372 +
16373 +#define VCOS_FALSE   0
16374 +#define VCOS_TRUE    (!VCOS_FALSE)
16375 +
16376 +/** Mark unused arguments to keep compilers quiet */
16377 +#define vcos_unused(x) (void)(x)
16378 +
16379 +/** For backward compatibility */
16380 +typedef vcos_fourcc_t fourcc_t;
16381 +typedef vcos_fourcc_t FOURCC_T;
16382 +
16383 +#endif