| 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_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, ¶ms, 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, ¶ms, 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, ¶ms, 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, ¶ms, 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(¶ms, 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 | + ¶ms, |
| 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(¶ms, 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 | + ¶ms, |
| 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; ¶m->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( ¶m, cmd_globals.cmd_entry ); |
| 9213 | + |
| 9214 | + if ( param.use_log ) |
| 9215 | + { |
| 9216 | + cmd_log_results( ¶m ); |
| 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( ¶m, "\n" ); |
| 9227 | + } |
| 9228 | + } |
| 9229 | + |
| 9230 | + vcos_mutex_unlock( &cmd_globals.lock ); |
| 9231 | + |
| 9232 | + return rc; |
| 9233 | +} |
| 9234 | + |
| 9235 | +/***************************************************************************** |
| 9236 | +* |
| 9237 | +* Registers a command entry with the command line processor |
| 9238 | +* |
| 9239 | +*****************************************************************************/ |
| 9240 | + |
| 9241 | +VCOS_STATUS_T vcos_cmd_register( VCOS_CMD_T *cmd_entry ) |
| 9242 | +{ |
| 9243 | + VCOS_STATUS_T rc; |
| 9244 | + VCOS_UNSIGNED new_num_cmd_alloc; |
| 9245 | + VCOS_CMD_T *new_cmd_entry; |
| 9246 | + VCOS_CMD_T *old_cmd_entry; |
| 9247 | + VCOS_CMD_T *scan_entry; |
| 9248 | + |
| 9249 | + vcos_once( &cmd_globals.initialized, vcos_cmd_init ); |
| 9250 | + |
| 9251 | + vcos_assert( cmd_entry != NULL ); |
| 9252 | + vcos_assert( cmd_entry->name != NULL ); |
| 9253 | + |
| 9254 | + vcos_log_trace( "%s: cmd '%s'", __FUNCTION__, cmd_entry->name ); |
| 9255 | + |
| 9256 | + vcos_assert( cmd_entry->args != NULL ); |
| 9257 | + vcos_assert(( cmd_entry->cmd_fn != NULL ) || ( cmd_entry->sub_cmd_entry != NULL )); |
| 9258 | + vcos_assert( cmd_entry->descr != NULL ); |
| 9259 | + |
| 9260 | + /* We expect vcos_cmd_init to be called before vcos_logging_init, so we |
| 9261 | + * need to defer registering our logging category until someplace |
| 9262 | + * like right here. |
| 9263 | + */ |
| 9264 | + |
| 9265 | + if ( vcos_cmd_log_category.name == NULL ) |
| 9266 | + { |
| 9267 | + /* |
| 9268 | + * If you're using the command interface, you pretty much always want |
| 9269 | + * log messages from this file to show up. So we change the default |
| 9270 | + * from ERROR to be the more reasonable INFO level. |
| 9271 | + */ |
| 9272 | + |
| 9273 | + vcos_log_set_level(&vcos_cmd_log_category, VCOS_LOG_INFO); |
| 9274 | + vcos_log_register("vcos_cmd", &vcos_cmd_log_category); |
| 9275 | + |
| 9276 | + /* We register a help command so that it shows up in the usage. */ |
| 9277 | + |
| 9278 | + vcos_cmd_register( &cmd_help ); |
| 9279 | +#ifdef HAVE_VCOS_VERSION |
| 9280 | + vcos_cmd_register( &cmd_version ); |
| 9281 | +#endif |
| 9282 | + } |
| 9283 | + |
| 9284 | + vcos_mutex_lock( &cmd_globals.lock ); |
| 9285 | + |
| 9286 | + if ( cmd_globals.num_cmd_entries >= cmd_globals.num_cmd_alloc ) |
| 9287 | + { |
| 9288 | + if ( cmd_globals.num_cmd_alloc == 0 ) |
| 9289 | + { |
| 9290 | + /* We haven't allocated a table yet */ |
| 9291 | + } |
| 9292 | + |
| 9293 | + /* The number 8 is rather arbitrary. */ |
| 9294 | + |
| 9295 | + new_num_cmd_alloc = cmd_globals.num_cmd_alloc + 8; |
| 9296 | + |
| 9297 | + /* The + 1 is to ensure that we always have a NULL entry at the end. */ |
| 9298 | + |
| 9299 | + new_cmd_entry = (VCOS_CMD_T *)vcos_calloc( new_num_cmd_alloc + 1, sizeof( *cmd_entry ), "vcos_cmd_entries" ); |
| 9300 | + if ( new_cmd_entry == NULL ) |
| 9301 | + { |
| 9302 | + rc = VCOS_ENOMEM; |
| 9303 | + goto out; |
| 9304 | + } |
| 9305 | + memcpy( new_cmd_entry, cmd_globals.cmd_entry, cmd_globals.num_cmd_entries * sizeof( *cmd_entry )); |
| 9306 | + cmd_globals.num_cmd_alloc = new_num_cmd_alloc; |
| 9307 | + old_cmd_entry = cmd_globals.cmd_entry; |
| 9308 | + cmd_globals.cmd_entry = new_cmd_entry; |
| 9309 | + vcos_free( old_cmd_entry ); |
| 9310 | + } |
| 9311 | + |
| 9312 | + if ( cmd_globals.num_cmd_entries == 0 ) |
| 9313 | + { |
| 9314 | + /* This is the first command being registered */ |
| 9315 | + |
| 9316 | + cmd_globals.cmd_entry[0] = *cmd_entry; |
| 9317 | + } |
| 9318 | + else |
| 9319 | + { |
| 9320 | + /* Keep the list in alphabetical order. We start at the end and work backwards |
| 9321 | + * shuffling entries up one until we find an insertion point. |
| 9322 | + */ |
| 9323 | + |
| 9324 | + for ( scan_entry = &cmd_globals.cmd_entry[cmd_globals.num_cmd_entries - 1]; |
| 9325 | + scan_entry >= cmd_globals.cmd_entry; scan_entry-- ) |
| 9326 | + { |
| 9327 | + if ( vcos_strcmp( cmd_entry->name, scan_entry->name ) > 0 ) |
| 9328 | + { |
| 9329 | + /* We found an insertion point. */ |
| 9330 | + |
| 9331 | + break; |
| 9332 | + } |
| 9333 | + |
| 9334 | + scan_entry[1] = scan_entry[0]; |
| 9335 | + } |
| 9336 | + scan_entry[1] = *cmd_entry; |
| 9337 | + } |
| 9338 | + cmd_globals.num_cmd_entries++; |
| 9339 | + |
| 9340 | + rc = VCOS_SUCCESS; |
| 9341 | + |
| 9342 | +out: |
| 9343 | + |
| 9344 | + vcos_mutex_unlock( &cmd_globals.lock ); |
| 9345 | + return rc; |
| 9346 | +} |
| 9347 | + |
| 9348 | +/***************************************************************************** |
| 9349 | +* |
| 9350 | +* Registers multiple commands. |
| 9351 | +* |
| 9352 | +*****************************************************************************/ |
| 9353 | + |
| 9354 | +VCOS_STATUS_T vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry ) |
| 9355 | +{ |
| 9356 | + VCOS_STATUS_T status; |
| 9357 | + |
| 9358 | + while ( cmd_entry->name != NULL ) |
| 9359 | + { |
| 9360 | + if (( status = vcos_cmd_register( cmd_entry )) != VCOS_SUCCESS ) |
| 9361 | + { |
| 9362 | + return status; |
| 9363 | + } |
| 9364 | + cmd_entry++; |
| 9365 | + } |
| 9366 | + return VCOS_SUCCESS; |
| 9367 | +} |
| 9368 | + |
| 9369 | --- /dev/null |
| 9370 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_common.h |
| 9371 | @@ -0,0 +1,76 @@ |
| 9372 | +/*============================================================================= |
| 9373 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 9374 | +All rights reserved. |
| 9375 | + |
| 9376 | +Project : vcfw |
| 9377 | +Module : chip driver |
| 9378 | + |
| 9379 | +FILE DESCRIPTION |
| 9380 | +VideoCore OS Abstraction Layer - common postamble code |
| 9381 | +=============================================================================*/ |
| 9382 | + |
| 9383 | +/** \file |
| 9384 | + * |
| 9385 | + * Postamble code included by the platform-specific header files |
| 9386 | + */ |
| 9387 | + |
| 9388 | +#define VCOS_THREAD_PRI_DEFAULT VCOS_THREAD_PRI_NORMAL |
| 9389 | + |
| 9390 | +#if !defined(VCOS_THREAD_PRI_INCREASE) |
| 9391 | +#error Which way to thread priorities go? |
| 9392 | +#endif |
| 9393 | + |
| 9394 | +#if VCOS_THREAD_PRI_INCREASE < 0 |
| 9395 | +/* smaller numbers are higher priority */ |
| 9396 | +#define VCOS_THREAD_PRI_LESS(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX) |
| 9397 | +#define VCOS_THREAD_PRI_MORE(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN) |
| 9398 | +#else |
| 9399 | +/* bigger numbers are lower priority */ |
| 9400 | +#define VCOS_THREAD_PRI_MORE(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX) |
| 9401 | +#define VCOS_THREAD_PRI_LESS(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN) |
| 9402 | +#endif |
| 9403 | + |
| 9404 | +/* Convenience for Brits: */ |
| 9405 | +#define VCOS_APPLICATION_INITIALISE VCOS_APPLICATION_INITIALIZE |
| 9406 | + |
| 9407 | +/* |
| 9408 | + * Check for constant definitions |
| 9409 | + */ |
| 9410 | +#ifndef VCOS_TICKS_PER_SECOND |
| 9411 | +#error VCOS_TICKS_PER_SECOND not defined |
| 9412 | +#endif |
| 9413 | + |
| 9414 | +#if !defined(VCOS_THREAD_PRI_MIN) || !defined(VCOS_THREAD_PRI_MAX) |
| 9415 | +#error Priority range not defined |
| 9416 | +#endif |
| 9417 | + |
| 9418 | +#if !defined(VCOS_THREAD_PRI_HIGHEST) || !defined(VCOS_THREAD_PRI_LOWEST) || !defined(VCOS_THREAD_PRI_NORMAL) |
| 9419 | +#error Priority ordering not defined |
| 9420 | +#endif |
| 9421 | + |
| 9422 | +#if !defined(VCOS_CAN_SET_STACK_ADDR) |
| 9423 | +#error Can stack addresses be set on this platform? Please set this macro to either 0 or 1. |
| 9424 | +#endif |
| 9425 | + |
| 9426 | +#if (_VCOS_AFFINITY_CPU0|_VCOS_AFFINITY_CPU1) & (~_VCOS_AFFINITY_MASK) |
| 9427 | +#error _VCOS_AFFINITY_CPUxxx values are not consistent with _VCOS_AFFINITY_MASK |
| 9428 | +#endif |
| 9429 | + |
| 9430 | +/** Append to the end of a singly-linked queue, O(1). Works with |
| 9431 | + * any structure where list has members 'head' and 'tail' and |
| 9432 | + * item has a 'next' pointer. |
| 9433 | + */ |
| 9434 | +#define VCOS_QUEUE_APPEND_TAIL(list, item) {\ |
| 9435 | + (item)->next = NULL;\ |
| 9436 | + if (!(list)->head) {\ |
| 9437 | + (list)->head = (list)->tail = (item); \ |
| 9438 | + } else {\ |
| 9439 | + (list)->tail->next = (item); \ |
| 9440 | + (list)->tail = (item); \ |
| 9441 | + } \ |
| 9442 | +} |
| 9443 | + |
| 9444 | +#ifndef VCOS_HAVE_TIMER |
| 9445 | +VCOSPRE_ void VCOSPOST_ vcos_timer_init(void); |
| 9446 | +#endif |
| 9447 | + |
| 9448 | --- /dev/null |
| 9449 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_blockpool.h |
| 9450 | @@ -0,0 +1,260 @@ |
| 9451 | +/*============================================================================= |
| 9452 | +Copyright (c) 2011 Broadcom Europe Limited. |
| 9453 | +All rights reserved. |
| 9454 | + |
| 9455 | +Project : vcfw |
| 9456 | +Module : chip driver |
| 9457 | + |
| 9458 | +FILE DESCRIPTION |
| 9459 | +VideoCore OS Abstraction Layer - event flags implemented via a semaphore |
| 9460 | +=============================================================================*/ |
| 9461 | + |
| 9462 | +#ifndef VCOS_GENERIC_BLOCKPOOL_H |
| 9463 | +#define VCOS_GENERIC_BLOCKPOOL_H |
| 9464 | + |
| 9465 | +/** |
| 9466 | + * \file |
| 9467 | + * |
| 9468 | + * This provides a generic, thread safe implementation of a VCOS block pool |
| 9469 | + * fixed size memory allocator. |
| 9470 | + */ |
| 9471 | + |
| 9472 | +#ifdef __cplusplus |
| 9473 | +extern "C" { |
| 9474 | +#endif |
| 9475 | + |
| 9476 | +#include "interface/vcos/vcos_types.h" |
| 9477 | + |
| 9478 | +/** Bits 0 to (VCOS_BLOCKPOOL_SUBPOOL_BITS - 1) are used to store the |
| 9479 | + * subpool id. */ |
| 9480 | +#define VCOS_BLOCKPOOL_SUBPOOL_BITS 3 |
| 9481 | +#define VCOS_BLOCKPOOL_MAX_SUBPOOLS (1 << VCOS_BLOCKPOOL_SUBPOOL_BITS) |
| 9482 | + |
| 9483 | +/* Make zero an invalid handle at the cost of decreasing the maximum |
| 9484 | + * number of blocks (2^28) by 1. Alternatively, a spare bit could be |
| 9485 | + * used to indicated valid blocks but there are likely to be better |
| 9486 | + * uses for spare bits. e.g. allowing more subpools |
| 9487 | + */ |
| 9488 | +#define INDEX_OFFSET 1 |
| 9489 | + |
| 9490 | +#define VCOS_BLOCKPOOL_HANDLE_GET_INDEX(h) \ |
| 9491 | + (((h) >> VCOS_BLOCKPOOL_SUBPOOL_BITS) - INDEX_OFFSET) |
| 9492 | + |
| 9493 | +#define VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(h) \ |
| 9494 | + ((h) & ((1 << VCOS_BLOCKPOOL_SUBPOOL_BITS) - 1)) |
| 9495 | + |
| 9496 | +#define VCOS_BLOCKPOOL_HANDLE_CREATE(i,s) \ |
| 9497 | + ((((i) + INDEX_OFFSET) << VCOS_BLOCKPOOL_SUBPOOL_BITS) | (s)) |
| 9498 | + |
| 9499 | +#define VCOS_BLOCKPOOL_INVALID_HANDLE 0 |
| 9500 | + |
| 9501 | +typedef struct VCOS_BLOCKPOOL_HEADER_TAG |
| 9502 | +{ |
| 9503 | + /* Blocks either refer to to the pool if they are allocated |
| 9504 | + * or the free list if they are available. |
| 9505 | + */ |
| 9506 | + union { |
| 9507 | + struct VCOS_BLOCKPOOL_HEADER_TAG *next; |
| 9508 | + struct VCOS_BLOCKPOOL_SUBPOOL_TAG* subpool; |
| 9509 | + } owner; |
| 9510 | +} VCOS_BLOCKPOOL_HEADER_T; |
| 9511 | + |
| 9512 | +typedef struct VCOS_BLOCKPOOL_SUBPOOL_TAG |
| 9513 | +{ |
| 9514 | + /** VCOS_BLOCKPOOL_SUBPOOL_MAGIC */ |
| 9515 | + uint32_t magic; |
| 9516 | + VCOS_BLOCKPOOL_HEADER_T* free_list; |
| 9517 | + /* The start of the pool memory */ |
| 9518 | + void *mem; |
| 9519 | + /* Address of the first block header */ |
| 9520 | + void *start; |
| 9521 | + /** The number of blocks in this sub-pool */ |
| 9522 | + VCOS_UNSIGNED num_blocks; |
| 9523 | + /** Current number of available blocks in this sub-pool */ |
| 9524 | + VCOS_UNSIGNED available_blocks; |
| 9525 | + /** Pointers to the pool that owns this sub-pool */ |
| 9526 | + struct VCOS_BLOCKPOOL_TAG* owner; |
| 9527 | + /** Define properties such as memory ownership */ |
| 9528 | + uint32_t flags; |
| 9529 | +} VCOS_BLOCKPOOL_SUBPOOL_T; |
| 9530 | + |
| 9531 | +typedef struct VCOS_BLOCKPOOL_TAG |
| 9532 | +{ |
| 9533 | + /** VCOS_BLOCKPOOL_MAGIC */ |
| 9534 | + uint32_t magic; |
| 9535 | + /** Thread safety for Alloc, Free, Delete, Stats */ |
| 9536 | + VCOS_MUTEX_T mutex; |
| 9537 | + /** The size of the block data */ |
| 9538 | + size_t block_data_size; |
| 9539 | + /** Block size inc overheads */ |
| 9540 | + size_t block_size; |
| 9541 | + /** Name for debugging */ |
| 9542 | + const char *name; |
| 9543 | + /* The number of subpools that may be used */ |
| 9544 | + VCOS_UNSIGNED num_subpools; |
| 9545 | + /** Number of blocks in each dynamically allocated subpool */ |
| 9546 | + VCOS_UNSIGNED num_extension_blocks; |
| 9547 | + /** Array of subpools. Subpool zero is is not deleted until the pool is |
| 9548 | + * destroed. If the index of the pool is < num_subpools and |
| 9549 | + * subpool[index.mem] is null then the subpool entry is valid but |
| 9550 | + * "not currently allocated" */ |
| 9551 | + VCOS_BLOCKPOOL_SUBPOOL_T subpools[VCOS_BLOCKPOOL_MAX_SUBPOOLS]; |
| 9552 | +} VCOS_BLOCKPOOL_T; |
| 9553 | + |
| 9554 | +#define VCOS_BLOCKPOOL_ROUND_UP(x,s) (((x) + ((s) - 1)) & ~((s) - 1)) |
| 9555 | +/** |
| 9556 | + * Calculates the size in bytes required for a block pool containing |
| 9557 | + * num_blocks of size block_size plus any overheads. |
| 9558 | + * |
| 9559 | + * The block pool header (VCOS_BLOCKPOOL_T) is allocated separately |
| 9560 | + * |
| 9561 | + * Overheads: |
| 9562 | + * block_size + header must be a multiple of sizeof(void*) |
| 9563 | + * The start of the first block may need to be up to wordsize - 1 bytes |
| 9564 | + * into the given buffer because statically allocated buffers within structures |
| 9565 | + * are not guaranteed to be word aligned. |
| 9566 | + */ |
| 9567 | +#define VCOS_BLOCKPOOL_SIZE(num_blocks, block_size) \ |
| 9568 | + ((VCOS_BLOCKPOOL_ROUND_UP((block_size) + sizeof(VCOS_BLOCKPOOL_HEADER_T), \ |
| 9569 | + sizeof(void*)) * (num_blocks)) + sizeof(void*)) |
| 9570 | + |
| 9571 | +/** |
| 9572 | + * Sanity check to verify whether a handle is potentially a blockpool handle |
| 9573 | + * when the pool pointer is not available. |
| 9574 | + * |
| 9575 | + * If the pool pointer is availabe use vcos_blockpool_elem_to_handle instead. |
| 9576 | + * |
| 9577 | + * @param handle the handle to verify |
| 9578 | + * @param max_blocks the expected maximum number of block in the pool |
| 9579 | + * that the handle belongs to. |
| 9580 | + */ |
| 9581 | +#define VCOS_BLOCKPOOL_IS_VALID_HANDLE_FORMAT(handle, max_blocks) \ |
| 9582 | + ((handle) != VCOS_BLOCKPOOL_INVALID_HANDLE \ |
| 9583 | + && VCOS_BLOCKPOOL_HANDLE_GET_INDEX((handle)) < (max_blocks)) |
| 9584 | + |
| 9585 | +VCOSPRE_ |
| 9586 | + VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_init(VCOS_BLOCKPOOL_T *pool, |
| 9587 | + VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, |
| 9588 | + void *start, VCOS_UNSIGNED pool_size, const char *name); |
| 9589 | + |
| 9590 | +VCOSPRE_ |
| 9591 | + VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_create_on_heap( |
| 9592 | + VCOS_BLOCKPOOL_T *pool, VCOS_UNSIGNED num_blocks, |
| 9593 | + VCOS_UNSIGNED block_size, const char *name); |
| 9594 | + |
| 9595 | +VCOSPRE_ |
| 9596 | + VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool, |
| 9597 | + VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks); |
| 9598 | + |
| 9599 | +VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool); |
| 9600 | + |
| 9601 | +VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool); |
| 9602 | + |
| 9603 | +VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_free(void *block); |
| 9604 | + |
| 9605 | +VCOSPRE_ |
| 9606 | + VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_available_count( |
| 9607 | + VCOS_BLOCKPOOL_T *pool); |
| 9608 | + |
| 9609 | +VCOSPRE_ |
| 9610 | + VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_used_count( |
| 9611 | + VCOS_BLOCKPOOL_T *pool); |
| 9612 | + |
| 9613 | +VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool); |
| 9614 | + |
| 9615 | +VCOSPRE_ uint32_t VCOSPOST_ vcos_generic_blockpool_elem_to_handle(void *block); |
| 9616 | + |
| 9617 | +VCOSPRE_ void VCOSPOST_ |
| 9618 | + *vcos_generic_blockpool_elem_from_handle( |
| 9619 | + VCOS_BLOCKPOOL_T *pool, uint32_t handle); |
| 9620 | + |
| 9621 | +VCOSPRE_ uint32_t VCOSPOST_ |
| 9622 | + vcos_generic_blockpool_is_valid_elem( |
| 9623 | + VCOS_BLOCKPOOL_T *pool, const void *block); |
| 9624 | +#if defined(VCOS_INLINE_BODIES) |
| 9625 | + |
| 9626 | +VCOS_INLINE_IMPL |
| 9627 | +VCOS_STATUS_T vcos_blockpool_init(VCOS_BLOCKPOOL_T *pool, |
| 9628 | + VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, |
| 9629 | + void *start, VCOS_UNSIGNED pool_size, const char *name) |
| 9630 | +{ |
| 9631 | + return vcos_generic_blockpool_init(pool, num_blocks, block_size, |
| 9632 | + start, pool_size, name); |
| 9633 | +} |
| 9634 | + |
| 9635 | +VCOS_INLINE_IMPL |
| 9636 | +VCOS_STATUS_T vcos_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool, |
| 9637 | + VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, const char *name) |
| 9638 | +{ |
| 9639 | + return vcos_generic_blockpool_create_on_heap( |
| 9640 | + pool, num_blocks, block_size, name); |
| 9641 | +} |
| 9642 | + |
| 9643 | +VCOS_INLINE_IMPL |
| 9644 | + VCOS_STATUS_T VCOSPOST_ vcos_blockpool_extend(VCOS_BLOCKPOOL_T *pool, |
| 9645 | + VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks) |
| 9646 | +{ |
| 9647 | + return vcos_generic_blockpool_extend(pool, num_extensions, num_blocks); |
| 9648 | +} |
| 9649 | + |
| 9650 | +VCOS_INLINE_IMPL |
| 9651 | +void *vcos_blockpool_alloc(VCOS_BLOCKPOOL_T *pool) |
| 9652 | +{ |
| 9653 | + return vcos_generic_blockpool_alloc(pool); |
| 9654 | +} |
| 9655 | + |
| 9656 | +VCOS_INLINE_IMPL |
| 9657 | +void *vcos_blockpool_calloc(VCOS_BLOCKPOOL_T *pool) |
| 9658 | +{ |
| 9659 | + return vcos_generic_blockpool_calloc(pool); |
| 9660 | +} |
| 9661 | + |
| 9662 | +VCOS_INLINE_IMPL |
| 9663 | +void vcos_blockpool_free(void *block) |
| 9664 | +{ |
| 9665 | + vcos_generic_blockpool_free(block); |
| 9666 | +} |
| 9667 | + |
| 9668 | +VCOS_INLINE_IMPL |
| 9669 | +VCOS_UNSIGNED vcos_blockpool_available_count(VCOS_BLOCKPOOL_T *pool) |
| 9670 | +{ |
| 9671 | + return vcos_generic_blockpool_available_count(pool); |
| 9672 | +} |
| 9673 | + |
| 9674 | +VCOS_INLINE_IMPL |
| 9675 | +VCOS_UNSIGNED vcos_blockpool_used_count(VCOS_BLOCKPOOL_T *pool) |
| 9676 | +{ |
| 9677 | + return vcos_generic_blockpool_used_count(pool); |
| 9678 | +} |
| 9679 | + |
| 9680 | +VCOS_INLINE_IMPL |
| 9681 | +void vcos_blockpool_delete(VCOS_BLOCKPOOL_T *pool) |
| 9682 | +{ |
| 9683 | + vcos_generic_blockpool_delete(pool); |
| 9684 | +} |
| 9685 | + |
| 9686 | +VCOS_INLINE_IMPL |
| 9687 | +uint32_t vcos_blockpool_elem_to_handle(void *block) |
| 9688 | +{ |
| 9689 | + return vcos_generic_blockpool_elem_to_handle(block); |
| 9690 | +} |
| 9691 | + |
| 9692 | +VCOS_INLINE_IMPL |
| 9693 | +void *vcos_blockpool_elem_from_handle(VCOS_BLOCKPOOL_T *pool, uint32_t handle) |
| 9694 | +{ |
| 9695 | + return vcos_generic_blockpool_elem_from_handle(pool, handle); |
| 9696 | +} |
| 9697 | + |
| 9698 | +VCOS_INLINE_IMPL |
| 9699 | +uint32_t vcos_blockpool_is_valid_elem(VCOS_BLOCKPOOL_T *pool, const void *block) |
| 9700 | +{ |
| 9701 | + return vcos_generic_blockpool_is_valid_elem(pool, block); |
| 9702 | +} |
| 9703 | +#endif /* VCOS_INLINE_BODIES */ |
| 9704 | + |
| 9705 | + |
| 9706 | +#ifdef __cplusplus |
| 9707 | +} |
| 9708 | +#endif |
| 9709 | +#endif /* VCOS_GENERIC_BLOCKPOOL_H */ |
| 9710 | + |
| 9711 | --- /dev/null |
| 9712 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.c |
| 9713 | @@ -0,0 +1,297 @@ |
| 9714 | +/*============================================================================= |
| 9715 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 9716 | +All rights reserved. |
| 9717 | + |
| 9718 | +FILE DESCRIPTION |
| 9719 | +VideoCore OS Abstraction Layer - event flags implemented via mutexes |
| 9720 | +=============================================================================*/ |
| 9721 | + |
| 9722 | +#include "interface/vcos/vcos.h" |
| 9723 | +#include "interface/vcos/generic/vcos_generic_event_flags.h" |
| 9724 | + |
| 9725 | +#include <stddef.h> |
| 9726 | + |
| 9727 | +/** A structure created by a thread that waits on the event flags |
| 9728 | + * for a particular combination of flags to arrive. |
| 9729 | + */ |
| 9730 | +typedef struct VCOS_EVENT_WAITER_T |
| 9731 | +{ |
| 9732 | + VCOS_UNSIGNED requested_events; /**< The events wanted */ |
| 9733 | + VCOS_UNSIGNED actual_events; /**< Actual events found */ |
| 9734 | + VCOS_UNSIGNED op; /**< The event operation to be used */ |
| 9735 | + VCOS_STATUS_T return_status; /**< The return status the waiter should pass back */ |
| 9736 | + VCOS_EVENT_FLAGS_T *flags; /**< Pointer to the original 'flags' structure */ |
| 9737 | + VCOS_THREAD_T *thread; /**< Thread waiting */ |
| 9738 | + struct VCOS_EVENT_WAITER_T *next; |
| 9739 | +} VCOS_EVENT_WAITER_T; |
| 9740 | + |
| 9741 | +#ifndef NDEBUG |
| 9742 | +static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags); |
| 9743 | +#endif |
| 9744 | +static void event_flags_timer_expired(void *cxt); |
| 9745 | + |
| 9746 | +VCOS_STATUS_T vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name) |
| 9747 | +{ |
| 9748 | + VCOS_STATUS_T rc; |
| 9749 | + if ((rc=vcos_mutex_create(&flags->lock, name)) != VCOS_SUCCESS) |
| 9750 | + { |
| 9751 | + return rc; |
| 9752 | + } |
| 9753 | + |
| 9754 | + flags->events = 0; |
| 9755 | + flags->waiters.head = flags->waiters.tail = 0; |
| 9756 | + return rc; |
| 9757 | +} |
| 9758 | + |
| 9759 | +void vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags, |
| 9760 | + VCOS_UNSIGNED bitmask, |
| 9761 | + VCOS_OPTION op) |
| 9762 | +{ |
| 9763 | + vcos_assert(flags); |
| 9764 | + vcos_mutex_lock(&flags->lock); |
| 9765 | + if (op == VCOS_OR) |
| 9766 | + { |
| 9767 | + flags->events |= bitmask; |
| 9768 | + } |
| 9769 | + else if (op == VCOS_AND) |
| 9770 | + { |
| 9771 | + flags->events &= bitmask; |
| 9772 | + } |
| 9773 | + else |
| 9774 | + { |
| 9775 | + vcos_assert(0); |
| 9776 | + } |
| 9777 | + |
| 9778 | + /* Now wake up any threads that have now become signalled. */ |
| 9779 | + if (flags->waiters.head != NULL) |
| 9780 | + { |
| 9781 | + VCOS_UNSIGNED consumed_events = 0; |
| 9782 | + VCOS_EVENT_WAITER_T **pcurrent_waiter = &flags->waiters.head; |
| 9783 | + VCOS_EVENT_WAITER_T *prev_waiter = NULL; |
| 9784 | + |
| 9785 | + /* Walk the chain of tasks suspend on this event flag group to determine |
| 9786 | + * if any of their requests can be satisfied. |
| 9787 | + */ |
| 9788 | + while ((*pcurrent_waiter) != NULL) |
| 9789 | + { |
| 9790 | + VCOS_EVENT_WAITER_T *curr_waiter = *pcurrent_waiter; |
| 9791 | + |
| 9792 | + /* Determine if this request has been satisfied */ |
| 9793 | + |
| 9794 | + /* First, find the event flags in common. */ |
| 9795 | + VCOS_UNSIGNED waiter_satisfied = flags->events & curr_waiter->requested_events; |
| 9796 | + |
| 9797 | + /* Second, determine if all the event flags must match */ |
| 9798 | + if (curr_waiter->op & VCOS_AND) |
| 9799 | + { |
| 9800 | + /* All requested events must be present */ |
| 9801 | + waiter_satisfied = (waiter_satisfied == curr_waiter->requested_events); |
| 9802 | + } |
| 9803 | + |
| 9804 | + /* Wake this one up? */ |
| 9805 | + if (waiter_satisfied) |
| 9806 | + { |
| 9807 | + |
| 9808 | + if (curr_waiter->op & VCOS_CONSUME) |
| 9809 | + { |
| 9810 | + consumed_events |= curr_waiter->requested_events; |
| 9811 | + } |
| 9812 | + |
| 9813 | + /* remove this block from the list, taking care at the end */ |
| 9814 | + *pcurrent_waiter = curr_waiter->next; |
| 9815 | + if (curr_waiter->next == NULL) |
| 9816 | + flags->waiters.tail = prev_waiter; |
| 9817 | + |
| 9818 | + vcos_assert(waiter_list_valid(flags)); |
| 9819 | + |
| 9820 | + curr_waiter->return_status = VCOS_SUCCESS; |
| 9821 | + curr_waiter->actual_events = flags->events; |
| 9822 | + |
| 9823 | + _vcos_thread_sem_post(curr_waiter->thread); |
| 9824 | + } |
| 9825 | + else |
| 9826 | + { |
| 9827 | + /* move to next element in the list */ |
| 9828 | + prev_waiter = *pcurrent_waiter; |
| 9829 | + pcurrent_waiter = &(curr_waiter->next); |
| 9830 | + } |
| 9831 | + } |
| 9832 | + |
| 9833 | + flags->events &= ~consumed_events; |
| 9834 | + |
| 9835 | + } |
| 9836 | + |
| 9837 | + vcos_mutex_unlock(&flags->lock); |
| 9838 | +} |
| 9839 | + |
| 9840 | +void vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *flags) |
| 9841 | +{ |
| 9842 | + vcos_mutex_delete(&flags->lock); |
| 9843 | +} |
| 9844 | + |
| 9845 | +extern VCOS_STATUS_T vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags, |
| 9846 | + VCOS_UNSIGNED bitmask, |
| 9847 | + VCOS_OPTION op, |
| 9848 | + VCOS_UNSIGNED suspend, |
| 9849 | + VCOS_UNSIGNED *retrieved_bits) |
| 9850 | +{ |
| 9851 | + VCOS_EVENT_WAITER_T waitreq; |
| 9852 | + VCOS_STATUS_T rc = VCOS_EAGAIN; |
| 9853 | + int satisfied = 0; |
| 9854 | + |
| 9855 | + vcos_assert(flags); |
| 9856 | + |
| 9857 | + /* default retrieved bits to 0 */ |
| 9858 | + *retrieved_bits = 0; |
| 9859 | + |
| 9860 | + vcos_mutex_lock(&flags->lock); |
| 9861 | + switch (op & VCOS_EVENT_FLAG_OP_MASK) |
| 9862 | + { |
| 9863 | + case VCOS_AND: |
| 9864 | + if ((flags->events & bitmask) == bitmask) |
| 9865 | + { |
| 9866 | + *retrieved_bits = flags->events; |
| 9867 | + rc = VCOS_SUCCESS; |
| 9868 | + satisfied = 1; |
| 9869 | + if (op & VCOS_CONSUME) |
| 9870 | + flags->events &= ~bitmask; |
| 9871 | + } |
| 9872 | + break; |
| 9873 | + |
| 9874 | + case VCOS_OR: |
| 9875 | + if (flags->events & bitmask) |
| 9876 | + { |
| 9877 | + *retrieved_bits = flags->events; |
| 9878 | + rc = VCOS_SUCCESS; |
| 9879 | + satisfied = 1; |
| 9880 | + if (op & VCOS_CONSUME) |
| 9881 | + flags->events &= ~bitmask; |
| 9882 | + } |
| 9883 | + break; |
| 9884 | + |
| 9885 | + default: |
| 9886 | + vcos_assert(0); |
| 9887 | + rc = VCOS_EINVAL; |
| 9888 | + break; |
| 9889 | + } |
| 9890 | + |
| 9891 | + if (!satisfied && suspend) |
| 9892 | + { |
| 9893 | + /* Have to go to sleep. |
| 9894 | + * |
| 9895 | + * Append to tail so we get FIFO ordering. |
| 9896 | + */ |
| 9897 | + waitreq.requested_events = bitmask; |
| 9898 | + waitreq.op = op; |
| 9899 | + waitreq.return_status = VCOS_EAGAIN; |
| 9900 | + waitreq.flags = flags; |
| 9901 | + waitreq.actual_events = 0; |
| 9902 | + waitreq.thread = vcos_thread_current(); |
| 9903 | + waitreq.next = 0; |
| 9904 | + vcos_assert(waitreq.thread != (VCOS_THREAD_T*)-1); |
| 9905 | + VCOS_QUEUE_APPEND_TAIL(&flags->waiters, &waitreq); |
| 9906 | + |
| 9907 | + if (suspend != (VCOS_UNSIGNED)-1) |
| 9908 | + _vcos_task_timer_set(event_flags_timer_expired, &waitreq, suspend); |
| 9909 | + |
| 9910 | + vcos_mutex_unlock(&flags->lock); |
| 9911 | + /* go to sleep and wait to be signalled or timeout */ |
| 9912 | + |
| 9913 | + _vcos_thread_sem_wait(); |
| 9914 | + |
| 9915 | + *retrieved_bits = waitreq.actual_events; |
| 9916 | + rc = waitreq.return_status; |
| 9917 | + |
| 9918 | + /* cancel the timer - do not do this while holding the mutex as it |
| 9919 | + * might be waiting for the timeout function to complete, which will |
| 9920 | + * try to take the mutex. |
| 9921 | + */ |
| 9922 | + if (suspend != (VCOS_UNSIGNED)-1) |
| 9923 | + _vcos_task_timer_cancel(); |
| 9924 | + } |
| 9925 | + else |
| 9926 | + { |
| 9927 | + vcos_mutex_unlock(&flags->lock); |
| 9928 | + } |
| 9929 | + |
| 9930 | + return rc; |
| 9931 | +} |
| 9932 | + |
| 9933 | + |
| 9934 | +/** Called when a get call times out. Remove this thread's |
| 9935 | + * entry from the waiting queue, then resume the thread. |
| 9936 | + */ |
| 9937 | +static void event_flags_timer_expired(void *cxt) |
| 9938 | +{ |
| 9939 | + VCOS_EVENT_WAITER_T *waitreq = (VCOS_EVENT_WAITER_T *)cxt; |
| 9940 | + VCOS_EVENT_FLAGS_T *flags = waitreq->flags; |
| 9941 | + VCOS_EVENT_WAITER_T **plist; |
| 9942 | + VCOS_EVENT_WAITER_T *prev = NULL; |
| 9943 | + VCOS_THREAD_T *thread = 0; |
| 9944 | + |
| 9945 | + vcos_assert(flags); |
| 9946 | + |
| 9947 | + vcos_mutex_lock(&flags->lock); |
| 9948 | + |
| 9949 | + /* walk the list of waiting threads on this event group, and remove |
| 9950 | + * the one that has expired. |
| 9951 | + * |
| 9952 | + * FIXME: could use doubly-linked list if lots of threads are found |
| 9953 | + * to be waiting on a single event flag instance. |
| 9954 | + */ |
| 9955 | + plist = &flags->waiters.head; |
| 9956 | + while (*plist != NULL) |
| 9957 | + { |
| 9958 | + if (*plist == waitreq) |
| 9959 | + { |
| 9960 | + int at_end; |
| 9961 | + /* found it */ |
| 9962 | + thread = (*plist)->thread; |
| 9963 | + at_end = ((*plist)->next == NULL); |
| 9964 | + |
| 9965 | + /* link past */ |
| 9966 | + *plist = (*plist)->next; |
| 9967 | + if (at_end) |
| 9968 | + flags->waiters.tail = prev; |
| 9969 | + |
| 9970 | + break; |
| 9971 | + } |
| 9972 | + prev = *plist; |
| 9973 | + plist = &(*plist)->next; |
| 9974 | + } |
| 9975 | + vcos_assert(waiter_list_valid(flags)); |
| 9976 | + |
| 9977 | + vcos_mutex_unlock(&flags->lock); |
| 9978 | + |
| 9979 | + if (thread) |
| 9980 | + { |
| 9981 | + _vcos_thread_sem_post(thread); |
| 9982 | + } |
| 9983 | +} |
| 9984 | + |
| 9985 | +#ifndef NDEBUG |
| 9986 | + |
| 9987 | +static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags) |
| 9988 | +{ |
| 9989 | + int valid; |
| 9990 | + /* Either both head and tail are NULL, or neither are NULL */ |
| 9991 | + if (flags->waiters.head == NULL) |
| 9992 | + { |
| 9993 | + valid = (flags->waiters.tail == NULL); |
| 9994 | + } |
| 9995 | + else |
| 9996 | + { |
| 9997 | + valid = (flags->waiters.tail != NULL); |
| 9998 | + } |
| 9999 | + |
| 10000 | + /* If head and tail point at the same non-NULL element, then there |
| 10001 | + * is only one element in the list. |
| 10002 | + */ |
| 10003 | + if (flags->waiters.head && (flags->waiters.head == flags->waiters.tail)) |
| 10004 | + { |
| 10005 | + valid = (flags->waiters.head->next == NULL); |
| 10006 | + } |
| 10007 | + return valid; |
| 10008 | +} |
| 10009 | + |
| 10010 | +#endif |
| 10011 | --- /dev/null |
| 10012 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_event_flags.h |
| 10013 | @@ -0,0 +1,104 @@ |
| 10014 | +/*============================================================================= |
| 10015 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 10016 | +All rights reserved. |
| 10017 | + |
| 10018 | +FILE DESCRIPTION |
| 10019 | +VideoCore OS Abstraction Layer - event flags implemented via a semaphore |
| 10020 | +=============================================================================*/ |
| 10021 | + |
| 10022 | +#ifndef VCOS_GENERIC_EVENT_FLAGS_H |
| 10023 | +#define VCOS_GENERIC_EVENT_FLAGS_H |
| 10024 | + |
| 10025 | +#ifdef __cplusplus |
| 10026 | +extern "C" { |
| 10027 | +#endif |
| 10028 | + |
| 10029 | +#include "interface/vcos/vcos_types.h" |
| 10030 | + |
| 10031 | +/** |
| 10032 | + * \file |
| 10033 | + * |
| 10034 | + * This provides event flags (as per Nucleus Event Groups) based on a |
| 10035 | + * mutex, a semaphore (per waiting thread) and a timer (per waiting |
| 10036 | + * thread). |
| 10037 | + * |
| 10038 | + * The data structure is a 32 bit unsigned int (the current set of |
| 10039 | + * flags) and a linked list of clients waiting to be 'satisfied'. |
| 10040 | + * |
| 10041 | + * The mutex merely locks access to the data structure. If a client |
| 10042 | + * calls vcos_event_flags_get() and the requested bits are not already |
| 10043 | + * present, it then sleeps on its per-thread semaphore after adding |
| 10044 | + * this semaphore to the queue waiting. It also sets up a timer. |
| 10045 | + * |
| 10046 | + * The per-thread semaphore and timer are actually stored in the |
| 10047 | + * thread context (joinable thread). In future it may become necessary |
| 10048 | + * to support non-VCOS threads by using thread local storage to |
| 10049 | + * create these objects and associate them with the thread. |
| 10050 | + */ |
| 10051 | + |
| 10052 | +struct VCOS_EVENT_WAITER_T; |
| 10053 | + |
| 10054 | +typedef struct VCOS_EVENT_FLAGS_T |
| 10055 | +{ |
| 10056 | + VCOS_UNSIGNED events; /**< Events currently set */ |
| 10057 | + VCOS_MUTEX_T lock; /**< Serialize access */ |
| 10058 | + struct |
| 10059 | + { |
| 10060 | + struct VCOS_EVENT_WAITER_T *head; /**< List of threads waiting */ |
| 10061 | + struct VCOS_EVENT_WAITER_T *tail; /**< List of threads waiting */ |
| 10062 | + } waiters; |
| 10063 | +} VCOS_EVENT_FLAGS_T; |
| 10064 | + |
| 10065 | +#define VCOS_OR 1 |
| 10066 | +#define VCOS_AND 2 |
| 10067 | +#define VCOS_CONSUME 4 |
| 10068 | +#define VCOS_OR_CONSUME (VCOS_OR | VCOS_CONSUME) |
| 10069 | +#define VCOS_AND_CONSUME (VCOS_AND | VCOS_CONSUME) |
| 10070 | +#define VCOS_EVENT_FLAG_OP_MASK (VCOS_OR|VCOS_AND) |
| 10071 | + |
| 10072 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name); |
| 10073 | +VCOSPRE_ void VCOSPOST_ vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags, |
| 10074 | + VCOS_UNSIGNED events, |
| 10075 | + VCOS_OPTION op); |
| 10076 | +VCOSPRE_ void VCOSPOST_ vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *); |
| 10077 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags, |
| 10078 | + VCOS_UNSIGNED requested_events, |
| 10079 | + VCOS_OPTION op, |
| 10080 | + VCOS_UNSIGNED suspend, |
| 10081 | + VCOS_UNSIGNED *retrieved_events); |
| 10082 | + |
| 10083 | +#ifdef VCOS_INLINE_BODIES |
| 10084 | + |
| 10085 | +VCOS_INLINE_IMPL |
| 10086 | +VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name) { |
| 10087 | + return vcos_generic_event_flags_create(flags, name); |
| 10088 | +} |
| 10089 | + |
| 10090 | +VCOS_INLINE_IMPL |
| 10091 | +void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags, |
| 10092 | + VCOS_UNSIGNED events, |
| 10093 | + VCOS_OPTION op) { |
| 10094 | + vcos_generic_event_flags_set(flags, events, op); |
| 10095 | +} |
| 10096 | + |
| 10097 | +VCOS_INLINE_IMPL |
| 10098 | +void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *f) { |
| 10099 | + vcos_generic_event_flags_delete(f); |
| 10100 | +} |
| 10101 | + |
| 10102 | +VCOS_INLINE_IMPL |
| 10103 | +VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags, |
| 10104 | + VCOS_UNSIGNED requested_events, |
| 10105 | + VCOS_OPTION op, |
| 10106 | + VCOS_UNSIGNED suspend, |
| 10107 | + VCOS_UNSIGNED *retrieved_events) { |
| 10108 | + return vcos_generic_event_flags_get(flags, requested_events, op, suspend, retrieved_events); |
| 10109 | +} |
| 10110 | + |
| 10111 | +#endif /* VCOS_INLINE_BODIES */ |
| 10112 | + |
| 10113 | +#ifdef __cplusplus |
| 10114 | +} |
| 10115 | +#endif |
| 10116 | +#endif |
| 10117 | + |
| 10118 | --- /dev/null |
| 10119 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_named_sem.h |
| 10120 | @@ -0,0 +1,81 @@ |
| 10121 | +/*============================================================================= |
| 10122 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 10123 | +All rights reserved. |
| 10124 | + |
| 10125 | +Project : vcfw |
| 10126 | +Module : chip driver |
| 10127 | + |
| 10128 | +FILE DESCRIPTION |
| 10129 | +VideoCore OS Abstraction Layer - named semaphores |
| 10130 | +=============================================================================*/ |
| 10131 | + |
| 10132 | +#ifndef VCOS_GENERIC_NAMED_SEM_H |
| 10133 | +#define VCOS_GENERIC_NAMED_SEM_H |
| 10134 | + |
| 10135 | +#ifdef __cplusplus |
| 10136 | +extern "C" { |
| 10137 | +#endif |
| 10138 | + |
| 10139 | +#include "interface/vcos/vcos_types.h" |
| 10140 | + |
| 10141 | +/** |
| 10142 | + * \file |
| 10143 | + * |
| 10144 | + * Generic support for named semaphores, using regular ones. This is only |
| 10145 | + * suitable for emulating them on an embedded MMUless system, since there is |
| 10146 | + * no support for opening semaphores across process boundaries. |
| 10147 | + * |
| 10148 | + */ |
| 10149 | + |
| 10150 | +#define VCOS_NAMED_SEMAPHORE_NAMELEN 64 |
| 10151 | + |
| 10152 | +/* In theory we could use the name facility provided within Nucleus. However, this |
| 10153 | + * is hard to do as semaphores are constantly being created and destroyed; we |
| 10154 | + * would need to stop everything while allocating the memory for the semaphore |
| 10155 | + * list and then walking it. So keep our own list. |
| 10156 | + */ |
| 10157 | +typedef struct VCOS_NAMED_SEMAPHORE_T |
| 10158 | +{ |
| 10159 | + struct VCOS_NAMED_SEMAPHORE_IMPL_T *actual; /**< There are 'n' named semaphores per 1 actual semaphore */ |
| 10160 | + VCOS_SEMAPHORE_T *sem; /**< Pointer to actual underlying semaphore */ |
| 10161 | +} VCOS_NAMED_SEMAPHORE_T; |
| 10162 | + |
| 10163 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ |
| 10164 | +vcos_generic_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count); |
| 10165 | + |
| 10166 | +VCOSPRE_ void VCOSPOST_ vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem); |
| 10167 | + |
| 10168 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ _vcos_named_semaphore_init(void); |
| 10169 | +VCOSPRE_ void VCOSPOST_ _vcos_named_semaphore_deinit(void); |
| 10170 | + |
| 10171 | +#if defined(VCOS_INLINE_BODIES) |
| 10172 | + |
| 10173 | +VCOS_INLINE_IMPL |
| 10174 | +VCOS_STATUS_T vcos_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count) { |
| 10175 | + return vcos_generic_named_semaphore_create(sem, name, count); |
| 10176 | +} |
| 10177 | + |
| 10178 | +VCOS_INLINE_IMPL |
| 10179 | +void vcos_named_semaphore_wait(VCOS_NAMED_SEMAPHORE_T *sem) { |
| 10180 | + vcos_semaphore_wait(sem->sem); |
| 10181 | +} |
| 10182 | + |
| 10183 | +VCOS_INLINE_IMPL |
| 10184 | +VCOS_STATUS_T vcos_named_semaphore_trywait(VCOS_NAMED_SEMAPHORE_T *sem) { |
| 10185 | + return vcos_semaphore_trywait(sem->sem); |
| 10186 | +} |
| 10187 | + |
| 10188 | +VCOS_INLINE_IMPL |
| 10189 | +void vcos_named_semaphore_post(VCOS_NAMED_SEMAPHORE_T *sem) { |
| 10190 | + vcos_semaphore_post(sem->sem); |
| 10191 | +} |
| 10192 | + |
| 10193 | + |
| 10194 | +#endif |
| 10195 | + |
| 10196 | +#ifdef __cplusplus |
| 10197 | +} |
| 10198 | +#endif |
| 10199 | +#endif |
| 10200 | + |
| 10201 | + |
| 10202 | --- /dev/null |
| 10203 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_quickslow_mutex.h |
| 10204 | @@ -0,0 +1,75 @@ |
| 10205 | +/*============================================================================= |
| 10206 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 10207 | +All rights reserved. |
| 10208 | + |
| 10209 | +Project : vcfw |
| 10210 | +Module : chip driver |
| 10211 | + |
| 10212 | +FILE DESCRIPTION |
| 10213 | +VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones. |
| 10214 | +=============================================================================*/ |
| 10215 | + |
| 10216 | +#ifndef VCOS_GENERIC_QUICKSLOW_MUTEX_H |
| 10217 | +#define VCOS_GENERIC_QUICKSLOW_MUTEX_H |
| 10218 | + |
| 10219 | +#ifdef __cplusplus |
| 10220 | +extern "C" { |
| 10221 | +#endif |
| 10222 | + |
| 10223 | +#include "interface/vcos/vcos_types.h" |
| 10224 | + |
| 10225 | +/** |
| 10226 | + * \file |
| 10227 | + * |
| 10228 | + * Quickslow Mutexes implemented as regular ones (i.e. quick and slow modes are the same). |
| 10229 | + * |
| 10230 | + */ |
| 10231 | + |
| 10232 | +typedef VCOS_MUTEX_T VCOS_QUICKSLOW_MUTEX_T; |
| 10233 | + |
| 10234 | +#if defined(VCOS_INLINE_BODIES) |
| 10235 | +VCOS_INLINE_IMPL |
| 10236 | +VCOS_STATUS_T vcos_quickslow_mutex_create(VCOS_QUICKSLOW_MUTEX_T *m, const char *name) |
| 10237 | +{ |
| 10238 | + return vcos_mutex_create(m, name); |
| 10239 | +} |
| 10240 | + |
| 10241 | +VCOS_INLINE_IMPL |
| 10242 | +void vcos_quickslow_mutex_delete(VCOS_QUICKSLOW_MUTEX_T *m) |
| 10243 | +{ |
| 10244 | + vcos_mutex_delete(m); |
| 10245 | +} |
| 10246 | + |
| 10247 | +VCOS_INLINE_IMPL |
| 10248 | +void vcos_quickslow_mutex_lock(VCOS_QUICKSLOW_MUTEX_T *m) |
| 10249 | +{ |
| 10250 | + while (vcos_mutex_lock(m) == VCOS_EAGAIN); |
| 10251 | +} |
| 10252 | + |
| 10253 | +VCOS_INLINE_IMPL |
| 10254 | +void vcos_quickslow_mutex_unlock(VCOS_QUICKSLOW_MUTEX_T *m) |
| 10255 | +{ |
| 10256 | + vcos_mutex_unlock(m); |
| 10257 | +} |
| 10258 | + |
| 10259 | +VCOS_INLINE_IMPL |
| 10260 | +void vcos_quickslow_mutex_lock_quick(VCOS_QUICKSLOW_MUTEX_T *m) |
| 10261 | +{ |
| 10262 | + while (vcos_mutex_lock(m) == VCOS_EAGAIN); |
| 10263 | +} |
| 10264 | + |
| 10265 | +VCOS_INLINE_IMPL |
| 10266 | +void vcos_quickslow_mutex_unlock_quick(VCOS_QUICKSLOW_MUTEX_T *m) |
| 10267 | +{ |
| 10268 | + vcos_mutex_unlock(m); |
| 10269 | +} |
| 10270 | + |
| 10271 | +#endif |
| 10272 | + |
| 10273 | + |
| 10274 | +#ifdef __cplusplus |
| 10275 | +} |
| 10276 | +#endif |
| 10277 | +#endif |
| 10278 | + |
| 10279 | + |
| 10280 | --- /dev/null |
| 10281 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_reentrant_mtx.h |
| 10282 | @@ -0,0 +1,75 @@ |
| 10283 | +/*============================================================================= |
| 10284 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 10285 | +All rights reserved. |
| 10286 | + |
| 10287 | +Project : vcfw |
| 10288 | +Module : chip driver |
| 10289 | + |
| 10290 | +FILE DESCRIPTION |
| 10291 | +VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones. |
| 10292 | +=============================================================================*/ |
| 10293 | + |
| 10294 | +#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H |
| 10295 | +#define VCOS_GENERIC_REENTRANT_MUTEX_H |
| 10296 | + |
| 10297 | +#ifdef __cplusplus |
| 10298 | +extern "C" { |
| 10299 | +#endif |
| 10300 | + |
| 10301 | +#include "interface/vcos/vcos_types.h" |
| 10302 | + |
| 10303 | +/** |
| 10304 | + * \file |
| 10305 | + * |
| 10306 | + * Reentrant Mutexes from regular ones. |
| 10307 | + * |
| 10308 | + */ |
| 10309 | + |
| 10310 | +typedef struct VCOS_REENTRANT_MUTEX_T |
| 10311 | +{ |
| 10312 | + VCOS_MUTEX_T mutex; |
| 10313 | + VCOS_THREAD_T *owner; |
| 10314 | + unsigned count; |
| 10315 | +} VCOS_REENTRANT_MUTEX_T; |
| 10316 | + |
| 10317 | +/* Extern definitions of functions that do the actual work */ |
| 10318 | + |
| 10319 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name); |
| 10320 | + |
| 10321 | +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m); |
| 10322 | + |
| 10323 | +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m); |
| 10324 | + |
| 10325 | +VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m); |
| 10326 | + |
| 10327 | +/* Inline forwarding functions */ |
| 10328 | + |
| 10329 | +#if defined(VCOS_INLINE_BODIES) |
| 10330 | + |
| 10331 | +VCOS_INLINE_IMPL |
| 10332 | +VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) { |
| 10333 | + return vcos_generic_reentrant_mutex_create(m,name); |
| 10334 | +} |
| 10335 | + |
| 10336 | +VCOS_INLINE_IMPL |
| 10337 | +void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) { |
| 10338 | + vcos_generic_reentrant_mutex_delete(m); |
| 10339 | +} |
| 10340 | + |
| 10341 | +VCOS_INLINE_IMPL |
| 10342 | +void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) { |
| 10343 | + vcos_generic_reentrant_mutex_lock(m); |
| 10344 | +} |
| 10345 | + |
| 10346 | +VCOS_INLINE_IMPL |
| 10347 | +void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) { |
| 10348 | + vcos_generic_reentrant_mutex_unlock(m); |
| 10349 | +} |
| 10350 | +#endif |
| 10351 | + |
| 10352 | +#ifdef __cplusplus |
| 10353 | +} |
| 10354 | +#endif |
| 10355 | +#endif |
| 10356 | + |
| 10357 | + |
| 10358 | --- /dev/null |
| 10359 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_generic_tls.h |
| 10360 | @@ -0,0 +1,144 @@ |
| 10361 | +/*============================================================================= |
| 10362 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 10363 | +All rights reserved. |
| 10364 | + |
| 10365 | +Project : vcfw |
| 10366 | +Module : chip driver |
| 10367 | + |
| 10368 | +FILE DESCRIPTION |
| 10369 | +VideoCore OS Abstraction Layer - generic thread local storage |
| 10370 | +=============================================================================*/ |
| 10371 | + |
| 10372 | +#ifndef VCOS_GENERIC_TLS_H |
| 10373 | +#define VCOS_GENERIC_TLS_H |
| 10374 | + |
| 10375 | +#ifdef __cplusplus |
| 10376 | +extern "C" { |
| 10377 | +#endif |
| 10378 | + |
| 10379 | +#include "interface/vcos/vcos_types.h" |
| 10380 | + |
| 10381 | +/** |
| 10382 | + * \file |
| 10383 | + * |
| 10384 | + * Do an emulation of Thread Local Storage. The platform needs to |
| 10385 | + * provide a way to set and get a per-thread pointer which is |
| 10386 | + * where the TLS data itself is stored. |
| 10387 | + * |
| 10388 | + * |
| 10389 | + * Each thread that wants to join in this scheme needs to call |
| 10390 | + * vcos_tls_thread_register(). |
| 10391 | + * |
| 10392 | + * The platform needs to support the macros/functions |
| 10393 | + * _vcos_tls_thread_ptr_set() and _vcos_tls_thread_ptr_get(). |
| 10394 | + */ |
| 10395 | + |
| 10396 | +#ifndef VCOS_WANT_TLS_EMULATION |
| 10397 | +#error Should not be included unless TLS emulation is defined |
| 10398 | +#endif |
| 10399 | + |
| 10400 | +/** Number of slots to reserve per thread. This results in an overhead |
| 10401 | + * of this many words per thread. |
| 10402 | + */ |
| 10403 | +#define VCOS_TLS_MAX_SLOTS 4 |
| 10404 | + |
| 10405 | +/** TLS key. Allocating one of these reserves the client one of the |
| 10406 | + * available slots. |
| 10407 | + */ |
| 10408 | +typedef VCOS_UNSIGNED VCOS_TLS_KEY_T; |
| 10409 | + |
| 10410 | +/** TLS per-thread structure. Each thread gets one of these |
| 10411 | + * if TLS emulation (rather than native TLS support) is |
| 10412 | + * being used. |
| 10413 | + */ |
| 10414 | +typedef struct VCOS_TLS_THREAD_T |
| 10415 | +{ |
| 10416 | + void *slots[VCOS_TLS_MAX_SLOTS]; |
| 10417 | +} VCOS_TLS_THREAD_T; |
| 10418 | + |
| 10419 | +/* |
| 10420 | + * Internal APIs |
| 10421 | + */ |
| 10422 | + |
| 10423 | +/** Register this thread's TLS storage area. */ |
| 10424 | +VCOSPRE_ void VCOSPOST_ vcos_tls_thread_register(VCOS_TLS_THREAD_T *); |
| 10425 | + |
| 10426 | +/** Create a new TLS key */ |
| 10427 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_tls_create(VCOS_TLS_KEY_T *key); |
| 10428 | + |
| 10429 | +/** Delete a TLS key */ |
| 10430 | +VCOSPRE_ void VCOSPOST_ vcos_generic_tls_delete(VCOS_TLS_KEY_T tls); |
| 10431 | + |
| 10432 | +/** Initialise the TLS library */ |
| 10433 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_tls_init(void); |
| 10434 | + |
| 10435 | +/** Deinitialise the TLS library */ |
| 10436 | +VCOSPRE_ void VCOSPOST_ vcos_tls_deinit(void); |
| 10437 | + |
| 10438 | +#if defined(VCOS_INLINE_BODIES) |
| 10439 | + |
| 10440 | +#undef VCOS_ASSERT_LOGGING_DISABLE |
| 10441 | +#define VCOS_ASSERT_LOGGING_DISABLE 1 |
| 10442 | + |
| 10443 | +/* |
| 10444 | + * Implementations of public API functions |
| 10445 | + */ |
| 10446 | + |
| 10447 | +/** Set the given value. Since everything is per-thread, there is no need |
| 10448 | + * for any locking. |
| 10449 | + */ |
| 10450 | +VCOS_INLINE_IMPL |
| 10451 | +VCOS_STATUS_T vcos_tls_set(VCOS_TLS_KEY_T tls, void *v) { |
| 10452 | + VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get(); |
| 10453 | + vcos_assert(tlsdata); /* Fires if this thread has not been registered */ |
| 10454 | + if (tls<VCOS_TLS_MAX_SLOTS) |
| 10455 | + { |
| 10456 | + tlsdata->slots[tls] = v; |
| 10457 | + return VCOS_SUCCESS; |
| 10458 | + } |
| 10459 | + else |
| 10460 | + { |
| 10461 | + vcos_assert(0); |
| 10462 | + return VCOS_EINVAL; |
| 10463 | + } |
| 10464 | +} |
| 10465 | + |
| 10466 | +/** Get the given value. No locking required. |
| 10467 | + */ |
| 10468 | +VCOS_INLINE_IMPL |
| 10469 | +void *vcos_tls_get(VCOS_TLS_KEY_T tls) { |
| 10470 | + VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get(); |
| 10471 | + vcos_assert(tlsdata); /* Fires if this thread has not been registered */ |
| 10472 | + if (tls<VCOS_TLS_MAX_SLOTS) |
| 10473 | + { |
| 10474 | + return tlsdata->slots[tls]; |
| 10475 | + } |
| 10476 | + else |
| 10477 | + { |
| 10478 | + vcos_assert(0); |
| 10479 | + return NULL; |
| 10480 | + } |
| 10481 | +} |
| 10482 | + |
| 10483 | +VCOS_INLINE_IMPL |
| 10484 | +VCOS_STATUS_T vcos_tls_create(VCOS_TLS_KEY_T *key) { |
| 10485 | + return vcos_generic_tls_create(key); |
| 10486 | +} |
| 10487 | + |
| 10488 | +VCOS_INLINE_IMPL |
| 10489 | +void vcos_tls_delete(VCOS_TLS_KEY_T tls) { |
| 10490 | + vcos_generic_tls_delete(tls); |
| 10491 | +} |
| 10492 | + |
| 10493 | +#undef VCOS_ASSERT_LOGGING_DISABLE |
| 10494 | +#define VCOS_ASSERT_LOGGING_DISABLE 0 |
| 10495 | + |
| 10496 | +#endif /* VCOS_INLINE_BODIES */ |
| 10497 | + |
| 10498 | +#ifdef __cplusplus |
| 10499 | +} |
| 10500 | +#endif |
| 10501 | + |
| 10502 | +#endif |
| 10503 | + |
| 10504 | + |
| 10505 | --- /dev/null |
| 10506 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_joinable_thread_from_plain.h |
| 10507 | @@ -0,0 +1,202 @@ |
| 10508 | +/*============================================================================= |
| 10509 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 10510 | +All rights reserved. |
| 10511 | + |
| 10512 | +Module : vcos |
| 10513 | + |
| 10514 | +FILE DESCRIPTION |
| 10515 | +VideoCore OS Abstraction Layer - implementation: joinable thread from plain |
| 10516 | +=============================================================================*/ |
| 10517 | + |
| 10518 | +/** \file |
| 10519 | + * |
| 10520 | + * Header file for platforms creating the joinable thread from a lowlevel |
| 10521 | + * thread. |
| 10522 | + * |
| 10523 | + * In addition to the actual thread, the following are also created: |
| 10524 | + * |
| 10525 | + * - a semaphore to wait on when joining the thread |
| 10526 | + * - a semaphore to support counted suspend/resume (used by event group) |
| 10527 | + * - a per-thread timer (used by event group, but could be removed) |
| 10528 | + */ |
| 10529 | + |
| 10530 | +#ifndef VCOS_JOINABLE_THREAD_FROM_PLAIN_H |
| 10531 | +#define VCOS_JOINABLE_THREAD_FROM_PLAIN_H |
| 10532 | + |
| 10533 | +#ifdef __cplusplus |
| 10534 | +extern "C" { |
| 10535 | +#endif |
| 10536 | + |
| 10537 | +#include "interface/vcos/vcos_semaphore.h" |
| 10538 | +#include "interface/vcos/vcos_lowlevel_thread.h" |
| 10539 | +#include "interface/vcos/vcos_timer.h" |
| 10540 | + |
| 10541 | +#ifdef VCOS_WANT_TLS_EMULATION |
| 10542 | +#include "interface/vcos/generic/vcos_generic_tls.h" |
| 10543 | +#endif |
| 10544 | + |
| 10545 | +#define VCOS_THREAD_MAGIC 0x56436a74 |
| 10546 | + |
| 10547 | +#define VCOS_THREAD_VALID(t) (t->magic == VCOS_THREAD_MAGIC) |
| 10548 | +#define VCOS_HAVE_THREAD_AT_EXIT 1 |
| 10549 | + |
| 10550 | +/** Thread attribute structure. Clients should not manipulate this directly, but |
| 10551 | + * should instead use the provided functions. |
| 10552 | + */ |
| 10553 | +typedef struct VCOS_THREAD_ATTR_T |
| 10554 | +{ |
| 10555 | + void *ta_stackaddr; |
| 10556 | + VCOS_UNSIGNED ta_stacksz; |
| 10557 | + VCOS_UNSIGNED ta_priority; |
| 10558 | + VCOS_UNSIGNED ta_affinity; |
| 10559 | + VCOS_UNSIGNED ta_timeslice; |
| 10560 | + VCOS_UNSIGNED legacy; |
| 10561 | + VCOS_UNSIGNED ta_autostart; |
| 10562 | +} VCOS_THREAD_ATTR_T; |
| 10563 | + |
| 10564 | +/** Each thread gets a timer, which is for internal VCOS use. |
| 10565 | + */ |
| 10566 | +typedef struct _VCOS_THREAD_TIMER_T |
| 10567 | +{ |
| 10568 | + VCOS_TIMER_T timer; |
| 10569 | + void (*pfn)(void *); |
| 10570 | + void *cxt; |
| 10571 | +} _VCOS_THREAD_TIMER_T; |
| 10572 | + |
| 10573 | +typedef void (*VCOS_THREAD_EXIT_HANDLER_T)(void *); |
| 10574 | +/** Called at thread exit. |
| 10575 | + */ |
| 10576 | +typedef struct VCOS_THREAD_EXIT_T |
| 10577 | +{ |
| 10578 | + VCOS_THREAD_EXIT_HANDLER_T pfn; |
| 10579 | + void *cxt; |
| 10580 | +} VCOS_THREAD_EXIT_T; |
| 10581 | +#define VCOS_MAX_EXIT_HANDLERS 8 |
| 10582 | + |
| 10583 | +/* The name field isn't used for anything, so we can just copy the |
| 10584 | + * the pointer. Nucleus makes its own copy. |
| 10585 | + */ |
| 10586 | +typedef const char * VCOS_LLTHREAD_T_NAME; |
| 10587 | +#define _VCOS_LLTHREAD_NAME(dst,src) (dst)=(src) |
| 10588 | + |
| 10589 | +/* |
| 10590 | + * Simulated TLS support |
| 10591 | + */ |
| 10592 | + |
| 10593 | + |
| 10594 | +/** Thread structure. |
| 10595 | + * |
| 10596 | + * \warning Do not access the members of this structure directly! |
| 10597 | + */ |
| 10598 | +typedef struct VCOS_THREAD_T |
| 10599 | +{ |
| 10600 | + VCOS_LLTHREAD_T thread; /**< The underlying thread */ |
| 10601 | + char name[16]; /**< The name */ |
| 10602 | + unsigned int magic; /**< For debug */ |
| 10603 | + void *exit_data; /**< Exit data passed out in vcos_joinable_thread_exit() */ |
| 10604 | + void *stack; /**< Stack, if not supplied by caller */ |
| 10605 | + VCOS_SEMAPHORE_T wait; /**< Semaphore to wait on at join */ |
| 10606 | + VCOS_SEMAPHORE_T suspend; /**< Semaphore to wait on for counted suspend */ |
| 10607 | + int16_t joined; /**< Joined yet? For debug. */ |
| 10608 | + VCOS_UNSIGNED legacy; /**< Use (argc,argv) for entry point arguments */ |
| 10609 | + void *(*entry)(void*); /**< Entry point */ |
| 10610 | + void *arg; /**< Argument passed to entry point */ |
| 10611 | + void *(*term)(void*); /**< Termination function, used by reaper */ |
| 10612 | + void *term_arg; /**< Argument passed to termination function */ |
| 10613 | + _VCOS_THREAD_TIMER_T _timer; /**< Internal timer, mainly for event groups */ |
| 10614 | +#ifdef VCOS_WANT_TLS_EMULATION |
| 10615 | + VCOS_TLS_THREAD_T _tls; /**< TLS data when native TLS not available, or NULL */ |
| 10616 | +#endif |
| 10617 | + /** Array of functions to call at thread exit */ |
| 10618 | + VCOS_THREAD_EXIT_T at_exit[VCOS_MAX_EXIT_HANDLERS]; |
| 10619 | + |
| 10620 | + struct VCOS_THREAD_T *next; /**< For linked lists of threads */ |
| 10621 | +} VCOS_THREAD_T; |
| 10622 | + |
| 10623 | +#if defined(VCOS_INLINE_BODIES) |
| 10624 | + |
| 10625 | +VCOS_INLINE_IMPL |
| 10626 | +void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED stacksz) { |
| 10627 | + attrs->ta_stackaddr = addr; |
| 10628 | + attrs->ta_stacksz = stacksz; |
| 10629 | +} |
| 10630 | + |
| 10631 | +VCOS_INLINE_IMPL |
| 10632 | +void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED stacksz) { |
| 10633 | + attrs->ta_stacksz = stacksz; |
| 10634 | +} |
| 10635 | + |
| 10636 | +VCOS_INLINE_IMPL |
| 10637 | +void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri) { |
| 10638 | + attrs->ta_priority = pri; |
| 10639 | +} |
| 10640 | + |
| 10641 | +VCOS_INLINE_IMPL |
| 10642 | +void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED affinity) { |
| 10643 | + attrs->ta_affinity = affinity; |
| 10644 | +} |
| 10645 | + |
| 10646 | +VCOS_INLINE_IMPL |
| 10647 | +void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts) { |
| 10648 | + attrs->ta_timeslice = ts; |
| 10649 | +} |
| 10650 | + |
| 10651 | +VCOS_INLINE_IMPL |
| 10652 | +void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy) { |
| 10653 | + attrs->legacy = legacy; |
| 10654 | +} |
| 10655 | + |
| 10656 | +VCOS_INLINE_IMPL |
| 10657 | +void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart) { |
| 10658 | + attrs->ta_autostart = autostart; |
| 10659 | +} |
| 10660 | + |
| 10661 | +VCOS_INLINE_IMPL |
| 10662 | +VCOS_THREAD_T *vcos_thread_current(void) { |
| 10663 | + VCOS_THREAD_T *ret = (VCOS_THREAD_T*)vcos_llthread_current(); |
| 10664 | + /*If we're called from a non-vcos thread, this assert will fail. |
| 10665 | + *XXX FIXME why is this commented out? |
| 10666 | + *vcos_assert(ret->magic == VCOS_THREAD_MAGIC); |
| 10667 | + */ |
| 10668 | + return ret; |
| 10669 | +} |
| 10670 | + |
| 10671 | +VCOS_INLINE_IMPL |
| 10672 | +int vcos_thread_running(VCOS_THREAD_T *thread) { |
| 10673 | + return vcos_llthread_running(&thread->thread); |
| 10674 | +} |
| 10675 | + |
| 10676 | +VCOS_INLINE_IMPL |
| 10677 | +void vcos_thread_resume(VCOS_THREAD_T *thread) { |
| 10678 | + vcos_llthread_resume(&thread->thread); |
| 10679 | +} |
| 10680 | + |
| 10681 | +#endif /* VCOS_INLINE_BODIES */ |
| 10682 | + |
| 10683 | +/** |
| 10684 | + * \brief Create a VCOS_THREAD_T for the current thread. This is so we can have |
| 10685 | + * VCOS_THREAD_Ts even for threads not originally created by VCOS (eg the |
| 10686 | + * thread that calls vcos_init) |
| 10687 | + */ |
| 10688 | +extern VCOS_STATUS_T _vcos_thread_create_attach(VCOS_THREAD_T *thread, |
| 10689 | + const char *name); |
| 10690 | + |
| 10691 | +/** |
| 10692 | + * \brief Deletes the VCOS_THREAD_T, but does not wait for the underlying |
| 10693 | + * thread to exit. This will cleanup everything created by |
| 10694 | + * _vcos_thread_create_attach |
| 10695 | + */ |
| 10696 | +extern void _vcos_thread_delete(VCOS_THREAD_T *thread); |
| 10697 | + |
| 10698 | +/** Register a function to be called when the current thread exits. |
| 10699 | + */ |
| 10700 | +extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt); |
| 10701 | + |
| 10702 | +/** Deregister a previously registered at-exit function. |
| 10703 | + */ |
| 10704 | +extern void vcos_thread_deregister_at_exit(void (*pfn)(void*), void *cxt); |
| 10705 | + |
| 10706 | +#ifdef __cplusplus |
| 10707 | +} |
| 10708 | +#endif |
| 10709 | +#endif /* VCOS_JOINABLE_THREAD_FROM_PLAIN_H */ |
| 10710 | --- /dev/null |
| 10711 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_latch_from_sem.h |
| 10712 | @@ -0,0 +1,48 @@ |
| 10713 | +/*============================================================================= |
| 10714 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 10715 | +All rights reserved. |
| 10716 | + |
| 10717 | +Project : vcfw |
| 10718 | +Module : vcos |
| 10719 | + |
| 10720 | +FILE DESCRIPTION |
| 10721 | +VideoCore OS Abstraction Layer - Construct a latch from a semaphore |
| 10722 | +=============================================================================*/ |
| 10723 | + |
| 10724 | +/** FIXME: rename to vcos_mutex_from_sem.c |
| 10725 | + */ |
| 10726 | + |
| 10727 | +typedef struct VCOS_MUTEX_T { |
| 10728 | + VCOS_SEMAPHORE_T sem; |
| 10729 | + struct VCOS_THREAD_T *owner; |
| 10730 | +} VCOS_MUTEX_T; |
| 10731 | + |
| 10732 | +extern VCOS_STATUS_T vcos_generic_mutex_create(VCOS_MUTEX_T *latch, const char *name); |
| 10733 | +extern void vcos_generic_mutex_delete(VCOS_MUTEX_T *latch); |
| 10734 | +extern VCOS_STATUS_T vcos_generic_mutex_lock(VCOS_MUTEX_T *latch); |
| 10735 | +extern void vcos_generic_mutex_unlock(VCOS_MUTEX_T *latch); |
| 10736 | + |
| 10737 | +#if defined(VCOS_INLINE_BODIES) |
| 10738 | + |
| 10739 | +VCOS_INLINE_IMPL |
| 10740 | +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *latch, const char *name) { |
| 10741 | + return vcos_generic_mutex_create(latch,name); |
| 10742 | +} |
| 10743 | + |
| 10744 | +VCOS_INLINE_IMPL |
| 10745 | +void vcos_mutex_delete(VCOS_MUTEX_T *latch) { |
| 10746 | + vcos_generic_mutex_delete(latch); |
| 10747 | +} |
| 10748 | + |
| 10749 | +VCOS_INLINE_IMPL |
| 10750 | +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *latch) { |
| 10751 | + return vcos_generic_mutex_lock(latch); |
| 10752 | +} |
| 10753 | + |
| 10754 | +VCOS_INLINE_IMPL |
| 10755 | +void vcos_mutex_unlock(VCOS_MUTEX_T *latch) { |
| 10756 | + vcos_generic_mutex_unlock(latch); |
| 10757 | +} |
| 10758 | + |
| 10759 | +#endif /* VCOS_INLINE_BODIES */ |
| 10760 | + |
| 10761 | --- /dev/null |
| 10762 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_logcat.c |
| 10763 | @@ -0,0 +1,549 @@ |
| 10764 | +/*============================================================================= |
| 10765 | +Copyright (c) 2010 Broadcom Europe Limited. |
| 10766 | +All rights reserved. |
| 10767 | + |
| 10768 | +Project : vcfw |
| 10769 | +Module : vcos |
| 10770 | + |
| 10771 | +FILE DESCRIPTION |
| 10772 | +Categorized logging for VCOS - a generic implementation. |
| 10773 | +=============================================================================*/ |
| 10774 | + |
| 10775 | +#include "interface/vcos/vcos.h" |
| 10776 | +#include "interface/vcos/vcos_ctype.h" |
| 10777 | +#include "interface/vcos/vcos_string.h" |
| 10778 | + |
| 10779 | +static VCOS_MUTEX_T lock; |
| 10780 | +static int warned_loglevel; /* only warn about invalid log level once */ |
| 10781 | +static VCOS_VLOG_IMPL_FUNC_T vcos_vlog_impl_func = vcos_vlog_default_impl; |
| 10782 | + |
| 10783 | +#define VCOS_LOG_CATEGORY (&dflt_log_category) |
| 10784 | +static VCOS_LOG_CAT_T dflt_log_category; |
| 10785 | +VCOS_LOG_CAT_T *vcos_logging_categories = NULL; |
| 10786 | +static int inited; |
| 10787 | + |
| 10788 | +#if VCOS_HAVE_CMD |
| 10789 | + |
| 10790 | +/* |
| 10791 | + * For kernel or videocore purposes, we generally want the log command. For |
| 10792 | + * user-space apps, they might want to provide their own log command, so we |
| 10793 | + * don't include the built in on. |
| 10794 | + * |
| 10795 | + * So pthreads/vcos_platform.h defines VCOS_WANT_LOG_CMD to be 0. It is |
| 10796 | + * undefined elsewhere. |
| 10797 | + */ |
| 10798 | + |
| 10799 | +# if !defined( VCOS_WANT_LOG_CMD ) |
| 10800 | +# define VCOS_WANT_LOG_CMD 1 |
| 10801 | +# endif |
| 10802 | +#else |
| 10803 | +# define VCOS_WANT_LOG_CMD 0 |
| 10804 | +#endif |
| 10805 | + |
| 10806 | +#if VCOS_WANT_LOG_CMD |
| 10807 | + |
| 10808 | +/***************************************************************************** |
| 10809 | +* |
| 10810 | +* Does a vcos_assert(0), which is useful to test logging. |
| 10811 | +* |
| 10812 | +*****************************************************************************/ |
| 10813 | + |
| 10814 | +VCOS_STATUS_T vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param ) |
| 10815 | +{ |
| 10816 | + (void)param; |
| 10817 | + |
| 10818 | +#if defined( NDEBUG ) && !defined( VCOS_RELEASE_ASSERTS ) |
| 10819 | + vcos_log_error( "vcos_asserts have been compiled out" ); |
| 10820 | + vcos_cmd_printf( param, "vcos_asserts have been compiled out - did a vcos_log_error instead\n" ); |
| 10821 | +#else |
| 10822 | + vcos_assert(0); |
| 10823 | + vcos_cmd_printf( param, "Executed vcos_assert(0)\n" ); |
| 10824 | +#endif |
| 10825 | + |
| 10826 | + return VCOS_SUCCESS; |
| 10827 | +} |
| 10828 | + |
| 10829 | +/***************************************************************************** |
| 10830 | +* |
| 10831 | +* Sets a vcos logging level |
| 10832 | +* |
| 10833 | +*****************************************************************************/ |
| 10834 | + |
| 10835 | +VCOS_STATUS_T vcos_log_set_cmd( VCOS_CMD_PARAM_T *param ) |
| 10836 | +{ |
| 10837 | + VCOS_LOG_CAT_T *cat; |
| 10838 | + char *name; |
| 10839 | + char *levelStr; |
| 10840 | + VCOS_LOG_LEVEL_T level; |
| 10841 | + VCOS_STATUS_T status; |
| 10842 | + |
| 10843 | + if ( param->argc != 3 ) |
| 10844 | + { |
| 10845 | + vcos_cmd_usage( param ); |
| 10846 | + return VCOS_EINVAL; |
| 10847 | + } |
| 10848 | + |
| 10849 | + name = param->argv[1]; |
| 10850 | + levelStr = param->argv[2]; |
| 10851 | + |
| 10852 | + if ( vcos_string_to_log_level( levelStr, &level ) != VCOS_SUCCESS ) |
| 10853 | + { |
| 10854 | + vcos_cmd_printf( param, "Unrecognized logging level: '%s'\n", levelStr ); |
| 10855 | + return VCOS_EINVAL; |
| 10856 | + } |
| 10857 | + |
| 10858 | + vcos_mutex_lock(&lock); |
| 10859 | + |
| 10860 | + status = VCOS_SUCCESS; |
| 10861 | + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next ) |
| 10862 | + { |
| 10863 | + if ( vcos_strcmp( name, cat->name ) == 0 ) |
| 10864 | + { |
| 10865 | + cat->level = level; |
| 10866 | + vcos_cmd_printf( param, "Category %s level set to %s\n", name, levelStr ); |
| 10867 | + break; |
| 10868 | + } |
| 10869 | + } |
| 10870 | + if ( cat == NULL ) |
| 10871 | + { |
| 10872 | + vcos_cmd_printf( param, "Unrecognized category: '%s'\n", name ); |
| 10873 | + status = VCOS_ENOENT; |
| 10874 | + } |
| 10875 | + |
| 10876 | + vcos_mutex_unlock(&lock); |
| 10877 | + |
| 10878 | + return status; |
| 10879 | +} |
| 10880 | + |
| 10881 | +/***************************************************************************** |
| 10882 | +* |
| 10883 | +* Prints out the current settings for a given category (or all cvategories) |
| 10884 | +* |
| 10885 | +*****************************************************************************/ |
| 10886 | + |
| 10887 | +VCOS_STATUS_T vcos_log_status_cmd( VCOS_CMD_PARAM_T *param ) |
| 10888 | +{ |
| 10889 | + VCOS_LOG_CAT_T *cat; |
| 10890 | + VCOS_STATUS_T status; |
| 10891 | + |
| 10892 | + vcos_mutex_lock(&lock); |
| 10893 | + |
| 10894 | + if ( param->argc == 1) |
| 10895 | + { |
| 10896 | + int nw; |
| 10897 | + int nameWidth = 0; |
| 10898 | + |
| 10899 | + /* Print information about all of the categories. */ |
| 10900 | + |
| 10901 | + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next ) |
| 10902 | + { |
| 10903 | + nw = (int)strlen( cat->name ); |
| 10904 | + |
| 10905 | + if ( nw > nameWidth ) |
| 10906 | + { |
| 10907 | + nameWidth = nw; |
| 10908 | + } |
| 10909 | + } |
| 10910 | + |
| 10911 | + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next ) |
| 10912 | + { |
| 10913 | + vcos_cmd_printf( param, "%-*s - %s\n", nameWidth, cat->name, vcos_log_level_to_string( cat->level )); |
| 10914 | + } |
| 10915 | + } |
| 10916 | + else |
| 10917 | + { |
| 10918 | + /* Print information about a particular category */ |
| 10919 | + |
| 10920 | + for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next ) |
| 10921 | + { |
| 10922 | + if ( vcos_strcmp( cat->name, param->argv[1] ) == 0 ) |
| 10923 | + { |
| 10924 | + vcos_cmd_printf( param, "%s - %s\n", cat->name, vcos_log_level_to_string( cat->level )); |
| 10925 | + break; |
| 10926 | + } |
| 10927 | + } |
| 10928 | + if ( cat == NULL ) |
| 10929 | + { |
| 10930 | + vcos_cmd_printf( param, "Unrecognized logging category: '%s'\n", param->argv[1] ); |
| 10931 | + status = VCOS_ENOENT; |
| 10932 | + goto out; |
| 10933 | + } |
| 10934 | + } |
| 10935 | + |
| 10936 | + status = VCOS_SUCCESS; |
| 10937 | +out: |
| 10938 | + vcos_mutex_unlock(&lock); |
| 10939 | + |
| 10940 | + return status; |
| 10941 | +} |
| 10942 | + |
| 10943 | +/***************************************************************************** |
| 10944 | +* |
| 10945 | +* Prints out the current settings for a given category (or all cvategories) |
| 10946 | +* |
| 10947 | +*****************************************************************************/ |
| 10948 | + |
| 10949 | +VCOS_STATUS_T vcos_log_test_cmd( VCOS_CMD_PARAM_T *param ) |
| 10950 | +{ |
| 10951 | + if ( param->argc == 1 ) |
| 10952 | + { |
| 10953 | + static int seq_num = 100; |
| 10954 | + |
| 10955 | + /* No additional arguments - generate a message with an incrementing number */ |
| 10956 | + |
| 10957 | + vcos_log_error( "Test message %d", seq_num ); |
| 10958 | + |
| 10959 | + seq_num++; |
| 10960 | + vcos_cmd_printf( param, "Logged 'Test message %d'\n", seq_num ); |
| 10961 | + } |
| 10962 | + else |
| 10963 | + { |
| 10964 | + int arg_idx; |
| 10965 | + |
| 10966 | + /* Arguments supplied - log these */ |
| 10967 | + |
| 10968 | + for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ ) |
| 10969 | + { |
| 10970 | + vcos_log_error( "argv[%d] = '%s'", arg_idx, param->argv[arg_idx] ); |
| 10971 | + } |
| 10972 | + vcos_cmd_printf( param, "Logged %d line(s) of test data\n", param->argc ); |
| 10973 | + } |
| 10974 | + return VCOS_SUCCESS; |
| 10975 | +} |
| 10976 | + |
| 10977 | +/***************************************************************************** |
| 10978 | +* |
| 10979 | +* Internal commands |
| 10980 | +* |
| 10981 | +*****************************************************************************/ |
| 10982 | + |
| 10983 | +static VCOS_CMD_T log_cmd_entry[] = |
| 10984 | +{ |
| 10985 | + { "assert", "", vcos_log_assert_cmd, NULL, "Does a vcos_assert(0) to test logging" }, |
| 10986 | + { "set", "category level", vcos_log_set_cmd, NULL, "Sets the vcos logging level for a category" }, |
| 10987 | + { "status", "[category]", vcos_log_status_cmd, NULL, "Prints the vcos log status for a (or all) categories" }, |
| 10988 | + { "test", "[arbitrary text]", vcos_log_test_cmd, NULL, "Does a vcos_log to test logging" }, |
| 10989 | + |
| 10990 | + { NULL, NULL, NULL, NULL, NULL } |
| 10991 | +}; |
| 10992 | + |
| 10993 | +static VCOS_CMD_T cmd_log = |
| 10994 | + { "log", "command [args]", NULL, log_cmd_entry, "Commands related to vcos logging" }; |
| 10995 | + |
| 10996 | +#endif |
| 10997 | + |
| 10998 | +void vcos_logging_init(void) |
| 10999 | +{ |
| 11000 | + if (inited) |
| 11001 | + { |
| 11002 | + /* FIXME: should print a warning or something here */ |
| 11003 | + return; |
| 11004 | + } |
| 11005 | + vcos_mutex_create(&lock, "vcos_log"); |
| 11006 | + |
| 11007 | + vcos_log_platform_init(); |
| 11008 | + |
| 11009 | + vcos_log_register("default", &dflt_log_category); |
| 11010 | + |
| 11011 | +#if VCOS_WANT_LOG_CMD |
| 11012 | + vcos_cmd_register( &cmd_log ); |
| 11013 | +#endif |
| 11014 | + |
| 11015 | + vcos_assert(!inited); |
| 11016 | + inited = 1; |
| 11017 | +} |
| 11018 | + |
| 11019 | +/** Read an alphanumeric token, returning True if we succeeded. |
| 11020 | + */ |
| 11021 | + |
| 11022 | +static int read_tok(char *tok, size_t toklen, const char **pstr, char sep) |
| 11023 | +{ |
| 11024 | + const char *str = *pstr; |
| 11025 | + size_t n = 0; |
| 11026 | + char ch; |
| 11027 | + |
| 11028 | + /* skip past any whitespace */ |
| 11029 | + while (str[0] && isspace((int)(str[0]))) |
| 11030 | + str++; |
| 11031 | + |
| 11032 | + while ((ch = *str) != '\0' && |
| 11033 | + ch != sep && |
| 11034 | + (isalnum((int)ch) || (ch == '_')) && |
| 11035 | + n != toklen-1) |
| 11036 | + { |
| 11037 | + tok[n++] = ch; |
| 11038 | + str++; |
| 11039 | + } |
| 11040 | + |
| 11041 | + /* did it work out? */ |
| 11042 | + if (ch == '\0' || ch == sep) |
| 11043 | + { |
| 11044 | + if (ch) str++; /* move to next token if not at end */ |
| 11045 | + /* yes */ |
| 11046 | + tok[n] = '\0'; |
| 11047 | + *pstr = str; |
| 11048 | + return 1; |
| 11049 | + } |
| 11050 | + else |
| 11051 | + { |
| 11052 | + /* no */ |
| 11053 | + return 0; |
| 11054 | + } |
| 11055 | +} |
| 11056 | + |
| 11057 | +const char *vcos_log_level_to_string( VCOS_LOG_LEVEL_T level ) |
| 11058 | +{ |
| 11059 | + switch (level) |
| 11060 | + { |
| 11061 | + case VCOS_LOG_UNINITIALIZED: return "uninit"; |
| 11062 | + case VCOS_LOG_NEVER: return "never"; |
| 11063 | + case VCOS_LOG_ERROR: return "error"; |
| 11064 | + case VCOS_LOG_WARN: return "warn"; |
| 11065 | + case VCOS_LOG_INFO: return "info"; |
| 11066 | + case VCOS_LOG_TRACE: return "trace"; |
| 11067 | + } |
| 11068 | + return "???"; |
| 11069 | +} |
| 11070 | + |
| 11071 | +VCOS_STATUS_T vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level ) |
| 11072 | +{ |
| 11073 | + if (strcmp(str,"error") == 0) |
| 11074 | + *level = VCOS_LOG_ERROR; |
| 11075 | + else if (strcmp(str,"never") == 0) |
| 11076 | + *level = VCOS_LOG_NEVER; |
| 11077 | + else if (strcmp(str,"warn") == 0) |
| 11078 | + *level = VCOS_LOG_WARN; |
| 11079 | + else if (strcmp(str,"warning") == 0) |
| 11080 | + *level = VCOS_LOG_WARN; |
| 11081 | + else if (strcmp(str,"info") == 0) |
| 11082 | + *level = VCOS_LOG_INFO; |
| 11083 | + else if (strcmp(str,"trace") == 0) |
| 11084 | + *level = VCOS_LOG_TRACE; |
| 11085 | + else |
| 11086 | + return VCOS_EINVAL; |
| 11087 | + |
| 11088 | + return VCOS_SUCCESS; |
| 11089 | +} |
| 11090 | + |
| 11091 | +static int read_level(VCOS_LOG_LEVEL_T *level, const char **pstr, char sep) |
| 11092 | +{ |
| 11093 | + char buf[16]; |
| 11094 | + int ret = 1; |
| 11095 | + if (read_tok(buf,sizeof(buf),pstr,sep)) |
| 11096 | + { |
| 11097 | + if (vcos_string_to_log_level(buf,level) != VCOS_SUCCESS) |
| 11098 | + { |
| 11099 | + vcos_log("Invalid trace level '%s'\n", buf); |
| 11100 | + ret = 0; |
| 11101 | + } |
| 11102 | + } |
| 11103 | + else |
| 11104 | + { |
| 11105 | + ret = 0; |
| 11106 | + } |
| 11107 | + return ret; |
| 11108 | +} |
| 11109 | + |
| 11110 | +void vcos_log_register(const char *name, VCOS_LOG_CAT_T *category) |
| 11111 | +{ |
| 11112 | + const char *env; |
| 11113 | + VCOS_LOG_CAT_T *i; |
| 11114 | + |
| 11115 | + category->name = name; |
| 11116 | + if ( category->level == VCOS_LOG_UNINITIALIZED ) |
| 11117 | + { |
| 11118 | + category->level = VCOS_LOG_ERROR; |
| 11119 | + } |
| 11120 | + category->flags.want_prefix = (category != &dflt_log_category ); |
| 11121 | + |
| 11122 | + vcos_mutex_lock(&lock); |
| 11123 | + |
| 11124 | + /* is it already registered? */ |
| 11125 | + for (i = vcos_logging_categories; i ; i = i->next ) |
| 11126 | + { |
| 11127 | + if (i == category) |
| 11128 | + { |
| 11129 | + i->refcount++; |
| 11130 | + break; |
| 11131 | + } |
| 11132 | + } |
| 11133 | + |
| 11134 | + if (!i) |
| 11135 | + { |
| 11136 | + /* not yet registered */ |
| 11137 | + category->next = vcos_logging_categories; |
| 11138 | + vcos_logging_categories = category; |
| 11139 | + category->refcount++; |
| 11140 | + |
| 11141 | + vcos_log_platform_register(category); |
| 11142 | + } |
| 11143 | + |
| 11144 | + vcos_mutex_unlock(&lock); |
| 11145 | + |
| 11146 | + /* Check to see if this log level has been enabled. Look for |
| 11147 | + * (<category:level>,)* |
| 11148 | + * |
| 11149 | + * VC_LOGLEVEL=ilcs:info,vchiq:warn |
| 11150 | + */ |
| 11151 | + |
| 11152 | + env = _VCOS_LOG_LEVEL(); |
| 11153 | + if (env) |
| 11154 | + { |
| 11155 | + do |
| 11156 | + { |
| 11157 | + char env_name[64]; |
| 11158 | + VCOS_LOG_LEVEL_T level; |
| 11159 | + if (read_tok(env_name, sizeof(env_name), &env, ':') && |
| 11160 | + read_level(&level, &env, ',')) |
| 11161 | + { |
| 11162 | + if (strcmp(env_name, name) == 0) |
| 11163 | + { |
| 11164 | + category->level = level; |
| 11165 | + break; |
| 11166 | + } |
| 11167 | + } |
| 11168 | + else |
| 11169 | + { |
| 11170 | + if (!warned_loglevel) |
| 11171 | + { |
| 11172 | + vcos_log("VC_LOGLEVEL format invalid at %s\n", env); |
| 11173 | + warned_loglevel = 1; |
| 11174 | + } |
| 11175 | + return; |
| 11176 | + } |
| 11177 | + } while (env[0] != '\0'); |
| 11178 | + } |
| 11179 | + |
| 11180 | + vcos_log_info( "Registered log category '%s' with level %s", |
| 11181 | + category->name, |
| 11182 | + vcos_log_level_to_string( category->level )); |
| 11183 | +} |
| 11184 | + |
| 11185 | +void vcos_log_unregister(VCOS_LOG_CAT_T *category) |
| 11186 | +{ |
| 11187 | + VCOS_LOG_CAT_T **pcat; |
| 11188 | + vcos_mutex_lock(&lock); |
| 11189 | + category->refcount--; |
| 11190 | + if (category->refcount == 0) |
| 11191 | + { |
| 11192 | + pcat = &vcos_logging_categories; |
| 11193 | + while (*pcat != category) |
| 11194 | + { |
| 11195 | + if (!*pcat) |
| 11196 | + break; /* possibly deregistered twice? */ |
| 11197 | + if ((*pcat)->next == NULL) |
| 11198 | + { |
| 11199 | + vcos_assert(0); /* already removed! */ |
| 11200 | + vcos_mutex_unlock(&lock); |
| 11201 | + return; |
| 11202 | + } |
| 11203 | + pcat = &(*pcat)->next; |
| 11204 | + } |
| 11205 | + if (*pcat) |
| 11206 | + *pcat = category->next; |
| 11207 | + |
| 11208 | + vcos_log_platform_unregister(category); |
| 11209 | + } |
| 11210 | + vcos_mutex_unlock(&lock); |
| 11211 | +} |
| 11212 | + |
| 11213 | +VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void) |
| 11214 | +{ |
| 11215 | + return &dflt_log_category; |
| 11216 | +} |
| 11217 | + |
| 11218 | +void vcos_set_log_options(const char *opt) |
| 11219 | +{ |
| 11220 | + (void)opt; |
| 11221 | +} |
| 11222 | + |
| 11223 | +void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat, |
| 11224 | + const char *label, |
| 11225 | + uint32_t addr, |
| 11226 | + const void *voidMem, |
| 11227 | + size_t numBytes ) |
| 11228 | +{ |
| 11229 | + const uint8_t *mem = (const uint8_t *)voidMem; |
| 11230 | + size_t offset; |
| 11231 | + char lineBuf[ 100 ]; |
| 11232 | + char *s; |
| 11233 | + |
| 11234 | + while ( numBytes > 0 ) |
| 11235 | + { |
| 11236 | + s = lineBuf; |
| 11237 | + |
| 11238 | + for ( offset = 0; offset < 16; offset++ ) |
| 11239 | + { |
| 11240 | + if ( offset < numBytes ) |
| 11241 | + { |
| 11242 | + s += vcos_snprintf( s, 4, "%02x ", mem[ offset ]); |
| 11243 | + } |
| 11244 | + else |
| 11245 | + { |
| 11246 | + s += vcos_snprintf( s, 4, " " ); |
| 11247 | + } |
| 11248 | + } |
| 11249 | + |
| 11250 | + for ( offset = 0; offset < 16; offset++ ) |
| 11251 | + { |
| 11252 | + if ( offset < numBytes ) |
| 11253 | + { |
| 11254 | + uint8_t ch = mem[ offset ]; |
| 11255 | + |
| 11256 | + if (( ch < ' ' ) || ( ch > '~' )) |
| 11257 | + { |
| 11258 | + ch = '.'; |
| 11259 | + } |
| 11260 | + *s++ = (char)ch; |
| 11261 | + } |
| 11262 | + } |
| 11263 | + *s++ = '\0'; |
| 11264 | + |
| 11265 | + if (( label != NULL ) && ( *label != '\0' )) |
| 11266 | + { |
| 11267 | + vcos_log_impl( cat, VCOS_LOG_INFO, "%s: %08x: %s", label, addr, lineBuf ); |
| 11268 | + } |
| 11269 | + else |
| 11270 | + { |
| 11271 | + vcos_log_impl( cat, VCOS_LOG_INFO, "%08x: %s", addr, lineBuf ); |
| 11272 | + } |
| 11273 | + |
| 11274 | + addr += 16; |
| 11275 | + mem += 16; |
| 11276 | + if ( numBytes > 16 ) |
| 11277 | + { |
| 11278 | + numBytes -= 16; |
| 11279 | + } |
| 11280 | + else |
| 11281 | + { |
| 11282 | + numBytes = 0; |
| 11283 | + } |
| 11284 | + } |
| 11285 | + |
| 11286 | +} |
| 11287 | + |
| 11288 | +void vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...) |
| 11289 | +{ |
| 11290 | + va_list ap; |
| 11291 | + va_start(ap,fmt); |
| 11292 | + vcos_vlog_impl( cat, _level, fmt, ap ); |
| 11293 | + va_end(ap); |
| 11294 | +} |
| 11295 | + |
| 11296 | +void vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) |
| 11297 | +{ |
| 11298 | + vcos_vlog_impl_func( cat, _level, fmt, args ); |
| 11299 | +} |
| 11300 | + |
| 11301 | +void vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func ) |
| 11302 | +{ |
| 11303 | + if ( vlog_impl_func == NULL ) |
| 11304 | + { |
| 11305 | + vcos_vlog_impl_func = vcos_vlog_default_impl; |
| 11306 | + } |
| 11307 | + else |
| 11308 | + { |
| 11309 | + vcos_vlog_impl_func = vlog_impl_func; |
| 11310 | + } |
| 11311 | +} |
| 11312 | + |
| 11313 | --- /dev/null |
| 11314 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.c |
| 11315 | @@ -0,0 +1,73 @@ |
| 11316 | +/*============================================================================= |
| 11317 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 11318 | +All rights reserved. |
| 11319 | + |
| 11320 | +Project : vcfw |
| 11321 | +Module : vcos |
| 11322 | + |
| 11323 | +FILE DESCRIPTION |
| 11324 | +VideoCore OS Abstraction Layer - memory alloc implementation |
| 11325 | +=============================================================================*/ |
| 11326 | + |
| 11327 | +#include "interface/vcos/vcos.h" |
| 11328 | + |
| 11329 | +#ifndef _vcos_platform_malloc |
| 11330 | +#include <stdlib.h> |
| 11331 | +#define _vcos_platform_malloc malloc |
| 11332 | +#define _vcos_platform_free free |
| 11333 | +#endif |
| 11334 | + |
| 11335 | +typedef struct malloc_header_s { |
| 11336 | + uint32_t guardword; |
| 11337 | + uint32_t size; |
| 11338 | + const char *description; |
| 11339 | + void *ptr; |
| 11340 | +} MALLOC_HEADER_T; |
| 11341 | + |
| 11342 | + |
| 11343 | +#define MIN_ALIGN sizeof(MALLOC_HEADER_T) |
| 11344 | + |
| 11345 | +#define GUARDWORDHEAP 0xa55a5aa5 |
| 11346 | + |
| 11347 | +void *vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *desc) |
| 11348 | +{ |
| 11349 | + int local_align = align == 0 ? 1 : align; |
| 11350 | + int required_size = size + local_align + sizeof(MALLOC_HEADER_T); |
| 11351 | + void *ptr = _vcos_platform_malloc(required_size); |
| 11352 | + void *ret = (void *)VCOS_ALIGN_UP(((char *)ptr)+sizeof(MALLOC_HEADER_T), local_align); |
| 11353 | + MALLOC_HEADER_T *h = ((MALLOC_HEADER_T *)ret)-1; |
| 11354 | + |
| 11355 | + h->size = size; |
| 11356 | + h->description = desc; |
| 11357 | + h->guardword = GUARDWORDHEAP; |
| 11358 | + h->ptr = ptr; |
| 11359 | + |
| 11360 | + return ret; |
| 11361 | +} |
| 11362 | + |
| 11363 | +void *vcos_generic_mem_alloc(VCOS_UNSIGNED size, const char *desc) |
| 11364 | +{ |
| 11365 | + return vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc); |
| 11366 | +} |
| 11367 | + |
| 11368 | +void *vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *desc) |
| 11369 | +{ |
| 11370 | + uint32_t size = count*sz; |
| 11371 | + void *ptr = vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc); |
| 11372 | + if (ptr) |
| 11373 | + { |
| 11374 | + memset(ptr, 0, size); |
| 11375 | + } |
| 11376 | + return ptr; |
| 11377 | +} |
| 11378 | + |
| 11379 | +void vcos_generic_mem_free(void *ptr) |
| 11380 | +{ |
| 11381 | + MALLOC_HEADER_T *h; |
| 11382 | + if (! ptr) return; |
| 11383 | + |
| 11384 | + h = ((MALLOC_HEADER_T *)ptr)-1; |
| 11385 | + vcos_assert(h->guardword == GUARDWORDHEAP); |
| 11386 | + _vcos_platform_free(h->ptr); |
| 11387 | +} |
| 11388 | + |
| 11389 | --- /dev/null |
| 11390 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mem_from_malloc.h |
| 11391 | @@ -0,0 +1,54 @@ |
| 11392 | +/*============================================================================= |
| 11393 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 11394 | +All rights reserved. |
| 11395 | + |
| 11396 | +Project : VMCS Host Apps |
| 11397 | +Module : Framework - VMCS |
| 11398 | + |
| 11399 | +FILE DESCRIPTION |
| 11400 | +Create the vcos_malloc API from the regular system malloc/free |
| 11401 | +=============================================================================*/ |
| 11402 | + |
| 11403 | +/** |
| 11404 | + * \file |
| 11405 | + * |
| 11406 | + * Create the vcos malloc API from a regular system malloc/free library. |
| 11407 | + * |
| 11408 | + * The API lets callers specify an alignment. |
| 11409 | + * |
| 11410 | + * Under VideoCore this is not needed, as we can simply use the rtos_malloc routines. |
| 11411 | + * But on host platforms that won't be the case. |
| 11412 | + * |
| 11413 | + */ |
| 11414 | + |
| 11415 | +VCOSPRE_ void * VCOSPOST_ vcos_generic_mem_alloc(VCOS_UNSIGNED sz, const char *desc); |
| 11416 | +VCOSPRE_ void * VCOSPOST_ vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *descr); |
| 11417 | +VCOSPRE_ void VCOSPOST_ vcos_generic_mem_free(void *ptr); |
| 11418 | +VCOSPRE_ void * VCOSPOST_ vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED sz, VCOS_UNSIGNED align, const char *desc); |
| 11419 | + |
| 11420 | +#ifdef VCOS_INLINE_BODIES |
| 11421 | + |
| 11422 | +VCOS_INLINE_IMPL |
| 11423 | +void *vcos_malloc(VCOS_UNSIGNED size, const char *description) { |
| 11424 | + return vcos_generic_mem_alloc(size, description); |
| 11425 | +} |
| 11426 | + |
| 11427 | +VCOS_INLINE_IMPL |
| 11428 | +void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description) { |
| 11429 | + return vcos_generic_mem_calloc(num, size, description); |
| 11430 | +} |
| 11431 | + |
| 11432 | +VCOS_INLINE_IMPL |
| 11433 | +void vcos_free(void *ptr) { |
| 11434 | + vcos_generic_mem_free(ptr); |
| 11435 | +} |
| 11436 | + |
| 11437 | +VCOS_INLINE_IMPL |
| 11438 | +void * vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description) { |
| 11439 | + return vcos_generic_mem_alloc_aligned(size, align, description); |
| 11440 | +} |
| 11441 | + |
| 11442 | + |
| 11443 | +#endif /* VCOS_INLINE_BODIES */ |
| 11444 | + |
| 11445 | + |
| 11446 | --- /dev/null |
| 11447 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_mutexes_are_reentrant.h |
| 11448 | @@ -0,0 +1,68 @@ |
| 11449 | +/*============================================================================= |
| 11450 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 11451 | +All rights reserved. |
| 11452 | + |
| 11453 | +Project : vcfw |
| 11454 | +Module : chip driver |
| 11455 | + |
| 11456 | +FILE DESCRIPTION |
| 11457 | +VideoCore OS Abstraction Layer - reentrant mutexes mapped directly to regular ones |
| 11458 | +=============================================================================*/ |
| 11459 | + |
| 11460 | +#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H |
| 11461 | +#define VCOS_GENERIC_REENTRANT_MUTEX_H |
| 11462 | + |
| 11463 | +#ifdef __cplusplus |
| 11464 | +extern "C" { |
| 11465 | +#endif |
| 11466 | + |
| 11467 | +#include "interface/vcos/vcos_types.h" |
| 11468 | +#include "interface/vcos/vcos_mutex.h" |
| 11469 | + |
| 11470 | +/** |
| 11471 | + * \file |
| 11472 | + * |
| 11473 | + * Reentrant Mutexes directly using the native re-entrant mutex. |
| 11474 | + * |
| 11475 | + */ |
| 11476 | + |
| 11477 | +typedef VCOS_MUTEX_T VCOS_REENTRANT_MUTEX_T; |
| 11478 | + |
| 11479 | +/* Inline forwarding functions */ |
| 11480 | + |
| 11481 | +#if defined(VCOS_INLINE_BODIES) |
| 11482 | + |
| 11483 | +VCOS_INLINE_IMPL |
| 11484 | +VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) { |
| 11485 | + return vcos_mutex_create(m,name); |
| 11486 | +} |
| 11487 | + |
| 11488 | +VCOS_INLINE_IMPL |
| 11489 | +void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) { |
| 11490 | + vcos_mutex_delete(m); |
| 11491 | +} |
| 11492 | + |
| 11493 | +VCOS_INLINE_IMPL |
| 11494 | +void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) { |
| 11495 | + vcos_mutex_lock(m); |
| 11496 | +} |
| 11497 | + |
| 11498 | +VCOS_INLINE_IMPL |
| 11499 | +void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) { |
| 11500 | + vcos_mutex_unlock(m); |
| 11501 | +} |
| 11502 | + |
| 11503 | +VCOS_INLINE_IMPL |
| 11504 | +int vcos_reentrant_mutex_is_locked(VCOS_REENTRANT_MUTEX_T *m) { |
| 11505 | + return vcos_mutex_is_locked(m); |
| 11506 | +} |
| 11507 | + |
| 11508 | +#endif |
| 11509 | + |
| 11510 | +#ifdef __cplusplus |
| 11511 | +} |
| 11512 | +#endif |
| 11513 | +#endif |
| 11514 | + |
| 11515 | + |
| 11516 | + |
| 11517 | --- /dev/null |
| 11518 | +++ b/drivers/misc/vc04_services/interface/vcos/generic/vcos_thread_reaper.h |
| 11519 | @@ -0,0 +1,35 @@ |
| 11520 | +/*============================================================================= |
| 11521 | +Copyright (c) 2010 Broadcom Europe Limited. |
| 11522 | +All rights reserved. |
| 11523 | + |
| 11524 | +Project : vcfw |
| 11525 | +Module : vcos |
| 11526 | + |
| 11527 | +FILE DESCRIPTION |
| 11528 | +VideoCore OS Abstraction Layer - thread reaping |
| 11529 | +=============================================================================*/ |
| 11530 | + |
| 11531 | +#ifndef VCOS_THREAD_REAPER_H |
| 11532 | +#define VCOS_THREAD_REAPER_H |
| 11533 | + |
| 11534 | +#define VCOS_HAVE_THREAD_REAPER |
| 11535 | + |
| 11536 | +/** Initialise the thread reaper. |
| 11537 | + */ |
| 11538 | +VCOS_STATUS_T vcos_thread_reaper_init(void); |
| 11539 | + |
| 11540 | +/** Reap a thread. Arranges for the thread to be automatically |
| 11541 | + * joined. |
| 11542 | + * |
| 11543 | + * @sa vcos_thread_join(). |
| 11544 | + * |
| 11545 | + * @param thread the thread to terminate |
| 11546 | + * @param on_terminated called after the thread has exited |
| 11547 | + * @param cxt pass back to the callback |
| 11548 | + * |
| 11549 | + */ |
| 11550 | +void vcos_thread_reap(VCOS_THREAD_T *thread, void (*on_terminated)(void*), void *cxt); |
| 11551 | + |
| 11552 | +#endif |
| 11553 | + |
| 11554 | + |
| 11555 | --- /dev/null |
| 11556 | +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/stdint.h |
| 11557 | @@ -0,0 +1,17 @@ |
| 11558 | +/*============================================================================= |
| 11559 | +Copyright (c) 2010 Broadcom Europe Limited. |
| 11560 | +All rights reserved. |
| 11561 | + |
| 11562 | +FILE DESCRIPTION |
| 11563 | +VideoCore OS fAbstraction Layer - stdint.h C standard header |
| 11564 | +=============================================================================*/ |
| 11565 | + |
| 11566 | +#ifndef _VCOS_PLATFORM_LINUX_STDINT_H |
| 11567 | +#define _VCOS_PLATFORM_LINUX_STDINT_H |
| 11568 | + |
| 11569 | +/* The Linux kernel does not have a <stdint.h> so we have to provide one of |
| 11570 | + our own. */ |
| 11571 | + |
| 11572 | +#include <linux/types.h> /* includes integer types */ |
| 11573 | + |
| 11574 | +#endif /* _VCOS_PLATFORM_LINUX_STDINT_H */ |
| 11575 | --- /dev/null |
| 11576 | +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel.c |
| 11577 | @@ -0,0 +1,616 @@ |
| 11578 | +/*============================================================================= |
| 11579 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 11580 | +All rights reserved. |
| 11581 | + |
| 11582 | +Project : vcfw |
| 11583 | +Module : vcos |
| 11584 | + |
| 11585 | +FILE DESCRIPTION |
| 11586 | +VideoCore OS Abstraction Layer - pthreads types |
| 11587 | +=============================================================================*/ |
| 11588 | + |
| 11589 | +#define VCOS_INLINE_BODIES |
| 11590 | +#include <linux/module.h> |
| 11591 | +#include <linux/kernel.h> |
| 11592 | +#include <linux/time.h> |
| 11593 | +#include <linux/pid.h> |
| 11594 | +#include <linux/mm.h> |
| 11595 | +#include <linux/version.h> |
| 11596 | + |
| 11597 | +#if defined( CONFIG_BCM_KNLLOG_SUPPORT ) |
| 11598 | +#include <linux/broadcom/knllog.h> |
| 11599 | +#endif |
| 11600 | +#include "interface/vcos/vcos.h" |
| 11601 | +#ifdef HAVE_VCOS_VERSION |
| 11602 | +#include "interface/vcos/vcos_build_info.h" |
| 11603 | +#endif |
| 11604 | + |
| 11605 | +VCOS_CFG_ENTRY_T vcos_cfg_dir; |
| 11606 | +VCOS_CFG_ENTRY_T vcos_logging_cfg_dir; |
| 11607 | +VCOS_CFG_ENTRY_T vcos_version_cfg; |
| 11608 | + |
| 11609 | +#ifndef VCOS_DEFAULT_STACK_SIZE |
| 11610 | +#define VCOS_DEFAULT_STACK_SIZE 4096 |
| 11611 | +#endif |
| 11612 | + |
| 11613 | +static VCOS_THREAD_ATTR_T default_attrs = { |
| 11614 | + 0, |
| 11615 | + VCOS_DEFAULT_STACK_SIZE, |
| 11616 | +}; |
| 11617 | + |
| 11618 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) |
| 11619 | +static DEFINE_SEMAPHORE(lock); |
| 11620 | +#else |
| 11621 | +static DECLARE_MUTEX(lock); |
| 11622 | +#endif |
| 11623 | + |
| 11624 | +typedef void (*LEGACY_ENTRY_FN_T)(int, void *); |
| 11625 | + |
| 11626 | +/** Wrapper function around the real thread function. Posts the semaphore |
| 11627 | + * when completed. |
| 11628 | + */ |
| 11629 | +static int vcos_thread_wrapper(void *arg) |
| 11630 | +{ |
| 11631 | + void *ret; |
| 11632 | + VCOS_THREAD_T *thread = arg; |
| 11633 | + |
| 11634 | + vcos_assert(thread->magic == VCOS_THREAD_MAGIC); |
| 11635 | + |
| 11636 | + thread->thread.thread = current; |
| 11637 | + |
| 11638 | + vcos_add_thread(thread); |
| 11639 | + |
| 11640 | +#ifdef VCOS_WANT_TLS_EMULATION |
| 11641 | + vcos_tls_thread_register(&thread->_tls); |
| 11642 | +#endif |
| 11643 | + |
| 11644 | + if (thread->legacy) |
| 11645 | + { |
| 11646 | + LEGACY_ENTRY_FN_T fn = (LEGACY_ENTRY_FN_T)thread->entry; |
| 11647 | + fn(0,thread->arg); |
| 11648 | + ret = 0; |
| 11649 | + } |
| 11650 | + else |
| 11651 | + { |
| 11652 | + ret = thread->entry(thread->arg); |
| 11653 | + } |
| 11654 | + |
| 11655 | + thread->exit_data = ret; |
| 11656 | + |
| 11657 | + vcos_remove_thread(current); |
| 11658 | + |
| 11659 | + /* For join and cleanup */ |
| 11660 | + vcos_semaphore_post(&thread->wait); |
| 11661 | + |
| 11662 | + return 0; |
| 11663 | +} |
| 11664 | + |
| 11665 | +VCOS_STATUS_T vcos_thread_create(VCOS_THREAD_T *thread, |
| 11666 | + const char *name, |
| 11667 | + VCOS_THREAD_ATTR_T *attrs, |
| 11668 | + VCOS_THREAD_ENTRY_FN_T entry, |
| 11669 | + void *arg) |
| 11670 | +{ |
| 11671 | + VCOS_STATUS_T st; |
| 11672 | + struct task_struct *kthread; |
| 11673 | + |
| 11674 | + memset(thread, 0, sizeof(*thread)); |
| 11675 | + thread->magic = VCOS_THREAD_MAGIC; |
| 11676 | + strlcpy( thread->name, name, sizeof( thread->name )); |
| 11677 | + thread->legacy = attrs ? attrs->legacy : 0; |
| 11678 | + thread->entry = entry; |
| 11679 | + thread->arg = arg; |
| 11680 | + |
| 11681 | + if (!name) |
| 11682 | + { |
| 11683 | + vcos_assert(0); |
| 11684 | + return VCOS_EINVAL; |
| 11685 | + } |
| 11686 | + |
| 11687 | + st = vcos_semaphore_create(&thread->wait, NULL, 0); |
| 11688 | + if (st != VCOS_SUCCESS) |
| 11689 | + { |
| 11690 | + return st; |
| 11691 | + } |
| 11692 | + |
| 11693 | + st = vcos_semaphore_create(&thread->suspend, NULL, 0); |
| 11694 | + if (st != VCOS_SUCCESS) |
| 11695 | + { |
| 11696 | + return st; |
| 11697 | + } |
| 11698 | + |
| 11699 | + /*required for event groups */ |
| 11700 | + vcos_timer_create(&thread->_timer.timer, thread->name, NULL, NULL); |
| 11701 | + |
| 11702 | + kthread = kthread_create((int (*)(void *))vcos_thread_wrapper, (void*)thread, name); |
| 11703 | + vcos_assert(kthread != NULL); |
| 11704 | + set_user_nice(kthread, attrs->ta_priority); |
| 11705 | + thread->thread.thread = kthread; |
| 11706 | + wake_up_process(kthread); |
| 11707 | + return VCOS_SUCCESS; |
| 11708 | +} |
| 11709 | + |
| 11710 | +void vcos_thread_join(VCOS_THREAD_T *thread, |
| 11711 | + void **pData) |
| 11712 | +{ |
| 11713 | + vcos_assert(thread); |
| 11714 | + vcos_assert(thread->magic == VCOS_THREAD_MAGIC); |
| 11715 | + |
| 11716 | + thread->joined = 1; |
| 11717 | + |
| 11718 | + vcos_semaphore_wait(&thread->wait); |
| 11719 | + |
| 11720 | + if (pData) |
| 11721 | + { |
| 11722 | + *pData = thread->exit_data; |
| 11723 | + } |
| 11724 | + |
| 11725 | + /* Clean up */ |
| 11726 | + if (thread->stack) |
| 11727 | + vcos_free(thread->stack); |
| 11728 | + |
| 11729 | + vcos_semaphore_delete(&thread->wait); |
| 11730 | + vcos_semaphore_delete(&thread->suspend); |
| 11731 | + |
| 11732 | +} |
| 11733 | + |
| 11734 | +uint32_t vcos_getmicrosecs( void ) |
| 11735 | +{ |
| 11736 | + struct timeval tv; |
| 11737 | +/*XXX FIX ME! switch to ktime_get_ts to use MONOTONIC clock */ |
| 11738 | + do_gettimeofday(&tv); |
| 11739 | + return (tv.tv_sec*1000000) + tv.tv_usec; |
| 11740 | +} |
| 11741 | + |
| 11742 | +VCOS_STATUS_T vcos_timer_init(void) |
| 11743 | +{ |
| 11744 | + return VCOS_SUCCESS; |
| 11745 | +} |
| 11746 | + |
| 11747 | +static const char *log_prefix[] = |
| 11748 | +{ |
| 11749 | + "", /* VCOS_LOG_UNINITIALIZED */ |
| 11750 | + "", /* VCOS_LOG_NEVER */ |
| 11751 | + KERN_ERR, /* VCOS_LOG_ERROR */ |
| 11752 | + KERN_WARNING, /* VCOS_LOG_WARN */ |
| 11753 | + KERN_INFO, /* VCOS_LOG_INFO */ |
| 11754 | + KERN_INFO /* VCOS_LOG_TRACE */ |
| 11755 | +}; |
| 11756 | + |
| 11757 | +void vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) |
| 11758 | +{ |
| 11759 | + char *newline = strchr( fmt, '\n' ); |
| 11760 | + const char *prefix; |
| 11761 | + const char *real_fmt; |
| 11762 | + |
| 11763 | + preempt_disable(); |
| 11764 | + { |
| 11765 | + if ( *fmt == '<' ) |
| 11766 | + { |
| 11767 | + prefix = fmt; |
| 11768 | + real_fmt= &fmt[3]; |
| 11769 | + } |
| 11770 | + else |
| 11771 | + { |
| 11772 | + prefix = log_prefix[_level]; |
| 11773 | + real_fmt = fmt; |
| 11774 | + } |
| 11775 | +#if defined( CONFIG_BCM_KNLLOG_SUPPORT ) |
| 11776 | + knllog_ventry( "vcos", real_fmt, args ); |
| 11777 | +#endif |
| 11778 | + printk( "%.3svcos: [%d]: ", prefix, current->pid ); |
| 11779 | + vprintk( real_fmt, args ); |
| 11780 | + |
| 11781 | + if ( newline == NULL ) |
| 11782 | + { |
| 11783 | + printk("\n"); |
| 11784 | + } |
| 11785 | + } |
| 11786 | + preempt_enable(); |
| 11787 | +} |
| 11788 | + |
| 11789 | + |
| 11790 | +const char * _vcos_log_level(void) |
| 11791 | +{ |
| 11792 | + return NULL; |
| 11793 | +} |
| 11794 | + |
| 11795 | +/***************************************************************************** |
| 11796 | +* |
| 11797 | +* Displays the version information in /proc/vcos/version |
| 11798 | +* |
| 11799 | +*****************************************************************************/ |
| 11800 | + |
| 11801 | +#ifdef HAVE_VCOS_VERSION |
| 11802 | + |
| 11803 | +static void show_version( VCOS_CFG_BUF_T buf, void *data ) |
| 11804 | +{ |
| 11805 | + static const char* copyright = "Copyright (c) 2011 Broadcom"; |
| 11806 | + |
| 11807 | + vcos_cfg_buf_printf( buf, "Built %s %s on %s\n%s\nversion %s\n", |
| 11808 | + vcos_get_build_date(), |
| 11809 | + vcos_get_build_time(), |
| 11810 | + vcos_get_build_hostname(), |
| 11811 | + copyright, |
| 11812 | + vcos_get_build_version() ); |
| 11813 | +} |
| 11814 | + |
| 11815 | +#endif |
| 11816 | + |
| 11817 | +/***************************************************************************** |
| 11818 | +* |
| 11819 | +* Initialises vcos |
| 11820 | +* |
| 11821 | +*****************************************************************************/ |
| 11822 | + |
| 11823 | +VCOS_STATUS_T vcos_init(void) |
| 11824 | +{ |
| 11825 | + if ( vcos_cfg_mkdir( &vcos_cfg_dir, NULL, "vcos" ) != VCOS_SUCCESS ) |
| 11826 | + { |
| 11827 | + printk( KERN_ERR "%s: Unable to create vcos cfg entry\n", __func__ ); |
| 11828 | + } |
| 11829 | + vcos_logging_init(); |
| 11830 | + |
| 11831 | +#ifdef HAVE_VCOS_VERSION |
| 11832 | + if ( vcos_cfg_create_entry( &vcos_version_cfg, &vcos_cfg_dir, "version", |
| 11833 | + show_version, NULL, NULL ) != VCOS_SUCCESS ) |
| 11834 | + { |
| 11835 | + printk( KERN_ERR "%s: Unable to create vcos cfg entry 'version'\n", __func__ ); |
| 11836 | + } |
| 11837 | +#endif |
| 11838 | + |
| 11839 | + return VCOS_SUCCESS; |
| 11840 | +} |
| 11841 | + |
| 11842 | +/***************************************************************************** |
| 11843 | +* |
| 11844 | +* Deinitializes vcos |
| 11845 | +* |
| 11846 | +*****************************************************************************/ |
| 11847 | + |
| 11848 | +void vcos_deinit(void) |
| 11849 | +{ |
| 11850 | +#ifdef HAVE_VCOS_VERSION |
| 11851 | + vcos_cfg_remove_entry( &vcos_version_cfg ); |
| 11852 | +#endif |
| 11853 | + vcos_cfg_remove_entry( &vcos_cfg_dir ); |
| 11854 | +} |
| 11855 | + |
| 11856 | +void vcos_global_lock(void) |
| 11857 | +{ |
| 11858 | + down(&lock); |
| 11859 | +} |
| 11860 | + |
| 11861 | +void vcos_global_unlock(void) |
| 11862 | +{ |
| 11863 | + up(&lock); |
| 11864 | +} |
| 11865 | + |
| 11866 | +/* vcos_thread_exit() doesn't really stop this thread here |
| 11867 | + * |
| 11868 | + * At the moment, call to do_exit() will leak task_struct for |
| 11869 | + * current thread, so we let the vcos_thread_wrapper() do the |
| 11870 | + * cleanup and exit job, and we return w/o actually stopping the thread. |
| 11871 | + * |
| 11872 | + * ToDo: Kernel v2.6.31 onwards, it is considered safe to call do_exit() |
| 11873 | + * from kthread, the implementation of which is combined in 2 patches |
| 11874 | + * with commit-ids "63706172" and "cdd140bd" in oss Linux kernel tree |
| 11875 | + */ |
| 11876 | + |
| 11877 | +void vcos_thread_exit(void *arg) |
| 11878 | +{ |
| 11879 | + VCOS_THREAD_T *thread = vcos_thread_current(); |
| 11880 | + |
| 11881 | + vcos_assert(thread); |
| 11882 | + vcos_assert(thread->magic == VCOS_THREAD_MAGIC); |
| 11883 | + |
| 11884 | + thread->exit_data = arg; |
| 11885 | +} |
| 11886 | + |
| 11887 | +void vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs) |
| 11888 | +{ |
| 11889 | + *attrs = default_attrs; |
| 11890 | +} |
| 11891 | + |
| 11892 | +void _vcos_task_timer_set(void (*pfn)(void *), void *cxt, VCOS_UNSIGNED ms) |
| 11893 | +{ |
| 11894 | + VCOS_THREAD_T *self = vcos_thread_current(); |
| 11895 | + vcos_assert(self); |
| 11896 | + vcos_assert(self->_timer.pfn == NULL); |
| 11897 | + |
| 11898 | + vcos_timer_create( &self->_timer.timer, "TaskTimer", pfn, cxt ); |
| 11899 | + vcos_timer_set(&self->_timer.timer, ms); |
| 11900 | +} |
| 11901 | + |
| 11902 | +void _vcos_task_timer_cancel(void) |
| 11903 | +{ |
| 11904 | + VCOS_THREAD_T *self = vcos_thread_current(); |
| 11905 | + if (self->_timer.timer.linux_timer.function) |
| 11906 | + { |
| 11907 | + vcos_timer_cancel(&self->_timer.timer); |
| 11908 | + vcos_timer_delete(&self->_timer.timer); |
| 11909 | + } |
| 11910 | +} |
| 11911 | + |
| 11912 | +int vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap ) |
| 11913 | +{ |
| 11914 | + return vsnprintf( buf, buflen, fmt, ap ); |
| 11915 | +} |
| 11916 | + |
| 11917 | +int vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...) |
| 11918 | +{ |
| 11919 | + int ret; |
| 11920 | + va_list ap; |
| 11921 | + va_start(ap,fmt); |
| 11922 | + ret = vsnprintf(buf, buflen, fmt, ap); |
| 11923 | + va_end(ap); |
| 11924 | + return ret; |
| 11925 | +} |
| 11926 | + |
| 11927 | +int vcos_llthread_running(VCOS_LLTHREAD_T *t) { |
| 11928 | + vcos_assert(0); /* this function only exists as a nasty hack for the video codecs! */ |
| 11929 | + return 1; |
| 11930 | +} |
| 11931 | + |
| 11932 | +static int vcos_verify_bkpts = 1; |
| 11933 | + |
| 11934 | +int vcos_verify_bkpts_enabled(void) |
| 11935 | +{ |
| 11936 | + return vcos_verify_bkpts; |
| 11937 | +} |
| 11938 | + |
| 11939 | +/***************************************************************************** |
| 11940 | +* |
| 11941 | +* _vcos_log_platform_init is called from vcos_logging_init |
| 11942 | +* |
| 11943 | +*****************************************************************************/ |
| 11944 | + |
| 11945 | +void _vcos_log_platform_init(void) |
| 11946 | +{ |
| 11947 | + if ( vcos_cfg_mkdir( &vcos_logging_cfg_dir, &vcos_cfg_dir, "logging" ) != VCOS_SUCCESS ) |
| 11948 | + { |
| 11949 | + printk( KERN_ERR "%s: Unable to create logging cfg entry\n", __func__ ); |
| 11950 | + } |
| 11951 | +} |
| 11952 | + |
| 11953 | +/***************************************************************************** |
| 11954 | +* |
| 11955 | +* Called to display the contents of a logging category. |
| 11956 | +* |
| 11957 | +*****************************************************************************/ |
| 11958 | + |
| 11959 | +static void logging_show_category( VCOS_CFG_BUF_T buf, void *data ) |
| 11960 | +{ |
| 11961 | + VCOS_LOG_CAT_T *category = data; |
| 11962 | + |
| 11963 | + vcos_cfg_buf_printf( buf, "%s\n", vcos_log_level_to_string( category->level )); |
| 11964 | +} |
| 11965 | + |
| 11966 | +/***************************************************************************** |
| 11967 | +* |
| 11968 | +* Called to parse content for a logging category. |
| 11969 | +* |
| 11970 | +*****************************************************************************/ |
| 11971 | + |
| 11972 | +static void logging_parse_category( VCOS_CFG_BUF_T buf, void *data ) |
| 11973 | +{ |
| 11974 | + VCOS_LOG_CAT_T *category = data; |
| 11975 | + const char *str = vcos_cfg_buf_get_str( buf ); |
| 11976 | + VCOS_LOG_LEVEL_T level; |
| 11977 | + |
| 11978 | + if ( vcos_string_to_log_level( str, &level ) == VCOS_SUCCESS ) |
| 11979 | + { |
| 11980 | + category->level = level; |
| 11981 | + } |
| 11982 | + else |
| 11983 | + { |
| 11984 | + printk( KERN_ERR "%s: Unrecognized logging level: '%s'\n", |
| 11985 | + __func__, str ); |
| 11986 | + } |
| 11987 | +} |
| 11988 | + |
| 11989 | +/***************************************************************************** |
| 11990 | +* |
| 11991 | +* _vcos_log_platform_register is called from vcos_log_register whenever |
| 11992 | +* a new category is registered. |
| 11993 | +* |
| 11994 | +*****************************************************************************/ |
| 11995 | + |
| 11996 | +void _vcos_log_platform_register(VCOS_LOG_CAT_T *category) |
| 11997 | +{ |
| 11998 | + VCOS_CFG_ENTRY_T entry; |
| 11999 | + |
| 12000 | + if ( vcos_cfg_create_entry( &entry, &vcos_logging_cfg_dir, category->name, |
| 12001 | + logging_show_category, logging_parse_category, |
| 12002 | + category ) != VCOS_SUCCESS ) |
| 12003 | + { |
| 12004 | + printk( KERN_ERR "%s: Unable to create cfg entry for logging category '%s'\n", |
| 12005 | + __func__, category->name ); |
| 12006 | + category->platform_data = NULL; |
| 12007 | + } |
| 12008 | + else |
| 12009 | + { |
| 12010 | + category->platform_data = entry; |
| 12011 | + } |
| 12012 | +} |
| 12013 | + |
| 12014 | +/***************************************************************************** |
| 12015 | +* |
| 12016 | +* _vcos_log_platform_unregister is called from vcos_log_unregister whenever |
| 12017 | +* a new category is unregistered. |
| 12018 | +* |
| 12019 | +*****************************************************************************/ |
| 12020 | + |
| 12021 | +void _vcos_log_platform_unregister(VCOS_LOG_CAT_T *category) |
| 12022 | +{ |
| 12023 | + VCOS_CFG_ENTRY_T entry; |
| 12024 | + |
| 12025 | + entry = category->platform_data; |
| 12026 | + if ( entry != NULL ) |
| 12027 | + { |
| 12028 | + if ( vcos_cfg_remove_entry( &entry ) != VCOS_SUCCESS ) |
| 12029 | + { |
| 12030 | + printk( KERN_ERR "%s: Unable to remove cfg entry for logging category '%s'\n", |
| 12031 | + __func__, category->name ); |
| 12032 | + } |
| 12033 | + } |
| 12034 | +} |
| 12035 | + |
| 12036 | +/***************************************************************************** |
| 12037 | +* |
| 12038 | +* Allocate memory. |
| 12039 | +* |
| 12040 | +*****************************************************************************/ |
| 12041 | + |
| 12042 | +void *vcos_platform_malloc( VCOS_UNSIGNED required_size ) |
| 12043 | +{ |
| 12044 | + if ( required_size >= ( 2 * PAGE_SIZE )) |
| 12045 | + { |
| 12046 | + /* For larger allocations, use vmalloc, whose underlying allocator |
| 12047 | + * returns pages |
| 12048 | + */ |
| 12049 | + |
| 12050 | + return vmalloc( required_size ); |
| 12051 | + } |
| 12052 | + |
| 12053 | + /* For smaller allocation, use kmalloc */ |
| 12054 | + |
| 12055 | + return kmalloc( required_size, GFP_KERNEL ); |
| 12056 | +} |
| 12057 | + |
| 12058 | +/***************************************************************************** |
| 12059 | +* |
| 12060 | +* Free previously allocated memory |
| 12061 | +* |
| 12062 | +*****************************************************************************/ |
| 12063 | + |
| 12064 | +void vcos_platform_free( void *ptr ) |
| 12065 | +{ |
| 12066 | + if (((unsigned long)ptr >= VMALLOC_START ) |
| 12067 | + && ((unsigned long)ptr < VMALLOC_END )) |
| 12068 | + { |
| 12069 | + vfree( ptr ); |
| 12070 | + } |
| 12071 | + else |
| 12072 | + { |
| 12073 | + kfree( ptr ); |
| 12074 | + } |
| 12075 | +} |
| 12076 | + |
| 12077 | +/***************************************************************************** |
| 12078 | +* |
| 12079 | +* Execute a routine exactly once. |
| 12080 | +* |
| 12081 | +*****************************************************************************/ |
| 12082 | + |
| 12083 | +VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control, |
| 12084 | + void (*init_routine)(void)) |
| 12085 | +{ |
| 12086 | + /* In order to be thread-safe we need to re-test *once_control |
| 12087 | + * inside the lock. The outer test is basically an optimization |
| 12088 | + * so that once it is initialized we don't need to waste time |
| 12089 | + * trying to acquire the lock. |
| 12090 | + */ |
| 12091 | + |
| 12092 | + if ( *once_control == 0 ) |
| 12093 | + { |
| 12094 | + vcos_global_lock(); |
| 12095 | + if ( *once_control == 0 ) |
| 12096 | + { |
| 12097 | + init_routine(); |
| 12098 | + *once_control = 1; |
| 12099 | + } |
| 12100 | + vcos_global_unlock(); |
| 12101 | + } |
| 12102 | + |
| 12103 | + return VCOS_SUCCESS; |
| 12104 | +} |
| 12105 | + |
| 12106 | +/***************************************************************************** |
| 12107 | +* |
| 12108 | +* String duplication routine. |
| 12109 | +* |
| 12110 | +*****************************************************************************/ |
| 12111 | + |
| 12112 | +char *vcos_strdup(const char *str) |
| 12113 | +{ |
| 12114 | + return kstrdup(str, GFP_KERNEL); |
| 12115 | +} |
| 12116 | + |
| 12117 | + |
| 12118 | +/* Export functions for modules to use */ |
| 12119 | +EXPORT_SYMBOL( vcos_init ); |
| 12120 | + |
| 12121 | +EXPORT_SYMBOL( vcos_semaphore_trywait ); |
| 12122 | +EXPORT_SYMBOL( vcos_semaphore_post ); |
| 12123 | +EXPORT_SYMBOL( vcos_semaphore_create ); |
| 12124 | +EXPORT_SYMBOL( vcos_semaphore_wait ); |
| 12125 | +EXPORT_SYMBOL( vcos_semaphore_delete ); |
| 12126 | + |
| 12127 | +EXPORT_SYMBOL( vcos_log_impl ); |
| 12128 | +EXPORT_SYMBOL( vcos_vlog_impl ); |
| 12129 | +EXPORT_SYMBOL( vcos_vlog_default_impl ); |
| 12130 | +EXPORT_SYMBOL( vcos_log_get_default_category ); |
| 12131 | +EXPORT_SYMBOL( vcos_log_register ); |
| 12132 | +EXPORT_SYMBOL( vcos_log_unregister ); |
| 12133 | +EXPORT_SYMBOL( vcos_logging_init ); |
| 12134 | +EXPORT_SYMBOL( vcos_log_level_to_string ); |
| 12135 | +EXPORT_SYMBOL( vcos_string_to_log_level ); |
| 12136 | +EXPORT_SYMBOL( vcos_log_dump_mem_impl ); |
| 12137 | + |
| 12138 | +EXPORT_SYMBOL( vcos_event_create ); |
| 12139 | +EXPORT_SYMBOL( vcos_event_delete ); |
| 12140 | +EXPORT_SYMBOL( vcos_event_flags_set ); |
| 12141 | +EXPORT_SYMBOL( vcos_event_signal ); |
| 12142 | +EXPORT_SYMBOL( vcos_event_wait ); |
| 12143 | +EXPORT_SYMBOL( vcos_event_try ); |
| 12144 | + |
| 12145 | +EXPORT_SYMBOL( vcos_getmicrosecs ); |
| 12146 | + |
| 12147 | +EXPORT_SYMBOL( vcos_strcasecmp ); |
| 12148 | +EXPORT_SYMBOL( vcos_snprintf ); |
| 12149 | +EXPORT_SYMBOL( vcos_vsnprintf ); |
| 12150 | + |
| 12151 | +EXPORT_SYMBOL( vcos_thread_current ); |
| 12152 | +EXPORT_SYMBOL( vcos_thread_join ); |
| 12153 | +EXPORT_SYMBOL( vcos_thread_create ); |
| 12154 | +EXPORT_SYMBOL( vcos_thread_set_priority ); |
| 12155 | +EXPORT_SYMBOL( vcos_thread_exit ); |
| 12156 | +EXPORT_SYMBOL( vcos_once ); |
| 12157 | + |
| 12158 | +EXPORT_SYMBOL( vcos_thread_attr_init ); |
| 12159 | +EXPORT_SYMBOL( vcos_thread_attr_setpriority ); |
| 12160 | +EXPORT_SYMBOL( vcos_thread_attr_settimeslice ); |
| 12161 | +EXPORT_SYMBOL( vcos_thread_attr_setstacksize ); |
| 12162 | +EXPORT_SYMBOL( _vcos_thread_attr_setlegacyapi ); |
| 12163 | + |
| 12164 | +EXPORT_SYMBOL( vcos_event_flags_create ); |
| 12165 | +EXPORT_SYMBOL( vcos_event_flags_delete ); |
| 12166 | +EXPORT_SYMBOL( vcos_event_flags_get ); |
| 12167 | + |
| 12168 | +EXPORT_SYMBOL( vcos_sleep ); |
| 12169 | + |
| 12170 | +EXPORT_SYMBOL( vcos_calloc ); |
| 12171 | +EXPORT_SYMBOL( vcos_malloc ); |
| 12172 | +EXPORT_SYMBOL( vcos_malloc_aligned ); |
| 12173 | +EXPORT_SYMBOL( vcos_free ); |
| 12174 | + |
| 12175 | +EXPORT_SYMBOL( vcos_mutex_create ); |
| 12176 | +EXPORT_SYMBOL( vcos_mutex_delete ); |
| 12177 | +EXPORT_SYMBOL( vcos_mutex_lock ); |
| 12178 | +EXPORT_SYMBOL( vcos_mutex_unlock ); |
| 12179 | +EXPORT_SYMBOL( vcos_mutex_trylock ); |
| 12180 | + |
| 12181 | +EXPORT_SYMBOL( vcos_timer_cancel ); |
| 12182 | +EXPORT_SYMBOL( vcos_timer_create ); |
| 12183 | +EXPORT_SYMBOL( vcos_timer_delete ); |
| 12184 | +EXPORT_SYMBOL( vcos_timer_set ); |
| 12185 | + |
| 12186 | +EXPORT_SYMBOL( vcos_atomic_flags_create ); |
| 12187 | +EXPORT_SYMBOL( vcos_atomic_flags_delete ); |
| 12188 | +EXPORT_SYMBOL( vcos_atomic_flags_or ); |
| 12189 | +EXPORT_SYMBOL( vcos_atomic_flags_get_and_clear ); |
| 12190 | + |
| 12191 | +EXPORT_SYMBOL( vcos_verify_bkpts_enabled ); |
| 12192 | + |
| 12193 | +EXPORT_SYMBOL( vcos_strdup ); |
| 12194 | --- /dev/null |
| 12195 | +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_cfg.c |
| 12196 | @@ -0,0 +1,332 @@ |
| 12197 | +/***************************************************************************** |
| 12198 | +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved. |
| 12199 | +* |
| 12200 | +* Unless you and Broadcom execute a separate written software license |
| 12201 | +* agreement governing use of this software, this software is licensed to you |
| 12202 | +* under the terms of the GNU General Public License version 2, available at |
| 12203 | +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). |
| 12204 | +* |
| 12205 | +* Notwithstanding the above, under no circumstances may you combine this |
| 12206 | +* software in any way with any other Broadcom software provided under a |
| 12207 | +* license other than the GPL, without Broadcom's express prior written |
| 12208 | +* consent. |
| 12209 | +*****************************************************************************/ |
| 12210 | + |
| 12211 | +#include "interface/vcos/vcos.h" |
| 12212 | +#include <linux/module.h> |
| 12213 | +#include <linux/proc_fs.h> |
| 12214 | +#include <linux/seq_file.h> |
| 12215 | +#include <asm/uaccess.h> |
| 12216 | + |
| 12217 | +struct opaque_vcos_cfg_buf_t |
| 12218 | +{ |
| 12219 | + struct seq_file *seq; |
| 12220 | + char *charBuf; |
| 12221 | +}; |
| 12222 | + |
| 12223 | +struct opaque_vcos_cfg_entry_t |
| 12224 | +{ |
| 12225 | + struct proc_dir_entry *pde; |
| 12226 | + struct proc_dir_entry *parent_pde; |
| 12227 | + VCOS_CFG_SHOW_FPTR showFunc; |
| 12228 | + VCOS_CFG_PARSE_FPTR parseFunc; |
| 12229 | + void *data; |
| 12230 | + const char *name; |
| 12231 | +}; |
| 12232 | + |
| 12233 | +/***************************************************************************** |
| 12234 | +* |
| 12235 | +* cfg_proc_show |
| 12236 | +* |
| 12237 | +*****************************************************************************/ |
| 12238 | + |
| 12239 | +static int cfg_proc_show( struct seq_file *s, void *v ) |
| 12240 | +{ |
| 12241 | + VCOS_CFG_ENTRY_T entry; |
| 12242 | + struct opaque_vcos_cfg_buf_t buf; |
| 12243 | + |
| 12244 | + entry = s->private; |
| 12245 | + |
| 12246 | + if ( entry->showFunc ) |
| 12247 | + { |
| 12248 | + memset( &buf, 0, sizeof( buf )); |
| 12249 | + buf.seq = s; |
| 12250 | + |
| 12251 | + entry->showFunc( &buf, entry->data ); |
| 12252 | + } |
| 12253 | + |
| 12254 | + return 0; |
| 12255 | +} |
| 12256 | + |
| 12257 | +/***************************************************************************** |
| 12258 | +* |
| 12259 | +* cfg_proc_write |
| 12260 | +* |
| 12261 | +*****************************************************************************/ |
| 12262 | + |
| 12263 | +static ssize_t cfg_proc_write( struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
| 12264 | +{ |
| 12265 | + VCOS_CFG_ENTRY_T entry = PDE(file->f_path.dentry->d_inode)->data; |
| 12266 | + char *charBuf; |
| 12267 | + struct opaque_vcos_cfg_buf_t buf; |
| 12268 | + size_t len; |
| 12269 | + |
| 12270 | + if ( entry->parseFunc != NULL ) |
| 12271 | + { |
| 12272 | + /* The number 4000 is rather arbitrary. It just needs to be bigger than any input |
| 12273 | + * string we expect to use. |
| 12274 | + */ |
| 12275 | + |
| 12276 | + len = count; |
| 12277 | + if ( count > 4000 ) |
| 12278 | + { |
| 12279 | + len = 4000; |
| 12280 | + } |
| 12281 | + |
| 12282 | + /* Allocate a kernel buffer to contain the string being written. */ |
| 12283 | + |
| 12284 | + charBuf = kmalloc( len + 1, GFP_KERNEL ); |
| 12285 | + if ( copy_from_user( charBuf, buffer, len )) |
| 12286 | + { |
| 12287 | + kfree( charBuf ); |
| 12288 | + return -EFAULT; |
| 12289 | + } |
| 12290 | + |
| 12291 | + /* echo puts a trailing newline in the buffer - strip it out. */ |
| 12292 | + |
| 12293 | + if (( len > 0 ) && ( charBuf[ len - 1 ] == '\n' )) |
| 12294 | + { |
| 12295 | + len--; |
| 12296 | + } |
| 12297 | + charBuf[len] = '\0'; |
| 12298 | + |
| 12299 | + memset( &buf, 0, sizeof( buf )); |
| 12300 | + buf.charBuf = charBuf; |
| 12301 | + |
| 12302 | + entry->parseFunc( &buf, entry->data ); |
| 12303 | + kfree( charBuf ); |
| 12304 | + } |
| 12305 | + return count; |
| 12306 | +} |
| 12307 | + |
| 12308 | +/***************************************************************************** |
| 12309 | +* |
| 12310 | +* cfg_proc_open |
| 12311 | +* |
| 12312 | +*****************************************************************************/ |
| 12313 | + |
| 12314 | +static int cfg_proc_open( struct inode *inode, struct file *file ) |
| 12315 | +{ |
| 12316 | + return single_open( file, cfg_proc_show, PDE(inode)->data ); |
| 12317 | +} |
| 12318 | + |
| 12319 | +static const struct file_operations cfg_proc_fops = |
| 12320 | +{ |
| 12321 | + .open = cfg_proc_open, |
| 12322 | + .read = seq_read, |
| 12323 | + .llseek = seq_lseek, |
| 12324 | + .release = single_release, |
| 12325 | + .write = cfg_proc_write, |
| 12326 | +}; |
| 12327 | + |
| 12328 | +/***************************************************************************** |
| 12329 | +* |
| 12330 | +* vcos_cfg_mkdir |
| 12331 | +* |
| 12332 | +*****************************************************************************/ |
| 12333 | + |
| 12334 | +VCOS_STATUS_T vcos_cfg_mkdir( VCOS_CFG_ENTRY_T *entryp, |
| 12335 | + VCOS_CFG_ENTRY_T *parent, |
| 12336 | + const char *dirName ) |
| 12337 | +{ |
| 12338 | + VCOS_CFG_ENTRY_T entry; |
| 12339 | + |
| 12340 | + if (( entry = kzalloc( sizeof( *entry ), GFP_KERNEL )) == NULL ) |
| 12341 | + { |
| 12342 | + return VCOS_ENOMEM; |
| 12343 | + } |
| 12344 | + |
| 12345 | + if ( parent == NULL ) |
| 12346 | + { |
| 12347 | + entry->pde = proc_mkdir( dirName, NULL ); |
| 12348 | + } |
| 12349 | + else |
| 12350 | + { |
| 12351 | + entry->pde = proc_mkdir( dirName, (*parent)->pde ); |
| 12352 | + entry->parent_pde = (*parent)->pde; |
| 12353 | + } |
| 12354 | + if ( entry->pde == NULL ) |
| 12355 | + { |
| 12356 | + kfree( entry ); |
| 12357 | + return VCOS_ENOMEM; |
| 12358 | + } |
| 12359 | + |
| 12360 | + entry->name = dirName; |
| 12361 | + |
| 12362 | + *entryp = entry; |
| 12363 | + return VCOS_SUCCESS; |
| 12364 | +} |
| 12365 | + |
| 12366 | +/***************************************************************************** |
| 12367 | +* |
| 12368 | +* vcos_cfg_create_entry |
| 12369 | +* |
| 12370 | +*****************************************************************************/ |
| 12371 | + |
| 12372 | +VCOS_STATUS_T vcos_cfg_create_entry( VCOS_CFG_ENTRY_T *entryp, |
| 12373 | + VCOS_CFG_ENTRY_T *parent, |
| 12374 | + const char *entryName, |
| 12375 | + VCOS_CFG_SHOW_FPTR showFunc, |
| 12376 | + VCOS_CFG_PARSE_FPTR parseFunc, |
| 12377 | + void *data ) |
| 12378 | +{ |
| 12379 | + VCOS_CFG_ENTRY_T entry; |
| 12380 | + mode_t mode; |
| 12381 | + |
| 12382 | + *entryp = NULL; |
| 12383 | + |
| 12384 | + if (( entry = kzalloc( sizeof( *entry ), GFP_KERNEL )) == NULL ) |
| 12385 | + { |
| 12386 | + return VCOS_ENOMEM; |
| 12387 | + } |
| 12388 | + |
| 12389 | + mode = 0; |
| 12390 | + if ( showFunc != NULL ) |
| 12391 | + { |
| 12392 | + mode |= 0444; |
| 12393 | + } |
| 12394 | + if ( parseFunc != NULL ) |
| 12395 | + { |
| 12396 | + mode |= 0200; |
| 12397 | + } |
| 12398 | + |
| 12399 | + if ( parent == NULL ) |
| 12400 | + { |
| 12401 | + entry->pde = create_proc_entry( entryName, mode, NULL ); |
| 12402 | + } |
| 12403 | + else |
| 12404 | + { |
| 12405 | + entry->pde = create_proc_entry( entryName, mode, (*parent)->pde ); |
| 12406 | + entry->parent_pde = (*parent)->pde; |
| 12407 | + } |
| 12408 | + if ( entry->pde == NULL ) |
| 12409 | + { |
| 12410 | + kfree( entry ); |
| 12411 | + return -ENOMEM; |
| 12412 | + } |
| 12413 | + entry->showFunc = showFunc; |
| 12414 | + entry->parseFunc = parseFunc; |
| 12415 | + entry->data = data; |
| 12416 | + entry->name = entryName; |
| 12417 | + |
| 12418 | + entry->pde->data = entry; |
| 12419 | + entry->pde->proc_fops = &cfg_proc_fops; |
| 12420 | + |
| 12421 | + *entryp = entry; |
| 12422 | + return VCOS_SUCCESS; |
| 12423 | +} |
| 12424 | + |
| 12425 | +/***************************************************************************** |
| 12426 | +* |
| 12427 | +* vcos_cfg_remove_entry |
| 12428 | +* |
| 12429 | +*****************************************************************************/ |
| 12430 | + |
| 12431 | +VCOS_STATUS_T vcos_cfg_remove_entry( VCOS_CFG_ENTRY_T *entryp ) |
| 12432 | +{ |
| 12433 | + if (( entryp != NULL ) && ( *entryp != NULL )) |
| 12434 | + { |
| 12435 | + remove_proc_entry( (*entryp)->name, (*entryp)->parent_pde ); |
| 12436 | + |
| 12437 | + kfree( *entryp ); |
| 12438 | + *entryp = NULL; |
| 12439 | + } |
| 12440 | + |
| 12441 | + return VCOS_SUCCESS; |
| 12442 | +} |
| 12443 | + |
| 12444 | +/***************************************************************************** |
| 12445 | +* |
| 12446 | +* vcos_cfg_is_entry_created |
| 12447 | +* |
| 12448 | +*****************************************************************************/ |
| 12449 | + |
| 12450 | +int vcos_cfg_is_entry_created( VCOS_CFG_ENTRY_T entry ) |
| 12451 | +{ |
| 12452 | + return ( entry != NULL ) && ( entry->pde != NULL ); |
| 12453 | +} |
| 12454 | + |
| 12455 | +/***************************************************************************** |
| 12456 | +* |
| 12457 | +* vcos_cfg_buf_printf |
| 12458 | +* |
| 12459 | +*****************************************************************************/ |
| 12460 | + |
| 12461 | +void vcos_cfg_buf_printf( VCOS_CFG_BUF_T buf, const char *fmt, ... ) |
| 12462 | +{ |
| 12463 | + struct seq_file *m = buf->seq; |
| 12464 | + |
| 12465 | + /* Bah - there is no seq_vprintf */ |
| 12466 | + |
| 12467 | + va_list args; |
| 12468 | + int len; |
| 12469 | + |
| 12470 | + if (m->count < m->size) { |
| 12471 | + va_start(args, fmt); |
| 12472 | + len = vsnprintf(m->buf + m->count, m->size - m->count, fmt, args); |
| 12473 | + va_end(args); |
| 12474 | + if (m->count + len < m->size) { |
| 12475 | + m->count += len; |
| 12476 | + return; |
| 12477 | + } |
| 12478 | + } |
| 12479 | + m->count = m->size; |
| 12480 | +} |
| 12481 | + |
| 12482 | +/***************************************************************************** |
| 12483 | +* |
| 12484 | +* vcos_cfg_buf_get_str |
| 12485 | +* |
| 12486 | +*****************************************************************************/ |
| 12487 | + |
| 12488 | +char *vcos_cfg_buf_get_str( VCOS_CFG_BUF_T buf ) |
| 12489 | +{ |
| 12490 | + return buf->charBuf; |
| 12491 | +} |
| 12492 | + |
| 12493 | +/***************************************************************************** |
| 12494 | +* |
| 12495 | +* vcos_cfg_get_proc_entry |
| 12496 | +* |
| 12497 | +* This function is only created for a couple of backwards compatibility ' |
| 12498 | +* issues and shouldn't normally be used. |
| 12499 | +* |
| 12500 | +*****************************************************************************/ |
| 12501 | + |
| 12502 | +void *vcos_cfg_get_proc_entry( VCOS_CFG_ENTRY_T entry ) |
| 12503 | +{ |
| 12504 | + return entry->pde; |
| 12505 | +} |
| 12506 | + |
| 12507 | +/***************************************************************************** |
| 12508 | +* |
| 12509 | +* vcos_cfg_get_entry_name |
| 12510 | +* |
| 12511 | +*****************************************************************************/ |
| 12512 | + |
| 12513 | +const char *vcos_cfg_get_entry_name( VCOS_CFG_ENTRY_T entry ) |
| 12514 | +{ |
| 12515 | + return entry->pde->name; |
| 12516 | +} |
| 12517 | + |
| 12518 | + |
| 12519 | +EXPORT_SYMBOL( vcos_cfg_mkdir ); |
| 12520 | +EXPORT_SYMBOL( vcos_cfg_create_entry ); |
| 12521 | +EXPORT_SYMBOL( vcos_cfg_remove_entry ); |
| 12522 | +EXPORT_SYMBOL( vcos_cfg_get_entry_name ); |
| 12523 | +EXPORT_SYMBOL( vcos_cfg_is_entry_created ); |
| 12524 | +EXPORT_SYMBOL( vcos_cfg_buf_printf ); |
| 12525 | +EXPORT_SYMBOL( vcos_cfg_buf_get_str ); |
| 12526 | + |
| 12527 | +EXPORT_SYMBOL_GPL( vcos_cfg_get_proc_entry ); |
| 12528 | + |
| 12529 | --- /dev/null |
| 12530 | +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_linuxkernel_misc.c |
| 12531 | @@ -0,0 +1,113 @@ |
| 12532 | +// ############################################################################# |
| 12533 | +// START ####################################################################### |
| 12534 | +/***************************************************************************** |
| 12535 | +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved. |
| 12536 | +* |
| 12537 | +* Unless you and Broadcom execute a separate written software license |
| 12538 | +* agreement governing use of this software, this software is licensed to you |
| 12539 | +* under the terms of the GNU General Public License version 2, available at |
| 12540 | +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). |
| 12541 | +* |
| 12542 | +* Notwithstanding the above, under no circumstances may you combine this |
| 12543 | +* software in any way with any other Broadcom software provided under a |
| 12544 | +* license other than the GPL, without Broadcom's express prior written |
| 12545 | +* consent. |
| 12546 | +*****************************************************************************/ |
| 12547 | + |
| 12548 | +#include "interface/vcos/vcos.h" |
| 12549 | +#include <linux/sched.h> |
| 12550 | +#include <linux/module.h> |
| 12551 | +#include <linux/freezer.h> |
| 12552 | +#include <linux/string.h> |
| 12553 | +#include <linux/slab.h> |
| 12554 | + |
| 12555 | +/***************************************************************************** |
| 12556 | +* |
| 12557 | +* vcos_semaphore_wait_freezable |
| 12558 | +* |
| 12559 | +*****************************************************************************/ |
| 12560 | + |
| 12561 | +VCOS_STATUS_T vcos_semaphore_wait_freezable(VCOS_SEMAPHORE_T *sem) |
| 12562 | +{ |
| 12563 | + int rval, sig_pended = 0; |
| 12564 | + unsigned long flags; |
| 12565 | + struct task_struct *task = current; |
| 12566 | + |
| 12567 | + while (1) { |
| 12568 | + rval = down_interruptible((struct semaphore *)sem); |
| 12569 | + if (rval == 0) { /* down now */ |
| 12570 | + break; |
| 12571 | + } else { |
| 12572 | + if (freezing(current)) { |
| 12573 | + try_to_freeze(); |
| 12574 | + } else { |
| 12575 | + spin_lock_irqsave(&task->sighand->siglock, flags); |
| 12576 | + if (test_tsk_thread_flag(task, TIF_SIGPENDING)) { |
| 12577 | + clear_tsk_thread_flag(task, TIF_SIGPENDING); |
| 12578 | + sig_pended = 1; |
| 12579 | + } |
| 12580 | + spin_unlock_irqrestore(&task->sighand->siglock, flags); |
| 12581 | + } |
| 12582 | + } |
| 12583 | + } |
| 12584 | + |
| 12585 | + if (sig_pended) { |
| 12586 | + spin_lock_irqsave(&task->sighand->siglock, flags); |
| 12587 | + set_tsk_thread_flag(task, TIF_SIGPENDING); |
| 12588 | + spin_unlock_irqrestore(&task->sighand->siglock, flags); |
| 12589 | + } |
| 12590 | + |
| 12591 | + return 0; |
| 12592 | +} |
| 12593 | + |
| 12594 | +EXPORT_SYMBOL( vcos_semaphore_wait_freezable ); |
| 12595 | + |
| 12596 | +/***************************************************************************** |
| 12597 | +* |
| 12598 | +* vcos_kmalloc |
| 12599 | +* |
| 12600 | +* We really need to convert malloc to do kmalloc or vmalloc based on the |
| 12601 | +* size, but for now we'll add a separate function. |
| 12602 | +* |
| 12603 | +*****************************************************************************/ |
| 12604 | + |
| 12605 | +void *vcos_kmalloc(VCOS_UNSIGNED size, const char *description) |
| 12606 | +{ |
| 12607 | + (void)description; |
| 12608 | + |
| 12609 | + return kmalloc( size, GFP_KERNEL ); |
| 12610 | +} |
| 12611 | + |
| 12612 | +/***************************************************************************** |
| 12613 | +* |
| 12614 | +* vcos_kmalloc |
| 12615 | +* |
| 12616 | +* We really need to convert malloc to do kmalloc or vmalloc based on the |
| 12617 | +* size, but for now we'll add a separate function. |
| 12618 | +* |
| 12619 | +*****************************************************************************/ |
| 12620 | + |
| 12621 | +void *vcos_kcalloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description) |
| 12622 | +{ |
| 12623 | + (void)description; |
| 12624 | + |
| 12625 | + return kzalloc( num * size, GFP_KERNEL ); |
| 12626 | +} |
| 12627 | + |
| 12628 | +/***************************************************************************** |
| 12629 | +* |
| 12630 | +* vcos_kfree |
| 12631 | +* |
| 12632 | +*****************************************************************************/ |
| 12633 | + |
| 12634 | +void vcos_kfree(void *ptr) |
| 12635 | +{ |
| 12636 | + kfree( ptr ); |
| 12637 | +} |
| 12638 | + |
| 12639 | +EXPORT_SYMBOL( vcos_kmalloc ); |
| 12640 | +EXPORT_SYMBOL( vcos_kcalloc ); |
| 12641 | +EXPORT_SYMBOL( vcos_kfree ); |
| 12642 | + |
| 12643 | +// END ######################################################################### |
| 12644 | +// ############################################################################# |
| 12645 | --- /dev/null |
| 12646 | +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_mod_init.c |
| 12647 | @@ -0,0 +1,64 @@ |
| 12648 | +/***************************************************************************** |
| 12649 | +* Copyright 2006 - 2008 Broadcom Corporation. All rights reserved. |
| 12650 | +* |
| 12651 | +* Unless you and Broadcom execute a separate written software license |
| 12652 | +* agreement governing use of this software, this software is licensed to you |
| 12653 | +* under the terms of the GNU General Public License version 2, available at |
| 12654 | +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). |
| 12655 | +* |
| 12656 | +* Notwithstanding the above, under no circumstances may you combine this |
| 12657 | +* software in any way with any other Broadcom software provided under a |
| 12658 | +* license other than the GPL, without Broadcom's express prior written |
| 12659 | +* consent. |
| 12660 | +****************************************************************************/ |
| 12661 | + |
| 12662 | +/* ---- Include Files ---------------------------------------------------- */ |
| 12663 | + |
| 12664 | +#include "interface/vcos/vcos.h" |
| 12665 | +#include <linux/module.h> |
| 12666 | + |
| 12667 | +/* ---- Public Variables ------------------------------------------------- */ |
| 12668 | + |
| 12669 | +/* ---- Private Constants and Types -------------------------------------- */ |
| 12670 | + |
| 12671 | +/* ---- Private Variables ------------------------------------------------ */ |
| 12672 | + |
| 12673 | +/* ---- Private Function Prototypes -------------------------------------- */ |
| 12674 | + |
| 12675 | +/* ---- Functions -------------------------------------------------------- */ |
| 12676 | + |
| 12677 | +/**************************************************************************** |
| 12678 | +* |
| 12679 | +* Called to perform module initialization when the module is loaded |
| 12680 | +* |
| 12681 | +***************************************************************************/ |
| 12682 | + |
| 12683 | +static int __init vcos_mod_init( void ) |
| 12684 | +{ |
| 12685 | + printk( KERN_INFO "VCOS Module\n" ); |
| 12686 | + |
| 12687 | + vcos_init(); |
| 12688 | + return 0; |
| 12689 | +} |
| 12690 | + |
| 12691 | +/**************************************************************************** |
| 12692 | +* |
| 12693 | +* Called to perform module cleanup when the module is unloaded. |
| 12694 | +* |
| 12695 | +***************************************************************************/ |
| 12696 | + |
| 12697 | +static void __exit vcos_mod_exit( void ) |
| 12698 | +{ |
| 12699 | + vcos_deinit(); |
| 12700 | +} |
| 12701 | + |
| 12702 | +/****************************************************************************/ |
| 12703 | + |
| 12704 | +module_init( vcos_mod_init ); |
| 12705 | +module_exit( vcos_mod_exit ); |
| 12706 | + |
| 12707 | +MODULE_AUTHOR("Broadcom"); |
| 12708 | +MODULE_DESCRIPTION( "VCOS Module Functions" ); |
| 12709 | +MODULE_LICENSE( "GPL" ); |
| 12710 | +MODULE_VERSION( "1.0" ); |
| 12711 | + |
| 12712 | --- /dev/null |
| 12713 | +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform.h |
| 12714 | @@ -0,0 +1,496 @@ |
| 12715 | +/*============================================================================= |
| 12716 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 12717 | +All rights reserved. |
| 12718 | + |
| 12719 | +Project : vcfw |
| 12720 | +Module : vcos |
| 12721 | + |
| 12722 | +FILE DESCRIPTION |
| 12723 | +VideoCore OS Abstraction Layer - Linux kernel (partial) implementation. |
| 12724 | +=============================================================================*/ |
| 12725 | + |
| 12726 | +/* Do not include this file directly - instead include it via vcos.h */ |
| 12727 | + |
| 12728 | +/** @file |
| 12729 | + * |
| 12730 | + * Linux kernel (partial) implementation of VCOS. |
| 12731 | + * |
| 12732 | + */ |
| 12733 | + |
| 12734 | +#ifndef VCOS_PLATFORM_H |
| 12735 | +#define VCOS_PLATFORM_H |
| 12736 | + |
| 12737 | +#include <linux/types.h> |
| 12738 | +#include <linux/semaphore.h> |
| 12739 | +#include <linux/mutex.h> |
| 12740 | +#include <asm/bitops.h> |
| 12741 | +#include <linux/kthread.h> |
| 12742 | +#include <linux/wait.h> |
| 12743 | +#include <linux/vmalloc.h> |
| 12744 | +#include <linux/jiffies.h> |
| 12745 | +#include <linux/delay.h> |
| 12746 | +#include <linux/string.h> |
| 12747 | +#include <linux/types.h> |
| 12748 | +#include <linux/interrupt.h> |
| 12749 | +#include <linux/random.h> |
| 12750 | +#include <linux/sched.h> |
| 12751 | +#include <linux/ctype.h> |
| 12752 | +#include <linux/uaccess.h> |
| 12753 | +#include <linux/time.h> /* for time_t */ |
| 12754 | +#include <linux/slab.h> |
| 12755 | +#include <linux/vmalloc.h> |
| 12756 | + |
| 12757 | +#define VCOS_HAVE_RTOS 1 |
| 12758 | +#define VCOS_HAVE_SEMAPHORE 1 |
| 12759 | +#define VCOS_HAVE_EVENT 1 |
| 12760 | +#define VCOS_HAVE_QUEUE 0 |
| 12761 | +#define VCOS_HAVE_LEGACY_ISR 0 |
| 12762 | +#define VCOS_HAVE_TIMER 1 |
| 12763 | +#define VCOS_HAVE_CANCELLATION_SAFE_TIMER 0 |
| 12764 | +#define VCOS_HAVE_MEMPOOL 0 |
| 12765 | +#define VCOS_HAVE_ISR 0 |
| 12766 | +#define VCOS_HAVE_ATOMIC_FLAGS 1 |
| 12767 | +#define VCOS_HAVE_BLOCK_POOL 0 |
| 12768 | +#define VCOS_HAVE_ONCE 1 |
| 12769 | +#define VCOS_HAVE_FILE 0 |
| 12770 | +#define VCOS_HAVE_USER_BUF 0 |
| 12771 | +#define VCOS_HAVE_CFG 1 |
| 12772 | +#define VCOS_HAVE_SPINLOCK 0 |
| 12773 | +#define VCOS_HAVE_CMD 1 |
| 12774 | +#define VCOS_HAVE_EVENT_FLAGS 1 |
| 12775 | + |
| 12776 | +/* Exclude many VCOS classes which don't have predicates */ |
| 12777 | +#define VCOS_TLS_H |
| 12778 | +#define VCOS_NAMED_MUTEX_H |
| 12779 | +#define VCOS_REENTRANT_MUTEX_H |
| 12780 | +#define VCOS_NAMED_SEMAPHORE_H |
| 12781 | +#define VCOS_QUICKSLOW_MUTEX_H |
| 12782 | +/*#define VCOS_INIT_H */ |
| 12783 | +/*#define VCOS_MEM_H */ |
| 12784 | +/*#define VCOS_STRING_H */ |
| 12785 | + |
| 12786 | +typedef struct semaphore VCOS_SEMAPHORE_T; |
| 12787 | +typedef struct semaphore VCOS_EVENT_T; |
| 12788 | +typedef struct mutex VCOS_MUTEX_T; |
| 12789 | +typedef volatile int VCOS_ONCE_T; |
| 12790 | + |
| 12791 | +typedef unsigned int VCOS_UNSIGNED; |
| 12792 | +typedef unsigned int VCOS_OPTION; |
| 12793 | +typedef atomic_t VCOS_ATOMIC_FLAGS_T; |
| 12794 | + |
| 12795 | +typedef struct |
| 12796 | +{ |
| 12797 | + struct timer_list linux_timer; |
| 12798 | + void *context; |
| 12799 | + void (*expiration_routine)(void *context); |
| 12800 | + |
| 12801 | +} VCOS_TIMER_T; |
| 12802 | + |
| 12803 | +typedef struct VCOS_LLTHREAD_T |
| 12804 | +{ |
| 12805 | + struct task_struct *thread; /**< The thread itself */ |
| 12806 | + VCOS_SEMAPHORE_T suspend; /**< For support event groups and similar - a per thread semaphore */ |
| 12807 | +} VCOS_LLTHREAD_T; |
| 12808 | + |
| 12809 | +typedef enum |
| 12810 | +{ |
| 12811 | + VCOS_O_RDONLY = 00000000, |
| 12812 | + VCOS_O_WRONLY = 00000001, |
| 12813 | + VCOS_O_RDWR = 00000002, |
| 12814 | + VCOS_O_TRUNC = 00001000, |
| 12815 | +} VCOS_FILE_FLAGS_T; |
| 12816 | + |
| 12817 | +typedef struct file *VCOS_FILE_T; |
| 12818 | + |
| 12819 | +#define VCOS_SUSPEND -1 |
| 12820 | +#define VCOS_NO_SUSPEND 0 |
| 12821 | + |
| 12822 | +#define VCOS_START 1 |
| 12823 | +#define VCOS_NO_START 0 |
| 12824 | + |
| 12825 | +#define VCOS_THREAD_PRI_MIN -20 |
| 12826 | +#define VCOS_THREAD_PRI_MAX 19 |
| 12827 | + |
| 12828 | +#define VCOS_THREAD_PRI_INCREASE -1 |
| 12829 | +#define VCOS_THREAD_PRI_HIGHEST VCOS_THREAD_PRI_MIN |
| 12830 | +#define VCOS_THREAD_PRI_LOWEST VCOS_THREAD_PRI_MAX |
| 12831 | +#define VCOS_THREAD_PRI_NORMAL ((VCOS_THREAD_PRI_MAX+VCOS_THREAD_PRI_MIN)/2) |
| 12832 | +#define VCOS_THREAD_PRI_ABOVE_NORMAL (VCOS_THREAD_PRI_NORMAL + VCOS_THREAD_PRI_INCREASE) |
| 12833 | +#define VCOS_THREAD_PRI_REALTIME VCOS_THREAD_PRI_HIGHEST |
| 12834 | + |
| 12835 | +#define _VCOS_AFFINITY_DEFAULT 0 |
| 12836 | +#define _VCOS_AFFINITY_CPU0 0 |
| 12837 | +#define _VCOS_AFFINITY_CPU1 0 |
| 12838 | +#define _VCOS_AFFINITY_MASK 0 |
| 12839 | +#define VCOS_CAN_SET_STACK_ADDR 0 |
| 12840 | + |
| 12841 | +#define VCOS_TICKS_PER_SECOND HZ |
| 12842 | + |
| 12843 | +#include "interface/vcos/generic/vcos_generic_event_flags.h" |
| 12844 | +#include "interface/vcos/generic/vcos_mem_from_malloc.h" |
| 12845 | +#include "interface/vcos/generic/vcos_joinable_thread_from_plain.h" |
| 12846 | + |
| 12847 | +/*********************************************************** |
| 12848 | + * |
| 12849 | + * Memory allcoation |
| 12850 | + * |
| 12851 | + ***********************************************************/ |
| 12852 | + |
| 12853 | +#define _vcos_platform_malloc vcos_platform_malloc |
| 12854 | +#define _vcos_platform_free vcos_platform_free |
| 12855 | + |
| 12856 | +void *vcos_platform_malloc( VCOS_UNSIGNED required_size ); |
| 12857 | +void vcos_platform_free( void *ptr ); |
| 12858 | + |
| 12859 | +#if defined(VCOS_INLINE_BODIES) |
| 12860 | + |
| 12861 | +#undef VCOS_ASSERT_LOGGING_DISABLE |
| 12862 | +#define VCOS_ASSERT_LOGGING_DISABLE 1 |
| 12863 | + |
| 12864 | +/*********************************************************** |
| 12865 | + * |
| 12866 | + * Counted Semaphores |
| 12867 | + * |
| 12868 | + ***********************************************************/ |
| 12869 | + |
| 12870 | +VCOS_INLINE_IMPL |
| 12871 | +VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem) { |
| 12872 | + int ret = down_interruptible(sem); |
| 12873 | + if ( ret == 0 ) |
| 12874 | + /* Success */ |
| 12875 | + return VCOS_SUCCESS; |
| 12876 | + else if ( ret == -EINTR ) |
| 12877 | + /* Interrupted */ |
| 12878 | + return VCOS_EINTR; |
| 12879 | + else |
| 12880 | + /* Default (timeout) */ |
| 12881 | + return VCOS_EAGAIN; |
| 12882 | +} |
| 12883 | + |
| 12884 | +VCOS_INLINE_IMPL |
| 12885 | +VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem) { |
| 12886 | + if (down_trylock(sem) != 0) |
| 12887 | + return VCOS_EAGAIN; |
| 12888 | + return VCOS_SUCCESS; |
| 12889 | +} |
| 12890 | + |
| 12891 | +VCOS_INLINE_IMPL |
| 12892 | +VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem, |
| 12893 | + const char *name, |
| 12894 | + VCOS_UNSIGNED initial_count) { |
| 12895 | + sema_init(sem, initial_count); |
| 12896 | + return VCOS_SUCCESS; |
| 12897 | +} |
| 12898 | + |
| 12899 | +VCOS_INLINE_IMPL |
| 12900 | +void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem) { |
| 12901 | +} |
| 12902 | + |
| 12903 | +VCOS_INLINE_IMPL |
| 12904 | +VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem) { |
| 12905 | + up(sem); |
| 12906 | + return VCOS_SUCCESS; |
| 12907 | +} |
| 12908 | + |
| 12909 | +/*********************************************************** |
| 12910 | + * |
| 12911 | + * Threads |
| 12912 | + * |
| 12913 | + ***********************************************************/ |
| 12914 | + |
| 12915 | +#include "vcos_thread_map.h" |
| 12916 | + |
| 12917 | +VCOS_INLINE_IMPL |
| 12918 | +VCOS_LLTHREAD_T *vcos_llthread_current(void) { |
| 12919 | + return &vcos_kthread_current()->thread; |
| 12920 | +} |
| 12921 | + |
| 12922 | +VCOS_INLINE_IMPL |
| 12923 | +void vcos_llthread_resume(VCOS_LLTHREAD_T *thread) { |
| 12924 | + vcos_assert(0); |
| 12925 | +} |
| 12926 | + |
| 12927 | +VCOS_INLINE_IMPL |
| 12928 | +void vcos_sleep(uint32_t ms) { |
| 12929 | + msleep(ms); |
| 12930 | +} |
| 12931 | + |
| 12932 | +VCOS_INLINE_IMPL |
| 12933 | +void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED p) { |
| 12934 | + /* not implemented */ |
| 12935 | +} |
| 12936 | +VCOS_INLINE_IMPL |
| 12937 | +VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread) { |
| 12938 | + /* not implemented */ |
| 12939 | + return 0; |
| 12940 | +} |
| 12941 | + |
| 12942 | +/*********************************************************** |
| 12943 | + * |
| 12944 | + * Miscellaneous |
| 12945 | + * |
| 12946 | + ***********************************************************/ |
| 12947 | + |
| 12948 | +VCOS_INLINE_IMPL |
| 12949 | +int vcos_strcasecmp(const char *s1, const char *s2) { |
| 12950 | + return strcasecmp(s1,s2); |
| 12951 | +} |
| 12952 | + |
| 12953 | + |
| 12954 | +/*********************************************************** |
| 12955 | + * |
| 12956 | + * Mutexes |
| 12957 | + * |
| 12958 | + ***********************************************************/ |
| 12959 | + |
| 12960 | +VCOS_INLINE_IMPL |
| 12961 | +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *m, const char *name) { |
| 12962 | + mutex_init(m); |
| 12963 | + return VCOS_SUCCESS; |
| 12964 | +} |
| 12965 | + |
| 12966 | +VCOS_INLINE_IMPL |
| 12967 | +void vcos_mutex_delete(VCOS_MUTEX_T *m) { |
| 12968 | +} |
| 12969 | + |
| 12970 | +VCOS_INLINE_IMPL |
| 12971 | +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *m) { |
| 12972 | + int ret = mutex_lock_interruptible(m); |
| 12973 | + if ( ret == 0 ) |
| 12974 | + /* Success */ |
| 12975 | + return VCOS_SUCCESS; |
| 12976 | + else if ( ret == -EINTR ) |
| 12977 | + /* Interrupted */ |
| 12978 | + return VCOS_EINTR; |
| 12979 | + else |
| 12980 | + /* Default */ |
| 12981 | + return VCOS_EAGAIN; |
| 12982 | +} |
| 12983 | + |
| 12984 | +VCOS_INLINE_IMPL |
| 12985 | +void vcos_mutex_unlock(VCOS_MUTEX_T *m) { |
| 12986 | + mutex_unlock(m); |
| 12987 | +} |
| 12988 | + |
| 12989 | +VCOS_INLINE_IMPL |
| 12990 | +int vcos_mutex_is_locked(VCOS_MUTEX_T *m) { |
| 12991 | + if (mutex_trylock(m) != 0) |
| 12992 | + return 1; /* it was locked */ |
| 12993 | + mutex_unlock(m); |
| 12994 | + /* it wasn't locked */ |
| 12995 | + return 0; |
| 12996 | +} |
| 12997 | + |
| 12998 | +VCOS_INLINE_IMPL |
| 12999 | +VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m) { |
| 13000 | + if (mutex_trylock(m) == 0) |
| 13001 | + return VCOS_SUCCESS; |
| 13002 | + else |
| 13003 | + return VCOS_EAGAIN; |
| 13004 | +} |
| 13005 | + |
| 13006 | +/* For supporting event groups - per thread semaphore */ |
| 13007 | +VCOS_INLINE_IMPL |
| 13008 | +void _vcos_thread_sem_wait(void) { |
| 13009 | + VCOS_THREAD_T *t = vcos_thread_current(); |
| 13010 | + vcos_semaphore_wait(&t->suspend); |
| 13011 | +} |
| 13012 | + |
| 13013 | +VCOS_INLINE_IMPL |
| 13014 | +void _vcos_thread_sem_post(VCOS_THREAD_T *target) { |
| 13015 | + vcos_semaphore_post(&target->suspend); |
| 13016 | +} |
| 13017 | + |
| 13018 | +/*********************************************************** |
| 13019 | + * |
| 13020 | + * Events |
| 13021 | + * |
| 13022 | + ***********************************************************/ |
| 13023 | + |
| 13024 | +VCOS_INLINE_IMPL |
| 13025 | +VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *debug_name) |
| 13026 | +{ |
| 13027 | + sema_init(event, 0); |
| 13028 | + return VCOS_SUCCESS; |
| 13029 | +} |
| 13030 | + |
| 13031 | +VCOS_INLINE_IMPL |
| 13032 | +void vcos_event_signal(VCOS_EVENT_T *event) |
| 13033 | +{ |
| 13034 | + up(event); |
| 13035 | +} |
| 13036 | + |
| 13037 | +VCOS_INLINE_IMPL |
| 13038 | +VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event) |
| 13039 | +{ |
| 13040 | + int ret = down_interruptible(event); |
| 13041 | + if ( ret == -EINTR ) |
| 13042 | + /* Interrupted */ |
| 13043 | + return VCOS_EINTR; |
| 13044 | + else if (ret != 0) |
| 13045 | + /* Default (timeout) */ |
| 13046 | + return VCOS_EAGAIN; |
| 13047 | + /* Emulate a maximum count of 1 by removing any extra upness */ |
| 13048 | + while (down_trylock(event) == 0) continue; |
| 13049 | + return VCOS_SUCCESS; |
| 13050 | +} |
| 13051 | + |
| 13052 | +VCOS_INLINE_DECL |
| 13053 | +VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event) |
| 13054 | +{ |
| 13055 | + return (down_trylock(event) == 0) ? VCOS_SUCCESS : VCOS_EAGAIN; |
| 13056 | +} |
| 13057 | + |
| 13058 | +VCOS_INLINE_IMPL |
| 13059 | +void vcos_event_delete(VCOS_EVENT_T *event) |
| 13060 | +{ |
| 13061 | +} |
| 13062 | + |
| 13063 | +/*********************************************************** |
| 13064 | + * |
| 13065 | + * Timers |
| 13066 | + * |
| 13067 | + ***********************************************************/ |
| 13068 | + |
| 13069 | +VCOS_INLINE_DECL |
| 13070 | +void vcos_timer_linux_func(unsigned long data) |
| 13071 | +{ |
| 13072 | + VCOS_TIMER_T *vcos_timer = (VCOS_TIMER_T *)data; |
| 13073 | + |
| 13074 | + vcos_timer->expiration_routine( vcos_timer->context ); |
| 13075 | +} |
| 13076 | + |
| 13077 | +VCOS_INLINE_DECL |
| 13078 | +VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer, |
| 13079 | + const char *name, |
| 13080 | + void (*expiration_routine)(void *context), |
| 13081 | + void *context) { |
| 13082 | + init_timer(&timer->linux_timer); |
| 13083 | + timer->linux_timer.data = (unsigned long)timer; |
| 13084 | + timer->linux_timer.function = vcos_timer_linux_func; |
| 13085 | + |
| 13086 | + timer->context = context; |
| 13087 | + timer->expiration_routine = expiration_routine; |
| 13088 | + |
| 13089 | + return VCOS_SUCCESS; |
| 13090 | +} |
| 13091 | + |
| 13092 | +VCOS_INLINE_IMPL |
| 13093 | +void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms) { |
| 13094 | + timer->linux_timer.expires = jiffies + msecs_to_jiffies(delay_ms); |
| 13095 | + add_timer(&timer->linux_timer); |
| 13096 | +} |
| 13097 | + |
| 13098 | +VCOS_INLINE_IMPL |
| 13099 | +void vcos_timer_cancel(VCOS_TIMER_T *timer) { |
| 13100 | + del_timer(&timer->linux_timer); |
| 13101 | +} |
| 13102 | + |
| 13103 | +VCOS_INLINE_IMPL |
| 13104 | +void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms) { |
| 13105 | + del_timer_sync(&timer->linux_timer); |
| 13106 | + timer->linux_timer.expires = jiffies + msecs_to_jiffies(delay_ms); |
| 13107 | + add_timer(&timer->linux_timer); |
| 13108 | +} |
| 13109 | + |
| 13110 | +VCOS_INLINE_IMPL |
| 13111 | +void vcos_timer_delete(VCOS_TIMER_T *timer) { |
| 13112 | + timer->context = NULL; |
| 13113 | + timer->expiration_routine = NULL; |
| 13114 | + timer->linux_timer.function = NULL; |
| 13115 | + timer->linux_timer.data = 0; |
| 13116 | + return; |
| 13117 | +} |
| 13118 | + |
| 13119 | +VCOS_INLINE_IMPL |
| 13120 | +VCOS_UNSIGNED vcos_process_id_current(void) { |
| 13121 | + return (VCOS_UNSIGNED)current->pid; |
| 13122 | +} |
| 13123 | + |
| 13124 | + |
| 13125 | +VCOS_INLINE_IMPL |
| 13126 | +int vcos_in_interrupt(void) { |
| 13127 | + return in_interrupt(); |
| 13128 | +} |
| 13129 | + |
| 13130 | +/*********************************************************** |
| 13131 | + * |
| 13132 | + * Atomic flags |
| 13133 | + * |
| 13134 | + ***********************************************************/ |
| 13135 | + |
| 13136 | +VCOS_INLINE_IMPL |
| 13137 | +VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags) |
| 13138 | +{ |
| 13139 | + atomic_set(atomic_flags, 0); |
| 13140 | + return VCOS_SUCCESS; |
| 13141 | +} |
| 13142 | + |
| 13143 | +VCOS_INLINE_IMPL |
| 13144 | +void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags) |
| 13145 | +{ |
| 13146 | + uint32_t value; |
| 13147 | + do { |
| 13148 | + value = atomic_read(atomic_flags); |
| 13149 | + } while (atomic_cmpxchg(atomic_flags, value, value | flags) != value); |
| 13150 | +} |
| 13151 | + |
| 13152 | +VCOS_INLINE_IMPL |
| 13153 | +uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags) |
| 13154 | +{ |
| 13155 | + return atomic_xchg(atomic_flags, 0); |
| 13156 | +} |
| 13157 | + |
| 13158 | +VCOS_INLINE_IMPL |
| 13159 | +void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags) |
| 13160 | +{ |
| 13161 | +} |
| 13162 | + |
| 13163 | +#undef VCOS_ASSERT_LOGGING_DISABLE |
| 13164 | +#define VCOS_ASSERT_LOGGING_DISABLE 0 |
| 13165 | + |
| 13166 | +#endif /* VCOS_INLINE_BODIES */ |
| 13167 | + |
| 13168 | +VCOS_INLINE_DECL void _vcos_thread_sem_wait(void); |
| 13169 | +VCOS_INLINE_DECL void _vcos_thread_sem_post(VCOS_THREAD_T *); |
| 13170 | + |
| 13171 | +/*********************************************************** |
| 13172 | + * |
| 13173 | + * Misc |
| 13174 | + * |
| 13175 | + ***********************************************************/ |
| 13176 | +VCOS_INLINE_DECL char *vcos_strdup(const char *str); |
| 13177 | + |
| 13178 | +/*********************************************************** |
| 13179 | + * |
| 13180 | + * Logging |
| 13181 | + * |
| 13182 | + ***********************************************************/ |
| 13183 | + |
| 13184 | +VCOSPRE_ const char * VCOSPOST_ _vcos_log_level(void); |
| 13185 | +#define _VCOS_LOG_LEVEL() _vcos_log_level() |
| 13186 | + |
| 13187 | +#define vcos_log_platform_init() _vcos_log_platform_init() |
| 13188 | +#define vcos_log_platform_register(category) _vcos_log_platform_register(category) |
| 13189 | +#define vcos_log_platform_unregister(category) _vcos_log_platform_unregister(category) |
| 13190 | + |
| 13191 | +struct VCOS_LOG_CAT_T; /* Forward declaration since vcos_logging.h hasn't been included yet */ |
| 13192 | + |
| 13193 | +void _vcos_log_platform_init(void); |
| 13194 | +void _vcos_log_platform_register(struct VCOS_LOG_CAT_T *category); |
| 13195 | +void _vcos_log_platform_unregister(struct VCOS_LOG_CAT_T *category); |
| 13196 | + |
| 13197 | +/*********************************************************** |
| 13198 | + * |
| 13199 | + * Memory barriers |
| 13200 | + * |
| 13201 | + ***********************************************************/ |
| 13202 | + |
| 13203 | +#define vcos_wmb(x) wmb() |
| 13204 | +#define vcos_rmb() rmb() |
| 13205 | + |
| 13206 | +#include "interface/vcos/generic/vcos_common.h" |
| 13207 | +/*#include "interface/vcos/generic/vcos_generic_quickslow_mutex.h" */ |
| 13208 | + |
| 13209 | +#endif /* VCOS_PLATFORM_H */ |
| 13210 | + |
| 13211 | --- /dev/null |
| 13212 | +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_platform_types.h |
| 13213 | @@ -0,0 +1,47 @@ |
| 13214 | +/*============================================================================= |
| 13215 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 13216 | +All rights reserved. |
| 13217 | + |
| 13218 | +Project : vcfw |
| 13219 | +Module : osal |
| 13220 | + |
| 13221 | +FILE DESCRIPTION |
| 13222 | +VideoCore OS Abstraction Layer - platform-specific types and defines |
| 13223 | +=============================================================================*/ |
| 13224 | + |
| 13225 | +#ifndef VCOS_PLATFORM_TYPES_H |
| 13226 | +#define VCOS_PLATFORM_TYPES_H |
| 13227 | + |
| 13228 | +#include <stddef.h> |
| 13229 | +#include <linux/types.h> |
| 13230 | +#include <linux/bug.h> |
| 13231 | + |
| 13232 | +#define VCOSPRE_ extern |
| 13233 | +#define VCOSPOST_ |
| 13234 | + |
| 13235 | +#if defined(__GNUC__) && (( __GNUC__ > 2 ) || (( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 3 ))) |
| 13236 | +#define VCOS_FORMAT_ATTR_(ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK) __attribute__ ((format (ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK))) |
| 13237 | +#else |
| 13238 | +#define VCOS_FORMAT_ATTR_(ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK) |
| 13239 | +#endif |
| 13240 | + |
| 13241 | +#if !defined( __STDC_VERSION__ ) |
| 13242 | +#define __STDC_VERSION__ 199901L |
| 13243 | +#endif |
| 13244 | + |
| 13245 | +#if !defined( __STDC_VERSION ) |
| 13246 | +#define __STDC_VERSION __STDC_VERSION__ |
| 13247 | +#endif |
| 13248 | + |
| 13249 | +static inline void __vcos_bkpt( void ) { BUG(); } |
| 13250 | +#define VCOS_BKPT __vcos_bkpt() |
| 13251 | + |
| 13252 | +#define VCOS_ASSERT_MSG(...) printk( KERN_ERR "vcos_assert: " __VA_ARGS__ ) |
| 13253 | + |
| 13254 | +#define PRId64 "lld" |
| 13255 | +#define PRIi64 "lli" |
| 13256 | +#define PRIo64 "llo" |
| 13257 | +#define PRIu64 "llu" |
| 13258 | +#define PRIx64 "llx" |
| 13259 | + |
| 13260 | +#endif |
| 13261 | --- /dev/null |
| 13262 | +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.c |
| 13263 | @@ -0,0 +1,129 @@ |
| 13264 | +/***************************************************************************** |
| 13265 | +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved. |
| 13266 | +* |
| 13267 | +* Unless you and Broadcom execute a separate written software license |
| 13268 | +* agreement governing use of this software, this software is licensed to you |
| 13269 | +* under the terms of the GNU General Public License version 2, available at |
| 13270 | +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). |
| 13271 | +* |
| 13272 | +* Notwithstanding the above, under no circumstances may you combine this |
| 13273 | +* software in any way with any other Broadcom software provided under a |
| 13274 | +* license other than the GPL, without Broadcom's express prior written |
| 13275 | +* consent. |
| 13276 | +*****************************************************************************/ |
| 13277 | + |
| 13278 | +/** Support to allow VCOS thread-related functions to be called from |
| 13279 | + * threads that were not created by VCOS. |
| 13280 | + */ |
| 13281 | + |
| 13282 | +#include <linux/semaphore.h> |
| 13283 | +#include <linux/vmalloc.h> |
| 13284 | +#include <linux/list.h> |
| 13285 | +#include <linux/sched.h> |
| 13286 | + |
| 13287 | +#include "vcos_thread_map.h" |
| 13288 | +#include "interface/vcos/vcos_logging.h" |
| 13289 | + |
| 13290 | +/* |
| 13291 | + * Store the vcos_thread pointer at the end of |
| 13292 | + * current kthread stack, right after the thread_info |
| 13293 | + * structure. |
| 13294 | + * |
| 13295 | + * I belive we should be safe here to steal these 4 bytes |
| 13296 | + * from the stack, as long as the vcos thread does not use up |
| 13297 | + * all the stack available |
| 13298 | + * |
| 13299 | + * NOTE: This scheme will not work on architectures with stack growing up |
| 13300 | + */ |
| 13301 | + |
| 13302 | +/* Shout, if we are not being compiled for ARM kernel */ |
| 13303 | + |
| 13304 | +#ifndef CONFIG_ARM |
| 13305 | +#error " **** The vcos kthread implementation may not work for non-ARM kernel ****" |
| 13306 | +#endif |
| 13307 | + |
| 13308 | +static inline void *to_current_vcos_thread(void) |
| 13309 | +{ |
| 13310 | + unsigned long *vcos_data; |
| 13311 | + |
| 13312 | + vcos_data = (unsigned long *)((char *)current_thread_info() + sizeof(struct thread_info)); |
| 13313 | + |
| 13314 | + return (void *)vcos_data; |
| 13315 | +} |
| 13316 | + |
| 13317 | + |
| 13318 | +static inline void *to_vcos_thread(struct task_struct *tsk) |
| 13319 | +{ |
| 13320 | + unsigned long *vcos_data; |
| 13321 | + |
| 13322 | + vcos_data = (unsigned long *)((char *)tsk->stack + sizeof(struct thread_info)); |
| 13323 | + |
| 13324 | + return (void *)vcos_data; |
| 13325 | +} |
| 13326 | + |
| 13327 | +/** |
| 13328 | + @fn uint32_t vcos_add_thread(THREAD_MAP_T *vcos_thread); |
| 13329 | +*/ |
| 13330 | +uint32_t vcos_add_thread(VCOS_THREAD_T *vcos_thread) |
| 13331 | +{ |
| 13332 | + VCOS_THREAD_T **vcos_thread_storage = (VCOS_THREAD_T **)to_current_vcos_thread(); |
| 13333 | + |
| 13334 | + *vcos_thread_storage = vcos_thread; |
| 13335 | + |
| 13336 | + return(0); |
| 13337 | +} |
| 13338 | + |
| 13339 | + |
| 13340 | +/** |
| 13341 | + @fn uint32_t vcos_remove_thread(struct task_struct * thread_id); |
| 13342 | +*/ |
| 13343 | +uint32_t vcos_remove_thread(struct task_struct *thread_id) |
| 13344 | +{ |
| 13345 | + /* Remove thread_id -> VCOS_THREAD_T relationship */ |
| 13346 | + VCOS_THREAD_T **vcos_thread_storage; |
| 13347 | + |
| 13348 | + /* |
| 13349 | + * We want to be able to build vcos as a loadable module, which |
| 13350 | + * means that we can't call get_task_struct. So we assert if we're |
| 13351 | + * ever called with thread_id != current. |
| 13352 | + */ |
| 13353 | + |
| 13354 | + BUG_ON( thread_id != current ); |
| 13355 | + |
| 13356 | + vcos_thread_storage = (VCOS_THREAD_T **)to_vcos_thread(thread_id); |
| 13357 | + |
| 13358 | + *(unsigned long *)vcos_thread_storage = 0xCAFEBABE; |
| 13359 | + |
| 13360 | + return(0); |
| 13361 | +} |
| 13362 | + |
| 13363 | + |
| 13364 | +VCOS_THREAD_T *vcos_kthread_current(void) |
| 13365 | +{ |
| 13366 | + VCOS_THREAD_T **vcos_thread_storage = (VCOS_THREAD_T **)to_current_vcos_thread(); |
| 13367 | + |
| 13368 | + /* If we find this, either the thread is already dead or stack pages of a |
| 13369 | + * dead vcos thread are re-allocated to this one. |
| 13370 | + * |
| 13371 | + * Since there's no way to differentiate between these 2 cases, we just dump |
| 13372 | + * the current task name to the log. |
| 13373 | + * |
| 13374 | + * If the current thread is created using VCOS API, you should *never* see this |
| 13375 | + * print. |
| 13376 | + * |
| 13377 | + * If its a non-VCOS thread, just let it go ... |
| 13378 | + * |
| 13379 | + * To debug VCOS, uncomment printk's under the "if" condition below |
| 13380 | + * |
| 13381 | + */ |
| 13382 | + if (*vcos_thread_storage == (void *)0xCAFEBABE) |
| 13383 | + { |
| 13384 | + #if 0 |
| 13385 | + printk(KERN_DEBUG"****************************************************\n"); |
| 13386 | + printk(KERN_DEBUG"%s : You have a problem, if \"%s\" is a VCOS thread\n",__func__, current->comm); |
| 13387 | + printk(KERN_DEBUG"****************************************************\n"); |
| 13388 | + #endif |
| 13389 | + } |
| 13390 | + |
| 13391 | + return *vcos_thread_storage; |
| 13392 | +} |
| 13393 | --- /dev/null |
| 13394 | +++ b/drivers/misc/vc04_services/interface/vcos/linuxkernel/vcos_thread_map.h |
| 13395 | @@ -0,0 +1,39 @@ |
| 13396 | +/***************************************************************************** |
| 13397 | +* Copyright 2009 - 2010 Broadcom Corporation. All rights reserved. |
| 13398 | +* |
| 13399 | +* Unless you and Broadcom execute a separate written software license |
| 13400 | +* agreement governing use of this software, this software is licensed to you |
| 13401 | +* under the terms of the GNU General Public License version 2, available at |
| 13402 | +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). |
| 13403 | +* |
| 13404 | +* Notwithstanding the above, under no circumstances may you combine this |
| 13405 | +* software in any way with any other Broadcom software provided under a |
| 13406 | +* license other than the GPL, without Broadcom's express prior written |
| 13407 | +* consent. |
| 13408 | +*****************************************************************************/ |
| 13409 | + |
| 13410 | + |
| 13411 | +#ifndef VCOS_THREAD_MAP_H |
| 13412 | +#define VCOS_THREAD_MAP_H |
| 13413 | + |
| 13414 | +#include <linux/string.h> |
| 13415 | + |
| 13416 | +#include "vcos_platform.h" |
| 13417 | + |
| 13418 | +static inline void vcos_thread_map_init(void) |
| 13419 | +{ |
| 13420 | + return; |
| 13421 | +} |
| 13422 | + |
| 13423 | +static inline void vcos_thread_map_cleanup(void) |
| 13424 | +{ |
| 13425 | + return; |
| 13426 | +} |
| 13427 | + |
| 13428 | +uint32_t vcos_add_thread(VCOS_THREAD_T *vcos_thread); |
| 13429 | + |
| 13430 | +uint32_t vcos_remove_thread(struct task_struct *thread_id); |
| 13431 | + |
| 13432 | +VCOS_THREAD_T *vcos_kthread_current(void); |
| 13433 | + |
| 13434 | +#endif /*VCOS_THREAD_MAP_H */ |
| 13435 | --- /dev/null |
| 13436 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos.h |
| 13437 | @@ -0,0 +1,201 @@ |
| 13438 | +/*============================================================================= |
| 13439 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 13440 | +All rights reserved. |
| 13441 | + |
| 13442 | +Project : vcfw |
| 13443 | +Module : chip driver |
| 13444 | + |
| 13445 | +FILE DESCRIPTION |
| 13446 | +VideoCore OS Abstraction Layer - public header file |
| 13447 | +=============================================================================*/ |
| 13448 | + |
| 13449 | +/** |
| 13450 | + * \mainpage OS Abstraction Layer |
| 13451 | + * |
| 13452 | + * \section intro Introduction |
| 13453 | + * |
| 13454 | + * This abstraction layer is here to allow the underlying OS to be easily changed (e.g. from |
| 13455 | + * Nucleus to ThreadX) and to aid in porting host applications to new targets. |
| 13456 | + * |
| 13457 | + * \subsection error Error handling |
| 13458 | + * |
| 13459 | + * Wherever possible, VCOS functions assert internally and return void. The only exceptions |
| 13460 | + * are creation functions (which might fail due to lack of resources) and functions that |
| 13461 | + * might timeout or fail due to lack of space. Errors that might be reported by the underlying |
| 13462 | + * OS API (e.g. invalid mutex) are treated as a programming error, and are merely asserted on. |
| 13463 | + * |
| 13464 | + * \section thread_synch Threads and synchronisation |
| 13465 | + * |
| 13466 | + * \subsection thread Threads |
| 13467 | + * |
| 13468 | + * The thread API is somewhat different to that found in Nucleus. In particular, threads |
| 13469 | + * cannot just be destroyed at arbitrary times and nor can they merely exit. This is so |
| 13470 | + * that the same API can be implemented across all interesting platforms without too much |
| 13471 | + * difficulty. See vcos_thread.h for details. Thread attributes are configured via |
| 13472 | + * the VCOS_THREAD_ATTR_T structure, found in vcos_thread_attr.h. |
| 13473 | + * |
| 13474 | + * \subsection sema Semaphores |
| 13475 | + * |
| 13476 | + * Counted semaphores (c.f. Nucleus NU_SEMAPHORE) are created with VCOS_SEMAPHORE_T. |
| 13477 | + * Under ThreadX on VideoCore, semaphores are implemented using VideoCore spinlocks, and |
| 13478 | + * so are quite a lot faster than ordinary ThreadX semaphores. See vcos_semaphore.h. |
| 13479 | + * |
| 13480 | + * \subsection mtx Mutexes |
| 13481 | + * |
| 13482 | + * Mutexes are used for locking. Attempts to take a mutex twice, or to unlock it |
| 13483 | + * in a different thread to the one in which it was locked should be expected to fail. |
| 13484 | + * Mutexes are not re-entrant (see vcos_reentrant_mutex.h for a slightly slower |
| 13485 | + * re-entrant mutex). |
| 13486 | + * |
| 13487 | + * \subsection evflags Event flags |
| 13488 | + * |
| 13489 | + * Event flags (the ThreadX name - also known as event groups under Nucleus) provide |
| 13490 | + * 32 flags which can be waited on by multiple clients, and signalled by multiple clients. |
| 13491 | + * A timeout can be specified. See vcos_event_flags.h. An alternative to this is the |
| 13492 | + * VCOS_EVENT_T (see vcos_event.h) which is akin to the Win32 auto-reset event, or a |
| 13493 | + * saturating counted semaphore. |
| 13494 | + * |
| 13495 | + * \subsection event Events |
| 13496 | + * |
| 13497 | + * A VCOS_EVENT_T is a bit like a saturating semaphore. No matter how many times it |
| 13498 | + * is signalled, the waiter will only wake up once. See vcos_event.h. You might think this |
| 13499 | + * is useful if you suspect that the cost of reading the semaphore count (perhaps via a |
| 13500 | + * system call) is expensive on your platform. |
| 13501 | + * |
| 13502 | + * \subsection tls Thread local storage |
| 13503 | + * |
| 13504 | + * Thread local storage is supported using vcos_tls.h. This is emulated on Nucleus |
| 13505 | + * and ThreadX. |
| 13506 | + * |
| 13507 | + * \section int Interrupts |
| 13508 | + * |
| 13509 | + * The legacy LISR/HISR scheme found in Nucleus is supported via the legacy ISR API, |
| 13510 | + * which is also supported on ThreadX. New code should avoid this, and old code should |
| 13511 | + * be migrated away from it, since it is slow. See vcos_legacy_isr.h. |
| 13512 | + * |
| 13513 | + * Registering an interrupt handler, and disabling/restoring interrupts, is handled |
| 13514 | + * using the functions in vcos_isr.h. |
| 13515 | + * |
| 13516 | + */ |
| 13517 | + |
| 13518 | +/** |
| 13519 | + * \file vcos.h |
| 13520 | + * |
| 13521 | + * This is the top level header file. Clients include this. It pulls in the platform-specific |
| 13522 | + * header file (vcos_platform.h) together with header files defining the expected APIs, such |
| 13523 | + * as vcos_mutex.h, vcos_semaphore.h, etc. It is also possible to include these header files |
| 13524 | + * directly. |
| 13525 | + * |
| 13526 | + */ |
| 13527 | + |
| 13528 | +#ifndef VCOS_H |
| 13529 | +#define VCOS_H |
| 13530 | + |
| 13531 | +#include "interface/vcos/vcos_assert.h" |
| 13532 | +#include "vcos_types.h" |
| 13533 | +#include "vcos_platform.h" |
| 13534 | + |
| 13535 | +#ifndef VCOS_INIT_H |
| 13536 | +#include "interface/vcos/vcos_init.h" |
| 13537 | +#endif |
| 13538 | + |
| 13539 | +#ifndef VCOS_SEMAPHORE_H |
| 13540 | +#include "interface/vcos/vcos_semaphore.h" |
| 13541 | +#endif |
| 13542 | + |
| 13543 | +#ifndef VCOS_THREAD_H |
| 13544 | +#include "interface/vcos/vcos_thread.h" |
| 13545 | +#endif |
| 13546 | + |
| 13547 | +#ifndef VCOS_MUTEX_H |
| 13548 | +#include "interface/vcos/vcos_mutex.h" |
| 13549 | +#endif |
| 13550 | + |
| 13551 | +#ifndef VCOS_MEM_H |
| 13552 | +#include "interface/vcos/vcos_mem.h" |
| 13553 | +#endif |
| 13554 | + |
| 13555 | +#ifndef VCOS_LOGGING_H |
| 13556 | +#include "interface/vcos/vcos_logging.h" |
| 13557 | +#endif |
| 13558 | + |
| 13559 | +#ifndef VCOS_STRING_H |
| 13560 | +#include "interface/vcos/vcos_string.h" |
| 13561 | +#endif |
| 13562 | + |
| 13563 | +#ifndef VCOS_EVENT_H |
| 13564 | +#include "interface/vcos/vcos_event.h" |
| 13565 | +#endif |
| 13566 | + |
| 13567 | +#ifndef VCOS_THREAD_ATTR_H |
| 13568 | +#include "interface/vcos/vcos_thread_attr.h" |
| 13569 | +#endif |
| 13570 | + |
| 13571 | +#ifndef VCOS_TLS_H |
| 13572 | +#include "interface/vcos/vcos_tls.h" |
| 13573 | +#endif |
| 13574 | + |
| 13575 | +#ifndef VCOS_REENTRANT_MUTEX_H |
| 13576 | +#include "interface/vcos/vcos_reentrant_mutex.h" |
| 13577 | +#endif |
| 13578 | + |
| 13579 | +#ifndef VCOS_NAMED_SEMAPHORE_H |
| 13580 | +#include "interface/vcos/vcos_named_semaphore.h" |
| 13581 | +#endif |
| 13582 | + |
| 13583 | +#ifndef VCOS_QUICKSLOW_MUTEX_H |
| 13584 | +#include "interface/vcos/vcos_quickslow_mutex.h" |
| 13585 | +#endif |
| 13586 | + |
| 13587 | +/* Headers with predicates */ |
| 13588 | + |
| 13589 | +#if VCOS_HAVE_EVENT_FLAGS |
| 13590 | +#include "interface/vcos/vcos_event_flags.h" |
| 13591 | +#endif |
| 13592 | + |
| 13593 | +#if VCOS_HAVE_QUEUE |
| 13594 | +#include "interface/vcos/vcos_queue.h" |
| 13595 | +#endif |
| 13596 | + |
| 13597 | +#if VCOS_HAVE_LEGACY_ISR |
| 13598 | +#include "interface/vcos/vcos_legacy_isr.h" |
| 13599 | +#endif |
| 13600 | + |
| 13601 | +#if VCOS_HAVE_TIMER |
| 13602 | +#include "interface/vcos/vcos_timer.h" |
| 13603 | +#endif |
| 13604 | + |
| 13605 | +#if VCOS_HAVE_MEMPOOL |
| 13606 | +#include "interface/vcos/vcos_mempool.h" |
| 13607 | +#endif |
| 13608 | + |
| 13609 | +#if VCOS_HAVE_ISR |
| 13610 | +#include "interface/vcos/vcos_isr.h" |
| 13611 | +#endif |
| 13612 | + |
| 13613 | +#if VCOS_HAVE_ATOMIC_FLAGS |
| 13614 | +#include "interface/vcos/vcos_atomic_flags.h" |
| 13615 | +#endif |
| 13616 | + |
| 13617 | +#if VCOS_HAVE_ONCE |
| 13618 | +#include "interface/vcos/vcos_once.h" |
| 13619 | +#endif |
| 13620 | + |
| 13621 | +#if VCOS_HAVE_BLOCK_POOL |
| 13622 | +#include "interface/vcos/vcos_blockpool.h" |
| 13623 | +#endif |
| 13624 | + |
| 13625 | +#if VCOS_HAVE_FILE |
| 13626 | +#include "interface/vcos/vcos_file.h" |
| 13627 | +#endif |
| 13628 | + |
| 13629 | +#if VCOS_HAVE_CFG |
| 13630 | +#include "interface/vcos/vcos_cfg.h" |
| 13631 | +#endif |
| 13632 | + |
| 13633 | +#if VCOS_HAVE_CMD |
| 13634 | +#include "interface/vcos/vcos_cmd.h" |
| 13635 | +#endif |
| 13636 | + |
| 13637 | +#endif /* VCOS_H */ |
| 13638 | + |
| 13639 | --- /dev/null |
| 13640 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_assert.h |
| 13641 | @@ -0,0 +1,269 @@ |
| 13642 | +/*============================================================================= |
| 13643 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 13644 | +All rights reserved. |
| 13645 | + |
| 13646 | +Project : vcfw |
| 13647 | +Module : osal |
| 13648 | + |
| 13649 | +FILE DESCRIPTION |
| 13650 | +VideoCore OS Abstraction Layer - Assertion and error-handling macros. |
| 13651 | +=============================================================================*/ |
| 13652 | + |
| 13653 | + |
| 13654 | +#ifndef VCOS_ASSERT_H |
| 13655 | +#define VCOS_ASSERT_H |
| 13656 | + |
| 13657 | +/* |
| 13658 | + * Macro: |
| 13659 | + * vcos_assert(cond) |
| 13660 | + * vcos_assert_msg(cond, fmt, ...) |
| 13661 | + * Use: |
| 13662 | + * Detecting programming errors by ensuring that assumptions are correct. |
| 13663 | + * On failure: |
| 13664 | + * Performs a platform-dependent "breakpoint", usually with an assert-style |
| 13665 | + * message. The '_msg' variant expects a printf-style format string and |
| 13666 | + * parameters. |
| 13667 | + * If a failure is detected, the code should be fixed and rebuilt. |
| 13668 | + * In release builds: |
| 13669 | + * Generates no code, i.e. does not evaluate 'cond'. |
| 13670 | + * Returns: |
| 13671 | + * Nothing. |
| 13672 | + * |
| 13673 | + * Macro: |
| 13674 | + * vcos_demand(cond) |
| 13675 | + * vcos_demand_msg(cond, fmt, ...) |
| 13676 | + * Use: |
| 13677 | + * Detecting fatal system errors that require a reboot. |
| 13678 | + * On failure: |
| 13679 | + * Performs a platform-dependent "breakpoint", usually with an assert-style |
| 13680 | + * message, then calls vcos_abort (see below). |
| 13681 | + * In release builds: |
| 13682 | + * Calls vcos_abort() if 'cond' is false. |
| 13683 | + * Returns: |
| 13684 | + * Nothing (never, on failure). |
| 13685 | + * |
| 13686 | + * Macro: |
| 13687 | + * vcos_verify(cond) |
| 13688 | + * vcos_verify_msg(cond, fmt, ...) |
| 13689 | + * Use: |
| 13690 | + * Detecting run-time errors and interesting conditions, normally within an |
| 13691 | + * 'if' statement to catch the failures, i.e. |
| 13692 | + * if (!vcos_verify(cond)) handle_error(); |
| 13693 | + * On failure: |
| 13694 | + * Generates a message and optionally stops at a platform-dependent |
| 13695 | + * "breakpoint" (usually disabled). See vcos_verify_bkpts_enable below. |
| 13696 | + * In release builds: |
| 13697 | + * Just evaluates and returns 'cond'. |
| 13698 | + * Returns: |
| 13699 | + * Non-zero if 'cond' is true, otherwise zero. |
| 13700 | + * |
| 13701 | + * Macro: |
| 13702 | + * vcos_static_assert(cond) |
| 13703 | + * Use: |
| 13704 | + * Detecting compile-time errors. |
| 13705 | + * On failure: |
| 13706 | + * Generates a compiler error. |
| 13707 | + * In release builds: |
| 13708 | + * Generates a compiler error. |
| 13709 | + * |
| 13710 | + * Function: |
| 13711 | + * void vcos_abort(void) |
| 13712 | + * Use: |
| 13713 | + * Invokes the fatal error handling mechanism, alerting the host where |
| 13714 | + * applicable. |
| 13715 | + * Returns: |
| 13716 | + * Never. |
| 13717 | + * |
| 13718 | + * Macro: |
| 13719 | + * VCOS_VERIFY_BKPTS |
| 13720 | + * Use: |
| 13721 | + * Define in a module (before including vcos.h) to specify an alternative |
| 13722 | + * flag to control breakpoints on vcos_verify() failures. |
| 13723 | + * Returns: |
| 13724 | + * Non-zero values enable breakpoints. |
| 13725 | + * |
| 13726 | + * Function: |
| 13727 | + * int vcos_verify_bkpts_enable(int enable); |
| 13728 | + * Use: |
| 13729 | + * Sets the global flag controlling breakpoints on vcos_verify failures, |
| 13730 | + * enabling the breakpoints iff 'enable' is non-zero. |
| 13731 | + * Returns: |
| 13732 | + * The previous state of the flag. |
| 13733 | + * |
| 13734 | + * Function: |
| 13735 | + * int vcos_verify_bkpts_enabled(void); |
| 13736 | + * Use: |
| 13737 | + * Queries the state of the global flag enabling breakpoints on vcos_verify |
| 13738 | + * failures. |
| 13739 | + * Returns: |
| 13740 | + * The current state of the flag. |
| 13741 | + * |
| 13742 | + * Examples: |
| 13743 | + * |
| 13744 | + * int my_breakpoint_enable_flag = 1; |
| 13745 | + * |
| 13746 | + * #define VCOS_VERIFY_BKPTS my_breakpoint_enable_flag |
| 13747 | + * |
| 13748 | + * #include "interface/vcos/vcos.h" |
| 13749 | + * |
| 13750 | + * vcos_static_assert((sizeof(object) % 32) == 0); |
| 13751 | + * |
| 13752 | + * // ... |
| 13753 | + * |
| 13754 | + * vcos_assert_msg(postcondition_is_true, "Coding error"); |
| 13755 | + * |
| 13756 | + * if (!vcos_verify_msg(buf, "Buffer allocation failed (%d bytes)", size)) |
| 13757 | + * { |
| 13758 | + * // Tidy up |
| 13759 | + * // ... |
| 13760 | + * return OUT_OF_MEMORY; |
| 13761 | + * } |
| 13762 | + * |
| 13763 | + * vcos_demand(*p++==GUARDWORDHEAP); |
| 13764 | + */ |
| 13765 | + |
| 13766 | +#ifdef __cplusplus |
| 13767 | +extern "C" { |
| 13768 | +#endif |
| 13769 | + |
| 13770 | +#include "interface/vcos/vcos_types.h" |
| 13771 | + |
| 13772 | +#ifdef __COVERITY__ |
| 13773 | +#undef VCOS_ASSERT_BKPT |
| 13774 | +#define VCOS_ASSERT_BKPT __coverity_panic__() |
| 13775 | +#endif |
| 13776 | + |
| 13777 | +#ifndef VCOS_VERIFY_BKPTS |
| 13778 | +#define VCOS_VERIFY_BKPTS vcos_verify_bkpts_enabled() |
| 13779 | +#endif |
| 13780 | + |
| 13781 | +#ifndef VCOS_BKPT |
| 13782 | +#if defined(__VIDEOCORE__) && !defined(VCOS_ASSERT_NO_BKPTS) |
| 13783 | +#define VCOS_BKPT _bkpt() |
| 13784 | +#else |
| 13785 | +#define VCOS_BKPT (void )0 |
| 13786 | +#endif |
| 13787 | +#endif |
| 13788 | + |
| 13789 | +#ifndef VCOS_ASSERT_BKPT |
| 13790 | +#define VCOS_ASSERT_BKPT VCOS_BKPT |
| 13791 | +#endif |
| 13792 | + |
| 13793 | +#ifndef VCOS_VERIFY_BKPT |
| 13794 | +#define VCOS_VERIFY_BKPT (VCOS_VERIFY_BKPTS ? VCOS_BKPT : (void)0) |
| 13795 | +#endif |
| 13796 | + |
| 13797 | +VCOSPRE_ int VCOSPOST_ vcos_verify_bkpts_enabled(void); |
| 13798 | +VCOSPRE_ int VCOSPOST_ vcos_verify_bkpts_enable(int enable); |
| 13799 | +VCOSPRE_ void VCOSPOST_ vcos_abort(void); |
| 13800 | + |
| 13801 | +#ifndef VCOS_ASSERT_MSG |
| 13802 | +#ifdef LOGGING |
| 13803 | +extern void logging_assert(const char *file, const char *func, int line, const char *format, ...); |
| 13804 | +#define VCOS_ASSERT_MSG(...) ((VCOS_ASSERT_LOGGING && !VCOS_ASSERT_LOGGING_DISABLE) ? logging_assert(__FILE__, __func__, __LINE__, __VA_ARGS__) : (void)0) |
| 13805 | +#else |
| 13806 | +#define VCOS_ASSERT_MSG(...) ((void)0) |
| 13807 | +#endif |
| 13808 | +#endif |
| 13809 | + |
| 13810 | +#ifndef VCOS_VERIFY_MSG |
| 13811 | +#define VCOS_VERIFY_MSG(...) VCOS_ASSERT_MSG(__VA_ARGS__) |
| 13812 | +#endif |
| 13813 | + |
| 13814 | +#ifndef VCOS_ASSERT_LOGGING |
| 13815 | +#define VCOS_ASSERT_LOGGING 0 |
| 13816 | +#endif |
| 13817 | + |
| 13818 | +#ifndef VCOS_ASSERT_LOGGING_DISABLE |
| 13819 | +#define VCOS_ASSERT_LOGGING_DISABLE 0 |
| 13820 | +#endif |
| 13821 | + |
| 13822 | +#if !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) |
| 13823 | + |
| 13824 | +#ifndef vcos_assert |
| 13825 | +#define vcos_assert(cond) \ |
| 13826 | + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG("%s", #cond), VCOS_ASSERT_BKPT) ) |
| 13827 | +#endif |
| 13828 | + |
| 13829 | +#ifndef vcos_assert_msg |
| 13830 | +#define vcos_assert_msg(cond, ...) \ |
| 13831 | + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT) ) |
| 13832 | +#endif |
| 13833 | + |
| 13834 | +#else /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */ |
| 13835 | + |
| 13836 | +#ifndef vcos_assert |
| 13837 | +#define vcos_assert(cond) (void)0 |
| 13838 | +#endif |
| 13839 | + |
| 13840 | +#ifndef vcos_assert_msg |
| 13841 | +#define vcos_assert_msg(cond, ...) (void)0 |
| 13842 | +#endif |
| 13843 | + |
| 13844 | +#endif /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */ |
| 13845 | + |
| 13846 | +#if !defined(NDEBUG) |
| 13847 | + |
| 13848 | +#ifndef vcos_demand |
| 13849 | +#define vcos_demand(cond) \ |
| 13850 | + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG("%s", #cond), VCOS_ASSERT_BKPT, vcos_abort()) ) |
| 13851 | +#endif |
| 13852 | + |
| 13853 | +#ifndef vcos_demand_msg |
| 13854 | +#define vcos_demand_msg(cond, ...) \ |
| 13855 | + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT, vcos_abort()) ) |
| 13856 | +#endif |
| 13857 | + |
| 13858 | +#ifndef vcos_verify |
| 13859 | +#define vcos_verify(cond) \ |
| 13860 | + ( (cond) ? 1 : (VCOS_VERIFY_MSG("%s", #cond), VCOS_VERIFY_BKPT, 0) ) |
| 13861 | +#endif |
| 13862 | + |
| 13863 | +#ifndef vcos_verify_msg |
| 13864 | +#define vcos_verify_msg(cond, ...) \ |
| 13865 | + ( (cond) ? 1 : (VCOS_VERIFY_MSG(__VA_ARGS__), VCOS_VERIFY_BKPT, 0) ) |
| 13866 | +#endif |
| 13867 | + |
| 13868 | +#else /* !defined(NDEBUG) */ |
| 13869 | + |
| 13870 | +#ifndef vcos_demand |
| 13871 | +#define vcos_demand(cond) \ |
| 13872 | + ( (cond) ? (void)0 : vcos_abort() ) |
| 13873 | +#endif |
| 13874 | + |
| 13875 | +#ifndef vcos_demand_msg |
| 13876 | +#define vcos_demand_msg(cond, ...) \ |
| 13877 | + ( (cond) ? (void)0 : vcos_abort() ) |
| 13878 | +#endif |
| 13879 | + |
| 13880 | +#ifndef vcos_verify |
| 13881 | +#define vcos_verify(cond) (cond) |
| 13882 | +#endif |
| 13883 | + |
| 13884 | +#ifndef vcos_verify_msg |
| 13885 | +#define vcos_verify_msg(cond, ...) (cond) |
| 13886 | +#endif |
| 13887 | + |
| 13888 | +#endif /* !defined(NDEBUG) */ |
| 13889 | + |
| 13890 | +#ifndef vcos_static_assert |
| 13891 | +#if defined(__GNUC__) |
| 13892 | +#define vcos_static_assert(cond) __attribute__((unused)) extern int vcos_static_assert[(cond)?1:-1] |
| 13893 | +#else |
| 13894 | +#define vcos_static_assert(cond) extern int vcos_static_assert[(cond)?1:-1] |
| 13895 | +#endif |
| 13896 | +#endif |
| 13897 | + |
| 13898 | +#ifndef vc_assert |
| 13899 | +#define vc_assert(cond) vcos_assert(cond) |
| 13900 | +#endif |
| 13901 | + |
| 13902 | +/** Print out a backtrace, on supported platforms. |
| 13903 | + */ |
| 13904 | +extern void vcos_backtrace_self(void); |
| 13905 | + |
| 13906 | +#ifdef __cplusplus |
| 13907 | +} |
| 13908 | +#endif |
| 13909 | + |
| 13910 | +#endif /* VCOS_ASSERT_H */ |
| 13911 | --- /dev/null |
| 13912 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_atomic_flags.h |
| 13913 | @@ -0,0 +1,72 @@ |
| 13914 | +/*============================================================================= |
| 13915 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 13916 | +All rights reserved. |
| 13917 | + |
| 13918 | +Project : vcfw |
| 13919 | +Module : chip driver (just for consistency with the rest of vcos ;) |
| 13920 | + |
| 13921 | +FILE DESCRIPTION |
| 13922 | +VideoCore OS Abstraction Layer - public header file |
| 13923 | +=============================================================================*/ |
| 13924 | + |
| 13925 | +#ifndef VCOS_ATOMIC_FLAGS_H |
| 13926 | +#define VCOS_ATOMIC_FLAGS_H |
| 13927 | + |
| 13928 | +#ifdef __cplusplus |
| 13929 | +extern "C" { |
| 13930 | +#endif |
| 13931 | + |
| 13932 | +#include "interface/vcos/vcos_types.h" |
| 13933 | +#include "vcos_platform.h" |
| 13934 | + |
| 13935 | +/** |
| 13936 | + * \file vcos_atomic_flags.h |
| 13937 | + * |
| 13938 | + * Defines atomic flags API. |
| 13939 | + * |
| 13940 | + * 32 flags. Atomic "or" and "get and clear" operations |
| 13941 | + */ |
| 13942 | + |
| 13943 | +/** |
| 13944 | + * Create an atomic flags instance. |
| 13945 | + * |
| 13946 | + * @param atomic_flags Pointer to atomic flags instance, filled in on return |
| 13947 | + * |
| 13948 | + * @return VCOS_SUCCESS if succeeded. |
| 13949 | + */ |
| 13950 | +VCOS_INLINE_DECL |
| 13951 | +VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags); |
| 13952 | + |
| 13953 | +/** |
| 13954 | + * Atomically set the specified flags. |
| 13955 | + * |
| 13956 | + * @param atomic_flags Instance to set flags on |
| 13957 | + * @param flags Mask of flags to set |
| 13958 | + */ |
| 13959 | +VCOS_INLINE_DECL |
| 13960 | +void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags); |
| 13961 | + |
| 13962 | +/** |
| 13963 | + * Retrieve the current flags and then clear them. The entire operation is |
| 13964 | + * atomic. |
| 13965 | + * |
| 13966 | + * @param atomic_flags Instance to get/clear flags from/on |
| 13967 | + * |
| 13968 | + * @return Mask of flags which were set (and we cleared) |
| 13969 | + */ |
| 13970 | +VCOS_INLINE_DECL |
| 13971 | +uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags); |
| 13972 | + |
| 13973 | +/** |
| 13974 | + * Delete an atomic flags instance. |
| 13975 | + * |
| 13976 | + * @param atomic_flags Instance to delete |
| 13977 | + */ |
| 13978 | +VCOS_INLINE_DECL |
| 13979 | +void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags); |
| 13980 | + |
| 13981 | +#ifdef __cplusplus |
| 13982 | +} |
| 13983 | +#endif |
| 13984 | + |
| 13985 | +#endif |
| 13986 | --- /dev/null |
| 13987 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_build_info.h |
| 13988 | @@ -0,0 +1,5 @@ |
| 13989 | +const char *vcos_get_build_hostname( void ); |
| 13990 | +const char *vcos_get_build_version( void ); |
| 13991 | +const char *vcos_get_build_time( void ); |
| 13992 | +const char *vcos_get_build_date( void ); |
| 13993 | + |
| 13994 | --- /dev/null |
| 13995 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_cfg.h |
| 13996 | @@ -0,0 +1,113 @@ |
| 13997 | +/***************************************************************************** |
| 13998 | +* Copyright 2009 - 2011 Broadcom Corporation. All rights reserved. |
| 13999 | +* |
| 14000 | +* Unless you and Broadcom execute a separate written software license |
| 14001 | +* agreement governing use of this software, this software is licensed to you |
| 14002 | +* under the terms of the GNU General Public License version 2, available at |
| 14003 | +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). |
| 14004 | +* |
| 14005 | +* Notwithstanding the above, under no circumstances may you combine this |
| 14006 | +* software in any way with any other Broadcom software provided under a |
| 14007 | +* license other than the GPL, without Broadcom's express prior written |
| 14008 | +* consent. |
| 14009 | +*****************************************************************************/ |
| 14010 | + |
| 14011 | +#if !defined( VCOS_CFG_H ) |
| 14012 | +#define VCOS_CFG_H |
| 14013 | + |
| 14014 | +#ifdef __cplusplus |
| 14015 | +extern "C" { |
| 14016 | +#endif |
| 14017 | + |
| 14018 | +#include "interface/vcos/vcos_types.h" |
| 14019 | +#include "vcos_platform.h" |
| 14020 | + |
| 14021 | +typedef struct opaque_vcos_cfg_buf_t *VCOS_CFG_BUF_T; |
| 14022 | +typedef struct opaque_vcos_cfg_entry_t *VCOS_CFG_ENTRY_T; |
| 14023 | + |
| 14024 | +/** \file vcos_file.h |
| 14025 | + * |
| 14026 | + * API for accessing configuration/statistics information. This |
| 14027 | + * is loosely modelled on the linux proc entries. |
| 14028 | + */ |
| 14029 | + |
| 14030 | +typedef void (*VCOS_CFG_SHOW_FPTR)( VCOS_CFG_BUF_T buf, void *data ); |
| 14031 | +typedef void (*VCOS_CFG_PARSE_FPTR)( VCOS_CFG_BUF_T buf, void *data ); |
| 14032 | + |
| 14033 | +/** Create a configuration directory. |
| 14034 | + * |
| 14035 | + * @param entry Place to store the created config entry. |
| 14036 | + * @param parent Parent entry (for directory like config |
| 14037 | + * options). |
| 14038 | + * @param entryName Name of the directory. |
| 14039 | + */ |
| 14040 | + |
| 14041 | +VCOS_STATUS_T vcos_cfg_mkdir( VCOS_CFG_ENTRY_T *entry, |
| 14042 | + VCOS_CFG_ENTRY_T *parent, |
| 14043 | + const char *dirName ); |
| 14044 | + |
| 14045 | +/** Create a configuration entry. |
| 14046 | + * |
| 14047 | + * @param entry Place to store the created config entry. |
| 14048 | + * @param parent Parent entry (for directory like config |
| 14049 | + * options). |
| 14050 | + * @param entryName Name of the configuration entry. |
| 14051 | + * @param showFunc Function pointer to show configuration |
| 14052 | + * data. |
| 14053 | + * @param parseFunc Function pointer to parse new data. |
| 14054 | + */ |
| 14055 | + |
| 14056 | +VCOS_STATUS_T vcos_cfg_create_entry( VCOS_CFG_ENTRY_T *entry, |
| 14057 | + VCOS_CFG_ENTRY_T *parent, |
| 14058 | + const char *entryName, |
| 14059 | + VCOS_CFG_SHOW_FPTR showFunc, |
| 14060 | + VCOS_CFG_PARSE_FPTR parseFunc, |
| 14061 | + void *data ); |
| 14062 | + |
| 14063 | +/** Determines if a configuration entry has been created or not. |
| 14064 | + * |
| 14065 | + * @param entry Configuration entry to query. |
| 14066 | + */ |
| 14067 | + |
| 14068 | +int vcos_cfg_is_entry_created( VCOS_CFG_ENTRY_T entry ); |
| 14069 | + |
| 14070 | +/** Returns the name of a configuration entry. |
| 14071 | + * |
| 14072 | + * @param entry Configuration entry to query. |
| 14073 | + */ |
| 14074 | + |
| 14075 | +const char *vcos_cfg_get_entry_name( VCOS_CFG_ENTRY_T entry ); |
| 14076 | + |
| 14077 | +/** Removes a configuration entry. |
| 14078 | + * |
| 14079 | + * @param entry Configuration entry to remove. |
| 14080 | + */ |
| 14081 | + |
| 14082 | +VCOS_STATUS_T vcos_cfg_remove_entry( VCOS_CFG_ENTRY_T *entry ); |
| 14083 | + |
| 14084 | + |
| 14085 | +/** Writes data into a configuration buffer. Only valid inside |
| 14086 | + * the show function. |
| 14087 | + * |
| 14088 | + * @param buf Buffer to write data into. |
| 14089 | + * @param fmt printf style format string. |
| 14090 | + */ |
| 14091 | + |
| 14092 | +void vcos_cfg_buf_printf( VCOS_CFG_BUF_T buf, const char *fmt, ... ); |
| 14093 | + |
| 14094 | +/** Retrieves a null terminated string of the data associated |
| 14095 | + * with the buffer. Only valid inside the parse function. |
| 14096 | + * |
| 14097 | + * @param buf Buffer to get data from. |
| 14098 | + * @param fmt printf style format string. |
| 14099 | + */ |
| 14100 | + |
| 14101 | +char *vcos_cfg_buf_get_str( VCOS_CFG_BUF_T buf ); |
| 14102 | + |
| 14103 | +void *vcos_cfg_get_proc_entry( VCOS_CFG_ENTRY_T entry ); |
| 14104 | + |
| 14105 | +#ifdef __cplusplus |
| 14106 | +} |
| 14107 | +#endif |
| 14108 | +#endif |
| 14109 | + |
| 14110 | --- /dev/null |
| 14111 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_cmd.h |
| 14112 | @@ -0,0 +1,98 @@ |
| 14113 | +/***************************************************************************** |
| 14114 | +* Copyright 2009 - 2011 Broadcom Corporation. All rights reserved. |
| 14115 | +* |
| 14116 | +* Unless you and Broadcom execute a separate written software license |
| 14117 | +* agreement governing use of this software, this software is licensed to you |
| 14118 | +* under the terms of the GNU General Public License version 2, available at |
| 14119 | +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). |
| 14120 | +* |
| 14121 | +* Notwithstanding the above, under no circumstances may you combine this |
| 14122 | +* software in any way with any other Broadcom software provided under a |
| 14123 | +* license other than the GPL, without Broadcom's express prior written |
| 14124 | +* consent. |
| 14125 | +*****************************************************************************/ |
| 14126 | + |
| 14127 | +#if !defined( VCOS_CMD_H ) |
| 14128 | +#define VCOS_CMD_H |
| 14129 | + |
| 14130 | +/* ---- Include Files ----------------------------------------------------- */ |
| 14131 | + |
| 14132 | +#include "interface/vcos/vcos.h" |
| 14133 | +#include "interface/vcos/vcos_stdint.h" |
| 14134 | + |
| 14135 | + |
| 14136 | +/* ---- Constants and Types ---------------------------------------------- */ |
| 14137 | + |
| 14138 | +struct VCOS_CMD_S; |
| 14139 | +typedef struct VCOS_CMD_S VCOS_CMD_T; |
| 14140 | + |
| 14141 | +typedef struct |
| 14142 | +{ |
| 14143 | + int argc; /* Number of arguments (includes the command/sub-command) */ |
| 14144 | + char **argv; /* Array of arguments */ |
| 14145 | + char **argv_orig; /* Original array of arguments */ |
| 14146 | + |
| 14147 | + VCOS_CMD_T *cmd_entry; |
| 14148 | + VCOS_CMD_T *cmd_parent_entry; |
| 14149 | + |
| 14150 | + int use_log; /* Output being logged? */ |
| 14151 | + size_t result_size; /* Size of result buffer. */ |
| 14152 | + char *result_ptr; /* Next place to put output. */ |
| 14153 | + char *result_buf; /* Start of the buffer. */ |
| 14154 | + |
| 14155 | +} VCOS_CMD_PARAM_T; |
| 14156 | + |
| 14157 | +typedef VCOS_STATUS_T (*VCOS_CMD_FUNC_T)( VCOS_CMD_PARAM_T *param ); |
| 14158 | + |
| 14159 | +struct VCOS_CMD_S |
| 14160 | +{ |
| 14161 | + const char *name; |
| 14162 | + const char *args; |
| 14163 | + VCOS_CMD_FUNC_T cmd_fn; |
| 14164 | + VCOS_CMD_T *sub_cmd_entry; |
| 14165 | + const char *descr; |
| 14166 | + |
| 14167 | +}; |
| 14168 | + |
| 14169 | +/* ---- Variable Externs ------------------------------------------------- */ |
| 14170 | + |
| 14171 | +/* ---- Function Prototypes ---------------------------------------------- */ |
| 14172 | + |
| 14173 | +/* |
| 14174 | + * Common printing routine for generating command output. |
| 14175 | + */ |
| 14176 | +VCOSPRE_ void VCOSPOST_ vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) VCOS_FORMAT_ATTR_(printf, 2, 3); |
| 14177 | +VCOSPRE_ void VCOSPOST_ vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) VCOS_FORMAT_ATTR_(printf, 2, 3); |
| 14178 | +VCOSPRE_ void VCOSPOST_ vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args ) VCOS_FORMAT_ATTR_(printf, 2, 0); |
| 14179 | + |
| 14180 | +/* |
| 14181 | + * Cause vcos_cmd_error, printf and vprintf to always log to the provided |
| 14182 | + * category. When this call is made, the results buffer passed into |
| 14183 | + * vcos_cmd_execute is used as a line buffer and does not need to be |
| 14184 | + * output by the caller. |
| 14185 | + */ |
| 14186 | +VCOSPRE_ void VCOSPOST_ vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category ); |
| 14187 | + |
| 14188 | +/* |
| 14189 | + * Prints command usage for the current command. |
| 14190 | + */ |
| 14191 | +VCOSPRE_ void VCOSPOST_ vcos_cmd_usage( VCOS_CMD_PARAM_T *param ); |
| 14192 | + |
| 14193 | +/* |
| 14194 | + * Register commands to be processed |
| 14195 | + */ |
| 14196 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register( VCOS_CMD_T *cmd_entry ); |
| 14197 | + |
| 14198 | +/* |
| 14199 | + * Registers multiple commands to be processed. The array should |
| 14200 | + * be terminated by an entry with all zeros. |
| 14201 | + */ |
| 14202 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry ); |
| 14203 | + |
| 14204 | +/* |
| 14205 | + * Executes a command based on a command line. |
| 14206 | + */ |
| 14207 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf ); |
| 14208 | + |
| 14209 | +#endif /* VCOS_CMD_H */ |
| 14210 | + |
| 14211 | --- /dev/null |
| 14212 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_ctype.h |
| 14213 | @@ -0,0 +1,29 @@ |
| 14214 | +/*============================================================================= |
| 14215 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 14216 | +All rights reserved. |
| 14217 | + |
| 14218 | +Project : vcfw |
| 14219 | +Module : chip driver |
| 14220 | + |
| 14221 | +FILE DESCRIPTION |
| 14222 | +VideoCore OS Abstraction Layer - public header file |
| 14223 | +=============================================================================*/ |
| 14224 | + |
| 14225 | +#ifndef VCOS_CTYPE_H |
| 14226 | +#define VCOS_CTYPE_H |
| 14227 | + |
| 14228 | +/** |
| 14229 | + * \file |
| 14230 | + * |
| 14231 | + * ctype functions. |
| 14232 | + * |
| 14233 | + */ |
| 14234 | + |
| 14235 | +#ifdef __KERNEL__ |
| 14236 | +#include <linux/ctype.h> |
| 14237 | +#else |
| 14238 | +#include <ctype.h> |
| 14239 | +#endif |
| 14240 | + |
| 14241 | +#endif |
| 14242 | + |
| 14243 | --- /dev/null |
| 14244 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_dlfcn.h |
| 14245 | @@ -0,0 +1,69 @@ |
| 14246 | +/*============================================================================= |
| 14247 | +Copyright (c) 2010 Broadcom Europe Limited. |
| 14248 | +All rights reserved. |
| 14249 | + |
| 14250 | +Project : vcfw |
| 14251 | +Module : chip driver |
| 14252 | + |
| 14253 | +FILE DESCRIPTION |
| 14254 | +VCOS - abstraction over dynamic library opening |
| 14255 | +=============================================================================*/ |
| 14256 | + |
| 14257 | +#ifndef VCOS_DLFCN_H |
| 14258 | +#define VCOS_DLFCN_H |
| 14259 | + |
| 14260 | +#include "interface/vcos/vcos_types.h" |
| 14261 | +#include "vcos_platform.h" |
| 14262 | + |
| 14263 | +#ifdef __cplusplus |
| 14264 | +extern "C" { |
| 14265 | +#endif |
| 14266 | + |
| 14267 | +#define VCOS_DL_LAZY 1 |
| 14268 | +#define VCOS_DL_NOW 2 |
| 14269 | + |
| 14270 | +/** |
| 14271 | + * \file |
| 14272 | + * |
| 14273 | + * Loading dynamic libraries. See also dlfcn.h. |
| 14274 | + */ |
| 14275 | + |
| 14276 | +/** Open a dynamic library. |
| 14277 | + * |
| 14278 | + * @param name name of the library |
| 14279 | + * @param mode Load lazily or immediately (VCOS_DL_LAZY, VCOS_DL_NOW). |
| 14280 | + * |
| 14281 | + * @return A handle for use in subsequent calls. |
| 14282 | + */ |
| 14283 | +VCOSPRE_ void * VCOSPOST_ vcos_dlopen(const char *name, int mode); |
| 14284 | + |
| 14285 | +/** Look up a symbol. |
| 14286 | + * |
| 14287 | + * @param handle Handle to open |
| 14288 | + * @param name Name of function |
| 14289 | + * |
| 14290 | + * @return Function pointer, or NULL. |
| 14291 | + */ |
| 14292 | +VCOSPRE_ void VCOSPOST_ (*vcos_dlsym(void *handle, const char *name))(void); |
| 14293 | + |
| 14294 | +/** Close a library |
| 14295 | + * |
| 14296 | + * @param handle Handle to close |
| 14297 | + */ |
| 14298 | +VCOSPRE_ int VCOSPOST_ vcos_dlclose (void *handle); |
| 14299 | + |
| 14300 | +/** Return error message from library. |
| 14301 | + * |
| 14302 | + * @param err On return, set to non-zero if an error has occurred |
| 14303 | + * @param buf Buffer to write error to |
| 14304 | + * @param len Size of buffer (including terminating NUL). |
| 14305 | + */ |
| 14306 | +VCOSPRE_ int VCOSPOST_ vcos_dlerror(int *err, char *buf, size_t buflen); |
| 14307 | + |
| 14308 | + |
| 14309 | +#ifdef __cplusplus |
| 14310 | +} |
| 14311 | +#endif |
| 14312 | +#endif |
| 14313 | + |
| 14314 | + |
| 14315 | --- /dev/null |
| 14316 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_event.h |
| 14317 | @@ -0,0 +1,97 @@ |
| 14318 | +/*============================================================================= |
| 14319 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 14320 | +All rights reserved. |
| 14321 | + |
| 14322 | +Project : vcfw |
| 14323 | +Module : chip driver |
| 14324 | + |
| 14325 | +FILE DESCRIPTION |
| 14326 | +VideoCore OS Abstraction Layer - public header file for events |
| 14327 | +=============================================================================*/ |
| 14328 | + |
| 14329 | +#ifndef VCOS_EVENT_H |
| 14330 | +#define VCOS_EVENT_H |
| 14331 | + |
| 14332 | +#ifdef __cplusplus |
| 14333 | +extern "C" { |
| 14334 | +#endif |
| 14335 | + |
| 14336 | +#include "interface/vcos/vcos_types.h" |
| 14337 | +#include "vcos_platform.h" |
| 14338 | + |
| 14339 | +/** |
| 14340 | + * \file |
| 14341 | + * |
| 14342 | + * An event is akin to the Win32 auto-reset event. |
| 14343 | + * |
| 14344 | + * |
| 14345 | + * Signalling an event will wake up one waiting thread only. Once one |
| 14346 | + * thread has been woken the event atomically returns to the unsignalled |
| 14347 | + * state. |
| 14348 | + * |
| 14349 | + * If no threads are waiting on the event when it is signalled it remains |
| 14350 | + * signalled. |
| 14351 | + * |
| 14352 | + * This is almost, but not quite, completely unlike the "event flags" |
| 14353 | + * object based on Nucleus event groups and ThreadX event flags. |
| 14354 | + * |
| 14355 | + * In particular, it should be similar in speed to a semaphore, unlike |
| 14356 | + * the event flags. |
| 14357 | + */ |
| 14358 | + |
| 14359 | +/** |
| 14360 | + * Create an event instance. |
| 14361 | + * |
| 14362 | + * @param event Filled in with constructed event. |
| 14363 | + * @param name Name of the event (for debugging) |
| 14364 | + * |
| 14365 | + * @return VCOS_SUCCESS on success, or error code. |
| 14366 | + */ |
| 14367 | +VCOS_INLINE_DECL |
| 14368 | +VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *name); |
| 14369 | + |
| 14370 | +#ifndef vcos_event_signal |
| 14371 | + |
| 14372 | +/** |
| 14373 | + * Signal the event. The event will return to being unsignalled |
| 14374 | + * after exactly one waiting thread has been woken up. If no |
| 14375 | + * threads are waiting it remains signalled. |
| 14376 | + * |
| 14377 | + * @param event The event to signal |
| 14378 | + */ |
| 14379 | +VCOS_INLINE_DECL |
| 14380 | +void vcos_event_signal(VCOS_EVENT_T *event); |
| 14381 | + |
| 14382 | +/** |
| 14383 | + * Wait for the event. |
| 14384 | + * |
| 14385 | + * @param event The event to wait for |
| 14386 | + * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the wait was interrupted. |
| 14387 | + */ |
| 14388 | +VCOS_INLINE_DECL |
| 14389 | +VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event); |
| 14390 | + |
| 14391 | +/** |
| 14392 | + * Try event, but don't block. |
| 14393 | + * |
| 14394 | + * @param event The event to try |
| 14395 | + * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the event is not currently signalled |
| 14396 | + */ |
| 14397 | +VCOS_INLINE_DECL |
| 14398 | +VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event); |
| 14399 | + |
| 14400 | +#endif |
| 14401 | + |
| 14402 | +/* |
| 14403 | + * Destroy an event. |
| 14404 | + */ |
| 14405 | +VCOS_INLINE_DECL |
| 14406 | +void vcos_event_delete(VCOS_EVENT_T *event); |
| 14407 | + |
| 14408 | +#ifdef __cplusplus |
| 14409 | +} |
| 14410 | +#endif |
| 14411 | + |
| 14412 | +#endif |
| 14413 | + |
| 14414 | + |
| 14415 | --- /dev/null |
| 14416 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_event_flags.h |
| 14417 | @@ -0,0 +1,98 @@ |
| 14418 | +/*============================================================================= |
| 14419 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 14420 | +All rights reserved. |
| 14421 | + |
| 14422 | +Project : vcfw |
| 14423 | +Module : chip driver |
| 14424 | + |
| 14425 | +FILE DESCRIPTION |
| 14426 | +VideoCore OS Abstraction Layer - public header file |
| 14427 | +=============================================================================*/ |
| 14428 | + |
| 14429 | +#ifndef VCOS_EVENT_FLAGS_H |
| 14430 | +#define VCOS_EVENT_FLAGS_H |
| 14431 | + |
| 14432 | + |
| 14433 | +#ifdef __cplusplus |
| 14434 | +extern "C" { |
| 14435 | +#endif |
| 14436 | + |
| 14437 | +#include "interface/vcos/vcos_types.h" |
| 14438 | +#include "vcos_platform.h" |
| 14439 | + |
| 14440 | +#define VCOS_EVENT_FLAGS_SUSPEND VCOS_SUSPEND |
| 14441 | +#define VCOS_EVENT_FLAGS_NO_SUSPEND VCOS_NO_SUSPEND |
| 14442 | +typedef VCOS_OPTION VCOS_EVENTGROUP_OPERATION_T; |
| 14443 | + |
| 14444 | +/** |
| 14445 | + * \file vcos_event_flags.h |
| 14446 | + * |
| 14447 | + * Defines event flags API. |
| 14448 | + * |
| 14449 | + * Similar to Nucleus event groups. |
| 14450 | + * |
| 14451 | + * These have the same semantics as Nucleus event groups and ThreadX event |
| 14452 | + * flags. As such, they are quite complex internally; if speed is important |
| 14453 | + * they might not be your best choice. |
| 14454 | + * |
| 14455 | + */ |
| 14456 | + |
| 14457 | +/** |
| 14458 | + * Create an event flags instance. |
| 14459 | + * |
| 14460 | + * @param flags Pointer to event flags instance, filled in on return. |
| 14461 | + * @param name Name for the event flags, used for debug. |
| 14462 | + * |
| 14463 | + * @return VCOS_SUCCESS if succeeded. |
| 14464 | + */ |
| 14465 | + |
| 14466 | +VCOS_INLINE_DECL |
| 14467 | +VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name); |
| 14468 | + |
| 14469 | +/** |
| 14470 | + * Set some events. |
| 14471 | + * |
| 14472 | + * @param flags Instance to set flags on |
| 14473 | + * @param events Bitmask of the flags to actually set |
| 14474 | + * @param op How the flags should be set. VCOS_OR will OR in the flags; VCOS_AND |
| 14475 | + * will AND them in, possibly clearing existing flags. |
| 14476 | + */ |
| 14477 | +VCOS_INLINE_DECL |
| 14478 | +void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags, |
| 14479 | + VCOS_UNSIGNED events, |
| 14480 | + VCOS_OPTION op); |
| 14481 | + |
| 14482 | +/** |
| 14483 | + * Retrieve some events. |
| 14484 | + * |
| 14485 | + * Waits until the specified events have been set. |
| 14486 | + * |
| 14487 | + * @param flags Instance to wait on |
| 14488 | + * @param requested_events The bitmask to wait for |
| 14489 | + * @param op VCOS_OR - get any; VCOS_AND - get all. |
| 14490 | + * @param ms_suspend How long to wait, in milliseconds |
| 14491 | + * @param retrieved_events the events actually retrieved. |
| 14492 | + * |
| 14493 | + * @return VCOS_SUCCESS if events were retrieved. VCOS_EAGAIN if the |
| 14494 | + * timeout expired. |
| 14495 | + */ |
| 14496 | +VCOS_INLINE_DECL |
| 14497 | +VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags, |
| 14498 | + VCOS_UNSIGNED requested_events, |
| 14499 | + VCOS_OPTION op, |
| 14500 | + VCOS_UNSIGNED ms_suspend, |
| 14501 | + VCOS_UNSIGNED *retrieved_events); |
| 14502 | + |
| 14503 | + |
| 14504 | +/** |
| 14505 | + * Delete an event flags instance. |
| 14506 | + */ |
| 14507 | +VCOS_INLINE_DECL |
| 14508 | +void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *); |
| 14509 | + |
| 14510 | +#ifdef __cplusplus |
| 14511 | +} |
| 14512 | +#endif |
| 14513 | + |
| 14514 | +#endif |
| 14515 | + |
| 14516 | --- /dev/null |
| 14517 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_init.h |
| 14518 | @@ -0,0 +1,43 @@ |
| 14519 | +/*============================================================================= |
| 14520 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 14521 | +All rights reserved. |
| 14522 | + |
| 14523 | +Project : vcfw |
| 14524 | +Module : chip driver |
| 14525 | + |
| 14526 | +FILE DESCRIPTION |
| 14527 | +VideoCore OS Abstraction Layer - initialization routines |
| 14528 | +=============================================================================*/ |
| 14529 | + |
| 14530 | + |
| 14531 | +#include "interface/vcos/vcos_types.h" |
| 14532 | +#include "vcos_platform.h" |
| 14533 | + |
| 14534 | +#ifdef __cplusplus |
| 14535 | +extern "C" { |
| 14536 | +#endif |
| 14537 | + |
| 14538 | +/** \file |
| 14539 | + * |
| 14540 | + * Some OS support libraries need some initialization. To support this, call this |
| 14541 | + * function at the start of day. |
| 14542 | + */ |
| 14543 | + |
| 14544 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_init(void); |
| 14545 | +VCOSPRE_ void VCOSPOST_ vcos_deinit(void); |
| 14546 | +VCOSPRE_ void VCOSPOST_ vcos_global_lock(void); |
| 14547 | +VCOSPRE_ void VCOSPOST_ vcos_global_unlock(void); |
| 14548 | + |
| 14549 | +/** Pass in the argv/argc arguments passed to main() */ |
| 14550 | +VCOSPRE_ void VCOSPOST_ vcos_set_args(int argc, const char **argv); |
| 14551 | + |
| 14552 | +/** Return argc. */ |
| 14553 | +VCOSPRE_ int VCOSPOST_ vcos_get_argc(void); |
| 14554 | + |
| 14555 | +/** Return argv. */ |
| 14556 | +VCOSPRE_ const char ** VCOSPOST_ vcos_get_argv(void); |
| 14557 | + |
| 14558 | +#ifdef __cplusplus |
| 14559 | +} |
| 14560 | +#endif |
| 14561 | + |
| 14562 | --- /dev/null |
| 14563 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_logging.h |
| 14564 | @@ -0,0 +1,279 @@ |
| 14565 | +/*============================================================================= |
| 14566 | +Copyright (c) 2009-2011 Broadcom Europe Limited. |
| 14567 | +All rights reserved. |
| 14568 | + |
| 14569 | +Project : vcfw |
| 14570 | +Module : chip driver |
| 14571 | + |
| 14572 | +FILE DESCRIPTION |
| 14573 | +VideoCore OS Abstraction Layer - logging support |
| 14574 | +=============================================================================*/ |
| 14575 | + |
| 14576 | +#ifndef VCOS_LOGGING_H |
| 14577 | +#define VCOS_LOGGING_H |
| 14578 | + |
| 14579 | +#ifdef __cplusplus |
| 14580 | +extern "C" { |
| 14581 | +#endif |
| 14582 | + |
| 14583 | +#include <stdarg.h> |
| 14584 | + |
| 14585 | +#include "interface/vcos/vcos_types.h" |
| 14586 | +#include "vcos_platform.h" |
| 14587 | + |
| 14588 | +/** |
| 14589 | + * \file |
| 14590 | + * |
| 14591 | + * Logging support |
| 14592 | + * |
| 14593 | + * This provides categorised logging. Clients register |
| 14594 | + * a category, and then get a number of logging levels for |
| 14595 | + * that category. |
| 14596 | + * |
| 14597 | + * The logging level flag is tested using a flag *before* the |
| 14598 | + * function call, which makes logging very fast when disabled - there |
| 14599 | + * is no function call overhead just to find out that this log |
| 14600 | + * message is disabled. |
| 14601 | + * |
| 14602 | + * \section VCOS_LOG_CATEGORY |
| 14603 | + * |
| 14604 | + * As a convenience, clients define VCOS_LOG_CATEGORY to point to |
| 14605 | + * their category; the various vcos_log_xxx() macros then expand to |
| 14606 | + * use this. |
| 14607 | + * |
| 14608 | + * e.g. |
| 14609 | + * |
| 14610 | + * #define VCOS_LOG_CATEGORY (&my_category) |
| 14611 | + * |
| 14612 | + * #include <interface/vcos/vcos.h> |
| 14613 | + * |
| 14614 | + * VCOS_LOG_CAT_T my_category; |
| 14615 | + * |
| 14616 | + * .... |
| 14617 | + * |
| 14618 | + * vcos_log_trace("Stuff happened: %d", n_stuff); |
| 14619 | + * |
| 14620 | + */ |
| 14621 | + |
| 14622 | +/** Logging levels */ |
| 14623 | +typedef enum VCOS_LOG_LEVEL_T |
| 14624 | +{ |
| 14625 | + VCOS_LOG_UNINITIALIZED = 0, |
| 14626 | + VCOS_LOG_NEVER, |
| 14627 | + VCOS_LOG_ERROR, |
| 14628 | + VCOS_LOG_WARN, |
| 14629 | + VCOS_LOG_INFO, |
| 14630 | + VCOS_LOG_TRACE, |
| 14631 | +} VCOS_LOG_LEVEL_T; |
| 14632 | + |
| 14633 | + |
| 14634 | +/** Initialize a logging category without going through vcos_log_register(). |
| 14635 | + * |
| 14636 | + * This is useful for the case where there is no obvious point to do the |
| 14637 | + * registration (no initialization function for the module). However, it |
| 14638 | + * means that your logging category is not registered, so cannot be easily |
| 14639 | + * changed at run-time. |
| 14640 | + */ |
| 14641 | +#define VCOS_LOG_INIT(n,l) { l, n, 0, {0}, 0, 0 } |
| 14642 | + |
| 14643 | +/** A registered logging category. |
| 14644 | + */ |
| 14645 | +typedef struct VCOS_LOG_CAT_T |
| 14646 | +{ |
| 14647 | + VCOS_LOG_LEVEL_T level; /** Which levels are enabled for this category */ |
| 14648 | + const char *name; /** Name for this category. */ |
| 14649 | + struct VCOS_LOG_CAT_T *next; |
| 14650 | + struct { |
| 14651 | + unsigned int want_prefix:1; |
| 14652 | + } flags; |
| 14653 | + unsigned int refcount; |
| 14654 | + void *platform_data; /** platform specific data */ |
| 14655 | +} VCOS_LOG_CAT_T; |
| 14656 | + |
| 14657 | +typedef void (*VCOS_VLOG_IMPL_FUNC_T)(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args); |
| 14658 | + |
| 14659 | +/** Convert a VCOS_LOG_LEVEL_T into a printable string. |
| 14660 | + * The platform needs to implement this function. |
| 14661 | + */ |
| 14662 | +VCOSPRE_ const char * VCOSPOST_ vcos_log_level_to_string( VCOS_LOG_LEVEL_T level ); |
| 14663 | + |
| 14664 | +/** Convert a string into a VCOS_LOG_LEVEL_T |
| 14665 | + * The platform needs to implement this function. |
| 14666 | + */ |
| 14667 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level ); |
| 14668 | + |
| 14669 | +/** Log a message. Basic API. Normal code should not use this. |
| 14670 | + * The platform needs to implement this function. |
| 14671 | + */ |
| 14672 | +VCOSPRE_ void VCOSPOST_ vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...) VCOS_FORMAT_ATTR_(printf, 3, 4); |
| 14673 | + |
| 14674 | +/** Log a message using a varargs parameter list. Normal code should |
| 14675 | + * not use this. |
| 14676 | + */ |
| 14677 | +VCOSPRE_ void VCOSPOST_ vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) VCOS_FORMAT_ATTR_(printf, 3, 0); |
| 14678 | + |
| 14679 | +/** Set the function which does the actual logging output. |
| 14680 | + * Passing in NULL causes the default logging function to be |
| 14681 | + * used. |
| 14682 | + */ |
| 14683 | +VCOSPRE_ void VCOSPOST_ vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func ); |
| 14684 | + |
| 14685 | +/** The default logging function, which is provided by each |
| 14686 | + * platform. |
| 14687 | + */ |
| 14688 | + |
| 14689 | +VCOSPRE_ void VCOSPOST_ vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) VCOS_FORMAT_ATTR_(printf, 3, 0); |
| 14690 | + |
| 14691 | +/* |
| 14692 | + * Initialise the logging subsystem. This is called from |
| 14693 | + * vcos_init() so you don't normally need to call it. |
| 14694 | + */ |
| 14695 | +VCOSPRE_ void VCOSPOST_ vcos_logging_init(void); |
| 14696 | + |
| 14697 | +/** Register a logging category. |
| 14698 | + * |
| 14699 | + * @param name the name of this category. |
| 14700 | + * @param category the category to register. |
| 14701 | + */ |
| 14702 | +VCOSPRE_ void VCOSPOST_ vcos_log_register(const char *name, VCOS_LOG_CAT_T *category); |
| 14703 | + |
| 14704 | +/** Unregister a logging category. |
| 14705 | + */ |
| 14706 | +VCOSPRE_ void VCOSPOST_ vcos_log_unregister(VCOS_LOG_CAT_T *category); |
| 14707 | + |
| 14708 | +/** Return a default logging category, for people too lazy to create their own. |
| 14709 | + * |
| 14710 | + * Using the default category will be slow (there's an extra function |
| 14711 | + * call overhead). Don't do this in normal code. |
| 14712 | + */ |
| 14713 | +VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void); |
| 14714 | + |
| 14715 | +VCOSPRE_ void VCOSPOST_ vcos_set_log_options(const char *opt); |
| 14716 | + |
| 14717 | +/** Set the logging level for a category at run time. Without this, the level |
| 14718 | + * will be that set by vcos_log_register from a platform-specific source. |
| 14719 | + * |
| 14720 | + * @param category the category to modify. |
| 14721 | + * @param level the new logging level for this category. |
| 14722 | + */ |
| 14723 | +VCOS_STATIC_INLINE void vcos_log_set_level(VCOS_LOG_CAT_T *category, VCOS_LOG_LEVEL_T level) |
| 14724 | +{ |
| 14725 | + category->level = level; |
| 14726 | +} |
| 14727 | + |
| 14728 | +#define vcos_log_dump_mem(cat,label,addr,voidMem,numBytes) do { if (vcos_is_log_enabled(cat,VCOS_LOG_TRACE)) vcos_log_dump_mem_impl(cat,label,addr,voidMem,numBytes); } while (0) |
| 14729 | + |
| 14730 | +void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat, |
| 14731 | + const char *label, |
| 14732 | + uint32_t addr, |
| 14733 | + const void *voidMem, |
| 14734 | + size_t numBytes ); |
| 14735 | + |
| 14736 | +/* |
| 14737 | + * Platform specific hooks (optional). |
| 14738 | + */ |
| 14739 | +#ifndef vcos_log_platform_init |
| 14740 | +#define vcos_log_platform_init() (void)0 |
| 14741 | +#endif |
| 14742 | + |
| 14743 | +#ifndef vcos_log_platform_register |
| 14744 | +#define vcos_log_platform_register(category) (void)0 |
| 14745 | +#endif |
| 14746 | + |
| 14747 | +#ifndef vcos_log_platform_unregister |
| 14748 | +#define vcos_log_platform_unregister(category) (void)0 |
| 14749 | +#endif |
| 14750 | + |
| 14751 | +/* VCOS_TRACE() - deprecated macro which just outputs in a debug build and |
| 14752 | + * is a no-op in a release build. |
| 14753 | + * |
| 14754 | + * _VCOS_LOG_X() - internal macro which outputs if the current level for the |
| 14755 | + * particular category is higher than the supplied message level. |
| 14756 | + */ |
| 14757 | + |
| 14758 | +#define VCOS_LOG_DFLT_CATEGORY vcos_log_get_default_category() |
| 14759 | + |
| 14760 | +#define _VCOS_LEVEL(x) (x) |
| 14761 | + |
| 14762 | +#define vcos_is_log_enabled(cat,_level) (_VCOS_LEVEL((cat)->level) >= _VCOS_LEVEL(_level)) |
| 14763 | + |
| 14764 | +#if defined(_VCOS_METAWARE) || defined(__GNUC__) |
| 14765 | + |
| 14766 | +# if !defined(NDEBUG) || defined(VCOS_ALWAYS_WANT_LOGGING) |
| 14767 | +# define VCOS_LOGGING_ENABLED |
| 14768 | +# define _VCOS_LOG_X(cat, _level, fmt...) do { if (vcos_is_log_enabled(cat,_level)) vcos_log_impl(cat,_level,fmt); } while (0) |
| 14769 | +# define _VCOS_VLOG_X(cat, _level, fmt, ap) do { if (vcos_is_log_enabled(cat,_level)) vcos_vlog_impl(cat,_level,fmt,ap); } while (0) |
| 14770 | +# else |
| 14771 | +# define _VCOS_LOG_X(cat, _level, fmt...) (void)0 |
| 14772 | +# define _VCOS_VLOG_X(cat, _level, fmt, ap) (void)0 |
| 14773 | +# endif |
| 14774 | + |
| 14775 | + |
| 14776 | + |
| 14777 | +# define vcos_log_error(...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, __VA_ARGS__) |
| 14778 | +# define vcos_log_warn(...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, __VA_ARGS__) |
| 14779 | +# define vcos_log_info(...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__) |
| 14780 | +# define vcos_log_trace(...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, __VA_ARGS__) |
| 14781 | + |
| 14782 | +# define vcos_vlog_error(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, fmt, ap) |
| 14783 | +# define vcos_vlog_warn(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, fmt, ap) |
| 14784 | +# define vcos_vlog_info(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, fmt, ap) |
| 14785 | +# define vcos_vlog_trace(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, fmt, ap) |
| 14786 | + |
| 14787 | +# define vcos_log(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__) |
| 14788 | +# define vcos_vlog(fmt,ap) _VCOS_VLOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt, ap) |
| 14789 | +# define VCOS_ALERT(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_ERROR, __VA_ARGS__) |
| 14790 | +# define VCOS_TRACE(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__) |
| 14791 | + |
| 14792 | +/* |
| 14793 | + * MS Visual Studio - pre 2005 does not grok variadic macros |
| 14794 | + */ |
| 14795 | +#elif defined(_MSC_VER) |
| 14796 | + |
| 14797 | +# if _MSC_VER >= 1400 |
| 14798 | + |
| 14799 | +# if !defined(NDEBUG) || defined(VCOS_ALWAYS_WANT_LOGGING) |
| 14800 | +# define VCOS_LOGGING_ENABLED |
| 14801 | +# define _VCOS_LOG_X(cat, _level, fmt,...) do { if (vcos_is_log_enabled(cat,_level)) vcos_log_impl(cat, _level, fmt, __VA_ARGS__); } while (0) |
| 14802 | +# else |
| 14803 | +# define _VCOS_LOG_X(cat, _level, fmt,...) (void)0 |
| 14804 | +# endif |
| 14805 | + |
| 14806 | +# define vcos_log_error(fmt,...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, fmt, __VA_ARGS__) |
| 14807 | +# define vcos_log_warn(fmt,...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, fmt, __VA_ARGS__) |
| 14808 | +# define vcos_log_info(fmt,...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, fmt, __VA_ARGS__) |
| 14809 | +# define vcos_log_trace(fmt,...) _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, fmt, __VA_ARGS__) |
| 14810 | + |
| 14811 | +# define vcos_log(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt) |
| 14812 | +# define VCOS_ALERT(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_ERROR, fmt) |
| 14813 | +# define VCOS_TRACE(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt) |
| 14814 | + |
| 14815 | +# else /* _MSC_VER >= 1400 */ |
| 14816 | + |
| 14817 | +/* do not define these */ |
| 14818 | + |
| 14819 | +# endif /* _MSC_VER >= 1400 */ |
| 14820 | + |
| 14821 | +#endif |
| 14822 | + |
| 14823 | +#if VCOS_HAVE_CMD |
| 14824 | + |
| 14825 | +#include "interface/vcos/vcos_cmd.h" |
| 14826 | + |
| 14827 | +/* |
| 14828 | + * These are the log sub-commands. They're exported here for user-mode apps which |
| 14829 | + * may want to call these, since the "log" command isn't registered for user-mode |
| 14830 | + * apps (vcdbg for example, has its own log command). |
| 14831 | + */ |
| 14832 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param ); |
| 14833 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_set_cmd( VCOS_CMD_PARAM_T *param ); |
| 14834 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_status_cmd( VCOS_CMD_PARAM_T *param ); |
| 14835 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_test_cmd( VCOS_CMD_PARAM_T *param ); |
| 14836 | +#endif |
| 14837 | + |
| 14838 | +#ifdef __cplusplus |
| 14839 | +} |
| 14840 | +#endif |
| 14841 | +#endif /* VCOS_LOGGING_H */ |
| 14842 | + |
| 14843 | + |
| 14844 | --- /dev/null |
| 14845 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_lowlevel_thread.h |
| 14846 | @@ -0,0 +1,107 @@ |
| 14847 | +/*============================================================================= |
| 14848 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 14849 | +All rights reserved. |
| 14850 | + |
| 14851 | +Project : vcfw |
| 14852 | +Module : chip driver |
| 14853 | + |
| 14854 | +FILE DESCRIPTION |
| 14855 | +VideoCore OS Abstraction Layer - low level thread support |
| 14856 | +=============================================================================*/ |
| 14857 | + |
| 14858 | +#ifndef VCOS_LOWLEVEL_THREAD_H |
| 14859 | +#define VCOS_LOWLEVEL_THREAD_H |
| 14860 | + |
| 14861 | +#ifdef __cplusplus |
| 14862 | +extern "C" { |
| 14863 | +#endif |
| 14864 | + |
| 14865 | +#include "interface/vcos/vcos_types.h" |
| 14866 | +#include "vcos_platform.h" |
| 14867 | + |
| 14868 | +/** |
| 14869 | + * \file |
| 14870 | + * |
| 14871 | + * This defines a low level thread API that is supported by *some* operating systems |
| 14872 | + * and can be used to construct the regular "joinable thread" API on those operating |
| 14873 | + * systems. |
| 14874 | + * |
| 14875 | + * Most clients will not need to use this code. |
| 14876 | + * |
| 14877 | + * \sa vcos_joinable_thread.h |
| 14878 | + */ |
| 14879 | + |
| 14880 | +/** |
| 14881 | + * \brief Create a thread. |
| 14882 | + * |
| 14883 | + * This creates a thread which can be stopped either by returning from the |
| 14884 | + * entry point function or by calling vcos_llthread_exit from within the entry |
| 14885 | + * point function. The thread must be cleaned up by calling |
| 14886 | + * vcos_llthread_delete. vcos_llthread_delete may or may not terminate the |
| 14887 | + * thread. |
| 14888 | + * |
| 14889 | + * The preemptible parameter familiar from Nucleus is removed, as it is unused in |
| 14890 | + * VideoCore code. Affinity is added, since we do use this. |
| 14891 | + * |
| 14892 | + * @param thread Filled in with thread instance |
| 14893 | + * @param name An optional name for the thread. "" may be used (but |
| 14894 | + * a name will aid in debugging). |
| 14895 | + * @param entry Entry point |
| 14896 | + * @param arg A single argument passed to the entry point function |
| 14897 | + * @param stack Pointer to stack address |
| 14898 | + * @param stacksz Size of stack in bytes |
| 14899 | + * @param priority Priority of task, between VCOS_PRI_LOW and VCOS_PRI_HIGH |
| 14900 | + * @param affinity CPU affinity |
| 14901 | + * |
| 14902 | + * @sa vcos_llthread_terminate vcos_llthread_delete |
| 14903 | + */ |
| 14904 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_llthread_create(VCOS_LLTHREAD_T *thread, |
| 14905 | + const char *name, |
| 14906 | + VCOS_LLTHREAD_ENTRY_FN_T entry, |
| 14907 | + void *arg, |
| 14908 | + void *stack, |
| 14909 | + VCOS_UNSIGNED stacksz, |
| 14910 | + VCOS_UNSIGNED priority, |
| 14911 | + VCOS_UNSIGNED affinity, |
| 14912 | + VCOS_UNSIGNED timeslice, |
| 14913 | + VCOS_UNSIGNED autostart); |
| 14914 | + |
| 14915 | +/** |
| 14916 | + * \brief Exits the current thread. |
| 14917 | + */ |
| 14918 | +VCOSPRE_ void VCOSPOST_ vcos_llthread_exit(void); |
| 14919 | + |
| 14920 | +/** |
| 14921 | + * \brief Delete a thread. This must be called to cleanup after |
| 14922 | + * vcos_llthread_create. This may or may not terminate the thread. |
| 14923 | + * It does not clean up any resources that may have been |
| 14924 | + * allocated by the thread. |
| 14925 | + */ |
| 14926 | +VCOSPRE_ void VCOSPOST_ vcos_llthread_delete(VCOS_LLTHREAD_T *thread); |
| 14927 | + |
| 14928 | +/** |
| 14929 | + * \brief Return current lowlevel thread pointer. |
| 14930 | + */ |
| 14931 | +VCOS_INLINE_DECL |
| 14932 | +VCOS_LLTHREAD_T *vcos_llthread_current(void); |
| 14933 | + |
| 14934 | +/** |
| 14935 | + * Resume a thread. |
| 14936 | + */ |
| 14937 | +VCOS_INLINE_DECL |
| 14938 | +void vcos_llthread_resume(VCOS_LLTHREAD_T *thread); |
| 14939 | + |
| 14940 | +VCOSPRE_ int VCOSPOST_ vcos_llthread_running(VCOS_LLTHREAD_T *thread); |
| 14941 | + |
| 14942 | +/** |
| 14943 | + * \brief Create a VCOS_LLTHREAD_T for the current thread. This is so we can |
| 14944 | + * have VCOS_LLTHREAD_Ts even for threads not originally created by VCOS (eg |
| 14945 | + * the thread that calls vcos_init). |
| 14946 | + */ |
| 14947 | +extern VCOS_STATUS_T _vcos_llthread_create_attach(VCOS_LLTHREAD_T *thread); |
| 14948 | + |
| 14949 | +#ifdef __cplusplus |
| 14950 | +} |
| 14951 | +#endif |
| 14952 | +#endif |
| 14953 | + |
| 14954 | --- /dev/null |
| 14955 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_mem.h |
| 14956 | @@ -0,0 +1,81 @@ |
| 14957 | +/*============================================================================= |
| 14958 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 14959 | +All rights reserved. |
| 14960 | + |
| 14961 | +Project : vcfw |
| 14962 | +Module : chip driver |
| 14963 | + |
| 14964 | +FILE DESCRIPTION |
| 14965 | +VideoCore OS Abstraction Layer - memory support |
| 14966 | +=============================================================================*/ |
| 14967 | + |
| 14968 | +#ifndef VCOS_MEM_H |
| 14969 | +#define VCOS_MEM_H |
| 14970 | + |
| 14971 | +#ifdef __cplusplus |
| 14972 | +extern "C" { |
| 14973 | +#endif |
| 14974 | + |
| 14975 | +#include "interface/vcos/vcos_types.h" |
| 14976 | +#include "vcos_platform.h" |
| 14977 | + |
| 14978 | +/** \file |
| 14979 | + * |
| 14980 | + * Memory allocation api (malloc/free equivalents) is for benefit of host |
| 14981 | + * applications. VideoCore code should use rtos_XXX functions. |
| 14982 | + * |
| 14983 | + */ |
| 14984 | + |
| 14985 | + |
| 14986 | +/** Allocate memory |
| 14987 | + * |
| 14988 | + * @param size Size of memory to allocate |
| 14989 | + * @param description Description, to aid in debugging. May be ignored internally on some platforms. |
| 14990 | + */ |
| 14991 | +VCOS_INLINE_DECL |
| 14992 | +void *vcos_malloc(VCOS_UNSIGNED size, const char *description); |
| 14993 | + |
| 14994 | +void *vcos_kmalloc(VCOS_UNSIGNED size, const char *description); |
| 14995 | +void *vcos_kcalloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description); |
| 14996 | + |
| 14997 | +/** Allocate cleared memory |
| 14998 | + * |
| 14999 | + * @param num Number of items to allocate. |
| 15000 | + * @param size Size of each item in bytes. |
| 15001 | + * @param description Description, to aid in debugging. May be ignored internally on some platforms. |
| 15002 | + */ |
| 15003 | +VCOS_INLINE_DECL |
| 15004 | +void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description); |
| 15005 | + |
| 15006 | +/** Free memory |
| 15007 | + * |
| 15008 | + * Free memory that has been allocated. |
| 15009 | + */ |
| 15010 | +VCOS_INLINE_DECL |
| 15011 | +void vcos_free(void *ptr); |
| 15012 | + |
| 15013 | +void vcos_kfree(void *ptr); |
| 15014 | + |
| 15015 | +/** Allocate aligned memory |
| 15016 | + * |
| 15017 | + * Allocate memory aligned on the specified boundary. |
| 15018 | + * |
| 15019 | + * @param size Size of memory to allocate |
| 15020 | + * @param description Description, to aid in debugging. May be ignored internally on some platforms. |
| 15021 | + */ |
| 15022 | +VCOS_INLINE_DECL |
| 15023 | +void *vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description); |
| 15024 | + |
| 15025 | +/** Return the amount of free heap memory |
| 15026 | + * |
| 15027 | + */ |
| 15028 | +VCOS_INLINE_DECL |
| 15029 | +unsigned long vcos_get_free_mem(void); |
| 15030 | + |
| 15031 | +#ifdef __cplusplus |
| 15032 | +} |
| 15033 | +#endif |
| 15034 | + |
| 15035 | +#endif |
| 15036 | + |
| 15037 | + |
| 15038 | --- /dev/null |
| 15039 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_msgqueue.h |
| 15040 | @@ -0,0 +1,157 @@ |
| 15041 | +/*============================================================================= |
| 15042 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 15043 | +All rights reserved. |
| 15044 | + |
| 15045 | +Project : vcfw |
| 15046 | +Module : chip driver |
| 15047 | + |
| 15048 | +FILE DESCRIPTION |
| 15049 | +VCOS - packet-like messages, based loosely on those found in TRIPOS. |
| 15050 | +=============================================================================*/ |
| 15051 | + |
| 15052 | +#ifndef VCOS_MSGQUEUE_H |
| 15053 | +#define VCOS_MSGQUEUE_H |
| 15054 | + |
| 15055 | +#ifdef __cplusplus |
| 15056 | +extern "C" { |
| 15057 | +#endif |
| 15058 | + |
| 15059 | +#include "interface/vcos/vcos_types.h" |
| 15060 | +#include "vcos_platform.h" |
| 15061 | + |
| 15062 | +/** |
| 15063 | + * \file |
| 15064 | + * |
| 15065 | + * Packet-like messages, based loosely on those found in TRIPOS and |
| 15066 | + * derivatives thereof. |
| 15067 | + * |
| 15068 | + * A task can send a message *pointer* to another task, where it is |
| 15069 | + * queued on a linked list and the task woken up. The receiving task |
| 15070 | + * consumes all of the messages on its input queue, and optionally |
| 15071 | + * sends back replies using the original message memory. |
| 15072 | + * |
| 15073 | + * A caller can wait for the reply to a specific message - any other |
| 15074 | + * messages that arrive in the meantime are queued separately. |
| 15075 | + * |
| 15076 | + * |
| 15077 | + * All messages have a standard common layout, but the payload area can |
| 15078 | + * be used freely to extend this. |
| 15079 | + */ |
| 15080 | + |
| 15081 | +/** Map the payload portion of a message to a structure pointer. |
| 15082 | + */ |
| 15083 | +#define VCOS_MSG_DATA(_msg) (void*)((_msg)->data) |
| 15084 | + |
| 15085 | +/** Standard message ids - FIXME - these need to be done properly! */ |
| 15086 | +#define VCOS_MSG_N_QUIT 1 |
| 15087 | +#define VCOS_MSG_N_OPEN 2 |
| 15088 | +#define VCOS_MSG_N_CLOSE 3 |
| 15089 | +#define VCOS_MSG_N_PRIVATE (1<<20) |
| 15090 | + |
| 15091 | +#define VCOS_MSG_REPLY_BIT (1<<31) |
| 15092 | + |
| 15093 | +/** Make gnuc compiler be happy about pointer punning */ |
| 15094 | +#ifdef __GNUC__ |
| 15095 | +#define __VCOS_MAY_ALIAS __attribute__((__may_alias__)) |
| 15096 | +#else |
| 15097 | +#define __VCOS_MAY_ALIAS |
| 15098 | +#endif |
| 15099 | + |
| 15100 | +/** A single message queue. |
| 15101 | + */ |
| 15102 | +typedef struct VCOS_MSGQUEUE_T |
| 15103 | +{ |
| 15104 | + struct VCOS_MSG_T *head; /**< head of linked list of messages waiting on this queue */ |
| 15105 | + struct VCOS_MSG_T *tail; /**< tail of message queue */ |
| 15106 | + VCOS_SEMAPHORE_T sem; /**< thread waits on this for new messages */ |
| 15107 | + VCOS_MUTEX_T lock; /**< locks the messages list */ |
| 15108 | +} VCOS_MSGQUEUE_T; |
| 15109 | + |
| 15110 | +/** A single message |
| 15111 | + */ |
| 15112 | +typedef struct VCOS_MSG_T |
| 15113 | +{ |
| 15114 | + uint32_t code; /**< message code */ |
| 15115 | + int error; /**< error status signalled back to caller */ |
| 15116 | + VCOS_MSGQUEUE_T *dst; /**< destination queue */ |
| 15117 | + VCOS_MSGQUEUE_T *src; /**< source; replies go back to here */ |
| 15118 | + struct VCOS_MSG_T *next; /**< next in queue */ |
| 15119 | + VCOS_THREAD_T *src_thread; /**< for debug */ |
| 15120 | + uint32_t data[25]; /**< payload area */ |
| 15121 | +} VCOS_MSG_T; |
| 15122 | + |
| 15123 | +/** An endpoint |
| 15124 | + */ |
| 15125 | +typedef struct VCOS_MSG_ENDPOINT_T |
| 15126 | +{ |
| 15127 | + VCOS_MSGQUEUE_T primary; /**< incoming messages */ |
| 15128 | + VCOS_MSGQUEUE_T secondary; /**< this is used for waitspecific */ |
| 15129 | + char name[32]; /**< name of this endpoint, for find() */ |
| 15130 | + struct VCOS_MSG_ENDPOINT_T *next; /**< next in global list of endpoints */ |
| 15131 | +} VCOS_MSG_ENDPOINT_T; |
| 15132 | +#define MSG_REPLY_BIT (1<<31) |
| 15133 | + |
| 15134 | +/** Initalise the library. Normally called from vcos_init(). |
| 15135 | + */ |
| 15136 | +extern VCOS_STATUS_T vcos_msgq_init(void); |
| 15137 | + |
| 15138 | +/** Find a message queue by name and get a handle to it. |
| 15139 | + * |
| 15140 | + * @param name the name of the queue to find |
| 15141 | + * |
| 15142 | + * @return The message queue, or NULL if not found. |
| 15143 | + */ |
| 15144 | +VCOSPRE_ VCOS_MSGQUEUE_T VCOSPOST_ *vcos_msgq_find(const char *name); |
| 15145 | + |
| 15146 | +/** Wait for a message queue to come into existence. If it already exists, |
| 15147 | + * return immediately, otherwise block. |
| 15148 | + * |
| 15149 | + * On the whole, if you find yourself using this, it is probably a sign |
| 15150 | + * of poor design, since you should create all the server threads first, |
| 15151 | + * and then the client threads. But it is sometimes useful. |
| 15152 | + * |
| 15153 | + * @param name the name of the queue to find |
| 15154 | + * @return The message queue |
| 15155 | + */ |
| 15156 | +VCOSPRE_ VCOS_MSGQUEUE_T VCOSPOST_ *vcos_msgq_wait(const char *name); |
| 15157 | + |
| 15158 | +/** Send a message. |
| 15159 | + */ |
| 15160 | +VCOSPRE_ void VCOSPOST_ vcos_msg_send(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg); |
| 15161 | + |
| 15162 | +/** Send a message and wait for a reply. |
| 15163 | + */ |
| 15164 | +VCOSPRE_ void VCOSPOST_ vcos_msg_sendwait(VCOS_MSGQUEUE_T *queue, uint32_t code, VCOS_MSG_T *msg); |
| 15165 | + |
| 15166 | +/** Wait for a message on this thread's endpoint. |
| 15167 | + */ |
| 15168 | +VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_wait(void); |
| 15169 | + |
| 15170 | +/** Wait for a specific message. |
| 15171 | + */ |
| 15172 | +VCOS_MSG_T * vcos_msg_wait_specific(VCOS_MSGQUEUE_T *queue, VCOS_MSG_T *msg); |
| 15173 | + |
| 15174 | +/** Peek for a message on this thread's endpoint, if a message is not available, NULL is |
| 15175 | + returned. If a message is available it will be removed from the endpoint and returned. |
| 15176 | + */ |
| 15177 | +VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_peek(void); |
| 15178 | + |
| 15179 | +/** Send a reply to a message |
| 15180 | + */ |
| 15181 | +VCOSPRE_ void VCOSPOST_ vcos_msg_reply(VCOS_MSG_T *msg); |
| 15182 | + |
| 15183 | +/** Create an endpoint. Each thread should need no more than one of these - if you |
| 15184 | + * find yourself needing a second one, you've done something wrong. |
| 15185 | + */ |
| 15186 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_endpoint_create(VCOS_MSG_ENDPOINT_T *ep, const char *name); |
| 15187 | + |
| 15188 | +/** Destroy an endpoint. |
| 15189 | + */ |
| 15190 | +VCOSPRE_ void VCOSPOST_ vcos_msgq_endpoint_delete(VCOS_MSG_ENDPOINT_T *ep); |
| 15191 | + |
| 15192 | +#ifdef __cplusplus |
| 15193 | +} |
| 15194 | +#endif |
| 15195 | +#endif |
| 15196 | + |
| 15197 | + |
| 15198 | --- /dev/null |
| 15199 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_mutex.h |
| 15200 | @@ -0,0 +1,92 @@ |
| 15201 | +/*============================================================================= |
| 15202 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 15203 | +All rights reserved. |
| 15204 | + |
| 15205 | +Project : vcfw |
| 15206 | +Module : chip driver |
| 15207 | + |
| 15208 | +FILE DESCRIPTION |
| 15209 | +VideoCore OS Abstraction Layer - mutex public header file |
| 15210 | +=============================================================================*/ |
| 15211 | + |
| 15212 | +#ifndef VCOS_MUTEX_H |
| 15213 | +#define VCOS_MUTEX_H |
| 15214 | + |
| 15215 | +#ifdef __cplusplus |
| 15216 | +extern "C" { |
| 15217 | +#endif |
| 15218 | + |
| 15219 | +#include "interface/vcos/vcos_types.h" |
| 15220 | +#include "vcos_platform.h" |
| 15221 | + |
| 15222 | +/** |
| 15223 | + * \file vcos_mutex.h |
| 15224 | + * |
| 15225 | + * Mutex API. Mutexes are not re-entrant, as supporting this adds extra code |
| 15226 | + * that slows down clients which have been written sensibly. |
| 15227 | + * |
| 15228 | + * \sa vcos_reentrant_mutex.h |
| 15229 | + * |
| 15230 | + */ |
| 15231 | + |
| 15232 | +/** Create a mutex. |
| 15233 | + * |
| 15234 | + * @param m Filled in with mutex on return |
| 15235 | + * @param name A non-null name for the mutex, used for diagnostics. |
| 15236 | + * |
| 15237 | + * @return VCOS_SUCCESS if mutex was created, or error code. |
| 15238 | + */ |
| 15239 | +VCOS_INLINE_DECL |
| 15240 | +VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *m, const char *name); |
| 15241 | + |
| 15242 | +/** Delete the mutex. |
| 15243 | + */ |
| 15244 | +VCOS_INLINE_DECL |
| 15245 | +void vcos_mutex_delete(VCOS_MUTEX_T *m); |
| 15246 | + |
| 15247 | +/** |
| 15248 | + * \brief Wait to claim the mutex. |
| 15249 | + * |
| 15250 | + * On most platforms this always returns VCOS_SUCCESS, and so would ideally be |
| 15251 | + * a void function, however some platforms allow a wait to be interrupted so |
| 15252 | + * it remains non-void. |
| 15253 | + * |
| 15254 | + * Try to obtain the mutex. |
| 15255 | + * @param m Mutex to wait on |
| 15256 | + * @return VCOS_SUCCESS - mutex was taken. |
| 15257 | + * VCOS_EAGAIN - could not take mutex. |
| 15258 | + */ |
| 15259 | +#ifndef vcos_mutex_lock |
| 15260 | +VCOS_INLINE_DECL |
| 15261 | +VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *m); |
| 15262 | + |
| 15263 | +/** Release the mutex. |
| 15264 | + */ |
| 15265 | +VCOS_INLINE_DECL |
| 15266 | +void vcos_mutex_unlock(VCOS_MUTEX_T *m); |
| 15267 | +#endif |
| 15268 | + |
| 15269 | +/** Test if the mutex is already locked. |
| 15270 | + * |
| 15271 | + * @return 1 if mutex is locked, 0 if it is unlocked. |
| 15272 | + */ |
| 15273 | +VCOS_INLINE_DECL |
| 15274 | +int vcos_mutex_is_locked(VCOS_MUTEX_T *m); |
| 15275 | + |
| 15276 | +/** Obtain the mutex if possible. |
| 15277 | + * |
| 15278 | + * @param m the mutex to try to obtain |
| 15279 | + * |
| 15280 | + * @return VCOS_SUCCESS if mutex is succesfully obtained, or VCOS_EAGAIN |
| 15281 | + * if it is already in use by another thread. |
| 15282 | + */ |
| 15283 | +#ifndef vcos_mutex_trylock |
| 15284 | +VCOS_INLINE_DECL |
| 15285 | +VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m); |
| 15286 | +#endif |
| 15287 | + |
| 15288 | + |
| 15289 | +#ifdef __cplusplus |
| 15290 | +} |
| 15291 | +#endif |
| 15292 | +#endif |
| 15293 | --- /dev/null |
| 15294 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_once.h |
| 15295 | @@ -0,0 +1,42 @@ |
| 15296 | +/*============================================================================= |
| 15297 | +Copyright (c) 2011 Broadcom Europe Limited. |
| 15298 | +All rights reserved. |
| 15299 | + |
| 15300 | +Project : vcfw |
| 15301 | +Module : chip driver |
| 15302 | + |
| 15303 | +FILE DESCRIPTION |
| 15304 | +VideoCore OS Abstraction Layer - 'once' |
| 15305 | +=============================================================================*/ |
| 15306 | + |
| 15307 | +#ifndef VCOS_ONCE_H |
| 15308 | +#define VCOS_ONCE_H |
| 15309 | + |
| 15310 | +#ifdef __cplusplus |
| 15311 | +extern "C" { |
| 15312 | +#endif |
| 15313 | + |
| 15314 | +#include "interface/vcos/vcos_types.h" |
| 15315 | +#include "vcos_platform.h" |
| 15316 | + |
| 15317 | +/** |
| 15318 | + * \file vcos_once.h |
| 15319 | + * |
| 15320 | + * Ensure something is called only once. |
| 15321 | + * |
| 15322 | + * Initialize once_control to VCOS_ONCE_INIT. The first |
| 15323 | + * time this is called, the init_routine will be called. Thereafter |
| 15324 | + * it won't. |
| 15325 | + * |
| 15326 | + * \sa pthread_once() |
| 15327 | + * |
| 15328 | + */ |
| 15329 | + |
| 15330 | +VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control, |
| 15331 | + void (*init_routine)(void)); |
| 15332 | + |
| 15333 | +#ifdef __cplusplus |
| 15334 | +} |
| 15335 | +#endif |
| 15336 | +#endif |
| 15337 | + |
| 15338 | --- /dev/null |
| 15339 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_semaphore.h |
| 15340 | @@ -0,0 +1,115 @@ |
| 15341 | +/*============================================================================= |
| 15342 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 15343 | +All rights reserved. |
| 15344 | + |
| 15345 | +Project : vcfw |
| 15346 | +Module : chip driver |
| 15347 | + |
| 15348 | +FILE DESCRIPTION |
| 15349 | +VideoCore OS Abstraction Layer - public header file |
| 15350 | +=============================================================================*/ |
| 15351 | + |
| 15352 | +#ifndef VCOS_SEMAPHORE_H |
| 15353 | +#define VCOS_SEMAPHORE_H |
| 15354 | + |
| 15355 | +#ifdef __cplusplus |
| 15356 | +extern "C" { |
| 15357 | +#endif |
| 15358 | + |
| 15359 | +#include "interface/vcos/vcos_types.h" |
| 15360 | +#include "vcos_platform.h" |
| 15361 | + |
| 15362 | +/** |
| 15363 | + * \file vcos_semaphore.h |
| 15364 | + * |
| 15365 | + * \section sem Semaphores |
| 15366 | + * |
| 15367 | + * This provides counting semaphores. Semaphores are not re-entrant. On sensible |
| 15368 | + * operating systems a semaphore can always be posted but can only be taken in |
| 15369 | + * thread (not interrupt) context. Under Nucleus, a LISR cannot post a semaphore, |
| 15370 | + * although it would not be hard to lift this restriction. |
| 15371 | + * |
| 15372 | + * \subsection timeout Timeout |
| 15373 | + * |
| 15374 | + * On both Nucleus and ThreadX a semaphore can be taken with a timeout. This is |
| 15375 | + * not supported by VCOS because it makes the non-timeout code considerably more |
| 15376 | + * complicated (and hence slower). In the unlikely event that you need a timeout |
| 15377 | + * with a semaphore, and you cannot simply redesign your code to avoid it, use |
| 15378 | + * an event flag (vcos_event_flags.h). |
| 15379 | + * |
| 15380 | + * \subsection sem_nucleus Changes from Nucleus: |
| 15381 | + * |
| 15382 | + * Semaphores are always "FIFO" - i.e. sleeping threads are woken in FIFO order. That's |
| 15383 | + * because: |
| 15384 | + * \arg there's no support for NU_PRIORITY in threadx (though it can be emulated, slowly) |
| 15385 | + * \arg we don't appear to actually consciously use it - for example, Dispmanx uses |
| 15386 | + * it, but all threads waiting are the same priority. |
| 15387 | + * |
| 15388 | + */ |
| 15389 | + |
| 15390 | +/** |
| 15391 | + * \brief Create a semaphore. |
| 15392 | + * |
| 15393 | + * Create a semaphore. |
| 15394 | + * |
| 15395 | + * @param sem Pointer to memory to be initialized |
| 15396 | + * @param name A name for this semaphore. The name may be truncated internally. |
| 15397 | + * @param count The initial count for the semaphore. |
| 15398 | + * |
| 15399 | + * @return VCOS_SUCCESS if the semaphore was created. |
| 15400 | + * |
| 15401 | + */ |
| 15402 | +VCOS_INLINE_DECL |
| 15403 | +VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count); |
| 15404 | + |
| 15405 | +/** |
| 15406 | + * \brief Wait on a semaphore. |
| 15407 | + * |
| 15408 | + * There is no timeout option on a semaphore, as adding this will slow down |
| 15409 | + * implementations on some platforms. If you need that kind of behaviour, use |
| 15410 | + * an event group. |
| 15411 | + * |
| 15412 | + * On most platforms this always returns VCOS_SUCCESS, and so would ideally be |
| 15413 | + * a void function, however some platforms allow a wait to be interrupted so |
| 15414 | + * it remains non-void. |
| 15415 | + * |
| 15416 | + * @param sem Semaphore to wait on |
| 15417 | + * @return VCOS_SUCCESS - semaphore was taken. |
| 15418 | + * VCOS_EAGAIN - could not take semaphore |
| 15419 | + * |
| 15420 | + */ |
| 15421 | +VCOS_INLINE_DECL |
| 15422 | +VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem); |
| 15423 | + |
| 15424 | +/** |
| 15425 | + * \brief Try to wait for a semaphore. |
| 15426 | + * |
| 15427 | + * Try to obtain the semaphore. If it is already taken, return VCOS_TIMEOUT. |
| 15428 | + * @param sem Semaphore to wait on |
| 15429 | + * @return VCOS_SUCCESS - semaphore was taken. |
| 15430 | + * VCOS_EAGAIN - could not take semaphore |
| 15431 | + */ |
| 15432 | +VCOS_INLINE_DECL |
| 15433 | +VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem); |
| 15434 | + |
| 15435 | +/** |
| 15436 | + * \brief Post a semaphore. |
| 15437 | + * |
| 15438 | + * @param sem Semaphore to wait on |
| 15439 | + */ |
| 15440 | +VCOS_INLINE_DECL |
| 15441 | +VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem); |
| 15442 | + |
| 15443 | +/** |
| 15444 | + * \brief Delete a semaphore, releasing any resources consumed by it. |
| 15445 | + * |
| 15446 | + * @param sem Semaphore to wait on |
| 15447 | + */ |
| 15448 | +VCOS_INLINE_DECL |
| 15449 | +void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem); |
| 15450 | + |
| 15451 | +#ifdef __cplusplus |
| 15452 | +} |
| 15453 | +#endif |
| 15454 | +#endif |
| 15455 | + |
| 15456 | --- /dev/null |
| 15457 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_stdbool.h |
| 15458 | @@ -0,0 +1,17 @@ |
| 15459 | +#ifndef VCOS_STDBOOL_H |
| 15460 | +#define VCOS_STDBOOL_H |
| 15461 | + |
| 15462 | +#ifndef __cplusplus |
| 15463 | + |
| 15464 | +#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L) |
| 15465 | +#include <stdbool.h> |
| 15466 | +#else |
| 15467 | +typedef enum { |
| 15468 | + false, |
| 15469 | + true |
| 15470 | +} bool; |
| 15471 | +#endif |
| 15472 | + |
| 15473 | +#endif /* __cplusplus */ |
| 15474 | + |
| 15475 | +#endif |
| 15476 | --- /dev/null |
| 15477 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_stdint.h |
| 15478 | @@ -0,0 +1,193 @@ |
| 15479 | +/*============================================================================= |
| 15480 | +Copyright (c) 2011 Broadcom Europe Limited. |
| 15481 | +All rights reserved. |
| 15482 | + |
| 15483 | +FILE DESCRIPTION |
| 15484 | + |
| 15485 | +=============================================================================*/ |
| 15486 | + |
| 15487 | +#ifndef VCOS_STDINT_H |
| 15488 | +#define VCOS_STDINT_H |
| 15489 | + |
| 15490 | +/* Attempt to provide the types defined in stdint.h. |
| 15491 | + * |
| 15492 | + * Ideally this would either call out to a platform-specific |
| 15493 | + * header file (e.g. stdint.h) or define the types on a |
| 15494 | + * per-architecture/compiler basis. But for now we just |
| 15495 | + * use #ifdefs. |
| 15496 | + */ |
| 15497 | + |
| 15498 | +#ifdef __cplusplus |
| 15499 | +extern "C" { |
| 15500 | +#endif |
| 15501 | + |
| 15502 | +#ifdef __SYMBIAN32__ |
| 15503 | + |
| 15504 | +typedef signed char int8_t; |
| 15505 | +typedef unsigned char uint8_t; |
| 15506 | + |
| 15507 | +typedef signed short int16_t; |
| 15508 | +typedef unsigned short uint16_t; |
| 15509 | + |
| 15510 | +typedef int16_t int_least16_t; |
| 15511 | + |
| 15512 | +typedef signed long int32_t; |
| 15513 | +typedef unsigned long uint32_t; |
| 15514 | + |
| 15515 | +typedef signed long long int64_t; |
| 15516 | +typedef unsigned long long uint64_t; |
| 15517 | + |
| 15518 | +typedef int32_t intptr_t; |
| 15519 | +typedef uint32_t uintptr_t; |
| 15520 | + |
| 15521 | +typedef int64_t intmax_t; |
| 15522 | +typedef uint64_t uintmax_t; |
| 15523 | + |
| 15524 | +#define INT8_MIN SCHAR_MIN |
| 15525 | +#define INT8_MAX SCHAR_MAX |
| 15526 | +#define UINT8_MAX UCHAR_MAX |
| 15527 | +#define INT16_MIN SHRT_MIN |
| 15528 | +#define INT16_MAX SHRT_MAX |
| 15529 | +#define UINT16_MAX USHRT_MAX |
| 15530 | +#define INT32_MIN LONG_MIN |
| 15531 | +#define INT32_MAX LONG_MAX |
| 15532 | +#define UINT32_MAX ULONG_MAX |
| 15533 | +#define INT64_MIN LLONG_MIN |
| 15534 | +#define INT64_MAX LLONG_MAX |
| 15535 | +#define UINT64_MAX ULLONG_MAX |
| 15536 | + |
| 15537 | +#define INTPTR_MIN INT32_MIN |
| 15538 | +#define INTPTR_MAX INT32_MAX |
| 15539 | +#define UINTPTR_MAX UINT32_MAX |
| 15540 | +#define INTMAX_MIN INT64_MIN |
| 15541 | +#define INTMAX_MAX INT64_MAX |
| 15542 | +#define INT_LEAST16_MAX INT16_MAX |
| 15543 | +#define INT_LEAST16_MAX INT16_MAX |
| 15544 | + |
| 15545 | +/*{{{ C99 types - THIS WHOLE SECTION IS INCOMPATIBLE WITH C99. IT SHOULD RESIDE IN A STDINT.H SINCE THIS FILE GETS USED ON HOST SIDE */ |
| 15546 | + |
| 15547 | +#elif defined( __STDC__ ) && __STDC_VERSION__ >= 199901L |
| 15548 | + |
| 15549 | +#include <stdint.h> |
| 15550 | + |
| 15551 | +#elif defined( __GNUC__ ) |
| 15552 | + |
| 15553 | +#include <stdint.h> |
| 15554 | + |
| 15555 | +#elif defined(_MSC_VER) /* Visual C define equivalent types */ |
| 15556 | + |
| 15557 | +#include <stddef.h> /* Avoids intptr_t being defined in vadefs.h */ |
| 15558 | + |
| 15559 | +typedef __int8 int8_t; |
| 15560 | +typedef unsigned __int8 uint8_t; |
| 15561 | + |
| 15562 | +typedef __int16 int16_t; |
| 15563 | +typedef unsigned __int16 uint16_t; |
| 15564 | + |
| 15565 | +typedef __int32 int32_t; |
| 15566 | +typedef unsigned __int32 uint32_t; |
| 15567 | + |
| 15568 | +typedef __int64 int64_t; |
| 15569 | +typedef unsigned __int64 uint64_t; |
| 15570 | +typedef uint32_t uintptr_t; |
| 15571 | +typedef int64_t intmax_t; |
| 15572 | +typedef uint64_t uintmax_t; |
| 15573 | +typedef int16_t int_least16_t; |
| 15574 | + |
| 15575 | +#elif defined (VCMODS_LCC) |
| 15576 | +#include <limits.h> |
| 15577 | + |
| 15578 | +typedef signed char int8_t; |
| 15579 | +typedef unsigned char uint8_t; |
| 15580 | + |
| 15581 | +typedef signed short int16_t; |
| 15582 | +typedef unsigned short uint16_t; |
| 15583 | + |
| 15584 | +typedef signed long int32_t; |
| 15585 | +typedef unsigned long uint32_t; |
| 15586 | + |
| 15587 | +typedef signed long int64_t; /*!!!! PFCD, this means code using 64bit numbers will be broken on the VCE */ |
| 15588 | +typedef unsigned long uint64_t; /* !!!! PFCD */ |
| 15589 | + |
| 15590 | +typedef int32_t intptr_t; |
| 15591 | +typedef uint32_t uintptr_t; |
| 15592 | +typedef int64_t intmax_t; |
| 15593 | +typedef uint64_t uintmax_t; |
| 15594 | +typedef int16_t int_least16_t; |
| 15595 | + |
| 15596 | +#define INT8_MIN SCHAR_MIN |
| 15597 | +#define INT8_MAX SCHAR_MAX |
| 15598 | +#define UINT8_MAX UCHAR_MAX |
| 15599 | +#define INT16_MIN SHRT_MIN |
| 15600 | +#define INT16_MAX SHRT_MAX |
| 15601 | +#define UINT16_MAX USHRT_MAX |
| 15602 | +#define INT32_MIN LONG_MIN |
| 15603 | +#define INT32_MAX LONG_MAX |
| 15604 | +#define UINT32_MAX ULONG_MAX |
| 15605 | +#define INT64_MIN LONG_MIN /* !!!! PFCD */ |
| 15606 | +#define INT64_MAX LONG_MAX /* !!!! PFCD */ |
| 15607 | +#define UINT64_MAX ULONG_MAX /* !!!! PFCD */ |
| 15608 | + |
| 15609 | +#define INTPTR_MIN INT32_MIN |
| 15610 | +#define INTPTR_MAX INT32_MAX |
| 15611 | +#define UINTPTR_MAX UINT32_MAX |
| 15612 | +#define INTMAX_MIN INT64_MIN |
| 15613 | +#define INTMAX_MIN INT64_MIN |
| 15614 | +#define INT_LEAST16_MAX INT16_MAX |
| 15615 | +#define INT_LEAST16_MAX INT16_MAX |
| 15616 | + |
| 15617 | +#elif defined(__VIDEOCORE__) |
| 15618 | + |
| 15619 | +typedef signed char int8_t; |
| 15620 | +typedef unsigned char uint8_t; |
| 15621 | + |
| 15622 | +typedef signed short int16_t; |
| 15623 | +typedef unsigned short uint16_t; |
| 15624 | + |
| 15625 | +typedef signed long int32_t; |
| 15626 | +typedef unsigned long uint32_t; |
| 15627 | + |
| 15628 | +typedef signed long long int64_t; |
| 15629 | +typedef unsigned long long uint64_t; |
| 15630 | + |
| 15631 | +typedef int32_t intptr_t; |
| 15632 | +typedef uint32_t uintptr_t; |
| 15633 | +typedef int64_t intmax_t; |
| 15634 | +typedef uint64_t uintmax_t; |
| 15635 | +typedef int16_t int_least16_t; |
| 15636 | + |
| 15637 | +#define INT8_MIN SCHAR_MIN |
| 15638 | +#define INT8_MAX SCHAR_MAX |
| 15639 | +#define UINT8_MAX UCHAR_MAX |
| 15640 | +#define INT16_MIN SHRT_MIN |
| 15641 | +#define INT16_MAX SHRT_MAX |
| 15642 | +#define UINT16_MAX USHRT_MAX |
| 15643 | +#define INT32_MIN LONG_MIN |
| 15644 | +#define INT32_MAX LONG_MAX |
| 15645 | +#define UINT32_MAX ULONG_MAX |
| 15646 | +#define INT64_MIN LLONG_MIN |
| 15647 | +#define INT64_MAX LLONG_MAX |
| 15648 | +#define UINT64_MAX ULLONG_MAX |
| 15649 | + |
| 15650 | +#define INTPTR_MIN INT32_MIN |
| 15651 | +#define INTPTR_MAX INT32_MAX |
| 15652 | +#define UINTPTR_MAX UINT32_MAX |
| 15653 | +#define INTMAX_MIN INT64_MIN |
| 15654 | +#define INTMAX_MAX INT64_MAX |
| 15655 | +#define INT_LEAST16_MAX INT16_MAX |
| 15656 | +#define INT_LEAST16_MAX INT16_MAX |
| 15657 | + |
| 15658 | +#elif defined (__HIGHC__) && defined(_I386) |
| 15659 | + |
| 15660 | +#include <stdint.h> |
| 15661 | + |
| 15662 | +#else |
| 15663 | +#error Unknown platform |
| 15664 | +#endif |
| 15665 | + |
| 15666 | +#ifdef __cplusplus |
| 15667 | +} |
| 15668 | +#endif |
| 15669 | +#endif /* VCOS_STDINT_H */ |
| 15670 | + |
| 15671 | + |
| 15672 | --- /dev/null |
| 15673 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_string.h |
| 15674 | @@ -0,0 +1,73 @@ |
| 15675 | +/*============================================================================= |
| 15676 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 15677 | +All rights reserved. |
| 15678 | + |
| 15679 | +Project : vcfw |
| 15680 | +Module : chip driver |
| 15681 | + |
| 15682 | +FILE DESCRIPTION |
| 15683 | +VideoCore OS Abstraction Layer - public header file |
| 15684 | +=============================================================================*/ |
| 15685 | + |
| 15686 | +#ifndef VCOS_STRING_H |
| 15687 | +#define VCOS_STRING_H |
| 15688 | + |
| 15689 | +/** |
| 15690 | + * \file |
| 15691 | + * |
| 15692 | + * String functions. |
| 15693 | + * |
| 15694 | + */ |
| 15695 | + |
| 15696 | +#ifdef __cplusplus |
| 15697 | +extern "C" { |
| 15698 | +#endif |
| 15699 | + |
| 15700 | +#include "interface/vcos/vcos_types.h" |
| 15701 | +#include "vcos_platform.h" |
| 15702 | + |
| 15703 | +#ifdef __KERNEL__ |
| 15704 | +#include <linux/string.h> |
| 15705 | +#else |
| 15706 | +#include <string.h> |
| 15707 | +#endif |
| 15708 | + |
| 15709 | +/** Case insensitive string comparison. |
| 15710 | + * |
| 15711 | + */ |
| 15712 | + |
| 15713 | +VCOS_INLINE_DECL |
| 15714 | +int vcos_strcasecmp(const char *s1, const char *s2); |
| 15715 | + |
| 15716 | +VCOS_INLINE_DECL |
| 15717 | +int vcos_strncasecmp(const char *s1, const char *s2, size_t n); |
| 15718 | + |
| 15719 | +VCOSPRE_ int VCOSPOST_ vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap ); |
| 15720 | + |
| 15721 | +VCOSPRE_ int VCOSPOST_ vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...); |
| 15722 | + |
| 15723 | +VCOS_STATIC_INLINE |
| 15724 | +int vcos_strlen(const char *s) { return (int)strlen(s); } |
| 15725 | + |
| 15726 | +VCOS_STATIC_INLINE |
| 15727 | +int vcos_strcmp(const char *s1, const char *s2) { return strcmp(s1,s2); } |
| 15728 | + |
| 15729 | +VCOS_STATIC_INLINE |
| 15730 | +int vcos_strncmp(const char *cs, const char *ct, size_t count) { return strncmp(cs, ct, count); } |
| 15731 | + |
| 15732 | +VCOS_STATIC_INLINE |
| 15733 | +char *vcos_strcpy(char *dst, const char *src) { return strcpy(dst, src); } |
| 15734 | + |
| 15735 | +VCOS_STATIC_INLINE |
| 15736 | +char *vcos_strncpy(char *dst, const char *src, size_t count) { return strncpy(dst, src, count); } |
| 15737 | + |
| 15738 | +VCOS_STATIC_INLINE |
| 15739 | +void *vcos_memcpy(void *dst, const void *src, size_t n) { memcpy(dst, src, n); return dst; } |
| 15740 | + |
| 15741 | +VCOS_STATIC_INLINE |
| 15742 | +void *vcos_memset(void *p, int c, size_t n) { return memset(p, c, n); } |
| 15743 | + |
| 15744 | +#ifdef __cplusplus |
| 15745 | +} |
| 15746 | +#endif |
| 15747 | +#endif |
| 15748 | --- /dev/null |
| 15749 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_thread.h |
| 15750 | @@ -0,0 +1,259 @@ |
| 15751 | +/*============================================================================= |
| 15752 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 15753 | +All rights reserved. |
| 15754 | + |
| 15755 | +Project : vcfw |
| 15756 | +Module : chip driver |
| 15757 | + |
| 15758 | +FILE DESCRIPTION |
| 15759 | +VideoCore OS Abstraction Layer - public header file |
| 15760 | +=============================================================================*/ |
| 15761 | + |
| 15762 | +#ifndef VCOS_THREAD_H |
| 15763 | +#define VCOS_THREAD_H |
| 15764 | + |
| 15765 | +#ifdef __cplusplus |
| 15766 | +extern "C" { |
| 15767 | +#endif |
| 15768 | + |
| 15769 | +#include "interface/vcos/vcos_types.h" |
| 15770 | +#include "vcos_platform.h" |
| 15771 | + |
| 15772 | +/** |
| 15773 | + * \file vcos_thread.h |
| 15774 | + * |
| 15775 | + * \section thread Threads |
| 15776 | + * |
| 15777 | + * Under Nucleus, a thread is created by NU_Create_Task, passing in the stack |
| 15778 | + * and various other parameters. To stop the thread, NU_Terminate_Thread() and |
| 15779 | + * NU_Delete_Thread() are called. |
| 15780 | + * |
| 15781 | + * Unfortunately it's not possible to emulate this API under some fairly common |
| 15782 | + * operating systems. Under Windows you can't pass in the stack, and you can't |
| 15783 | + * safely terminate a thread. |
| 15784 | + * |
| 15785 | + * Therefore, an API which is similar to the pthreads API is used instead. This |
| 15786 | + * API can (mostly) be emulated under all interesting operating systems. |
| 15787 | + * |
| 15788 | + * Obviously this makes the code somewhat more complicated on VideoCore than it |
| 15789 | + * would otherwise be - we end up with an extra mutex per thread, and some code |
| 15790 | + * that waits for it. The benefit is that we have a single way of creating |
| 15791 | + * threads that works consistently on all platforms (apart from stack supplying). |
| 15792 | + * |
| 15793 | + * \subsection stack Stack |
| 15794 | + * |
| 15795 | + * It's still not possible to pass in the stack address, but this can be made |
| 15796 | + * much more obvious in the API: the relevant function is missing and the |
| 15797 | + * CPP symbol VCOS_CAN_SET_STACK_ADDR is zero rather than one. |
| 15798 | + * |
| 15799 | + * \subsection thr_create Creating a thread |
| 15800 | + * |
| 15801 | + * The simplest way to create a thread is with vcos_thread_create() passing in a |
| 15802 | + * NULL thread parameter argument. To wait for the thread to exit, call |
| 15803 | + * vcos_thread_join(). |
| 15804 | + * |
| 15805 | + * \subsection back Backward compatibility |
| 15806 | + * |
| 15807 | + * To ease migration, a "classic" thread creation API is provided for code |
| 15808 | + * that used to make use of Nucleus, vcos_thread_create_classic(). The |
| 15809 | + * arguments are not exactly the same, as the PREEMPT parameter is dropped. |
| 15810 | + * |
| 15811 | + */ |
| 15812 | + |
| 15813 | +#define VCOS_AFFINITY_CPU0 _VCOS_AFFINITY_CPU0 |
| 15814 | +#define VCOS_AFFINITY_CPU1 _VCOS_AFFINITY_CPU1 |
| 15815 | +#define VCOS_AFFINITY_MASK _VCOS_AFFINITY_MASK |
| 15816 | +#define VCOS_AFFINITY_DEFAULT _VCOS_AFFINITY_DEFAULT |
| 15817 | +#define VCOS_AFFINITY_THISCPU _VCOS_AFFINITY_THISCPU |
| 15818 | + |
| 15819 | +/** Report whether or not we have an RTOS at all, and hence the ability to |
| 15820 | + * create threads. |
| 15821 | + */ |
| 15822 | +VCOSPRE_ int VCOSPOST_ vcos_have_rtos(void); |
| 15823 | + |
| 15824 | +/** Create a thread. It must be cleaned up by calling vcos_thread_join(). |
| 15825 | + * |
| 15826 | + * @param thread Filled in on return with thread |
| 15827 | + * @param name A name for the thread. May be the empty string. |
| 15828 | + * @param attrs Attributes; default attributes will be used if this is NULL. |
| 15829 | + * @param entry Entry point. |
| 15830 | + * @param arg Argument passed to the entry point. |
| 15831 | + */ |
| 15832 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create(VCOS_THREAD_T *thread, |
| 15833 | + const char *name, |
| 15834 | + VCOS_THREAD_ATTR_T *attrs, |
| 15835 | + VCOS_THREAD_ENTRY_FN_T entry, |
| 15836 | + void *arg); |
| 15837 | + |
| 15838 | +/** Exit the thread from within the thread function itself. |
| 15839 | + * Resources must still be cleaned up via a call to thread_join(). |
| 15840 | + * |
| 15841 | + * The thread can also be terminated by simply exiting the thread function. |
| 15842 | + * |
| 15843 | + * @param data Data passed to thread_join. May be NULL. |
| 15844 | + */ |
| 15845 | +VCOSPRE_ void VCOSPOST_ vcos_thread_exit(void *data); |
| 15846 | + |
| 15847 | +/** Wait for a thread to terminate and then clean up its resources. |
| 15848 | + * |
| 15849 | + * @param thread Thread to wait for |
| 15850 | + * @param pData Updated to point at data provided in vcos_thread_exit or exit |
| 15851 | + * code of thread function. |
| 15852 | + */ |
| 15853 | +VCOSPRE_ void VCOSPOST_ vcos_thread_join(VCOS_THREAD_T *thread, |
| 15854 | + void **pData); |
| 15855 | + |
| 15856 | + |
| 15857 | +/** |
| 15858 | + * \brief Create a thread using an API similar to the one "traditionally" |
| 15859 | + * used under Nucleus. |
| 15860 | + * |
| 15861 | + * This creates a thread which must be cleaned up by calling vcos_thread_join(). |
| 15862 | + * The thread cannot be simply terminated (as in Nucleus and ThreadX) as thread |
| 15863 | + * termination is not universally supported. |
| 15864 | + * |
| 15865 | + * @param thread Filled in with thread instance |
| 15866 | + * @param name An optional name for the thread. NULL or "" may be used (but |
| 15867 | + * a name will aid in debugging). |
| 15868 | + * @param entry Entry point |
| 15869 | + * @param arg A single argument passed to the entry point function |
| 15870 | + * @param stack Pointer to stack address |
| 15871 | + * @param stacksz Size of stack in bytes |
| 15872 | + * @param priaff Priority of task, between VCOS_PRI_LOW and VCOS_PRI_HIGH, ORed with the CPU affinity |
| 15873 | + * @param autostart If non-zero the thread will start immediately. |
| 15874 | + * @param timeslice Timeslice (system ticks) for this thread. |
| 15875 | + * |
| 15876 | + * @sa vcos_thread_terminate vcos_thread_delete |
| 15877 | + */ |
| 15878 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create_classic(VCOS_THREAD_T *thread, |
| 15879 | + const char *name, |
| 15880 | + void *(*entry)(void *arg), |
| 15881 | + void *arg, |
| 15882 | + void *stack, |
| 15883 | + VCOS_UNSIGNED stacksz, |
| 15884 | + VCOS_UNSIGNED priaff, |
| 15885 | + VCOS_UNSIGNED timeslice, |
| 15886 | + VCOS_UNSIGNED autostart); |
| 15887 | + |
| 15888 | +/** |
| 15889 | + * \brief Set a thread's priority |
| 15890 | + * |
| 15891 | + * Set the priority for a thread. |
| 15892 | + * |
| 15893 | + * @param thread The thread |
| 15894 | + * @param pri Thread priority in VCOS_PRI_MASK bits; affinity in VCOS_AFFINITY_MASK bits. |
| 15895 | + */ |
| 15896 | +VCOS_INLINE_DECL |
| 15897 | +void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED pri); |
| 15898 | + |
| 15899 | +/** |
| 15900 | + * \brief Return the currently executing thread. |
| 15901 | + * |
| 15902 | + */ |
| 15903 | +VCOS_INLINE_DECL |
| 15904 | +VCOS_THREAD_T *vcos_thread_current(void); |
| 15905 | + |
| 15906 | +/** |
| 15907 | + * \brief Return the thread's priority. |
| 15908 | + */ |
| 15909 | +VCOS_INLINE_DECL |
| 15910 | +VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread); |
| 15911 | + |
| 15912 | +/** |
| 15913 | + * \brief Return the thread's cpu affinity. |
| 15914 | + */ |
| 15915 | +VCOS_INLINE_DECL |
| 15916 | +VCOS_UNSIGNED vcos_thread_get_affinity(VCOS_THREAD_T *thread); |
| 15917 | + |
| 15918 | +/** |
| 15919 | + * \brief Set the thread's cpu affinity. |
| 15920 | + */ |
| 15921 | + |
| 15922 | +VCOS_INLINE_DECL |
| 15923 | +void vcos_thread_set_affinity(VCOS_THREAD_T *thread, VCOS_UNSIGNED affinity); |
| 15924 | + |
| 15925 | +/** |
| 15926 | + * \brief Query whether we are in an interrupt. |
| 15927 | + * |
| 15928 | + * @return 1 if in interrupt context. |
| 15929 | + */ |
| 15930 | +VCOS_INLINE_DECL |
| 15931 | +int vcos_in_interrupt(void); |
| 15932 | + |
| 15933 | +/** |
| 15934 | + * \brief Sleep a while. |
| 15935 | + * |
| 15936 | + * @param ms Number of milliseconds to sleep for |
| 15937 | + * |
| 15938 | + * This may actually sleep a whole number of ticks. |
| 15939 | + */ |
| 15940 | +VCOS_INLINE_DECL |
| 15941 | +void vcos_sleep(uint32_t ms); |
| 15942 | + |
| 15943 | +/** |
| 15944 | + * \brief Return the value of the hardware microsecond counter. |
| 15945 | + * |
| 15946 | + */ |
| 15947 | +VCOS_INLINE_DECL |
| 15948 | +uint32_t vcos_getmicrosecs(void); |
| 15949 | + |
| 15950 | +#define vcos_get_ms() (vcos_getmicrosecs()/1000) |
| 15951 | + |
| 15952 | +/** |
| 15953 | + * \brief Return a unique identifier for the current process |
| 15954 | + * |
| 15955 | + */ |
| 15956 | +VCOS_INLINE_DECL |
| 15957 | +VCOS_UNSIGNED vcos_process_id_current(void); |
| 15958 | + |
| 15959 | +/** Relinquish this time slice. */ |
| 15960 | +VCOS_INLINE_DECL |
| 15961 | +void vcos_thread_relinquish(void); |
| 15962 | + |
| 15963 | +/** Return the name of the given thread. |
| 15964 | + */ |
| 15965 | +VCOSPRE_ const char * VCOSPOST_ vcos_thread_get_name(const VCOS_THREAD_T *thread); |
| 15966 | + |
| 15967 | +/** Change preemption. This is almost certainly not what you want, as it won't |
| 15968 | + * work reliably in a multicore system: although you can affect the preemption |
| 15969 | + * on *this* core, you won't affect what's happening on the other core(s). |
| 15970 | + * |
| 15971 | + * It's mainly here to ease migration. If you're using it in new code, you |
| 15972 | + * probably need to think again. |
| 15973 | + * |
| 15974 | + * @param pe New preemption, VCOS_PREEMPT or VCOS_NO_PREEMPT |
| 15975 | + * @return Old value of preemption. |
| 15976 | + */ |
| 15977 | +VCOS_INLINE_DECL |
| 15978 | +VCOS_UNSIGNED vcos_change_preemption(VCOS_UNSIGNED pe); |
| 15979 | + |
| 15980 | +/** Is a thread still running, or has it exited? |
| 15981 | + * |
| 15982 | + * Note: this exists for some fairly scary code in the video codec tests. Don't |
| 15983 | + * try to use it for anything else, as it may well not do what you expect. |
| 15984 | + * |
| 15985 | + * @param thread thread to query |
| 15986 | + * @return non-zero if thread is running, or zero if it has exited. |
| 15987 | + */ |
| 15988 | +VCOS_INLINE_DECL |
| 15989 | +int vcos_thread_running(VCOS_THREAD_T *thread); |
| 15990 | + |
| 15991 | +/** Resume a thread. |
| 15992 | + * |
| 15993 | + * @param thread thread to resume |
| 15994 | + */ |
| 15995 | +VCOS_INLINE_DECL |
| 15996 | +void vcos_thread_resume(VCOS_THREAD_T *thread); |
| 15997 | + |
| 15998 | +/* |
| 15999 | + * Internal APIs - may not always be present and should not be used in |
| 16000 | + * client code. |
| 16001 | + */ |
| 16002 | + |
| 16003 | +extern void _vcos_task_timer_set(void (*pfn)(void*), void *, VCOS_UNSIGNED ms); |
| 16004 | +extern void _vcos_task_timer_cancel(void); |
| 16005 | + |
| 16006 | +#ifdef __cplusplus |
| 16007 | +} |
| 16008 | +#endif |
| 16009 | +#endif |
| 16010 | --- /dev/null |
| 16011 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_thread_attr.h |
| 16012 | @@ -0,0 +1,73 @@ |
| 16013 | +/*============================================================================= |
| 16014 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 16015 | +All rights reserved. |
| 16016 | + |
| 16017 | +FILE DESCRIPTION |
| 16018 | +VideoCore OS Abstraction Layer - thread attributes |
| 16019 | +=============================================================================*/ |
| 16020 | + |
| 16021 | +#ifndef VCOS_THREAD_ATTR_H |
| 16022 | +#define VCOS_THREAD_ATTR_H |
| 16023 | + |
| 16024 | +#ifdef __cplusplus |
| 16025 | +extern "C" { |
| 16026 | +#endif |
| 16027 | + |
| 16028 | +/** |
| 16029 | + * \file |
| 16030 | + * |
| 16031 | + * Attributes for thread creation. |
| 16032 | + * |
| 16033 | + */ |
| 16034 | + |
| 16035 | +/** Initialize thread attribute struct. This call does not allocate memory, |
| 16036 | + * and so cannot fail. |
| 16037 | + * |
| 16038 | + */ |
| 16039 | +VCOSPRE_ void VCOSPOST_ vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs); |
| 16040 | + |
| 16041 | +/** Set the stack address and size. If not set, a stack will be allocated automatically. |
| 16042 | + * |
| 16043 | + * This can only be set on some platforms. It will always be possible to set the stack |
| 16044 | + * address on VideoCore, but on host platforms, support may well not be available. |
| 16045 | + */ |
| 16046 | +#if VCOS_CAN_SET_STACK_ADDR |
| 16047 | +VCOS_INLINE_DECL |
| 16048 | +void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED sz); |
| 16049 | +#endif |
| 16050 | + |
| 16051 | +/** Set the stack size. If not set, a default size will be used. Attempting to call this after having |
| 16052 | + * set the stack location with vcos_thread_attr_setstack() will result in undefined behaviour. |
| 16053 | + */ |
| 16054 | +VCOS_INLINE_DECL |
| 16055 | +void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED sz); |
| 16056 | + |
| 16057 | +/** Set the task priority. If not set, a default value will be used. |
| 16058 | + */ |
| 16059 | +VCOS_INLINE_DECL |
| 16060 | +void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri); |
| 16061 | + |
| 16062 | +/** Set the task cpu affinity. If not set, the default will be used. |
| 16063 | + */ |
| 16064 | +VCOS_INLINE_DECL |
| 16065 | +void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED aff); |
| 16066 | + |
| 16067 | +/** Set the timeslice. If not set the default will be used. |
| 16068 | + */ |
| 16069 | +VCOS_INLINE_DECL |
| 16070 | +void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts); |
| 16071 | + |
| 16072 | +/** The thread entry function takes (argc,argv), as per Nucleus, with |
| 16073 | + * argc being 0. This may be withdrawn in a future release and should not |
| 16074 | + * be used in new code. |
| 16075 | + */ |
| 16076 | +VCOS_INLINE_DECL |
| 16077 | +void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy); |
| 16078 | + |
| 16079 | +VCOS_INLINE_DECL |
| 16080 | +void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart); |
| 16081 | + |
| 16082 | +#ifdef __cplusplus |
| 16083 | +} |
| 16084 | +#endif |
| 16085 | +#endif |
| 16086 | --- /dev/null |
| 16087 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_timer.h |
| 16088 | @@ -0,0 +1,95 @@ |
| 16089 | +/*============================================================================= |
| 16090 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 16091 | +All rights reserved. |
| 16092 | + |
| 16093 | +Project : vcfw |
| 16094 | +Module : chip driver |
| 16095 | + |
| 16096 | +FILE DESCRIPTION |
| 16097 | +VideoCore OS Abstraction Layer - timer support |
| 16098 | +=============================================================================*/ |
| 16099 | + |
| 16100 | +#ifndef VCOS_TIMER_H |
| 16101 | +#define VCOS_TIMER_H |
| 16102 | + |
| 16103 | +#ifdef __cplusplus |
| 16104 | +extern "C" { |
| 16105 | +#endif |
| 16106 | + |
| 16107 | +#include "interface/vcos/vcos_types.h" |
| 16108 | +#include "vcos_platform.h" |
| 16109 | + |
| 16110 | +/** \file vcos_timer.h |
| 16111 | + * |
| 16112 | + * Timers are single shot. |
| 16113 | + * |
| 16114 | + * Timer times are in milliseconds. |
| 16115 | + * |
| 16116 | + * \note that timer callback functions are called from an arbitrary thread |
| 16117 | + * context. The expiration function should do its work as quickly as possible; |
| 16118 | + * blocking should be avoided. |
| 16119 | + * |
| 16120 | + * \note On Windows, the separate function vcos_timer_init() must be called |
| 16121 | + * as timer initialization from DllMain is not possible. |
| 16122 | + */ |
| 16123 | + |
| 16124 | +/** Perform timer subsystem initialization. This function is not needed |
| 16125 | + * on non-Windows platforms but is still present so that it can be |
| 16126 | + * called. On Windows it is needed because vcos_init() gets called |
| 16127 | + * from DLL initialization where it is not possible to create a |
| 16128 | + * time queue (deadlock occurs if you try). |
| 16129 | + * |
| 16130 | + * @return VCOS_SUCCESS on success. VCOS_EEXIST if this has already been called |
| 16131 | + * once. VCOS_ENOMEM if resource allocation failed. |
| 16132 | + */ |
| 16133 | +VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_timer_init(void); |
| 16134 | + |
| 16135 | +/** Create a timer in a disabled state. |
| 16136 | + * |
| 16137 | + * The timer is initially disabled. |
| 16138 | + * |
| 16139 | + * @param timer timer handle |
| 16140 | + * @param name name for timer |
| 16141 | + * @param expiration_routine function to call when timer expires |
| 16142 | + * @param context context passed to expiration routine |
| 16143 | + * |
| 16144 | + */ |
| 16145 | +VCOS_INLINE_DECL |
| 16146 | +VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer, |
| 16147 | + const char *name, |
| 16148 | + void (*expiration_routine)(void *context), |
| 16149 | + void *context); |
| 16150 | + |
| 16151 | + |
| 16152 | + |
| 16153 | +/** Start a timer running. |
| 16154 | + * |
| 16155 | + * Timer must be stopped. |
| 16156 | + * |
| 16157 | + * @param timer timer handle |
| 16158 | + * @param delay Delay to wait for, in ms |
| 16159 | + */ |
| 16160 | +VCOS_INLINE_DECL |
| 16161 | +void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay); |
| 16162 | + |
| 16163 | +/** Stop an already running timer. |
| 16164 | + * |
| 16165 | + * @param timer timer handle |
| 16166 | + */ |
| 16167 | +VCOS_INLINE_DECL |
| 16168 | +void vcos_timer_cancel(VCOS_TIMER_T *timer); |
| 16169 | + |
| 16170 | +/** Stop a timer and restart it. |
| 16171 | + * @param timer timer handle |
| 16172 | + * @param delay delay in ms |
| 16173 | + */ |
| 16174 | +VCOS_INLINE_DECL |
| 16175 | +void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay); |
| 16176 | + |
| 16177 | +VCOS_INLINE_DECL |
| 16178 | +void vcos_timer_delete(VCOS_TIMER_T *timer); |
| 16179 | + |
| 16180 | +#ifdef __cplusplus |
| 16181 | +} |
| 16182 | +#endif |
| 16183 | +#endif |
| 16184 | --- /dev/null |
| 16185 | +++ b/drivers/misc/vc04_services/interface/vcos/vcos_types.h |
| 16186 | @@ -0,0 +1,197 @@ |
| 16187 | +/*============================================================================= |
| 16188 | +Copyright (c) 2009 Broadcom Europe Limited. |
| 16189 | +All rights reserved. |
| 16190 | + |
| 16191 | +FILE DESCRIPTION |
| 16192 | +VideoCore OS Abstraction Layer - basic types |
| 16193 | +=============================================================================*/ |
| 16194 | + |
| 16195 | +#ifndef VCOS_TYPES_H |
| 16196 | +#define VCOS_TYPES_H |
| 16197 | + |
| 16198 | +#define VCOS_VERSION 1 |
| 16199 | + |
| 16200 | +#include "vcos_platform_types.h" |
| 16201 | + |
| 16202 | +#if !defined(VCOSPRE_) || !defined(VCOSPOST_) |
| 16203 | +#error VCOSPRE_ and VCOSPOST_ not defined! |
| 16204 | +#endif |
| 16205 | + |
| 16206 | +/* Redefine these here; this means that existing header files can carry on |
| 16207 | + * using the VCHPOST/VCHPRE macros rather than having huge changes, which |
| 16208 | + * could cause nasty merge problems. |
| 16209 | + */ |
| 16210 | +#ifndef VCHPOST_ |
| 16211 | +#define VCHPOST_ VCOSPOST_ |
| 16212 | +#endif |
| 16213 | +#ifndef VCHPRE_ |
| 16214 | +#define VCHPRE_ VCOSPRE_ |
| 16215 | +#endif |
| 16216 | + |
| 16217 | +/** Entry function for a lowlevel thread. |
| 16218 | + * |
| 16219 | + * Returns void for consistency with Nucleus/ThreadX. |
| 16220 | + */ |
| 16221 | +typedef void (*VCOS_LLTHREAD_ENTRY_FN_T)(void *); |
| 16222 | + |
| 16223 | +/** Thread entry point. Returns a void* for consistency |
| 16224 | + * with pthreads. |
| 16225 | + */ |
| 16226 | +typedef void *(*VCOS_THREAD_ENTRY_FN_T)(void*); |
| 16227 | + |
| 16228 | + |
| 16229 | +/* Error return codes - chosen to be similar to errno values */ |
| 16230 | +typedef enum |
| 16231 | +{ |
| 16232 | + VCOS_SUCCESS, |
| 16233 | + VCOS_EAGAIN, |
| 16234 | + VCOS_ENOENT, |
| 16235 | + VCOS_ENOSPC, |
| 16236 | + VCOS_EINVAL, |
| 16237 | + VCOS_EACCESS, |
| 16238 | + VCOS_ENOMEM, |
| 16239 | + VCOS_ENOSYS, |
| 16240 | + VCOS_EEXIST, |
| 16241 | + VCOS_ENXIO, |
| 16242 | + VCOS_EINTR |
| 16243 | +} VCOS_STATUS_T; |
| 16244 | + |
| 16245 | +/* Some compilers (MetaWare) won't inline with -g turned on, which then results |
| 16246 | + * in a lot of code bloat. To overcome this, inline functions are forward declared |
| 16247 | + * with the prefix VCOS_INLINE_DECL, and implemented with the prefix VCOS_INLINE_IMPL. |
| 16248 | + * |
| 16249 | + * That then means that in a release build, "static inline" can be used in the obvious |
| 16250 | + * way, but in a debug build the implementations can be skipped in all but one file, |
| 16251 | + * by using VCOS_INLINE_BODIES. |
| 16252 | + * |
| 16253 | + * VCOS_INLINE_DECL - put this at the start of an inline forward declaration of a VCOS |
| 16254 | + * function. |
| 16255 | + * |
| 16256 | + * VCOS_INLINE_IMPL - put this at the start of an inlined implementation of a VCOS |
| 16257 | + * function. |
| 16258 | + * |
| 16259 | + */ |
| 16260 | + |
| 16261 | +/* VCOS_EXPORT - it turns out that in some circumstances we need the implementation of |
| 16262 | + * a function even if it is usually inlined. |
| 16263 | + * |
| 16264 | + * In particular, if we have a codec that is usually provided in object form, if it |
| 16265 | + * was built for a debug build it will be full of calls to vcos_XXX(). If this is used |
| 16266 | + * in a *release* build, then there won't be any of these calls around in the main image |
| 16267 | + * as they will all have been inlined. The problem also exists for vcos functions called |
| 16268 | + * from assembler. |
| 16269 | + * |
| 16270 | + * VCOS_EXPORT ensures that the named function will be emitted as a regular (not static-inline) |
| 16271 | + * function inside vcos_<platform>.c so that it can be linked against. Doing this for every |
| 16272 | + * VCOS function would be a bit code-bloat-tastic, so it is only done for those that need it. |
| 16273 | + * |
| 16274 | + */ |
| 16275 | + |
| 16276 | +#ifdef __cplusplus |
| 16277 | +#define _VCOS_INLINE inline |
| 16278 | +#else |
| 16279 | +#define _VCOS_INLINE __inline |
| 16280 | +#endif |
| 16281 | + |
| 16282 | +#if defined(NDEBUG) |
| 16283 | + |
| 16284 | +#ifdef __GNUC__ |
| 16285 | +# define VCOS_INLINE_DECL extern __inline__ |
| 16286 | +# define VCOS_INLINE_IMPL static __inline__ |
| 16287 | +#else |
| 16288 | +# define VCOS_INLINE_DECL static _VCOS_INLINE /* declare a func */ |
| 16289 | +# define VCOS_INLINE_IMPL static _VCOS_INLINE /* implement a func inline */ |
| 16290 | +#endif |
| 16291 | + |
| 16292 | +# if defined(VCOS_WANT_IMPL) |
| 16293 | +# define VCOS_EXPORT |
| 16294 | +# else |
| 16295 | +# define VCOS_EXPORT VCOS_INLINE_IMPL |
| 16296 | +# endif /* VCOS_WANT_IMPL */ |
| 16297 | + |
| 16298 | +#define VCOS_INLINE_BODIES |
| 16299 | + |
| 16300 | +#else /* NDEBUG */ |
| 16301 | + |
| 16302 | +#if !defined(VCOS_INLINE_DECL) |
| 16303 | + #define VCOS_INLINE_DECL extern |
| 16304 | +#endif |
| 16305 | +#if !defined(VCOS_INLINE_IMPL) |
| 16306 | + #define VCOS_INLINE_IMPL |
| 16307 | +#endif |
| 16308 | +#define VCOS_EXPORT VCOS_INLINE_IMPL |
| 16309 | +#endif |
| 16310 | + |
| 16311 | +#define VCOS_STATIC_INLINE static _VCOS_INLINE |
| 16312 | + |
| 16313 | +#if defined(__HIGHC__) || defined(__HIGHC_ANSI__) |
| 16314 | +#define _VCOS_METAWARE |
| 16315 | +#endif |
| 16316 | + |
| 16317 | +/** It seems that __FUNCTION__ isn't standard! |
| 16318 | + */ |
| 16319 | +#if __STDC_VERSION__ < 199901L |
| 16320 | +# if __GNUC__ >= 2 || defined(__VIDEOCORE__) |
| 16321 | +# define VCOS_FUNCTION __FUNCTION__ |
| 16322 | +# else |
| 16323 | +# define VCOS_FUNCTION "<unknown>" |
| 16324 | +# endif |
| 16325 | +#else |
| 16326 | +# define VCOS_FUNCTION __func__ |
| 16327 | +#endif |
| 16328 | + |
| 16329 | +#define _VCOS_MS_PER_TICK (1000/VCOS_TICKS_PER_SECOND) |
| 16330 | + |
| 16331 | +/* Convert a number of milliseconds to a tick count. Internal use only - fails to |
| 16332 | + * convert VCOS_SUSPEND correctly. |
| 16333 | + */ |
| 16334 | +#define _VCOS_MS_TO_TICKS(ms) (((ms)+_VCOS_MS_PER_TICK-1)/_VCOS_MS_PER_TICK) |
| 16335 | + |
| 16336 | +#define VCOS_TICKS_TO_MS(ticks) ((ticks) * _VCOS_MS_PER_TICK) |
| 16337 | + |
| 16338 | +/** VCOS version of DATESTR, from pcdisk.h. Used by the hostreq service. |
| 16339 | + */ |
| 16340 | +typedef struct vcos_datestr |
| 16341 | +{ |
| 16342 | + uint8_t cmsec; /**< Centesimal mili second */ |
| 16343 | + uint16_t date; /**< Date */ |
| 16344 | + uint16_t time; /**< Time */ |
| 16345 | + |
| 16346 | +} VCOS_DATESTR; |
| 16347 | + |
| 16348 | +/* Compile-time assert - declares invalid array length if condition |
| 16349 | + * not met, or array of length one if OK. |
| 16350 | + */ |
| 16351 | +#define VCOS_CASSERT(e) extern char vcos_compile_time_check[1/(e)] |
| 16352 | + |
| 16353 | +#define vcos_min(x,y) ((x) < (y) ? (x) : (y)) |
| 16354 | +#define vcos_max(x,y) ((x) > (y) ? (x) : (y)) |
| 16355 | + |
| 16356 | +/** Return the count of an array. FIXME: under gcc we could make |
| 16357 | + * this report an error for pointers using __builtin_types_compatible(). |
| 16358 | + */ |
| 16359 | +#define vcos_countof(x) (sizeof((x)) / sizeof((x)[0])) |
| 16360 | + |
| 16361 | +/* for backward compatibility */ |
| 16362 | +#define countof(x) (sizeof((x)) / sizeof((x)[0])) |
| 16363 | + |
| 16364 | +#define VCOS_ALIGN_DOWN(p,n) (((ptrdiff_t)(p)) & ~((n)-1)) |
| 16365 | +#define VCOS_ALIGN_UP(p,n) VCOS_ALIGN_DOWN((ptrdiff_t)(p)+(n)-1,(n)) |
| 16366 | + |
| 16367 | +/** bool_t is not a POSIX type so cannot rely on it. Define it here. |
| 16368 | + * It's not even defined in stdbool.h. |
| 16369 | + */ |
| 16370 | +typedef int32_t vcos_bool_t; |
| 16371 | +typedef int32_t vcos_fourcc_t; |
| 16372 | + |
| 16373 | +#define VCOS_FALSE 0 |
| 16374 | +#define VCOS_TRUE (!VCOS_FALSE) |
| 16375 | + |
| 16376 | +/** Mark unused arguments to keep compilers quiet */ |
| 16377 | +#define vcos_unused(x) (void)(x) |
| 16378 | + |
| 16379 | +/** For backward compatibility */ |
| 16380 | +typedef vcos_fourcc_t fourcc_t; |
| 16381 | +typedef vcos_fourcc_t FOURCC_T; |
| 16382 | + |
| 16383 | +#endif |
| 16384 | |