Add a new ioctl, GPIOPULSE to gpio(4) to allow for pulsing a pin. If a pin can pulse in hardware, that will be used, else it will be pulsed in software. There is no way yet to set the pulse frequency for pins that pulse in hardware. While here, make the code mpsafe and allow more than one thread in the driver (access to ioctl is serialized).diff -r1.18 -r1.19 src/share/man/man4/gpio.4
(mbalmer)
--- src/share/man/man4/gpio.4 2010/03/22 18:58:31 1.18
+++ src/share/man/man4/gpio.4 2011/08/28 07:48:50 1.19
--- src/sys/dev/gpio/gpio.c 2011/08/12 08:00:52 1.35
+++ src/sys/dev/gpio/gpio.c 2011/08/28 07:48:50 1.36
@@ -1,104 +1,114 @@ | @@ -1,104 +1,114 @@ | |||
1 | /* $NetBSD: gpio.c,v 1.35 2011/08/12 08:00:52 mbalmer Exp $ */ | 1 | /* $NetBSD: gpio.c,v 1.36 2011/08/28 07:48:50 mbalmer Exp $ */ | |
2 | /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */ | 2 | /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2008, 2009, 2010, 2011 Marc Balmer <marc@msys.ch> | 5 | * Copyright (c) 2008, 2009, 2010, 2011 Marc Balmer <marc@msys.ch> | |
6 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> | 6 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> | |
7 | * | 7 | * | |
8 | * Permission to use, copy, modify, and distribute this software for any | 8 | * Permission to use, copy, modify, and distribute this software for any | |
9 | * purpose with or without fee is hereby granted, provided that the above | 9 | * purpose with or without fee is hereby granted, provided that the above | |
10 | * copyright notice and this permission notice appear in all copies. | 10 | * copyright notice and this permission notice appear in all copies. | |
11 | * | 11 | * | |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
19 | */ | 19 | */ | |
20 | 20 | |||
21 | #include <sys/cdefs.h> | 21 | #include <sys/cdefs.h> | |
22 | __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.35 2011/08/12 08:00:52 mbalmer Exp $"); | 22 | __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.36 2011/08/28 07:48:50 mbalmer Exp $"); | |
23 | 23 | |||
24 | /* | 24 | /* | |
25 | * General Purpose Input/Output framework. | 25 | * General Purpose Input/Output framework. | |
26 | */ | 26 | */ | |
27 | 27 | |||
28 | #include <sys/param.h> | 28 | #include <sys/param.h> | |
29 | #include <sys/callout.h> | |||
29 | #include <sys/systm.h> | 30 | #include <sys/systm.h> | |
30 | #include <sys/conf.h> | 31 | #include <sys/conf.h> | |
31 | #include <sys/device.h> | 32 | #include <sys/device.h> | |
32 | #include <sys/fcntl.h> | 33 | #include <sys/fcntl.h> | |
33 | #include <sys/ioctl.h> | 34 | #include <sys/ioctl.h> | |
34 | #include <sys/gpio.h> | 35 | #include <sys/gpio.h> | |
36 | #include <sys/kernel.h> | |||
35 | #include <sys/vnode.h> | 37 | #include <sys/vnode.h> | |
36 | #include <sys/kmem.h> | 38 | #include <sys/kmem.h> | |
39 | #include <sys/mutex.h> | |||
40 | #include <sys/condvar.h> | |||
37 | #include <sys/queue.h> | 41 | #include <sys/queue.h> | |
38 | #include <sys/kauth.h> | 42 | #include <sys/kauth.h> | |
39 | #ifdef _MODULE | 43 | #ifdef _MODULE | |
40 | #include <sys/module.h> | 44 | #include <sys/module.h> | |
41 | #endif | 45 | #endif | |
42 | #include <dev/gpio/gpiovar.h> | 46 | #include <dev/gpio/gpiovar.h> | |
43 | 47 | |||
44 | #include "locators.h" | 48 | #include "locators.h" | |
45 | 49 | |||
46 | #ifdef GPIO_DEBUG | 50 | #ifdef GPIO_DEBUG | |
47 | #define DPRINTFN(n, x) do { if (gpiodebug > (n)) printf x; } while (0) | 51 | #define DPRINTFN(n, x) do { if (gpiodebug > (n)) printf x; } while (0) | |
48 | int gpiodebug = 0; | 52 | int gpiodebug = 0; | |
49 | #else | 53 | #else | |
50 | #define DPRINTFN(n, x) | 54 | #define DPRINTFN(n, x) | |
51 | #endif | 55 | #endif | |
52 | #define DPRINTF(x) DPRINTFN(0, x) | 56 | #define DPRINTF(x) DPRINTFN(0, x) | |
53 | 57 | |||
54 | struct gpio_softc { | 58 | struct gpio_softc { | |
55 | device_t sc_dev; | 59 | device_t sc_dev; | |
56 | 60 | |||
57 | gpio_chipset_tag_t sc_gc; /* GPIO controller */ | 61 | gpio_chipset_tag_t sc_gc; /* GPIO controller */ | |
58 | gpio_pin_t *sc_pins; /* pins array */ | 62 | gpio_pin_t *sc_pins; /* pins array */ | |
59 | int sc_npins; /* number of pins */ | 63 | int sc_npins; /* number of pins */ | |
60 | 64 | |||
61 | int sc_opened; | 65 | kmutex_t sc_mtx; | |
66 | kcondvar_t sc_ioctl; /* ioctl in progress */ | |||
67 | int sc_ioctl_busy; /* ioctl is busy */ | |||
62 | LIST_HEAD(, gpio_dev) sc_devs; /* devices */ | 68 | LIST_HEAD(, gpio_dev) sc_devs; /* devices */ | |
63 | LIST_HEAD(, gpio_name) sc_names; /* named pins */ | 69 | LIST_HEAD(, gpio_name) sc_names; /* named pins */ | |
64 | }; | 70 | }; | |
65 | 71 | |||
66 | static int gpio_match(device_t, cfdata_t, void *); | 72 | static int gpio_match(device_t, cfdata_t, void *); | |
67 | int gpio_submatch(device_t, cfdata_t, const int *, void *); | 73 | int gpio_submatch(device_t, cfdata_t, const int *, void *); | |
68 | static void gpio_attach(device_t, device_t, void *); | 74 | static void gpio_attach(device_t, device_t, void *); | |
69 | static int gpio_rescan(device_t, const char *, const int *); | 75 | static int gpio_rescan(device_t, const char *, const int *); | |
70 | static void gpio_childdetached(device_t, device_t); | 76 | static void gpio_childdetached(device_t, device_t); | |
71 | static bool gpio_resume(device_t, const pmf_qual_t *); | 77 | static bool gpio_resume(device_t, const pmf_qual_t *); | |
72 | static int gpio_detach(device_t, int); | 78 | static int gpio_detach(device_t, int); | |
73 | static int gpio_search(device_t, cfdata_t, const int *, void *); | 79 | static int gpio_search(device_t, cfdata_t, const int *, void *); | |
74 | static int gpio_print(void *, const char *); | 80 | static int gpio_print(void *, const char *); | |
75 | static int gpio_pinbyname(struct gpio_softc *, char *); | 81 | static int gpio_pinbyname(struct gpio_softc *, char *); | |
82 | static void gpio_pulse(void *); | |||
83 | static int gpio_ioctl(struct gpio_softc *, u_long, void *, int, | |||
84 | struct lwp *); | |||
76 | 85 | |||
77 | /* Old API */ | 86 | /* Old API */ | |
78 | static int gpio_ioctl_oapi(struct gpio_softc *, u_long, void *, int, | 87 | static int gpio_ioctl_oapi(struct gpio_softc *, u_long, void *, int, | |
79 | kauth_cred_t); | 88 | kauth_cred_t); | |
80 | 89 | |||
81 | CFATTACH_DECL3_NEW(gpio, sizeof(struct gpio_softc), | 90 | CFATTACH_DECL3_NEW(gpio, sizeof(struct gpio_softc), | |
82 | gpio_match, gpio_attach, gpio_detach, NULL, gpio_rescan, | 91 | gpio_match, gpio_attach, gpio_detach, NULL, gpio_rescan, | |
83 | gpio_childdetached, DVF_DETACH_SHUTDOWN); | 92 | gpio_childdetached, DVF_DETACH_SHUTDOWN); | |
84 | 93 | |||
85 | dev_type_open(gpioopen); | 94 | dev_type_open(gpioopen); | |
86 | dev_type_close(gpioclose); | 95 | dev_type_close(gpioclose); | |
87 | dev_type_ioctl(gpioioctl); | 96 | dev_type_ioctl(gpioioctl); | |
97 | dev_type_ioctl(gpioioctl_locked); | |||
88 | 98 | |||
89 | const struct cdevsw gpio_cdevsw = { | 99 | const struct cdevsw gpio_cdevsw = { | |
90 | gpioopen, gpioclose, noread, nowrite, gpioioctl, | 100 | gpioopen, gpioclose, noread, nowrite, gpioioctl, | |
91 | nostop, notty, nopoll, nommap, nokqfilter, D_OTHER, | 101 | nostop, notty, nopoll, nommap, nokqfilter, D_OTHER | D_MPSAFE | |
92 | }; | 102 | }; | |
93 | 103 | |||
94 | extern struct cfdriver gpio_cd; | 104 | extern struct cfdriver gpio_cd; | |
95 | 105 | |||
96 | static int | 106 | static int | |
97 | gpio_match(device_t parent, cfdata_t cf, void *aux) | 107 | gpio_match(device_t parent, cfdata_t cf, void *aux) | |
98 | { | 108 | { | |
99 | return 1; | 109 | return 1; | |
100 | } | 110 | } | |
101 | 111 | |||
102 | int | 112 | int | |
103 | gpio_submatch(device_t parent, cfdata_t cf, const int *ip, void *aux) | 113 | gpio_submatch(device_t parent, cfdata_t cf, const int *ip, void *aux) | |
104 | { | 114 | { | |
@@ -134,52 +144,71 @@ gpio_rescan(device_t self, const char *i | @@ -134,52 +144,71 @@ gpio_rescan(device_t self, const char *i | |||
134 | { | 144 | { | |
135 | struct gpio_softc *sc = device_private(self); | 145 | struct gpio_softc *sc = device_private(self); | |
136 | 146 | |||
137 | config_search_loc(gpio_search, self, ifattr, locators, sc); | 147 | config_search_loc(gpio_search, self, ifattr, locators, sc); | |
138 | 148 | |||
139 | return 0; | 149 | return 0; | |
140 | } | 150 | } | |
141 | 151 | |||
142 | static void | 152 | static void | |
143 | gpio_attach(device_t parent, device_t self, void *aux) | 153 | gpio_attach(device_t parent, device_t self, void *aux) | |
144 | { | 154 | { | |
145 | struct gpio_softc *sc = device_private(self); | 155 | struct gpio_softc *sc = device_private(self); | |
146 | struct gpiobus_attach_args *gba = aux; | 156 | struct gpiobus_attach_args *gba = aux; | |
147 | 157 | int pin; | ||
148 | sc->sc_dev = self; | 158 | sc->sc_dev = self; | |
149 | sc->sc_gc = gba->gba_gc; | 159 | sc->sc_gc = gba->gba_gc; | |
150 | sc->sc_pins = gba->gba_pins; | 160 | sc->sc_pins = gba->gba_pins; | |
151 | sc->sc_npins = gba->gba_npins; | 161 | sc->sc_npins = gba->gba_npins; | |
152 | 162 | |||
153 | printf(": %d pins\n", sc->sc_npins); | 163 | printf(": %d pins\n", sc->sc_npins); | |
154 | 164 | |||
165 | for (pin = 0; pin < sc->sc_npins; pin++) { | |||
166 | callout_init(&sc->sc_pins[pin].pin_pulse, CALLOUT_MPSAFE); | |||
167 | callout_setfunc(&sc->sc_pins[pin].pin_pulse, gpio_pulse, | |||
168 | &sc->sc_pins[pin]); | |||
169 | } | |||
155 | if (!pmf_device_register(self, NULL, gpio_resume)) | 170 | if (!pmf_device_register(self, NULL, gpio_resume)) | |
156 | aprint_error_dev(self, "couldn't establish power handler\n"); | 171 | aprint_error_dev(self, "couldn't establish power handler\n"); | |
172 | mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM); | |||
173 | cv_init(&sc->sc_ioctl, "gpioctl"); | |||
157 | 174 | |||
158 | /* | 175 | /* | |
159 | * Attach all devices that can be connected to the GPIO pins | 176 | * Attach all devices that can be connected to the GPIO pins | |
160 | * described in the kernel configuration file. | 177 | * described in the kernel configuration file. | |
161 | */ | 178 | */ | |
162 | gpio_rescan(self, "gpio", NULL); | 179 | gpio_rescan(self, "gpio", NULL); | |
163 | } | 180 | } | |
164 | 181 | |||
165 | static int | 182 | static int | |
166 | gpio_detach(device_t self, int flags) | 183 | gpio_detach(device_t self, int flags) | |
167 | { | 184 | { | |
168 | int rc; | 185 | struct gpio_softc *sc; | |
186 | int pin, rc; | |||
187 | ||||
188 | sc = device_private(self); | |||
189 | ||||
190 | for (pin = 0; pin < sc->sc_npins; pin++) { | |||
191 | if (sc->sc_pins[pin].pin_state & GPIO_PIN_PULSE) { | |||
192 | callout_halt(&sc->sc_pins[pin].pin_pulse, NULL); | |||
193 | callout_destroy(&sc->sc_pins[pin].pin_pulse); | |||
194 | sc->sc_pins[pin].pin_state &= ~GPIO_PIN_PULSE; | |||
195 | } | |||
196 | } | |||
169 | 197 | |||
170 | if ((rc = config_detach_children(self, flags)) != 0) | 198 | if ((rc = config_detach_children(self, flags)) != 0) | |
171 | return rc; | 199 | return rc; | |
172 | 200 | mutex_destroy(&sc->sc_mtx); | ||
201 | cv_destroy(&sc->sc_ioctl); | |||
173 | #if 0 | 202 | #if 0 | |
174 | int maj, mn; | 203 | int maj, mn; | |
175 | 204 | |||
176 | /* Locate the major number */ | 205 | /* Locate the major number */ | |
177 | for (maj = 0; maj < nchrdev; maj++) | 206 | for (maj = 0; maj < nchrdev; maj++) | |
178 | if (cdevsw[maj].d_open == gpioopen) | 207 | if (cdevsw[maj].d_open == gpioopen) | |
179 | break; | 208 | break; | |
180 | 209 | |||
181 | /* Nuke the vnodes for any open instances (calls close) */ | 210 | /* Nuke the vnodes for any open instances (calls close) */ | |
182 | mn = device_unit(self); | 211 | mn = device_unit(self); | |
183 | vdevgone(maj, mn, mn, VCHR); | 212 | vdevgone(maj, mn, mn, VCHR); | |
184 | #endif | 213 | #endif | |
185 | return 0; | 214 | return 0; | |
@@ -218,49 +247,49 @@ int | @@ -218,49 +247,49 @@ int | |||
218 | gpiobus_print(void *aux, const char *pnp) | 247 | gpiobus_print(void *aux, const char *pnp) | |
219 | { | 248 | { | |
220 | #if 0 | 249 | #if 0 | |
221 | struct gpiobus_attach_args *gba = aux; | 250 | struct gpiobus_attach_args *gba = aux; | |
222 | #endif | 251 | #endif | |
223 | if (pnp != NULL) | 252 | if (pnp != NULL) | |
224 | aprint_normal("gpiobus at %s", pnp); | 253 | aprint_normal("gpiobus at %s", pnp); | |
225 | 254 | |||
226 | return UNCONF; | 255 | return UNCONF; | |
227 | } | 256 | } | |
228 | 257 | |||
229 | /* return 1 if all pins can be mapped, 0 if not */ | 258 | /* return 1 if all pins can be mapped, 0 if not */ | |
230 | int | 259 | int | |
231 | gpio_pin_can_map(void *gpio, int offset, u_int32_t mask) | 260 | gpio_pin_can_map(void *gpio, int offset, uint32_t mask) | |
232 | { | 261 | { | |
233 | struct gpio_softc *sc = gpio; | 262 | struct gpio_softc *sc = gpio; | |
234 | int npins, pin, i; | 263 | int npins, pin, i; | |
235 | 264 | |||
236 | npins = gpio_npins(mask); | 265 | npins = gpio_npins(mask); | |
237 | if (npins > sc->sc_npins) | 266 | if (npins > sc->sc_npins) | |
238 | return 0; | 267 | return 0; | |
239 | 268 | |||
240 | for (npins = 0, i = 0; i < 32; i++) | 269 | for (npins = 0, i = 0; i < 32; i++) | |
241 | if (mask & (1 << i)) { | 270 | if (mask & (1 << i)) { | |
242 | pin = offset + i; | 271 | pin = offset + i; | |
243 | if (pin < 0 || pin >= sc->sc_npins) | 272 | if (pin < 0 || pin >= sc->sc_npins) | |
244 | return 0; | 273 | return 0; | |
245 | if (sc->sc_pins[pin].pin_mapped) | 274 | if (sc->sc_pins[pin].pin_mapped) | |
246 | return 0; | 275 | return 0; | |
247 | } | 276 | } | |
248 | 277 | |||
249 | return 1; | 278 | return 1; | |
250 | } | 279 | } | |
251 | 280 | |||
252 | int | 281 | int | |
253 | gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map) | 282 | gpio_pin_map(void *gpio, int offset, uint32_t mask, struct gpio_pinmap *map) | |
254 | { | 283 | { | |
255 | struct gpio_softc *sc = gpio; | 284 | struct gpio_softc *sc = gpio; | |
256 | int npins, pin, i; | 285 | int npins, pin, i; | |
257 | 286 | |||
258 | npins = gpio_npins(mask); | 287 | npins = gpio_npins(mask); | |
259 | if (npins > sc->sc_npins) | 288 | if (npins > sc->sc_npins) | |
260 | return 1; | 289 | return 1; | |
261 | 290 | |||
262 | for (npins = 0, i = 0; i < 32; i++) | 291 | for (npins = 0, i = 0; i < 32; i++) | |
263 | if (mask & (1 << i)) { | 292 | if (mask & (1 << i)) { | |
264 | pin = offset + i; | 293 | pin = offset + i; | |
265 | if (pin < 0 || pin >= sc->sc_npins) | 294 | if (pin < 0 || pin >= sc->sc_npins) | |
266 | return 1; | 295 | return 1; | |
@@ -310,196 +339,289 @@ gpio_pin_ctl(void *gpio, struct gpio_pin | @@ -310,196 +339,289 @@ gpio_pin_ctl(void *gpio, struct gpio_pin | |||
310 | 339 | |||
311 | return gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags); | 340 | return gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags); | |
312 | } | 341 | } | |
313 | 342 | |||
314 | int | 343 | int | |
315 | gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin) | 344 | gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin) | |
316 | { | 345 | { | |
317 | struct gpio_softc *sc = gpio; | 346 | struct gpio_softc *sc = gpio; | |
318 | 347 | |||
319 | return sc->sc_pins[map->pm_map[pin]].pin_caps; | 348 | return sc->sc_pins[map->pm_map[pin]].pin_caps; | |
320 | } | 349 | } | |
321 | 350 | |||
322 | int | 351 | int | |
323 | gpio_npins(u_int32_t mask) | 352 | gpio_npins(uint32_t mask) | |
324 | { | 353 | { | |
325 | int npins, i; | 354 | int npins, i; | |
326 | 355 | |||
327 | for (npins = 0, i = 0; i < 32; i++) | 356 | for (npins = 0, i = 0; i < 32; i++) | |
328 | if (mask & (1 << i)) | 357 | if (mask & (1 << i)) | |
329 | npins++; | 358 | npins++; | |
330 | 359 | |||
331 | return npins; | 360 | return npins; | |
332 | } | 361 | } | |
333 | 362 | |||
334 | int | 363 | int | |
364 | gpio_lock(void *data) | |||
365 | { | |||
366 | struct gpio_softc *sc; | |||
367 | int error; | |||
368 | ||||
369 | error = 0; | |||
370 | sc = (struct gpio_softc *)data; | |||
371 | mutex_enter(&sc->sc_mtx); | |||
372 | while (sc->sc_ioctl_busy) { | |||
373 | error = cv_wait_sig(&sc->sc_ioctl, &sc->sc_mtx); | |||
374 | if (error) | |||
375 | break; | |||
376 | } | |||
377 | if (!error) | |||
378 | sc->sc_ioctl_busy = 1; | |||
379 | mutex_exit(&sc->sc_mtx); | |||
380 | return error; | |||
381 | } | |||
382 | ||||
383 | void | |||
384 | gpio_unlock(void *data) | |||
385 | { | |||
386 | struct gpio_softc *sc; | |||
387 | ||||
388 | sc = (struct gpio_softc *)data; | |||
389 | mutex_enter(&sc->sc_mtx); | |||
390 | sc->sc_ioctl_busy = 0; | |||
391 | cv_signal(&sc->sc_ioctl); | |||
392 | mutex_exit(&sc->sc_mtx); | |||
393 | } | |||
394 | ||||
395 | int | |||
335 | gpioopen(dev_t dev, int flag, int mode, struct lwp *l) | 396 | gpioopen(dev_t dev, int flag, int mode, struct lwp *l) | |
336 | { | 397 | { | |
337 | struct gpio_softc *sc; | 398 | struct gpio_softc *sc; | |
338 | int ret; | |||
339 | 399 | |||
340 | sc = device_lookup_private(&gpio_cd, minor(dev)); | 400 | sc = device_lookup_private(&gpio_cd, minor(dev)); | |
341 | if (sc == NULL) | 401 | if (sc == NULL) | |
342 | return ENXIO; | 402 | return ENXIO; | |
343 | DPRINTF(("%s: opening\n", device_xname(sc->sc_dev))); | |||
344 | if (sc->sc_opened) { | |||
345 | DPRINTF(("%s: already opened\n", device_xname(sc->sc_dev))); | |||
346 | return EBUSY; | |||
347 | } | |||
348 | ||||
349 | if ((ret = gpiobus_open(sc->sc_gc, sc->sc_dev))) { | |||
350 | DPRINTF(("%s: gpiobus_open returned %d\n", | |||
351 | device_xname(sc->sc_dev), | |||
352 | ret)); | |||
353 | return ret; | |||
354 | } | |||
355 | ||||
356 | sc->sc_opened = 1; | |||
357 | 403 | |||
358 | return 0; | 404 | return gpiobus_open(sc->sc_gc, sc->sc_dev); | |
359 | } | 405 | } | |
360 | 406 | |||
361 | int | 407 | int | |
362 | gpioclose(dev_t dev, int flag, int mode, struct lwp *l) | 408 | gpioclose(dev_t dev, int flag, int mode, struct lwp *l) | |
363 | { | 409 | { | |
364 | struct gpio_softc *sc; | 410 | struct gpio_softc *sc; | |
365 | 411 | |||
366 | sc = device_lookup_private(&gpio_cd, minor(dev)); | 412 | sc = device_lookup_private(&gpio_cd, minor(dev)); | |
367 | DPRINTF(("%s: closing\n", device_xname(sc->sc_dev))); | 413 | gpiobus_close(sc->sc_gc, sc->sc_dev); | |
368 | (void)gpiobus_close(sc->sc_gc, sc->sc_dev); | |||
369 | sc->sc_opened = 0; | |||
370 | ||||
371 | return 0; | 414 | return 0; | |
372 | } | 415 | } | |
373 | 416 | |||
374 | static int | 417 | static int | |
375 | gpio_pinbyname(struct gpio_softc *sc, char *gp_name) | 418 | gpio_pinbyname(struct gpio_softc *sc, char *gp_name) | |
376 | { | 419 | { | |
377 | struct gpio_name *nm; | 420 | struct gpio_name *nm; | |
378 | 421 | |||
379 | LIST_FOREACH(nm, &sc->sc_names, gp_next) | 422 | LIST_FOREACH(nm, &sc->sc_names, gp_next) | |
380 | if (!strcmp(nm->gp_name, gp_name)) | 423 | if (!strcmp(nm->gp_name, gp_name)) | |
381 | return nm->gp_pin; | 424 | return nm->gp_pin; | |
382 | return -1; | 425 | return -1; | |
383 | } | 426 | } | |
384 | 427 | |||
428 | static void | |||
429 | gpio_pulse(void *arg) | |||
430 | { | |||
431 | struct gpio_pin *pin; | |||
432 | ||||
433 | pin = (struct gpio_pin *)arg; | |||
434 | if ((pin->pin_state & GPIO_PIN_PULSE) == 0) | |||
435 | return; | |||
436 | ||||
437 | if (pin->pin_state & GPIO_PIN_HIGH) { | |||
438 | gpiobus_pin_write(pin->pin_gc, pin->pin_num, GPIO_PIN_LOW); | |||
439 | pin->pin_state &= ~GPIO_PIN_HIGH; | |||
440 | callout_schedule(&pin->pin_pulse, pin->pin_ticks_off); | |||
441 | } else { | |||
442 | gpiobus_pin_write(pin->pin_gc, pin->pin_num, GPIO_PIN_HIGH); | |||
443 | pin->pin_state |= GPIO_PIN_HIGH; | |||
444 | callout_schedule(&pin->pin_pulse, pin->pin_ticks_on); | |||
445 | } | |||
446 | } | |||
447 | ||||
385 | int | 448 | int | |
386 | gpioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) | 449 | gpioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) | |
387 | { | 450 | { | |
451 | int error; | |||
388 | struct gpio_softc *sc; | 452 | struct gpio_softc *sc; | |
453 | ||||
454 | sc = device_lookup_private(&gpio_cd, minor(dev)); | |||
455 | ||||
456 | error = gpio_lock(sc); | |||
457 | if (error) | |||
458 | return error; | |||
459 | ||||
460 | error = gpio_ioctl(sc, cmd, data, flag, l); | |||
461 | gpio_unlock(sc); | |||
462 | return error; | |||
463 | } | |||
464 | ||||
465 | static int | |||
466 | gpio_ioctl(struct gpio_softc *sc, u_long cmd, void *data, int flag, | |||
467 | struct lwp *l) | |||
468 | { | |||
389 | gpio_chipset_tag_t gc; | 469 | gpio_chipset_tag_t gc; | |
390 | struct gpio_info *info; | 470 | struct gpio_info *info; | |
391 | struct gpio_attach *attach; | 471 | struct gpio_attach *attach; | |
392 | struct gpio_attach_args ga; | 472 | struct gpio_attach_args ga; | |
393 | struct gpio_dev *gdev; | 473 | struct gpio_dev *gdev; | |
394 | struct gpio_req *req; | 474 | struct gpio_req *req; | |
475 | struct gpio_pulse *pulse; | |||
395 | struct gpio_name *nm; | 476 | struct gpio_name *nm; | |
396 | struct gpio_set *set; | 477 | struct gpio_set *set; | |
478 | struct gpio_pin *gpin; | |||
397 | device_t dv; | 479 | device_t dv; | |
398 | cfdata_t cf; | 480 | cfdata_t cf; | |
399 | kauth_cred_t cred; | 481 | kauth_cred_t cred; | |
400 | int locs[GPIOCF_NLOCS]; | 482 | int locs[GPIOCF_NLOCS]; | |
401 | int pin, value, flags, npins; | 483 | int pin, value, flags, npins; | |
402 | 484 | |||
403 | sc = device_lookup_private(&gpio_cd, minor(dev)); | |||
404 | gc = sc->sc_gc; | 485 | gc = sc->sc_gc; | |
405 | 486 | |||
406 | if (cmd != GPIOINFO && !device_is_active(sc->sc_dev)) { | 487 | if (cmd != GPIOINFO && !device_is_active(sc->sc_dev)) { | |
407 | DPRINTF(("%s: device is not active\n", | 488 | DPRINTF(("%s: device is not active\n", | |
408 | device_xname(sc->sc_dev))); | 489 | device_xname(sc->sc_dev))); | |
409 | return EBUSY; | 490 | return EBUSY; | |
410 | } | 491 | } | |
411 | 492 | |||
412 | cred = kauth_cred_get(); | 493 | cred = kauth_cred_get(); | |
413 | 494 | |||
414 | switch (cmd) { | 495 | switch (cmd) { | |
415 | case GPIOINFO: | 496 | case GPIOINFO: | |
416 | info = (struct gpio_info *)data; | 497 | info = (struct gpio_info *)data; | |
417 | if (!kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | 498 | if (!kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | |
418 | NULL, NULL, NULL, NULL)) | 499 | NULL, NULL, NULL, NULL)) | |
419 | info->gpio_npins = sc->sc_npins; | 500 | info->gpio_npins = sc->sc_npins; | |
420 | else { | 501 | else { | |
421 | for (pin = npins = 0; pin < sc->sc_npins; pin++) | 502 | for (pin = npins = 0; pin < sc->sc_npins; pin++) | |
422 | if (sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) | 503 | if (sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) | |
423 | ++npins; | 504 | ++npins; | |
424 | info->gpio_npins = npins; | 505 | info->gpio_npins = npins; | |
425 | } | 506 | } | |
426 | break; | 507 | break; | |
427 | case GPIOREAD: | 508 | case GPIOREAD: | |
428 | req = (struct gpio_req *)data; | 509 | req = (struct gpio_req *)data; | |
429 | 510 | |||
430 | if (req->gp_name[0] != '\0') { | 511 | if (req->gp_name[0] != '\0') | |
431 | pin = gpio_pinbyname(sc, req->gp_name); | 512 | pin = gpio_pinbyname(sc, req->gp_name); | |
432 | if (pin == -1) | 513 | else | |
433 | return EINVAL; | |||
434 | } else | |||
435 | pin = req->gp_pin; | 514 | pin = req->gp_pin; | |
436 | 515 | |||
437 | if (pin < 0 || pin >= sc->sc_npins) | 516 | if (pin < 0 || pin >= sc->sc_npins) | |
438 | return EINVAL; | 517 | return EINVAL; | |
439 | 518 | |||
440 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && | 519 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && | |
441 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | 520 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | |
442 | NULL, NULL, NULL, NULL)) | 521 | NULL, NULL, NULL, NULL)) | |
443 | return EPERM; | 522 | return EPERM; | |
444 | 523 | |||
445 | /* return read value */ | 524 | /* return read value */ | |
446 | req->gp_value = gpiobus_pin_read(gc, pin); | 525 | req->gp_value = gpiobus_pin_read(gc, pin); | |
447 | break; | 526 | break; | |
448 | case GPIOWRITE: | 527 | case GPIOWRITE: | |
449 | if ((flag & FWRITE) == 0) | 528 | if ((flag & FWRITE) == 0) | |
450 | return EBADF; | 529 | return EBADF; | |
451 | 530 | |||
452 | req = (struct gpio_req *)data; | 531 | req = (struct gpio_req *)data; | |
453 | 532 | |||
454 | if (req->gp_name[0] != '\0') { | 533 | if (req->gp_name[0] != '\0') | |
455 | pin = gpio_pinbyname(sc, req->gp_name); | 534 | pin = gpio_pinbyname(sc, req->gp_name); | |
456 | if (pin == -1) | 535 | else | |
457 | return EINVAL; | |||
458 | } else | |||
459 | pin = req->gp_pin; | 536 | pin = req->gp_pin; | |
460 | 537 | |||
461 | if (pin < 0 || pin >= sc->sc_npins) | 538 | if (pin < 0 || pin >= sc->sc_npins) | |
462 | return EINVAL; | 539 | return EINVAL; | |
463 | 540 | |||
464 | if (sc->sc_pins[pin].pin_mapped) | 541 | if (sc->sc_pins[pin].pin_mapped) | |
465 | return EBUSY; | 542 | return EBUSY; | |
466 | 543 | |||
467 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && | 544 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && | |
468 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | 545 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | |
469 | NULL, NULL, NULL, NULL)) | 546 | NULL, NULL, NULL, NULL)) | |
470 | return EPERM; | 547 | return EPERM; | |
471 | 548 | |||
472 | value = req->gp_value; | 549 | value = req->gp_value; | |
473 | if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH) | 550 | if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH) | |
474 | return EINVAL; | 551 | return EINVAL; | |
475 | 552 | |||
553 | if (sc->sc_pins[pin].pin_state & GPIO_PIN_PULSE) { | |||
554 | callout_halt(&sc->sc_pins[pin].pin_pulse, NULL); | |||
555 | sc->sc_pins[pin].pin_state &= ~GPIO_PIN_PULSE; | |||
556 | } | |||
476 | gpiobus_pin_write(gc, pin, value); | 557 | gpiobus_pin_write(gc, pin, value); | |
477 | /* return old value */ | 558 | /* return old value */ | |
478 | req->gp_value = sc->sc_pins[pin].pin_state; | 559 | req->gp_value = sc->sc_pins[pin].pin_state; | |
479 | /* update current value */ | 560 | /* update current value */ | |
480 | sc->sc_pins[pin].pin_state = value; | 561 | sc->sc_pins[pin].pin_state = value; | |
481 | break; | 562 | break; | |
563 | case GPIOPULSE: | |||
564 | if ((flag & FWRITE) == 0) | |||
565 | return EBADF; | |||
566 | ||||
567 | pulse = (struct gpio_pulse *)data; | |||
568 | if (pulse->gp_name[0] != '\0') | |||
569 | pin = gpio_pinbyname(sc, pulse->gp_name); | |||
570 | else | |||
571 | pin = pulse->gp_pin; | |||
572 | ||||
573 | if (pin < 0 || pin >= sc->sc_npins) | |||
574 | return EINVAL; | |||
575 | ||||
576 | gpin = &sc->sc_pins[pin]; | |||
577 | if (gpin->pin_mapped) | |||
578 | return EBUSY; | |||
579 | ||||
580 | if (!(gpin->pin_flags & GPIO_PIN_SET) && | |||
581 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | |||
582 | NULL, NULL, NULL, NULL)) | |||
583 | return EPERM; | |||
584 | ||||
585 | if (gpin->pin_flags & GPIO_PIN_PULSATE) { | |||
586 | gpiobus_pin_write(gc, pin, GPIO_PIN_HIGH); | |||
587 | gpin->pin_state = GPIO_PIN_PULSE; | |||
588 | return 0; | |||
589 | } | |||
590 | ||||
591 | if (gpin->pin_state & GPIO_PIN_PULSE) | |||
592 | callout_halt(&gpin->pin_pulse, NULL); | |||
593 | ||||
594 | gpin->pin_gc = gc; | |||
595 | ||||
596 | gpin->pin_ticks_on = tvtohz(&pulse->gp_pulse_on); | |||
597 | gpin->pin_ticks_off = tvtohz(&pulse->gp_pulse_off); | |||
598 | if (gpin->pin_ticks_on == 0 || gpin->pin_ticks_off == 0) { | |||
599 | gpin->pin_ticks_on = hz / 2; | |||
600 | gpin->pin_ticks_off = hz / 2; | |||
601 | } | |||
602 | gpiobus_pin_write(gc, pin, GPIO_PIN_HIGH); | |||
603 | gpin->pin_state = GPIO_PIN_HIGH | GPIO_PIN_PULSE; | |||
604 | callout_schedule(&gpin->pin_pulse, gpin->pin_ticks_on); | |||
605 | break; | |||
482 | case GPIOTOGGLE: | 606 | case GPIOTOGGLE: | |
483 | if ((flag & FWRITE) == 0) | 607 | if ((flag & FWRITE) == 0) | |
484 | return EBADF; | 608 | return EBADF; | |
485 | 609 | |||
486 | req = (struct gpio_req *)data; | 610 | req = (struct gpio_req *)data; | |
487 | 611 | |||
488 | if (req->gp_name[0] != '\0') { | 612 | if (req->gp_name[0] != '\0') | |
489 | pin = gpio_pinbyname(sc, req->gp_name); | 613 | pin = gpio_pinbyname(sc, req->gp_name); | |
490 | if (pin == -1) | 614 | else | |
491 | return EINVAL; | |||
492 | } else | |||
493 | pin = req->gp_pin; | 615 | pin = req->gp_pin; | |
494 | 616 | |||
495 | if (pin < 0 || pin >= sc->sc_npins) | 617 | if (pin < 0 || pin >= sc->sc_npins) | |
496 | return EINVAL; | 618 | return EINVAL; | |
497 | 619 | |||
498 | if (sc->sc_pins[pin].pin_mapped) | 620 | if (sc->sc_pins[pin].pin_mapped) | |
499 | return EBUSY; | 621 | return EBUSY; | |
500 | 622 | |||
501 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && | 623 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && | |
502 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | 624 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | |
503 | NULL, NULL, NULL, NULL)) | 625 | NULL, NULL, NULL, NULL)) | |
504 | return EPERM; | 626 | return EPERM; | |
505 | 627 | |||
@@ -516,80 +638,79 @@ gpioioctl(dev_t dev, u_long cmd, void *d | @@ -516,80 +638,79 @@ gpioioctl(dev_t dev, u_long cmd, void *d | |||
516 | NULL, NULL, NULL, NULL)) | 638 | NULL, NULL, NULL, NULL)) | |
517 | return EPERM; | 639 | return EPERM; | |
518 | 640 | |||
519 | attach = (struct gpio_attach *)data; | 641 | attach = (struct gpio_attach *)data; | |
520 | 642 | |||
521 | /* do not try to attach if the pins are already mapped */ | 643 | /* do not try to attach if the pins are already mapped */ | |
522 | if (!gpio_pin_can_map(sc, attach->ga_offset, attach->ga_mask)) | 644 | if (!gpio_pin_can_map(sc, attach->ga_offset, attach->ga_mask)) | |
523 | return EBUSY; | 645 | return EBUSY; | |
524 | 646 | |||
525 | ga.ga_gpio = sc; | 647 | ga.ga_gpio = sc; | |
526 | ga.ga_dvname = attach->ga_dvname; | 648 | ga.ga_dvname = attach->ga_dvname; | |
527 | ga.ga_offset = attach->ga_offset; | 649 | ga.ga_offset = attach->ga_offset; | |
528 | ga.ga_mask = attach->ga_mask; | 650 | ga.ga_mask = attach->ga_mask; | |
529 | DPRINTF(("%s: attach %s with offset %d and mask 0x%02x\n", | 651 | ga.ga_nolock = 1; | |
530 | device_xname(sc->sc_dev), ga.ga_dvname, ga.ga_offset, | 652 | DPRINTF(("%s: attach %s with offset %d and mask " | |
531 | ga.ga_mask)); | 653 | "0x%02x\n", device_xname(sc->sc_dev), ga.ga_dvname, | |
654 | ga.ga_offset, ga.ga_mask)); | |||
532 | 655 | |||
533 | locs[GPIOCF_OFFSET] = ga.ga_offset; | 656 | locs[GPIOCF_OFFSET] = ga.ga_offset; | |
534 | locs[GPIOCF_MASK] = ga.ga_mask; | 657 | locs[GPIOCF_MASK] = ga.ga_mask; | |
535 | 658 | |||
536 | cf = config_search_loc(NULL, sc->sc_dev, "gpio", locs, &ga); | 659 | cf = config_search_loc(NULL, sc->sc_dev, "gpio", locs, &ga); | |
537 | if (cf != NULL) { | 660 | if (cf != NULL) { | |
538 | dv = config_attach_loc(sc->sc_dev, cf, locs, &ga, | 661 | dv = config_attach_loc(sc->sc_dev, cf, locs, &ga, | |
539 | gpiobus_print); | 662 | gpiobus_print); | |
540 | if (dv != NULL) { | 663 | if (dv != NULL) { | |
541 | gdev = kmem_alloc(sizeof(struct gpio_dev), | 664 | gdev = kmem_alloc(sizeof(struct gpio_dev), | |
542 | KM_SLEEP); | 665 | KM_SLEEP); | |
543 | gdev->sc_dev = dv; | 666 | gdev->sc_dev = dv; | |
544 | LIST_INSERT_HEAD(&sc->sc_devs, gdev, sc_next); | 667 | LIST_INSERT_HEAD(&sc->sc_devs, gdev, sc_next); | |
545 | } else | 668 | } else | |
546 | return EINVAL; | 669 | return EINVAL; | |
547 | } else | 670 | } else | |
548 | return EINVAL; | 671 | return EINVAL; | |
549 | break; | 672 | return 0; | |
550 | case GPIODETACH: | 673 | case GPIODETACH: | |
551 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | 674 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | |
552 | NULL, NULL, NULL, NULL)) | 675 | NULL, NULL, NULL, NULL)) | |
553 | return EPERM; | 676 | return EPERM; | |
554 | 677 | |||
555 | attach = (struct gpio_attach *)data; | 678 | attach = (struct gpio_attach *)data; | |
556 | LIST_FOREACH(gdev, &sc->sc_devs, sc_next) { | 679 | LIST_FOREACH(gdev, &sc->sc_devs, sc_next) { | |
557 | if (strcmp(device_xname(gdev->sc_dev), | 680 | if (strcmp(device_xname(gdev->sc_dev), | |
558 | attach->ga_dvname) == 0) { | 681 | attach->ga_dvname) == 0) { | |
559 | if (config_detach(gdev->sc_dev, 0) == 0) { | 682 | if (config_detach(gdev->sc_dev, 0) == 0) { | |
560 | LIST_REMOVE(gdev, sc_next); | 683 | LIST_REMOVE(gdev, sc_next); | |
561 | kmem_free(gdev, | 684 | kmem_free(gdev, | |
562 | sizeof(struct gpio_dev)); | 685 | sizeof(struct gpio_dev)); | |
563 | return 0; | 686 | return 0; | |
564 | } | 687 | } | |
565 | break; | 688 | break; | |
566 | } | 689 | } | |
567 | } | 690 | } | |
568 | return EINVAL; | 691 | return EINVAL; | |
569 | break; | |||
570 | case GPIOSET: | 692 | case GPIOSET: | |
571 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | 693 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | |
572 | NULL, NULL, NULL, NULL)) | 694 | NULL, NULL, NULL, NULL)) | |
573 | return EPERM; | 695 | return EPERM; | |
574 | 696 | |||
575 | set = (struct gpio_set *)data; | 697 | set = (struct gpio_set *)data; | |
576 | 698 | |||
577 | if (set->gp_name[0] != '\0') { | 699 | if (set->gp_name[0] != '\0') | |
578 | pin = gpio_pinbyname(sc, set->gp_name); | 700 | pin = gpio_pinbyname(sc, set->gp_name); | |
579 | if (pin == -1) | 701 | else | |
580 | return EINVAL; | |||
581 | } else | |||
582 | pin = set->gp_pin; | 702 | pin = set->gp_pin; | |
703 | ||||
583 | if (pin < 0 || pin >= sc->sc_npins) | 704 | if (pin < 0 || pin >= sc->sc_npins) | |
584 | return EINVAL; | 705 | return EINVAL; | |
585 | flags = set->gp_flags; | 706 | flags = set->gp_flags; | |
586 | 707 | |||
587 | /* check that the controller supports all requested flags */ | 708 | /* check that the controller supports all requested flags */ | |
588 | if ((flags & sc->sc_pins[pin].pin_caps) != flags) | 709 | if ((flags & sc->sc_pins[pin].pin_caps) != flags) | |
589 | return ENODEV; | 710 | return ENODEV; | |
590 | flags = set->gp_flags | GPIO_PIN_SET; | 711 | flags = set->gp_flags | GPIO_PIN_SET; | |
591 | 712 | |||
592 | set->gp_caps = sc->sc_pins[pin].pin_caps; | 713 | set->gp_caps = sc->sc_pins[pin].pin_caps; | |
593 | /* return old value */ | 714 | /* return old value */ | |
594 | set->gp_flags = sc->sc_pins[pin].pin_flags; | 715 | set->gp_flags = sc->sc_pins[pin].pin_flags; | |
595 | if (flags > 0) { | 716 | if (flags > 0) { | |
@@ -619,31 +740,29 @@ gpioioctl(dev_t dev, u_long cmd, void *d | @@ -619,31 +740,29 @@ gpioioctl(dev_t dev, u_long cmd, void *d | |||
619 | strlcpy(nm->gp_name, set->gp_name2, | 740 | strlcpy(nm->gp_name, set->gp_name2, | |
620 | sizeof(nm->gp_name)); | 741 | sizeof(nm->gp_name)); | |
621 | nm->gp_pin = set->gp_pin; | 742 | nm->gp_pin = set->gp_pin; | |
622 | LIST_INSERT_HEAD(&sc->sc_names, nm, gp_next); | 743 | LIST_INSERT_HEAD(&sc->sc_names, nm, gp_next); | |
623 | } | 744 | } | |
624 | } | 745 | } | |
625 | break; | 746 | break; | |
626 | case GPIOUNSET: | 747 | case GPIOUNSET: | |
627 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | 748 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, | |
628 | NULL, NULL, NULL, NULL)) | 749 | NULL, NULL, NULL, NULL)) | |
629 | return EPERM; | 750 | return EPERM; | |
630 | 751 | |||
631 | set = (struct gpio_set *)data; | 752 | set = (struct gpio_set *)data; | |
632 | if (set->gp_name[0] != '\0') { | 753 | if (set->gp_name[0] != '\0') | |
633 | pin = gpio_pinbyname(sc, set->gp_name); | 754 | pin = gpio_pinbyname(sc, set->gp_name); | |
634 | if (pin == -1) | 755 | else | |
635 | return EINVAL; | |||
636 | } else | |||
637 | pin = set->gp_pin; | 756 | pin = set->gp_pin; | |
638 | 757 | |||
639 | if (pin < 0 || pin >= sc->sc_npins) | 758 | if (pin < 0 || pin >= sc->sc_npins) | |
640 | return EINVAL; | 759 | return EINVAL; | |
641 | if (sc->sc_pins[pin].pin_mapped) | 760 | if (sc->sc_pins[pin].pin_mapped) | |
642 | return EBUSY; | 761 | return EBUSY; | |
643 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET)) | 762 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET)) | |
644 | return EINVAL; | 763 | return EINVAL; | |
645 | 764 | |||
646 | LIST_FOREACH(nm, &sc->sc_names, gp_next) { | 765 | LIST_FOREACH(nm, &sc->sc_names, gp_next) { | |
647 | if (nm->gp_pin == pin) { | 766 | if (nm->gp_pin == pin) { | |
648 | LIST_REMOVE(nm, gp_next); | 767 | LIST_REMOVE(nm, gp_next); | |
649 | kmem_free(nm, sizeof(struct gpio_name)); | 768 | kmem_free(nm, sizeof(struct gpio_name)); |
--- src/sys/dev/gpio/gpiovar.h 2011/08/12 08:00:52 1.11
+++ src/sys/dev/gpio/gpiovar.h 2011/08/28 07:48:50 1.12
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: gpiovar.h,v 1.11 2011/08/12 08:00:52 mbalmer Exp $ */ | 1 | /* $NetBSD: gpiovar.h,v 1.12 2011/08/28 07:48:50 mbalmer Exp $ */ | |
2 | /* $OpenBSD: gpiovar.h,v 1.3 2006/01/14 12:33:49 grange Exp $ */ | 2 | /* $OpenBSD: gpiovar.h,v 1.3 2006/01/14 12:33:49 grange Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> | 5 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
@@ -25,76 +25,84 @@ | @@ -25,76 +25,84 @@ | |||
25 | /* GPIO controller description */ | 25 | /* GPIO controller description */ | |
26 | typedef struct gpio_chipset_tag { | 26 | typedef struct gpio_chipset_tag { | |
27 | void *gp_cookie; | 27 | void *gp_cookie; | |
28 | 28 | |||
29 | int (*gp_gc_open)(void *, device_t); | 29 | int (*gp_gc_open)(void *, device_t); | |
30 | void (*gp_gc_close)(void *, device_t); | 30 | void (*gp_gc_close)(void *, device_t); | |
31 | int (*gp_pin_read)(void *, int); | 31 | int (*gp_pin_read)(void *, int); | |
32 | void (*gp_pin_write)(void *, int, int); | 32 | void (*gp_pin_write)(void *, int, int); | |
33 | void (*gp_pin_ctl)(void *, int, int); | 33 | void (*gp_pin_ctl)(void *, int, int); | |
34 | } *gpio_chipset_tag_t; | 34 | } *gpio_chipset_tag_t; | |
35 | 35 | |||
36 | /* GPIO pin description */ | 36 | /* GPIO pin description */ | |
37 | typedef struct gpio_pin { | 37 | typedef struct gpio_pin { | |
38 | int pin_num; /* number */ | 38 | int pin_num; /* number */ | |
39 | int pin_caps; /* capabilities */ | 39 | int pin_caps; /* capabilities */ | |
40 | int pin_flags; /* current configuration */ | 40 | int pin_flags; /* current configuration */ | |
41 | int pin_state; /* current state */ | 41 | int pin_state; /* current state */ | |
42 | int pin_mapped; /* is mapped */ | 42 | int pin_mapped; /* is mapped */ | |
43 | callout_t pin_pulse; /* for pulsing */ | |||
44 | int pin_ticks_on; /* "on" period */ | |||
45 | int pin_ticks_off; /* "off" period */ | |||
46 | gpio_chipset_tag_t pin_gc; /* reference the controller */ | |||
43 | } gpio_pin_t; | 47 | } gpio_pin_t; | |
44 | 48 | |||
45 | /* Attach GPIO framework to the controller */ | 49 | /* Attach GPIO framework to the controller */ | |
46 | struct gpiobus_attach_args { | 50 | struct gpiobus_attach_args { | |
47 | gpio_chipset_tag_t gba_gc; /* underlying controller */ | 51 | gpio_chipset_tag_t gba_gc; /* underlying controller */ | |
48 | gpio_pin_t *gba_pins; /* pins array */ | 52 | gpio_pin_t *gba_pins; /* pins array */ | |
49 | int gba_npins; /* total number of pins */ | 53 | int gba_npins; /* total number of pins */ | |
50 | }; | 54 | }; | |
51 | 55 | |||
52 | int gpiobus_print(void *, const char *); | 56 | int gpiobus_print(void *, const char *); | |
53 | 57 | |||
54 | /* GPIO framework private methods */ | 58 | /* GPIO framework private methods */ | |
55 | #define gpiobus_open(gc, dev) \ | 59 | #define gpiobus_open(gc, dev) \ | |
56 | ((gc)->gp_gc_open ? ((gc)->gp_gc_open((gc)->gp_cookie, dev)) : 0) | 60 | ((gc)->gp_gc_open ? ((gc)->gp_gc_open((gc)->gp_cookie, dev)) : 0) | |
57 | #define gpiobus_close(gc, dev) \ | 61 | #define gpiobus_close(gc, dev) \ | |
58 | ((gc)->gp_gc_close ? ((gc)->gp_gc_close((gc)->gp_cookie, dev)), 1 : 0) | 62 | ((gc)->gp_gc_close ? ((gc)->gp_gc_close((gc)->gp_cookie, dev)), 1 : 0) | |
59 | #define gpiobus_pin_read(gc, pin) \ | 63 | #define gpiobus_pin_read(gc, pin) \ | |
60 | ((gc)->gp_pin_read((gc)->gp_cookie, (pin))) | 64 | ((gc)->gp_pin_read((gc)->gp_cookie, (pin))) | |
61 | #define gpiobus_pin_write(gc, pin, value) \ | 65 | #define gpiobus_pin_write(gc, pin, value) \ | |
62 | ((gc)->gp_pin_write((gc)->gp_cookie, (pin), (value))) | 66 | ((gc)->gp_pin_write((gc)->gp_cookie, (pin), (value))) | |
63 | #define gpiobus_pin_ctl(gc, pin, flags) \ | 67 | #define gpiobus_pin_ctl(gc, pin, flags) \ | |
64 | ((gc)->gp_pin_ctl((gc)->gp_cookie, (pin), (flags))) | 68 | ((gc)->gp_pin_ctl((gc)->gp_cookie, (pin), (flags))) | |
65 | 69 | |||
66 | /* Attach devices connected to the GPIO pins */ | 70 | /* Attach devices connected to the GPIO pins */ | |
67 | struct gpio_attach_args { | 71 | struct gpio_attach_args { | |
68 | void *ga_gpio; | 72 | void *ga_gpio; | |
69 | int ga_offset; | 73 | int ga_offset; | |
70 | u_int32_t ga_mask; | 74 | uint32_t ga_mask; | |
71 | char *ga_dvname; | 75 | char *ga_dvname; | |
76 | int ga_nolock; | |||
72 | }; | 77 | }; | |
73 | 78 | |||
74 | /* GPIO pin map */ | 79 | /* GPIO pin map */ | |
75 | struct gpio_pinmap { | 80 | struct gpio_pinmap { | |
76 | int *pm_map; /* pin map */ | 81 | int *pm_map; /* pin map */ | |
77 | int pm_size; /* map size */ | 82 | int pm_size; /* map size */ | |
78 | }; | 83 | }; | |
79 | 84 | |||
80 | struct gpio_dev { | 85 | struct gpio_dev { | |
81 | device_t sc_dev; /* the gpio device */ | 86 | device_t sc_dev; /* the gpio device */ | |
82 | LIST_ENTRY(gpio_dev) sc_next; | 87 | LIST_ENTRY(gpio_dev) sc_next; | |
83 | }; | 88 | }; | |
84 | 89 | |||
85 | struct gpio_name { | 90 | struct gpio_name { | |
86 | char gp_name[GPIOMAXNAME]; | 91 | char gp_name[GPIOMAXNAME]; | |
87 | int gp_pin; | 92 | int gp_pin; | |
88 | LIST_ENTRY(gpio_name) gp_next; | 93 | LIST_ENTRY(gpio_name) gp_next; | |
89 | }; | 94 | }; | |
90 | 95 | |||
91 | int gpio_pin_can_map(void *, int, u_int32_t); | 96 | int gpio_pin_can_map(void *, int, uint32_t); | |
92 | int gpio_pin_map(void *, int, u_int32_t, struct gpio_pinmap *); | 97 | int gpio_pin_map(void *, int, uint32_t, struct gpio_pinmap *); | |
93 | void gpio_pin_unmap(void *, struct gpio_pinmap *); | 98 | void gpio_pin_unmap(void *, struct gpio_pinmap *); | |
94 | int gpio_pin_read(void *, struct gpio_pinmap *, int); | 99 | int gpio_pin_read(void *, struct gpio_pinmap *, int); | |
95 | void gpio_pin_write(void *, struct gpio_pinmap *, int, int); | 100 | void gpio_pin_write(void *, struct gpio_pinmap *, int, int); | |
96 | void gpio_pin_ctl(void *, struct gpio_pinmap *, int, int); | 101 | void gpio_pin_ctl(void *, struct gpio_pinmap *, int, int); | |
97 | int gpio_pin_caps(void *, struct gpio_pinmap *, int); | 102 | int gpio_pin_caps(void *, struct gpio_pinmap *, int); | |
98 | int gpio_npins(u_int32_t); | 103 | int gpio_npins(uint32_t); | |
104 | ||||
105 | int gpio_lock(void *); | |||
106 | void gpio_unlock(void *); | |||
99 | 107 | |||
100 | #endif /* !_DEV_GPIO_GPIOVAR_H_ */ | 108 | #endif /* !_DEV_GPIO_GPIOVAR_H_ */ |
--- src/sys/sys/gpio.h 2011/06/23 00:46:37 1.8
+++ src/sys/sys/gpio.h 2011/08/28 07:48:50 1.9
@@ -1,38 +1,41 @@ | @@ -1,38 +1,41 @@ | |||
1 | /* $NetBSD: gpio.h,v 1.8 2011/06/23 00:46:37 matt Exp $ */ | 1 | /* $NetBSD: gpio.h,v 1.9 2011/08/28 07:48:50 mbalmer Exp $ */ | |
2 | /* $OpenBSD: gpio.h,v 1.7 2008/11/26 14:51:20 mbalmer Exp $ */ | 2 | /* $OpenBSD: gpio.h,v 1.7 2008/11/26 14:51:20 mbalmer Exp $ */ | |
3 | /* | 3 | /* | |
4 | * Copyright (c) 2009 Marc Balmer <marc@msys.ch> | 4 | * Copyright (c) 2009 Marc Balmer <marc@msys.ch> | |
5 | * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> | 5 | * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | 18 | */ | |
19 | 19 | |||
20 | #ifndef _SYS_GPIO_H_ | 20 | #ifndef _SYS_GPIO_H_ | |
21 | #define _SYS_GPIO_H_ | 21 | #define _SYS_GPIO_H_ | |
22 | 22 | |||
23 | #include <sys/time.h> | |||
24 | ||||
23 | /* GPIO pin states */ | 25 | /* GPIO pin states */ | |
24 | #define GPIO_PIN_LOW 0x00 /* low level (logical 0) */ | 26 | #define GPIO_PIN_LOW 0x00 /* low level (logical 0) */ | |
25 | #define GPIO_PIN_HIGH 0x01 /* high level (logical 1) */ | 27 | #define GPIO_PIN_HIGH 0x01 /* high level (logical 1) */ | |
28 | #define GPIO_PIN_PULSE 0x02 /* pulsing, or-ed with state */ | |||
26 | 29 | |||
27 | /* Max name length of a pin */ | 30 | /* Max name length of a pin */ | |
28 | #define GPIOMAXNAME 64 | 31 | #define GPIOMAXNAME 64 | |
29 | 32 | |||
30 | /* GPIO pin configuration flags */ | 33 | /* GPIO pin configuration flags */ | |
31 | #define GPIO_PIN_INPUT 0x0001 /* input direction */ | 34 | #define GPIO_PIN_INPUT 0x0001 /* input direction */ | |
32 | #define GPIO_PIN_OUTPUT 0x0002 /* output direction */ | 35 | #define GPIO_PIN_OUTPUT 0x0002 /* output direction */ | |
33 | #define GPIO_PIN_INOUT 0x0004 /* bi-directional */ | 36 | #define GPIO_PIN_INOUT 0x0004 /* bi-directional */ | |
34 | #define GPIO_PIN_OPENDRAIN 0x0008 /* open-drain output */ | 37 | #define GPIO_PIN_OPENDRAIN 0x0008 /* open-drain output */ | |
35 | #define GPIO_PIN_PUSHPULL 0x0010 /* push-pull output */ | 38 | #define GPIO_PIN_PUSHPULL 0x0010 /* push-pull output */ | |
36 | #define GPIO_PIN_TRISTATE 0x0020 /* output disabled */ | 39 | #define GPIO_PIN_TRISTATE 0x0020 /* output disabled */ | |
37 | #define GPIO_PIN_PULLUP 0x0040 /* internal pull-up enabled */ | 40 | #define GPIO_PIN_PULLUP 0x0040 /* internal pull-up enabled */ | |
38 | #define GPIO_PIN_PULLDOWN 0x0080 /* internal pull-down enabled */ | 41 | #define GPIO_PIN_PULLDOWN 0x0080 /* internal pull-down enabled */ | |
@@ -41,65 +44,74 @@ | @@ -41,65 +44,74 @@ | |||
41 | #define GPIO_PIN_USER 0x0400 /* user != 0 can access */ | 44 | #define GPIO_PIN_USER 0x0400 /* user != 0 can access */ | |
42 | #define GPIO_PIN_PULSATE 0x0800 /* pulsate in hardware */ | 45 | #define GPIO_PIN_PULSATE 0x0800 /* pulsate in hardware */ | |
43 | #define GPIO_PIN_INTR 0x1000 /* can be as an interrupt */ | 46 | #define GPIO_PIN_INTR 0x1000 /* can be as an interrupt */ | |
44 | #define GPIO_PIN_INTR_HIGH 0x2000 /* interrupt leading edge high */ | 47 | #define GPIO_PIN_INTR_HIGH 0x2000 /* interrupt leading edge high */ | |
45 | #define GPIO_PIN_SET 0x8000 /* set for securelevel access */ | 48 | #define GPIO_PIN_SET 0x8000 /* set for securelevel access */ | |
46 | 49 | |||
47 | /* GPIO controller description */ | 50 | /* GPIO controller description */ | |
48 | struct gpio_info { | 51 | struct gpio_info { | |
49 | int gpio_npins; /* total number of pins available */ | 52 | int gpio_npins; /* total number of pins available */ | |
50 | }; | 53 | }; | |
51 | 54 | |||
52 | /* GPIO pin request (read/write/toggle) */ | 55 | /* GPIO pin request (read/write/toggle) */ | |
53 | struct gpio_req { | 56 | struct gpio_req { | |
54 | char gp_name[GPIOMAXNAME]; /* pin name */ | 57 | char gp_name[GPIOMAXNAME]; /* pin name */ | |
55 | int gp_pin; /* pin number */ | 58 | int gp_pin; /* pin number */ | |
56 | int gp_value; /* value */ | 59 | int gp_value; /* value */ | |
60 | }; | |||
61 | ||||
62 | /* GPIO pulse request */ | |||
63 | struct gpio_pulse { | |||
64 | char gp_name[GPIOMAXNAME]; /* pin name */ | |||
65 | int gp_pin; /* pin number */ | |||
66 | struct timeval gp_pulse_on; /* "on" period */ | |||
67 | struct timeval gp_pulse_off; /* "off" period */ | |||
57 | }; | 68 | }; | |
58 | 69 | |||
59 | /* GPIO pin configuration */ | 70 | /* GPIO pin configuration */ | |
60 | struct gpio_set { | 71 | struct gpio_set { | |
61 | char gp_name[GPIOMAXNAME]; | 72 | char gp_name[GPIOMAXNAME]; | |
62 | int gp_pin; | 73 | int gp_pin; | |
63 | int gp_caps; | 74 | int gp_caps; | |
64 | int gp_flags; | 75 | int gp_flags; | |
65 | char gp_name2[GPIOMAXNAME]; /* new name */ | 76 | char gp_name2[GPIOMAXNAME]; /* new name */ | |
66 | }; | 77 | }; | |
67 | 78 | |||
68 | /* Attach/detach device drivers that use GPIO pins */ | 79 | /* Attach/detach device drivers that use GPIO pins */ | |
69 | struct gpio_attach { | 80 | struct gpio_attach { | |
70 | char ga_dvname[16]; /* device name */ | 81 | char ga_dvname[16]; /* device name */ | |
71 | int ga_offset; /* pin number */ | 82 | int ga_offset; /* pin number */ | |
72 | u_int32_t ga_mask; /* binary mask */ | 83 | uint32_t ga_mask; /* binary mask */ | |
73 | }; | 84 | }; | |
74 | 85 | |||
75 | /* GPIO pin control (old API) */ | 86 | /* GPIO pin control (old API) */ | |
76 | struct gpio_pin_ctl { | 87 | struct gpio_pin_ctl { | |
77 | int gp_pin; /* pin number */ | 88 | int gp_pin; /* pin number */ | |
78 | int gp_caps; /* pin capabilities (read-only) */ | 89 | int gp_caps; /* pin capabilities (read-only) */ | |
79 | int gp_flags; /* pin configuration flags */ | 90 | int gp_flags; /* pin configuration flags */ | |
80 | }; | 91 | }; | |
81 | 92 | |||
82 | /* GPIO pin operation (read/write/toggle) (old API) */ | 93 | /* GPIO pin operation (read/write/toggle) (old API) */ | |
83 | struct gpio_pin_op { | 94 | struct gpio_pin_op { | |
84 | int gp_pin; /* pin number */ | 95 | int gp_pin; /* pin number */ | |
85 | int gp_value; /* value */ | 96 | int gp_value; /* value */ | |
86 | }; | 97 | }; | |
87 | 98 | |||
88 | #define GPIOINFO _IOR('G', 0, struct gpio_info) | 99 | #define GPIOINFO _IOR('G', 0, struct gpio_info) | |
89 | 100 | |||
90 | /* the old API, kept for backwards compatibility */ | 101 | /* the old API, kept for backwards compatibility */ | |
91 | #define GPIOPINREAD _IOWR('G', 1, struct gpio_pin_op) | 102 | #define GPIOPINREAD _IOWR('G', 1, struct gpio_pin_op) | |
92 | #define GPIOPINWRITE _IOWR('G', 2, struct gpio_pin_op) | 103 | #define GPIOPINWRITE _IOWR('G', 2, struct gpio_pin_op) | |
93 | #define GPIOPINTOGGLE _IOWR('G', 3, struct gpio_pin_op) | 104 | #define GPIOPINTOGGLE _IOWR('G', 3, struct gpio_pin_op) | |
94 | #define GPIOPINCTL _IOWR('G', 4, struct gpio_pin_ctl) | 105 | #define GPIOPINCTL _IOWR('G', 4, struct gpio_pin_ctl) | |
95 | 106 | |||
96 | /* the new API */ | 107 | /* the new API */ | |
97 | #define GPIOSET _IOWR('G', 5, struct gpio_set) | 108 | #define GPIOSET _IOWR('G', 5, struct gpio_set) | |
98 | #define GPIOUNSET _IOWR('G', 6, struct gpio_set) | 109 | #define GPIOUNSET _IOWR('G', 6, struct gpio_set) | |
99 | #define GPIOREAD _IOWR('G', 7, struct gpio_req) | 110 | #define GPIOREAD _IOWR('G', 7, struct gpio_req) | |
100 | #define GPIOWRITE _IOWR('G', 8, struct gpio_req) | 111 | #define GPIOWRITE _IOWR('G', 8, struct gpio_req) | |
101 | #define GPIOTOGGLE _IOWR('G', 9, struct gpio_req) | 112 | #define GPIOTOGGLE _IOWR('G', 9, struct gpio_req) | |
102 | #define GPIOATTACH _IOWR('G', 10, struct gpio_attach) | 113 | #define GPIOATTACH _IOWR('G', 10, struct gpio_attach) | |
103 | #define GPIODETACH _IOWR('G', 11, struct gpio_attach) | 114 | #define GPIODETACH _IOWR('G', 11, struct gpio_attach) | |
115 | #define GPIOPULSE _IOWR('G', 12, struct gpio_pulse) | |||
104 | 116 | |||
105 | #endif /* !_SYS_GPIO_H_ */ | 117 | #endif /* !_SYS_GPIO_H_ */ |
--- src/usr.sbin/gpioctl/gpioctl.8 2011/08/12 08:02:33 1.8
+++ src/usr.sbin/gpioctl/gpioctl.8 2011/08/28 07:48:50 1.9
@@ -1,31 +1,31 @@ | @@ -1,31 +1,31 @@ | |||
1 | .\" $NetBSD: gpioctl.8,v 1.8 2011/08/12 08:02:33 mbalmer Exp $ | 1 | .\" $NetBSD: gpioctl.8,v 1.9 2011/08/28 07:48:50 mbalmer Exp $ | |
2 | .\" | 2 | .\" | |
3 | .\" Copyright (c) 2009, 2010 Marc Balmer <marc@msys.ch> | 3 | .\" Copyright (c) 2009, 2010, 2011 Marc Balmer <marc@msys.ch> | |
4 | .\" Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> | 4 | .\" Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> | |
5 | .\" | 5 | .\" | |
6 | .\" Permission to use, copy, modify, and distribute this software for any | 6 | .\" Permission to use, copy, modify, and distribute this software for any | |
7 | .\" purpose with or without fee is hereby granted, provided that the above | 7 | .\" purpose with or without fee is hereby granted, provided that the above | |
8 | .\" copyright notice and this permission notice appear in all copies. | 8 | .\" copyright notice and this permission notice appear in all copies. | |
9 | .\" | 9 | .\" | |
10 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 10 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 | .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 11 | .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 | .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 12 | .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 | .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 13 | .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 | .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 14 | .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 15 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 | .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 | .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 | .\" | 17 | .\" | |
18 | .Dd September 25, 2009 | 18 | .Dd August 21, 2011 | |
19 | .Dt GPIOCTL 8 | 19 | .Dt GPIOCTL 8 | |
20 | .Os | 20 | .Os | |
21 | .Sh NAME | 21 | .Sh NAME | |
22 | .Nm gpioctl | 22 | .Nm gpioctl | |
23 | .Nd control GPIO devices | 23 | .Nd control GPIO devices | |
24 | .Sh SYNOPSIS | 24 | .Sh SYNOPSIS | |
25 | .Nm gpioctl | 25 | .Nm gpioctl | |
26 | .Op Fl q | 26 | .Op Fl q | |
27 | .Ar device | 27 | .Ar device | |
28 | attach | 28 | attach | |
29 | .Ar device | 29 | .Ar device | |
30 | .Ar offset | 30 | .Ar offset | |
31 | .Ar mask | 31 | .Ar mask | |
@@ -38,26 +38,32 @@ detach | @@ -38,26 +38,32 @@ detach | |||
38 | .Op Fl q | 38 | .Op Fl q | |
39 | .Ar device | 39 | .Ar device | |
40 | .Ar pin | 40 | .Ar pin | |
41 | .Op Ar 0 | 1 | 2 | 41 | .Op Ar 0 | 1 | 2 | |
42 | .Nm gpioctl | 42 | .Nm gpioctl | |
43 | .Op Fl q | 43 | .Op Fl q | |
44 | .Ar device | 44 | .Ar device | |
45 | .Ar pin | 45 | .Ar pin | |
46 | .Op Ar on | off | toggle | 46 | .Op Ar on | off | toggle | |
47 | .Nm gpioctl | 47 | .Nm gpioctl | |
48 | .Op Fl q | 48 | .Op Fl q | |
49 | .Ar device | 49 | .Ar device | |
50 | .Ar pin | 50 | .Ar pin | |
51 | pulse | |||
52 | .Op Ar frequency Op Ar duty cycle | |||
53 | .Nm gpioctl | |||
54 | .Op Fl q | |||
55 | .Ar device | |||
56 | .Ar pin | |||
51 | set | 57 | set | |
52 | .Op Ar flags | 58 | .Op Ar flags | |
53 | .Op Ar name | 59 | .Op Ar name | |
54 | .Nm gpioctl | 60 | .Nm gpioctl | |
55 | .Op Fl q | 61 | .Op Fl q | |
56 | .Ar device | 62 | .Ar device | |
57 | .Ar pin | 63 | .Ar pin | |
58 | unset | 64 | unset | |
59 | .Sh DESCRIPTION | 65 | .Sh DESCRIPTION | |
60 | The | 66 | The | |
61 | .Nm | 67 | .Nm | |
62 | program allows manipulation of GPIO | 68 | program allows manipulation of GPIO | |
63 | (General Purpose Input/Output) device pins. | 69 | (General Purpose Input/Output) device pins. | |
@@ -82,36 +88,49 @@ or | @@ -82,36 +88,49 @@ or | |||
82 | GPIO pins can be either | 88 | GPIO pins can be either | |
83 | .Dq read | 89 | .Dq read | |
84 | or | 90 | or | |
85 | .Dq written | 91 | .Dq written | |
86 | with the values of logical 0 or 1. | 92 | with the values of logical 0 or 1. | |
87 | If only a | 93 | If only a | |
88 | .Ar pin | 94 | .Ar pin | |
89 | number is specified on the command line, the pin state will be read | 95 | number is specified on the command line, the pin state will be read | |
90 | from the GPIO controller and displayed. | 96 | from the GPIO controller and displayed. | |
91 | To write to a pin, a value must be specified after the | 97 | To write to a pin, a value must be specified after the | |
92 | .Ar pin | 98 | .Ar pin | |
93 | number. | 99 | number. | |
94 | Values can be either 0 or 1. | 100 | Values can be either 0 or 1. | |
95 | A value of 2 has a special meaning: it | 101 | A value of 2 | |
96 | .Dq toggles | 102 | .Dq toggles | |
97 | the pin, i.e. changes its state to the opposite. | 103 | the pin, i.e. changes its state to the opposite. | |
98 | Instead of the numerical values, the word | 104 | Instead of the numerical values, the word | |
99 | .Ar on , | 105 | .Ar on , | |
100 | .Ar off , | 106 | .Ar off , | |
101 | or | 107 | or | |
102 | .Ar toggle | 108 | .Ar toggle | |
103 | can be used. | 109 | can be used. | |
104 | .Pp | 110 | .Pp | |
111 | To | |||
112 | .Dq pulse | |||
113 | a pin, use the pulse command line option with an optional frequency value | |||
114 | in hertz and an optional duty cycle in percent. | |||
115 | If no frequency is specified, 1 Hz is assumed. | |||
116 | If no duty cycle is specified, 50% are assumed. | |||
117 | If the underlying hardware is not capable of pulsing in hardware, | |||
118 | pulsing is done in software using the | |||
119 | .Xr callout 9 | |||
120 | facility. | |||
121 | The frequency and duty cycle arguments are ignored for pins that are able to | |||
122 | pulse in hardware. | |||
123 | .Pp | |||
105 | Only pins that have been configured at securelevel 0, typically during system | 124 | Only pins that have been configured at securelevel 0, typically during system | |
106 | startup, are accessible once the securelevel has been raised. | 125 | startup, are accessible once the securelevel has been raised. | |
107 | Pins can be given symbolic names for easier use. | 126 | Pins can be given symbolic names for easier use. | |
108 | Besides using individual pins, device drivers that use GPIO pins can be | 127 | Besides using individual pins, device drivers that use GPIO pins can be | |
109 | attached to a | 128 | attached to a | |
110 | .Xr gpio 4 | 129 | .Xr gpio 4 | |
111 | device using the | 130 | device using the | |
112 | .Nm | 131 | .Nm | |
113 | command. | 132 | command. | |
114 | .Pp | 133 | .Pp | |
115 | The following configuration | 134 | The following configuration | |
116 | .Ar flags | 135 | .Ar flags | |
117 | are supported by the GPIO framework: | 136 | are supported by the GPIO framework: | |
@@ -197,15 +216,15 @@ Toggle the error_led: | @@ -197,15 +216,15 @@ Toggle the error_led: | |||
197 | .Xr gpio 4 | 216 | .Xr gpio 4 | |
198 | .Sh HISTORY | 217 | .Sh HISTORY | |
199 | The | 218 | The | |
200 | .Nm | 219 | .Nm | |
201 | command first appeared in | 220 | command first appeared in | |
202 | .Ox 3.6 | 221 | .Ox 3.6 | |
203 | and | 222 | and | |
204 | .Nx 4.0 . | 223 | .Nx 4.0 . | |
205 | .Sh AUTHORS | 224 | .Sh AUTHORS | |
206 | The | 225 | The | |
207 | .Nm | 226 | .Nm | |
208 | program was written by | 227 | program was written by | |
209 | .An Alexander Yurchenko Aq grange@openbsd.org . | 228 | .An Alexander Yurchenko Aq grange@openbsd.org . | |
210 | Device attachment was added by | 229 | Device attachment and pulsing was added by | |
211 | .An Marc Balmer Aq marc@msys.ch . | 230 | .An Marc Balmer Aq marc@msys.ch . |
--- src/usr.sbin/gpioctl/gpioctl.c 2011/08/12 08:06:23 1.10
+++ src/usr.sbin/gpioctl/gpioctl.c 2011/08/28 07:48:50 1.11
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: gpioctl.c,v 1.10 2011/08/12 08:06:23 mbalmer Exp $ */ | 1 | /* $NetBSD: gpioctl.c,v 1.11 2011/08/28 07:48:50 mbalmer Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2008, 2010 Marc Balmer <mbalmer@NetBSD.org> | 4 | * Copyright (c) 2008, 2010 Marc Balmer <mbalmer@NetBSD.org> | |
5 | * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> | 5 | * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
@@ -22,40 +22,41 @@ | @@ -22,40 +22,41 @@ | |||
22 | */ | 22 | */ | |
23 | 23 | |||
24 | #include <sys/types.h> | 24 | #include <sys/types.h> | |
25 | #include <sys/gpio.h> | 25 | #include <sys/gpio.h> | |
26 | #include <sys/ioctl.h> | 26 | #include <sys/ioctl.h> | |
27 | 27 | |||
28 | #include <err.h> | 28 | #include <err.h> | |
29 | #include <errno.h> | 29 | #include <errno.h> | |
30 | #include <fcntl.h> | 30 | #include <fcntl.h> | |
31 | #include <limits.h> | 31 | #include <limits.h> | |
32 | #include <paths.h> | 32 | #include <paths.h> | |
33 | #include <stdio.h> | 33 | #include <stdio.h> | |
34 | #include <stdlib.h> | 34 | #include <stdlib.h> | |
35 | #include <time.h> | |||
35 | #include <string.h> | 36 | #include <string.h> | |
36 | #include <unistd.h> | 37 | #include <unistd.h> | |
37 | 38 | |||
38 | ||||
39 | char *dev; | 39 | char *dev; | |
40 | int devfd = -1; | 40 | int devfd = -1; | |
41 | int quiet = 0; | 41 | int quiet = 0; | |
42 | 42 | |||
43 | static void getinfo(void); | 43 | static void getinfo(void); | |
44 | static void gpioread(int, char *); | 44 | static void gpioread(int, char *); | |
45 | static void gpiowrite(int, char *, int); | 45 | static void gpiowrite(int, char *, int); | |
46 | static void gpiopulse(int, char *, double, double); | |||
46 | static void gpioset(int pin, char *name, int flags, char *alias); | 47 | static void gpioset(int pin, char *name, int flags, char *alias); | |
47 | static void gpiounset(int pin, char *name); | 48 | static void gpiounset(int pin, char *name); | |
48 | static void devattach(char *, int, u_int32_t); | 49 | static void devattach(char *, int, uint32_t); | |
49 | static void devdetach(char *); | 50 | static void devdetach(char *); | |
50 | static void usage(void); | 51 | static void usage(void); | |
51 | 52 | |||
52 | extern long long strtonum(const char *numstr, long long minval, | 53 | extern long long strtonum(const char *numstr, long long minval, | |
53 | long long maxval, const char **errstrp); | 54 | long long maxval, const char **errstrp); | |
54 | 55 | |||
55 | const struct bitstr { | 56 | const struct bitstr { | |
56 | unsigned int mask; | 57 | unsigned int mask; | |
57 | const char *string; | 58 | const char *string; | |
58 | } pinflags[] = { | 59 | } pinflags[] = { | |
59 | { GPIO_PIN_INPUT, "in" }, | 60 | { GPIO_PIN_INPUT, "in" }, | |
60 | { GPIO_PIN_OUTPUT, "out" }, | 61 | { GPIO_PIN_OUTPUT, "out" }, | |
61 | { GPIO_PIN_INOUT, "inout" }, | 62 | { GPIO_PIN_INOUT, "inout" }, | |
@@ -64,51 +65,54 @@ const struct bitstr { | @@ -64,51 +65,54 @@ const struct bitstr { | |||
64 | { GPIO_PIN_TRISTATE, "tri" }, | 65 | { GPIO_PIN_TRISTATE, "tri" }, | |
65 | { GPIO_PIN_PULLUP, "pu" }, | 66 | { GPIO_PIN_PULLUP, "pu" }, | |
66 | { GPIO_PIN_PULLDOWN, "pd" }, | 67 | { GPIO_PIN_PULLDOWN, "pd" }, | |
67 | { GPIO_PIN_INVIN, "iin" }, | 68 | { GPIO_PIN_INVIN, "iin" }, | |
68 | { GPIO_PIN_INVOUT, "iout" }, | 69 | { GPIO_PIN_INVOUT, "iout" }, | |
69 | { GPIO_PIN_PULSATE, "pulsate" }, | 70 | { GPIO_PIN_PULSATE, "pulsate" }, | |
70 | { 0, NULL }, | 71 | { 0, NULL }, | |
71 | }; | 72 | }; | |
72 | 73 | |||
73 | int | 74 | int | |
74 | main(int argc, char *argv[]) | 75 | main(int argc, char *argv[]) | |
75 | { | 76 | { | |
76 | const struct bitstr *bs; | 77 | const struct bitstr *bs; | |
78 | double freq, dc; | |||
77 | int pin, ch, n, fl = 0, value = 0; | 79 | int pin, ch, n, fl = 0, value = 0; | |
78 | const char *errstr; | 80 | const char *errstr; | |
79 | char *ep; | 81 | char *ep; | |
80 | int ga_offset = -1; | 82 | int ga_offset = -1; | |
81 | u_int32_t ga_mask = 0; | 83 | uint32_t ga_mask = 0; | |
82 | long lval; | 84 | long lval; | |
83 | char *nam = NULL; | 85 | char *nam = NULL; | |
84 | char devn[32]; | 86 | char devn[32]; | |
85 | 87 | |||
86 | while ((ch = getopt(argc, argv, "q")) != -1) | 88 | while ((ch = getopt(argc, argv, "q")) != -1) | |
87 | switch (ch) { | 89 | switch (ch) { | |
88 | case 'q': | 90 | case 'q': | |
89 | quiet = 1; | 91 | quiet = 1; | |
90 | break; | 92 | break; | |
91 | default: | 93 | default: | |
92 | usage(); | 94 | usage(); | |
93 | /* NOTREACHED */ | 95 | /* NOTREACHED */ | |
94 | } | 96 | } | |
95 | argc -= optind; | 97 | argc -= optind; | |
96 | argv += optind; | 98 | argv += optind; | |
97 | 99 | |||
98 | if (argc < 1) | 100 | if (argc < 1) | |
99 | usage(); | 101 | usage(); | |
100 | dev = argv[0]; | 102 | dev = argv[0]; | |
101 | 103 | |||
104 | freq = dc = 0.0; | |||
105 | ||||
102 | if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) { | 106 | if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) { | |
103 | (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev); | 107 | (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev); | |
104 | dev = devn; | 108 | dev = devn; | |
105 | } | 109 | } | |
106 | 110 | |||
107 | if ((devfd = open(dev, O_RDWR)) == -1) | 111 | if ((devfd = open(dev, O_RDWR)) == -1) | |
108 | err(EXIT_FAILURE, "%s", dev); | 112 | err(EXIT_FAILURE, "%s", dev); | |
109 | 113 | |||
110 | if (argc == 1) { | 114 | if (argc == 1) { | |
111 | getinfo(); | 115 | getinfo(); | |
112 | return EXIT_SUCCESS; | 116 | return EXIT_SUCCESS; | |
113 | } | 117 | } | |
114 | 118 | |||
@@ -130,56 +134,66 @@ main(int argc, char *argv[]) | @@ -130,56 +134,66 @@ main(int argc, char *argv[]) | |||
130 | errx(EXIT_FAILURE, "invalid mask (not a number)"); | 134 | errx(EXIT_FAILURE, "invalid mask (not a number)"); | |
131 | if ((errno == ERANGE && (lval == LONG_MAX | 135 | if ((errno == ERANGE && (lval == LONG_MAX | |
132 | || lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX) | 136 | || lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX) | |
133 | errx(EXIT_FAILURE, "mask out of range"); | 137 | errx(EXIT_FAILURE, "mask out of range"); | |
134 | ga_mask = lval; | 138 | ga_mask = lval; | |
135 | devattach(driver, ga_offset, ga_mask); | 139 | devattach(driver, ga_offset, ga_mask); | |
136 | return EXIT_SUCCESS; | 140 | return EXIT_SUCCESS; | |
137 | } else if (!strcmp(argv[1], "detach")) { | 141 | } else if (!strcmp(argv[1], "detach")) { | |
138 | if (argc != 3) | 142 | if (argc != 3) | |
139 | usage(); | 143 | usage(); | |
140 | devdetach(argv[2]); | 144 | devdetach(argv[2]); | |
141 | } else { | 145 | } else { | |
142 | char *nm = NULL; | 146 | char *nm = NULL; | |
143 | 147 | |||
144 | /* expecting a pin number or name */ | 148 | /* expecting a pin number or name */ | |
145 | pin = strtonum(argv[1], 0, INT_MAX, &errstr); | 149 | pin = strtonum(argv[1], 0, INT_MAX, &errstr); | |
146 | if (errstr) | 150 | if (errstr) | |
147 | nm = argv[1]; /* try named pin */ | 151 | nm = argv[1]; /* try named pin */ | |
148 | if (argc > 2) { | 152 | if (argc > 2) { | |
149 | if (!strcmp(argv[2], "set")) { | 153 | if (!strcmp(argv[2], "set")) { | |
150 | for (n = 3; n < argc; n++) { | 154 | for (n = 3; n < argc; n++) { | |
151 | for (bs = pinflags; bs->string != NULL; | 155 | for (bs = pinflags; bs->string != NULL; | |
152 | bs++) { | 156 | bs++) { | |
153 | if (!strcmp(argv[n], | 157 | if (!strcmp(argv[n], | |
154 | bs->string)) { | 158 | bs->string)) { | |
155 | fl |= bs->mask; | 159 | fl |= bs->mask; | |
156 | break; | 160 | break; | |
157 | } | 161 | } | |
158 | } | 162 | } | |
159 | if (bs->string == NULL) | 163 | if (bs->string == NULL) | |
160 | nam = argv[n]; | 164 | nam = argv[n]; | |
161 | } | 165 | } | |
162 | gpioset(pin, nm, fl, nam); | 166 | gpioset(pin, nm, fl, nam); | |
163 | } else if (!strcmp(argv[2], "unset")) { | 167 | } else if (!strcmp(argv[2], "unset")) { | |
164 | gpiounset(pin, nm); | 168 | gpiounset(pin, nm); | |
169 | } else if (!strcmp(argv[2], "pulse")) { | |||
170 | if (argc == 4) { | |||
171 | freq = atof(argv[3]); | |||
172 | dc = 50.0; | |||
173 | } else if (argc == 5) { | |||
174 | freq = atof(argv[3]); | |||
175 | dc = atof(argv[4]); | |||
176 | } else | |||
177 | freq = dc = 0.0; | |||
178 | gpiopulse(pin, nm, freq, dc); | |||
165 | } else { | 179 | } else { | |
166 | value = strtonum(argv[2], INT_MIN, INT_MAX, | 180 | value = strtonum(argv[2], INT_MIN, INT_MAX, | |
167 | &errstr); | 181 | &errstr); | |
168 | if (errstr) { | 182 | if (errstr) { | |
169 | if (!strcmp(argv[2], "on")) | 183 | if (!strcmp(argv[2], "on")) | |
170 | value = 1; | 184 | value = GPIO_PIN_HIGH; | |
171 | else if (!strcmp(argv[2], "off")) | 185 | else if (!strcmp(argv[2], "off")) | |
172 | value = 0; | 186 | value = GPIO_PIN_LOW; | |
173 | else if (!strcmp(argv[2], "toggle")) | 187 | else if (!strcmp(argv[2], "toggle")) | |
174 | value = 2; | 188 | value = 2; | |
175 | else | 189 | else | |
176 | errx(EXIT_FAILURE, | 190 | errx(EXIT_FAILURE, | |
177 | "%s: invalid value", | 191 | "%s: invalid value", | |
178 | argv[2]); | 192 | argv[2]); | |
179 | } | 193 | } | |
180 | gpiowrite(pin, nm, value); | 194 | gpiowrite(pin, nm, value); | |
181 | } | 195 | } | |
182 | } else | 196 | } else | |
183 | gpioread(pin, nm); | 197 | gpioread(pin, nm); | |
184 | } | 198 | } | |
185 | 199 | |||
@@ -226,47 +240,104 @@ gpioread(int pin, char *gp_name) | @@ -226,47 +240,104 @@ gpioread(int pin, char *gp_name) | |||
226 | static void | 240 | static void | |
227 | gpiowrite(int pin, char *gp_name, int value) | 241 | gpiowrite(int pin, char *gp_name, int value) | |
228 | { | 242 | { | |
229 | struct gpio_req req; | 243 | struct gpio_req req; | |
230 | 244 | |||
231 | if (value < 0 || value > 2) | 245 | if (value < 0 || value > 2) | |
232 | errx(EXIT_FAILURE, "%d: invalid value", value); | 246 | errx(EXIT_FAILURE, "%d: invalid value", value); | |
233 | 247 | |||
234 | memset(&req, 0, sizeof(req)); | 248 | memset(&req, 0, sizeof(req)); | |
235 | if (gp_name != NULL) | 249 | if (gp_name != NULL) | |
236 | strlcpy(req.gp_name, gp_name, sizeof(req.gp_name)); | 250 | strlcpy(req.gp_name, gp_name, sizeof(req.gp_name)); | |
237 | else | 251 | else | |
238 | req.gp_pin = pin; | 252 | req.gp_pin = pin; | |
239 | req.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH); | 253 | ||
240 | if (value < 2) { | 254 | if (value == GPIO_PIN_HIGH || value == GPIO_PIN_LOW) { | |
255 | req.gp_value = value; | |||
241 | if (ioctl(devfd, GPIOWRITE, &req) == -1) | 256 | if (ioctl(devfd, GPIOWRITE, &req) == -1) | |
242 | err(EXIT_FAILURE, "GPIOWRITE"); | 257 | err(EXIT_FAILURE, "GPIOWRITE"); | |
243 | } else { | 258 | } else { | |
244 | if (ioctl(devfd, GPIOTOGGLE, &req) == -1) | 259 | if (ioctl(devfd, GPIOTOGGLE, &req) == -1) | |
245 | err(EXIT_FAILURE, "GPIOTOGGLE"); | 260 | err(EXIT_FAILURE, "GPIOTOGGLE"); | |
246 | } | 261 | } | |
247 | 262 | |||
248 | if (quiet) | 263 | if (quiet) | |
249 | return; | 264 | return; | |
250 | 265 | |||
251 | if (gp_name) | 266 | if (gp_name) | |
252 | printf("pin %s: state %d -> %d\n", gp_name, req.gp_value, | 267 | printf("pin %s: state %d -> %d\n", gp_name, req.gp_value, | |
253 | (value < 2 ? value : 1 - req.gp_value)); | 268 | (value < 2 ? value : 1 - req.gp_value)); | |
254 | else | 269 | else | |
255 | printf("pin %d: state %d -> %d\n", pin, req.gp_value, | 270 | printf("pin %d: state %d -> %d\n", pin, req.gp_value, | |
256 | (value < 2 ? value : 1 - req.gp_value)); | 271 | (value < 2 ? value : 1 - req.gp_value)); | |
257 | } | 272 | } | |
258 | 273 | |||
259 | static void | 274 | static void | |
275 | gpiopulse(int pin, char *gp_name, double freq, double dc) | |||
276 | { | |||
277 | struct gpio_pulse pulse; | |||
278 | suseconds_t period, on, off; | |||
279 | ||||
280 | if (freq < 0.0 || (dc < 0.0 || dc >= 100.0)) | |||
281 | errx(EXIT_FAILURE, "%.f Hz, %.f%% duty cycle: invalid value", | |||
282 | freq, dc); | |||
283 | ||||
284 | memset(&pulse, 0, sizeof(pulse)); | |||
285 | if (gp_name != NULL) | |||
286 | strlcpy(pulse.gp_name, gp_name, sizeof(pulse.gp_name)); | |||
287 | else | |||
288 | pulse.gp_pin = pin; | |||
289 | ||||
290 | if (freq > 0.0 && dc > 0.0) { | |||
291 | period = 1000000 / freq; | |||
292 | on = period * dc / 100; | |||
293 | off = period - on; | |||
294 | ||||
295 | if (on >= 1000000) { | |||
296 | pulse.gp_pulse_on.tv_sec = on / 1000000; | |||
297 | on -= pulse.gp_pulse_on.tv_sec * 1000000; | |||
298 | pulse.gp_pulse_on.tv_usec = on; | |||
299 | } else { | |||
300 | pulse.gp_pulse_on.tv_sec = 0; | |||
301 | pulse.gp_pulse_on.tv_usec = on; | |||
302 | } | |||
303 | if (off >= 1000000) { | |||
304 | pulse.gp_pulse_off.tv_sec = off / 1000000; | |||
305 | off -= pulse.gp_pulse_off.tv_sec * 1000000; | |||
306 | pulse.gp_pulse_off.tv_usec = off; | |||
307 | } else { | |||
308 | pulse.gp_pulse_off.tv_sec = 0; | |||
309 | pulse.gp_pulse_off.tv_usec = off; | |||
310 | } | |||
311 | } else { /* gpio(4) defaults */ | |||
312 | freq = 1.0; | |||
313 | dc = 50.0; | |||
314 | } | |||
315 | ||||
316 | if (ioctl(devfd, GPIOPULSE, &pulse) == -1) | |||
317 | err(EXIT_FAILURE, "GPIOPULSE"); | |||
318 | ||||
319 | if (quiet) | |||
320 | return; | |||
321 | ||||
322 | if (gp_name) | |||
323 | printf("pin %s: pulse at %.f Hz with a %.f%% duty cylce\n", | |||
324 | gp_name, freq, dc); | |||
325 | else | |||
326 | printf("pin %d: pulse at %.f Hz with a %.f%% duty cylce\n", | |||
327 | pin, freq, dc); | |||
328 | } | |||
329 | ||||
330 | static void | |||
260 | gpioset(int pin, char *name, int fl, char *alias) | 331 | gpioset(int pin, char *name, int fl, char *alias) | |
261 | { | 332 | { | |
262 | struct gpio_set set; | 333 | struct gpio_set set; | |
263 | const struct bitstr *bs; | 334 | const struct bitstr *bs; | |
264 | 335 | |||
265 | memset(&set, 0, sizeof(set)); | 336 | memset(&set, 0, sizeof(set)); | |
266 | if (name != NULL) | 337 | if (name != NULL) | |
267 | strlcpy(set.gp_name, name, sizeof(set.gp_name)); | 338 | strlcpy(set.gp_name, name, sizeof(set.gp_name)); | |
268 | else | 339 | else | |
269 | set.gp_pin = pin; | 340 | set.gp_pin = pin; | |
270 | set.gp_flags = fl; | 341 | set.gp_flags = fl; | |
271 | 342 | |||
272 | if (alias != NULL) | 343 | if (alias != NULL) | |
@@ -304,27 +375,27 @@ gpiounset(int pin, char *name) | @@ -304,27 +375,27 @@ gpiounset(int pin, char *name) | |||
304 | struct gpio_set set; | 375 | struct gpio_set set; | |
305 | 376 | |||
306 | memset(&set, 0, sizeof(set)); | 377 | memset(&set, 0, sizeof(set)); | |
307 | if (name != NULL) | 378 | if (name != NULL) | |
308 | strlcpy(set.gp_name, name, sizeof(set.gp_name)); | 379 | strlcpy(set.gp_name, name, sizeof(set.gp_name)); | |
309 | else | 380 | else | |
310 | set.gp_pin = pin; | 381 | set.gp_pin = pin; | |
311 | 382 | |||
312 | if (ioctl(devfd, GPIOUNSET, &set) == -1) | 383 | if (ioctl(devfd, GPIOUNSET, &set) == -1) | |
313 | err(EXIT_FAILURE, "GPIOUNSET"); | 384 | err(EXIT_FAILURE, "GPIOUNSET"); | |
314 | } | 385 | } | |
315 | 386 | |||
316 | static void | 387 | static void | |
317 | devattach(char *dvname, int offset, u_int32_t mask) | 388 | devattach(char *dvname, int offset, uint32_t mask) | |
318 | { | 389 | { | |
319 | struct gpio_attach attach; | 390 | struct gpio_attach attach; | |
320 | 391 | |||
321 | memset(&attach, 0, sizeof(attach)); | 392 | memset(&attach, 0, sizeof(attach)); | |
322 | strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); | 393 | strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); | |
323 | attach.ga_offset = offset; | 394 | attach.ga_offset = offset; | |
324 | attach.ga_mask = mask; | 395 | attach.ga_mask = mask; | |
325 | if (ioctl(devfd, GPIOATTACH, &attach) == -1) | 396 | if (ioctl(devfd, GPIOATTACH, &attach) == -1) | |
326 | err(EXIT_FAILURE, "GPIOATTACH"); | 397 | err(EXIT_FAILURE, "GPIOATTACH"); | |
327 | } | 398 | } | |
328 | 399 | |||
329 | static void | 400 | static void | |
330 | devdetach(char *dvname) | 401 | devdetach(char *dvname) | |
@@ -335,22 +406,24 @@ devdetach(char *dvname) | @@ -335,22 +406,24 @@ devdetach(char *dvname) | |||
335 | strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); | 406 | strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); | |
336 | if (ioctl(devfd, GPIODETACH, &attach) == -1) | 407 | if (ioctl(devfd, GPIODETACH, &attach) == -1) | |
337 | err(EXIT_FAILURE, "GPIODETACH"); | 408 | err(EXIT_FAILURE, "GPIODETACH"); | |
338 | } | 409 | } | |
339 | 410 | |||
340 | static void | 411 | static void | |
341 | usage(void) | 412 | usage(void) | |
342 | { | 413 | { | |
343 | const char *progname; | 414 | const char *progname; | |
344 | 415 | |||
345 | progname = getprogname(); | 416 | progname = getprogname(); | |
346 | fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | " | 417 | fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | " | |
347 | "on | off | toggle]\n", progname); | 418 | "on | off | toggle]\n", progname); | |
419 | fprintf(stderr, "usage: %s [-q] device pin pulse [frequency " | |||
420 | "[duty cycle]]\n", progname); | |||
348 | fprintf(stderr, " %s [-q] device pin set [flags] [name]\n", | 421 | fprintf(stderr, " %s [-q] device pin set [flags] [name]\n", | |
349 | progname); | 422 | progname); | |
350 | fprintf(stderr, " %s [-q] device pin unset\n", progname); | 423 | fprintf(stderr, " %s [-q] device pin unset\n", progname); | |
351 | fprintf(stderr, " %s [-q] device attach device offset mask\n", | 424 | fprintf(stderr, " %s [-q] device attach device offset mask\n", | |
352 | progname); | 425 | progname); | |
353 | fprintf(stderr, " %s [-q] device detach device\n", progname); | 426 | fprintf(stderr, " %s [-q] device detach device\n", progname); | |
354 | 427 | |||
355 | exit(EXIT_FAILURE); | 428 | exit(EXIT_FAILURE); | |
356 | } | 429 | } |