1 | /* $NetBSD: gpio.c,v 1.58 2016/05/11 18:33:40 bouyer Exp $ */ |
2 | /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 2008, 2009, 2010, 2011 Marc Balmer <marc@msys.ch> |
6 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> |
7 | * |
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 |
10 | * copyright notice and this permission notice appear in all copies. |
11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
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 |
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 | */ |
20 | |
21 | #include <sys/cdefs.h> |
22 | __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.58 2016/05/11 18:33:40 bouyer Exp $" ); |
23 | |
24 | /* |
25 | * General Purpose Input/Output framework. |
26 | */ |
27 | |
28 | #include <sys/param.h> |
29 | #include <sys/callout.h> |
30 | #include <sys/systm.h> |
31 | #include <sys/conf.h> |
32 | #include <sys/device.h> |
33 | #include <sys/fcntl.h> |
34 | #include <sys/ioctl.h> |
35 | #include <sys/gpio.h> |
36 | #include <sys/kernel.h> |
37 | #include <sys/vnode.h> |
38 | #include <sys/kmem.h> |
39 | #include <sys/mutex.h> |
40 | #include <sys/condvar.h> |
41 | #include <sys/queue.h> |
42 | #include <sys/kauth.h> |
43 | #include <sys/module.h> |
44 | #include <dev/gpio/gpiovar.h> |
45 | |
46 | #include "locators.h" |
47 | |
48 | #ifdef GPIO_DEBUG |
49 | #define DPRINTFN(n, x) do { if (gpiodebug > (n)) printf x; } while (0) |
50 | int gpiodebug = 0; |
51 | #else |
52 | #define DPRINTFN(n, x) |
53 | #endif |
54 | #define DPRINTF(x) DPRINTFN(0, x) |
55 | |
56 | struct gpio_softc { |
57 | device_t sc_dev; |
58 | |
59 | gpio_chipset_tag_t sc_gc; /* GPIO controller */ |
60 | gpio_pin_t *sc_pins; /* pins array */ |
61 | int sc_npins; /* number of pins */ |
62 | |
63 | kmutex_t sc_mtx; |
64 | kcondvar_t sc_ioctl; /* ioctl in progress */ |
65 | int sc_ioctl_busy; /* ioctl is busy */ |
66 | kcondvar_t sc_attach; /* attach/detach in progress */ |
67 | int sc_attach_busy;/* busy in attach/detach */ |
68 | #ifdef COMPAT_50 |
69 | LIST_HEAD(, gpio_dev) sc_devs; /* devices */ |
70 | #endif |
71 | LIST_HEAD(, gpio_name) sc_names; /* named pins */ |
72 | }; |
73 | |
74 | static int gpio_match(device_t, cfdata_t, void *); |
75 | int gpio_submatch(device_t, cfdata_t, const int *, void *); |
76 | static void gpio_attach(device_t, device_t, void *); |
77 | static int gpio_rescan(device_t, const char *, const int *); |
78 | static void gpio_childdetached(device_t, device_t); |
79 | static bool gpio_resume(device_t, const pmf_qual_t *); |
80 | static int gpio_detach(device_t, int); |
81 | static int gpio_search(device_t, cfdata_t, const int *, void *); |
82 | static int gpio_print(void *, const char *); |
83 | static int gpio_pinbyname(struct gpio_softc *, char *); |
84 | static int gpio_ioctl(struct gpio_softc *, u_long, void *, int, |
85 | struct lwp *); |
86 | |
87 | #ifdef COMPAT_50 |
88 | /* Old API */ |
89 | static int gpio_ioctl_oapi(struct gpio_softc *, u_long, void *, int, |
90 | kauth_cred_t); |
91 | #endif |
92 | |
93 | CFATTACH_DECL3_NEW(gpio, sizeof(struct gpio_softc), |
94 | gpio_match, gpio_attach, gpio_detach, NULL, gpio_rescan, |
95 | gpio_childdetached, DVF_DETACH_SHUTDOWN); |
96 | |
97 | dev_type_open(gpioopen); |
98 | dev_type_close(gpioclose); |
99 | dev_type_ioctl(gpioioctl); |
100 | dev_type_ioctl(gpioioctl_locked); |
101 | |
102 | const struct cdevsw gpio_cdevsw = { |
103 | .d_open = gpioopen, |
104 | .d_close = gpioclose, |
105 | .d_read = noread, |
106 | .d_write = nowrite, |
107 | .d_ioctl = gpioioctl, |
108 | .d_stop = nostop, |
109 | .d_tty = notty, |
110 | .d_poll = nopoll, |
111 | .d_mmap = nommap, |
112 | .d_kqfilter = nokqfilter, |
113 | .d_discard = nodiscard, |
114 | .d_flag = D_OTHER | D_MPSAFE |
115 | }; |
116 | |
117 | extern struct cfdriver gpio_cd; |
118 | |
119 | static int |
120 | gpio_match(device_t parent, cfdata_t cf, void *aux) |
121 | { |
122 | return 1; |
123 | } |
124 | |
125 | int |
126 | gpio_submatch(device_t parent, cfdata_t cf, const int *ip, void *aux) |
127 | { |
128 | struct gpio_attach_args *ga = aux; |
129 | |
130 | if (ga->ga_offset == -1) |
131 | return 0; |
132 | |
133 | return strcmp(ga->ga_dvname, cf->cf_name) == 0; |
134 | } |
135 | |
136 | static bool |
137 | gpio_resume(device_t self, const pmf_qual_t *qual) |
138 | { |
139 | struct gpio_softc *sc = device_private(self); |
140 | int pin; |
141 | |
142 | for (pin = 0; pin < sc->sc_npins; pin++) { |
143 | gpiobus_pin_ctl(sc->sc_gc, pin, sc->sc_pins[pin].pin_flags); |
144 | gpiobus_pin_write(sc->sc_gc, pin, sc->sc_pins[pin].pin_state); |
145 | } |
146 | return true; |
147 | } |
148 | |
149 | static void |
150 | gpio_childdetached(device_t self, device_t child) |
151 | { |
152 | #ifdef COMPAT_50 |
153 | struct gpio_dev *gdev; |
154 | struct gpio_softc *sc; |
155 | int error; |
156 | |
157 | /* |
158 | * gpio_childetached is serialized because it can be entered in |
159 | * different ways concurrently, e.g. via the GPIODETACH ioctl and |
160 | * drvctl(8) or modunload(8). |
161 | */ |
162 | sc = device_private(self); |
163 | error = 0; |
164 | mutex_enter(&sc->sc_mtx); |
165 | while (sc->sc_attach_busy) { |
166 | error = cv_wait_sig(&sc->sc_attach, &sc->sc_mtx); |
167 | if (error) |
168 | break; |
169 | } |
170 | if (!error) |
171 | sc->sc_attach_busy = 1; |
172 | mutex_exit(&sc->sc_mtx); |
173 | if (error) |
174 | return; |
175 | |
176 | LIST_FOREACH(gdev, &sc->sc_devs, sc_next) |
177 | if (gdev->sc_dev == child) { |
178 | LIST_REMOVE(gdev, sc_next); |
179 | kmem_free(gdev, sizeof(struct gpio_dev)); |
180 | break; |
181 | } |
182 | |
183 | mutex_enter(&sc->sc_mtx); |
184 | sc->sc_attach_busy = 0; |
185 | cv_signal(&sc->sc_attach); |
186 | mutex_exit(&sc->sc_mtx); |
187 | #endif |
188 | } |
189 | |
190 | static int |
191 | gpio_rescan(device_t self, const char *ifattr, const int *locators) |
192 | { |
193 | struct gpio_softc *sc = device_private(self); |
194 | |
195 | config_search_loc(gpio_search, self, ifattr, locators, sc); |
196 | |
197 | return 0; |
198 | } |
199 | |
200 | static void |
201 | gpio_attach(device_t parent, device_t self, void *aux) |
202 | { |
203 | struct gpio_softc *sc = device_private(self); |
204 | struct gpiobus_attach_args *gba = aux; |
205 | |
206 | sc->sc_dev = self; |
207 | sc->sc_gc = gba->gba_gc; |
208 | sc->sc_pins = gba->gba_pins; |
209 | sc->sc_npins = gba->gba_npins; |
210 | |
211 | aprint_normal(": %d pins\n" , sc->sc_npins); |
212 | aprint_naive("\n" ); |
213 | |
214 | if (!pmf_device_register(self, NULL, gpio_resume)) |
215 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
216 | mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM); |
217 | cv_init(&sc->sc_ioctl, "gpioctl" ); |
218 | cv_init(&sc->sc_attach, "gpioatch" ); |
219 | /* |
220 | * Attach all devices that can be connected to the GPIO pins |
221 | * described in the kernel configuration file. |
222 | */ |
223 | gpio_rescan(self, "gpio" , NULL); |
224 | } |
225 | |
226 | static int |
227 | gpio_detach(device_t self, int flags) |
228 | { |
229 | struct gpio_softc *sc; |
230 | int rc; |
231 | |
232 | sc = device_private(self); |
233 | |
234 | if ((rc = config_detach_children(self, flags)) != 0) |
235 | return rc; |
236 | mutex_destroy(&sc->sc_mtx); |
237 | cv_destroy(&sc->sc_ioctl); |
238 | #if 0 |
239 | int maj, mn; |
240 | |
241 | /* Locate the major number */ |
242 | for (maj = 0; maj < nchrdev; maj++) |
243 | if (cdevsw[maj].d_open == gpioopen) |
244 | break; |
245 | |
246 | /* Nuke the vnodes for any open instances (calls close) */ |
247 | mn = device_unit(self); |
248 | vdevgone(maj, mn, mn, VCHR); |
249 | #endif |
250 | return 0; |
251 | } |
252 | |
253 | static int |
254 | gpio_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) |
255 | { |
256 | struct gpio_attach_args ga; |
257 | size_t namlen; |
258 | |
259 | ga.ga_gpio = aux; |
260 | ga.ga_offset = cf->cf_loc[GPIOCF_OFFSET]; |
261 | ga.ga_mask = cf->cf_loc[GPIOCF_MASK]; |
262 | ga.ga_flags = cf->cf_loc[GPIOCF_FLAG]; |
263 | namlen = strlen(cf->cf_name) + 1; |
264 | ga.ga_dvname = kmem_alloc(namlen, KM_NOSLEEP); |
265 | if (ga.ga_dvname == NULL) |
266 | return 0; |
267 | strcpy(ga.ga_dvname, cf->cf_name); |
268 | |
269 | if (config_match(parent, cf, &ga) > 0) |
270 | config_attach(parent, cf, &ga, gpio_print); |
271 | kmem_free(ga.ga_dvname, namlen); |
272 | return 0; |
273 | } |
274 | |
275 | int |
276 | gpio_print(void *aux, const char *pnp) |
277 | { |
278 | struct gpio_attach_args *ga = aux; |
279 | int i; |
280 | |
281 | aprint_normal(" pins" ); |
282 | for (i = 0; i < 32; i++) |
283 | if (ga->ga_mask & (1 << i)) |
284 | aprint_normal(" %d" , ga->ga_offset + i); |
285 | |
286 | return UNCONF; |
287 | } |
288 | |
289 | int |
290 | gpiobus_print(void *aux, const char *pnp) |
291 | { |
292 | #if 0 |
293 | struct gpiobus_attach_args *gba = aux; |
294 | #endif |
295 | if (pnp != NULL) |
296 | aprint_normal("gpiobus at %s" , pnp); |
297 | |
298 | return UNCONF; |
299 | } |
300 | |
301 | /* called from backends when a interrupt even occurs */ |
302 | void |
303 | gpio_intr(device_t self, uint32_t evts) |
304 | { |
305 | struct gpio_softc *sc = device_private(self); |
306 | void (*callback)(void *); |
307 | void *callback_arg; |
308 | |
309 | for (int i = 0; i < sc->sc_npins; i++) { |
310 | if (evts & (1 << i)) { |
311 | mutex_enter(&sc->sc_mtx); |
312 | callback = sc->sc_pins[i].pin_callback; |
313 | callback_arg = sc->sc_pins[i].pin_callback_arg; |
314 | DPRINTFN(2, ("gpio pin %d event callback %p\n" , i, callback)); |
315 | if (callback != NULL) { |
316 | callback(callback_arg); |
317 | } |
318 | mutex_exit(&sc->sc_mtx); |
319 | } |
320 | } |
321 | } |
322 | |
323 | void * |
324 | gpio_find_device(const char *name) |
325 | { |
326 | device_t gpio_dev; |
327 | gpio_dev = device_find_by_xname(name); |
328 | if (gpio_dev == NULL) |
329 | return NULL; |
330 | return device_private(gpio_dev); |
331 | } |
332 | |
333 | const char * |
334 | gpio_get_name(void *gpio) |
335 | { |
336 | struct gpio_softc *sc = gpio; |
337 | return device_xname(sc->sc_dev); |
338 | } |
339 | |
340 | /* return 1 if all pins can be mapped, 0 if not */ |
341 | int |
342 | gpio_pin_can_map(void *gpio, int offset, uint32_t mask) |
343 | { |
344 | struct gpio_softc *sc = gpio; |
345 | int npins, pin, i; |
346 | |
347 | npins = gpio_npins(mask); |
348 | if (npins > sc->sc_npins) |
349 | return 0; |
350 | |
351 | for (npins = 0, i = 0; i < 32; i++) |
352 | if (mask & (1 << i)) { |
353 | pin = offset + i; |
354 | if (pin < 0 || pin >= sc->sc_npins) |
355 | return 0; |
356 | if (sc->sc_pins[pin].pin_mapped) |
357 | return 0; |
358 | } |
359 | |
360 | return 1; |
361 | } |
362 | |
363 | int |
364 | gpio_pin_map(void *gpio, int offset, uint32_t mask, struct gpio_pinmap *map) |
365 | { |
366 | struct gpio_softc *sc = gpio; |
367 | int npins, pin, i; |
368 | |
369 | npins = gpio_npins(mask); |
370 | if (npins > sc->sc_npins) |
371 | return 1; |
372 | |
373 | for (npins = 0, i = 0; i < 32; i++) |
374 | if (mask & (1 << i)) { |
375 | pin = offset + i; |
376 | if (pin < 0 || pin >= sc->sc_npins) |
377 | return 1; |
378 | if (sc->sc_pins[pin].pin_mapped) |
379 | return 1; |
380 | sc->sc_pins[pin].pin_mapped = 1; |
381 | map->pm_map[npins++] = pin; |
382 | } |
383 | map->pm_size = npins; |
384 | |
385 | return 0; |
386 | } |
387 | |
388 | void |
389 | gpio_pin_unmap(void *gpio, struct gpio_pinmap *map) |
390 | { |
391 | struct gpio_softc *sc = gpio; |
392 | int pin, i; |
393 | |
394 | for (i = 0; i < map->pm_size; i++) { |
395 | pin = map->pm_map[i]; |
396 | sc->sc_pins[pin].pin_mapped = 0; |
397 | } |
398 | } |
399 | |
400 | int |
401 | gpio_pin_read(void *gpio, struct gpio_pinmap *map, int pin) |
402 | { |
403 | struct gpio_softc *sc = gpio; |
404 | |
405 | return gpiobus_pin_read(sc->sc_gc, map->pm_map[pin]); |
406 | } |
407 | |
408 | void |
409 | gpio_pin_write(void *gpio, struct gpio_pinmap *map, int pin, int value) |
410 | { |
411 | struct gpio_softc *sc = gpio; |
412 | |
413 | gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value); |
414 | sc->sc_pins[map->pm_map[pin]].pin_state = value; |
415 | } |
416 | |
417 | void |
418 | gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags) |
419 | { |
420 | struct gpio_softc *sc = gpio; |
421 | struct gpio_pin *pinp = &sc->sc_pins[map->pm_map[pin]]; |
422 | |
423 | KASSERT((flags & GPIO_PIN_EVENTS) == 0); |
424 | mutex_enter(&sc->sc_mtx); |
425 | gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags); |
426 | pinp->pin_callback = NULL; |
427 | pinp->pin_callback_arg = NULL; |
428 | mutex_exit(&sc->sc_mtx); |
429 | } |
430 | |
431 | int |
432 | gpio_pin_ctl_intr(void *gpio, struct gpio_pinmap *map, int pin, int flags, |
433 | int ipl, void (*callback)(void *), void *arg) |
434 | { |
435 | struct gpio_softc *sc = gpio; |
436 | struct gpio_pin *pinp = &sc->sc_pins[map->pm_map[pin]]; |
437 | KASSERT((flags & GPIO_PIN_EVENTS) != 0); |
438 | if (ipl != IPL_VM) |
439 | return EINVAL; |
440 | mutex_enter(&sc->sc_mtx); |
441 | if (pinp->pin_callback != NULL) { |
442 | mutex_exit(&sc->sc_mtx); |
443 | return EEXIST; |
444 | } |
445 | pinp->pin_callback = callback; |
446 | pinp->pin_callback_arg = arg; |
447 | gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags); |
448 | mutex_exit(&sc->sc_mtx); |
449 | return 0; |
450 | } |
451 | |
452 | void |
453 | gpio_pin_irqen(void *gpio, struct gpio_pinmap *map, int pin, bool en) |
454 | { |
455 | struct gpio_softc *sc = gpio; |
456 | gpiobus_pin_irqen(sc->sc_gc, map->pm_map[pin], en); |
457 | } |
458 | |
459 | int |
460 | gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin) |
461 | { |
462 | struct gpio_softc *sc = gpio; |
463 | |
464 | return sc->sc_pins[map->pm_map[pin]].pin_caps; |
465 | } |
466 | |
467 | int |
468 | gpio_npins(uint32_t mask) |
469 | { |
470 | int npins, i; |
471 | |
472 | for (npins = 0, i = 0; i < 32; i++) |
473 | if (mask & (1 << i)) |
474 | npins++; |
475 | |
476 | return npins; |
477 | } |
478 | |
479 | int |
480 | gpio_lock(void *data) |
481 | { |
482 | struct gpio_softc *sc; |
483 | int error; |
484 | |
485 | error = 0; |
486 | sc = data; |
487 | mutex_enter(&sc->sc_mtx); |
488 | while (sc->sc_ioctl_busy) { |
489 | error = cv_wait_sig(&sc->sc_ioctl, &sc->sc_mtx); |
490 | if (error) |
491 | break; |
492 | } |
493 | if (!error) |
494 | sc->sc_ioctl_busy = 1; |
495 | mutex_exit(&sc->sc_mtx); |
496 | return error; |
497 | } |
498 | |
499 | void |
500 | gpio_unlock(void *data) |
501 | { |
502 | struct gpio_softc *sc; |
503 | |
504 | sc = data; |
505 | mutex_enter(&sc->sc_mtx); |
506 | sc->sc_ioctl_busy = 0; |
507 | cv_signal(&sc->sc_ioctl); |
508 | mutex_exit(&sc->sc_mtx); |
509 | } |
510 | |
511 | int |
512 | gpioopen(dev_t dev, int flag, int mode, struct lwp *l) |
513 | { |
514 | struct gpio_softc *sc; |
515 | |
516 | sc = device_lookup_private(&gpio_cd, minor(dev)); |
517 | if (sc == NULL) |
518 | return ENXIO; |
519 | |
520 | return gpiobus_open(sc->sc_gc, sc->sc_dev); |
521 | } |
522 | |
523 | int |
524 | gpioclose(dev_t dev, int flag, int mode, struct lwp *l) |
525 | { |
526 | struct gpio_softc *sc; |
527 | |
528 | sc = device_lookup_private(&gpio_cd, minor(dev)); |
529 | return gpiobus_close(sc->sc_gc, sc->sc_dev); |
530 | } |
531 | |
532 | static int |
533 | gpio_pinbyname(struct gpio_softc *sc, char *gp_name) |
534 | { |
535 | struct gpio_name *nm; |
536 | |
537 | LIST_FOREACH(nm, &sc->sc_names, gp_next) |
538 | if (!strcmp(nm->gp_name, gp_name)) |
539 | return nm->gp_pin; |
540 | return -1; |
541 | } |
542 | |
543 | int |
544 | gpioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) |
545 | { |
546 | int error; |
547 | struct gpio_softc *sc; |
548 | |
549 | sc = device_lookup_private(&gpio_cd, minor(dev)); |
550 | |
551 | error = gpio_lock(sc); |
552 | if (error) |
553 | return error; |
554 | |
555 | error = gpio_ioctl(sc, cmd, data, flag, l); |
556 | gpio_unlock(sc); |
557 | return error; |
558 | } |
559 | |
560 | static int |
561 | gpio_ioctl(struct gpio_softc *sc, u_long cmd, void *data, int flag, |
562 | struct lwp *l) |
563 | { |
564 | gpio_chipset_tag_t gc; |
565 | struct gpio_info *info; |
566 | struct gpio_attach *attach; |
567 | struct gpio_attach_args ga; |
568 | struct gpio_req *req; |
569 | struct gpio_name *nm; |
570 | struct gpio_set *set; |
571 | #ifdef COMPAT_50 |
572 | struct gpio_dev *gdev; |
573 | #endif |
574 | device_t dv; |
575 | cfdata_t cf; |
576 | kauth_cred_t cred; |
577 | int locs[GPIOCF_NLOCS]; |
578 | int error, pin, value, flags, npins; |
579 | |
580 | gc = sc->sc_gc; |
581 | ga.ga_flags = 0; |
582 | |
583 | if (cmd != GPIOINFO && !device_is_active(sc->sc_dev)) { |
584 | DPRINTF(("%s: device is not active\n" , |
585 | device_xname(sc->sc_dev))); |
586 | return EBUSY; |
587 | } |
588 | |
589 | cred = kauth_cred_get(); |
590 | |
591 | switch (cmd) { |
592 | case GPIOINFO: |
593 | info = data; |
594 | if (!kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
595 | NULL, NULL, NULL, NULL)) |
596 | info->gpio_npins = sc->sc_npins; |
597 | else { |
598 | for (pin = npins = 0; pin < sc->sc_npins; pin++) |
599 | if (sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) |
600 | ++npins; |
601 | info->gpio_npins = npins; |
602 | } |
603 | break; |
604 | case GPIOREAD: |
605 | req = data; |
606 | |
607 | if (req->gp_name[0] != '\0') |
608 | pin = gpio_pinbyname(sc, req->gp_name); |
609 | else |
610 | pin = req->gp_pin; |
611 | |
612 | if (pin < 0 || pin >= sc->sc_npins) |
613 | return EINVAL; |
614 | |
615 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
616 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
617 | NULL, NULL, NULL, NULL)) |
618 | return EPERM; |
619 | |
620 | /* return read value */ |
621 | req->gp_value = gpiobus_pin_read(gc, pin); |
622 | break; |
623 | case GPIOWRITE: |
624 | if ((flag & FWRITE) == 0) |
625 | return EBADF; |
626 | |
627 | req = data; |
628 | |
629 | if (req->gp_name[0] != '\0') |
630 | pin = gpio_pinbyname(sc, req->gp_name); |
631 | else |
632 | pin = req->gp_pin; |
633 | |
634 | if (pin < 0 || pin >= sc->sc_npins) |
635 | return EINVAL; |
636 | |
637 | if (sc->sc_pins[pin].pin_mapped) |
638 | return EBUSY; |
639 | |
640 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
641 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
642 | NULL, NULL, NULL, NULL)) |
643 | return EPERM; |
644 | |
645 | value = req->gp_value; |
646 | if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH) |
647 | return EINVAL; |
648 | |
649 | /* return old value */ |
650 | req->gp_value = gpiobus_pin_read(gc, pin); |
651 | gpiobus_pin_write(gc, pin, value); |
652 | /* update current value */ |
653 | sc->sc_pins[pin].pin_state = value; |
654 | break; |
655 | case GPIOTOGGLE: |
656 | if ((flag & FWRITE) == 0) |
657 | return EBADF; |
658 | |
659 | req = data; |
660 | |
661 | if (req->gp_name[0] != '\0') |
662 | pin = gpio_pinbyname(sc, req->gp_name); |
663 | else |
664 | pin = req->gp_pin; |
665 | |
666 | if (pin < 0 || pin >= sc->sc_npins) |
667 | return EINVAL; |
668 | |
669 | if (sc->sc_pins[pin].pin_mapped) |
670 | return EBUSY; |
671 | |
672 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
673 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
674 | NULL, NULL, NULL, NULL)) |
675 | return EPERM; |
676 | |
677 | value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ? |
678 | GPIO_PIN_HIGH : GPIO_PIN_LOW); |
679 | gpiobus_pin_write(gc, pin, value); |
680 | /* return old value */ |
681 | req->gp_value = sc->sc_pins[pin].pin_state; |
682 | /* update current value */ |
683 | sc->sc_pins[pin].pin_state = value; |
684 | break; |
685 | case GPIOATTACH: |
686 | attach = data; |
687 | ga.ga_flags = attach->ga_flags; |
688 | #ifdef COMPAT_50 |
689 | /* FALLTHROUGH */ |
690 | case GPIOATTACH50: |
691 | /* |
692 | * The double assignment to 'attach' in case of GPIOATTACH |
693 | * and COMPAT_50 is on purpose. It ensures backward |
694 | * compatability in case we are called through the old |
695 | * GPIOATTACH50 ioctl(2), which had not the ga_flags field |
696 | * in struct gpio_attach. |
697 | */ |
698 | attach = data; |
699 | #endif |
700 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
701 | NULL, NULL, NULL, NULL)) |
702 | return EPERM; |
703 | |
704 | /* do not try to attach if the pins are already mapped */ |
705 | if (!gpio_pin_can_map(sc, attach->ga_offset, attach->ga_mask)) |
706 | return EBUSY; |
707 | |
708 | error = 0; |
709 | mutex_enter(&sc->sc_mtx); |
710 | while (sc->sc_attach_busy) { |
711 | error = cv_wait_sig(&sc->sc_attach, &sc->sc_mtx); |
712 | if (error) |
713 | break; |
714 | } |
715 | if (!error) |
716 | sc->sc_attach_busy = 1; |
717 | mutex_exit(&sc->sc_mtx); |
718 | if (error) |
719 | return EBUSY; |
720 | |
721 | ga.ga_gpio = sc; |
722 | /* Don't access attach->ga_flags here. */ |
723 | ga.ga_dvname = attach->ga_dvname; |
724 | ga.ga_offset = attach->ga_offset; |
725 | ga.ga_mask = attach->ga_mask; |
726 | DPRINTF(("%s: attach %s with offset %d, mask " |
727 | "0x%02x, and flags 0x%02x\n" , device_xname(sc->sc_dev), |
728 | ga.ga_dvname, ga.ga_offset, ga.ga_mask, ga.ga_flags)); |
729 | |
730 | locs[GPIOCF_OFFSET] = ga.ga_offset; |
731 | locs[GPIOCF_MASK] = ga.ga_mask; |
732 | locs[GPIOCF_FLAG] = ga.ga_flags; |
733 | |
734 | cf = config_search_loc(NULL, sc->sc_dev, "gpio" , locs, &ga); |
735 | if (cf != NULL) { |
736 | dv = config_attach_loc(sc->sc_dev, cf, locs, &ga, |
737 | gpiobus_print); |
738 | #ifdef COMPAT_50 |
739 | if (dv != NULL) { |
740 | gdev = kmem_alloc(sizeof(struct gpio_dev), |
741 | KM_SLEEP); |
742 | gdev->sc_dev = dv; |
743 | LIST_INSERT_HEAD(&sc->sc_devs, gdev, sc_next); |
744 | } else |
745 | error = EINVAL; |
746 | #else |
747 | if (dv == NULL) |
748 | error = EINVAL; |
749 | #endif |
750 | } else |
751 | error = EINVAL; |
752 | mutex_enter(&sc->sc_mtx); |
753 | sc->sc_attach_busy = 0; |
754 | cv_signal(&sc->sc_attach); |
755 | mutex_exit(&sc->sc_mtx); |
756 | return error; |
757 | case GPIOSET: |
758 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
759 | NULL, NULL, NULL, NULL)) |
760 | return EPERM; |
761 | |
762 | set = data; |
763 | |
764 | if (set->gp_name[0] != '\0') |
765 | pin = gpio_pinbyname(sc, set->gp_name); |
766 | else |
767 | pin = set->gp_pin; |
768 | |
769 | if (pin < 0 || pin >= sc->sc_npins) |
770 | return EINVAL; |
771 | flags = set->gp_flags; |
772 | |
773 | /* check that the controller supports all requested flags */ |
774 | if ((flags & sc->sc_pins[pin].pin_caps) != flags) |
775 | return ENODEV; |
776 | flags = set->gp_flags; |
777 | |
778 | set->gp_caps = sc->sc_pins[pin].pin_caps; |
779 | /* return old value */ |
780 | set->gp_flags = sc->sc_pins[pin].pin_flags; |
781 | |
782 | if (flags > 0) { |
783 | flags |= GPIO_PIN_SET; |
784 | gpiobus_pin_ctl(gc, pin, flags); |
785 | /* update current value */ |
786 | sc->sc_pins[pin].pin_flags = flags; |
787 | } |
788 | |
789 | /* rename pin or new pin? */ |
790 | if (set->gp_name2[0] != '\0') { |
791 | struct gpio_name *gnm; |
792 | |
793 | gnm = NULL; |
794 | LIST_FOREACH(nm, &sc->sc_names, gp_next) { |
795 | if (!strcmp(nm->gp_name, set->gp_name2) && |
796 | nm->gp_pin != pin) |
797 | return EINVAL; /* duplicate name */ |
798 | if (nm->gp_pin == pin) |
799 | gnm = nm; |
800 | } |
801 | if (gnm != NULL) |
802 | strlcpy(gnm->gp_name, set->gp_name2, |
803 | sizeof(gnm->gp_name)); |
804 | else { |
805 | nm = kmem_alloc(sizeof(struct gpio_name), |
806 | KM_SLEEP); |
807 | strlcpy(nm->gp_name, set->gp_name2, |
808 | sizeof(nm->gp_name)); |
809 | nm->gp_pin = set->gp_pin; |
810 | LIST_INSERT_HEAD(&sc->sc_names, nm, gp_next); |
811 | } |
812 | } |
813 | break; |
814 | case GPIOUNSET: |
815 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
816 | NULL, NULL, NULL, NULL)) |
817 | return EPERM; |
818 | |
819 | set = data; |
820 | if (set->gp_name[0] != '\0') |
821 | pin = gpio_pinbyname(sc, set->gp_name); |
822 | else |
823 | pin = set->gp_pin; |
824 | |
825 | if (pin < 0 || pin >= sc->sc_npins) |
826 | return EINVAL; |
827 | if (sc->sc_pins[pin].pin_mapped) |
828 | return EBUSY; |
829 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET)) |
830 | return EINVAL; |
831 | |
832 | LIST_FOREACH(nm, &sc->sc_names, gp_next) { |
833 | if (nm->gp_pin == pin) { |
834 | LIST_REMOVE(nm, gp_next); |
835 | kmem_free(nm, sizeof(struct gpio_name)); |
836 | break; |
837 | } |
838 | } |
839 | sc->sc_pins[pin].pin_flags &= ~GPIO_PIN_SET; |
840 | break; |
841 | default: |
842 | #ifdef COMPAT_50 |
843 | /* Try the old API */ |
844 | DPRINTF(("%s: trying the old API\n" , device_xname(sc->sc_dev))); |
845 | return gpio_ioctl_oapi(sc, cmd, data, flag, cred); |
846 | #else |
847 | return ENOTTY; |
848 | #endif |
849 | } |
850 | return 0; |
851 | } |
852 | |
853 | #ifdef COMPAT_50 |
854 | static int |
855 | gpio_ioctl_oapi(struct gpio_softc *sc, u_long cmd, void *data, int flag, |
856 | kauth_cred_t cred) |
857 | { |
858 | gpio_chipset_tag_t gc; |
859 | struct gpio_pin_op *op; |
860 | struct gpio_pin_ctl *ctl; |
861 | struct gpio_attach *attach; |
862 | struct gpio_dev *gdev; |
863 | |
864 | int error, pin, value, flags; |
865 | |
866 | gc = sc->sc_gc; |
867 | |
868 | switch (cmd) { |
869 | case GPIOPINREAD: |
870 | op = data; |
871 | |
872 | pin = op->gp_pin; |
873 | |
874 | if (pin < 0 || pin >= sc->sc_npins) |
875 | return EINVAL; |
876 | |
877 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
878 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
879 | NULL, NULL, NULL, NULL)) |
880 | return EPERM; |
881 | |
882 | /* return read value */ |
883 | op->gp_value = gpiobus_pin_read(gc, pin); |
884 | break; |
885 | case GPIOPINWRITE: |
886 | if ((flag & FWRITE) == 0) |
887 | return EBADF; |
888 | |
889 | op = data; |
890 | |
891 | pin = op->gp_pin; |
892 | |
893 | if (pin < 0 || pin >= sc->sc_npins) |
894 | return EINVAL; |
895 | |
896 | if (sc->sc_pins[pin].pin_mapped) |
897 | return EBUSY; |
898 | |
899 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
900 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
901 | NULL, NULL, NULL, NULL)) |
902 | return EPERM; |
903 | |
904 | value = op->gp_value; |
905 | if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH) |
906 | return EINVAL; |
907 | |
908 | gpiobus_pin_write(gc, pin, value); |
909 | /* return old value */ |
910 | op->gp_value = sc->sc_pins[pin].pin_state; |
911 | /* update current value */ |
912 | sc->sc_pins[pin].pin_state = value; |
913 | break; |
914 | case GPIOPINTOGGLE: |
915 | if ((flag & FWRITE) == 0) |
916 | return EBADF; |
917 | |
918 | op = data; |
919 | |
920 | pin = op->gp_pin; |
921 | |
922 | if (pin < 0 || pin >= sc->sc_npins) |
923 | return EINVAL; |
924 | |
925 | if (sc->sc_pins[pin].pin_mapped) |
926 | return EBUSY; |
927 | |
928 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
929 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
930 | NULL, NULL, NULL, NULL)) |
931 | return EPERM; |
932 | |
933 | value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ? |
934 | GPIO_PIN_HIGH : GPIO_PIN_LOW); |
935 | gpiobus_pin_write(gc, pin, value); |
936 | /* return old value */ |
937 | op->gp_value = sc->sc_pins[pin].pin_state; |
938 | /* update current value */ |
939 | sc->sc_pins[pin].pin_state = value; |
940 | break; |
941 | case GPIOPINCTL: |
942 | ctl = data; |
943 | |
944 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
945 | NULL, NULL, NULL, NULL)) |
946 | return EPERM; |
947 | |
948 | pin = ctl->gp_pin; |
949 | |
950 | if (pin < 0 || pin >= sc->sc_npins) |
951 | return EINVAL; |
952 | if (sc->sc_pins[pin].pin_mapped) |
953 | return EBUSY; |
954 | flags = ctl->gp_flags; |
955 | |
956 | /* check that the controller supports all requested flags */ |
957 | if ((flags & sc->sc_pins[pin].pin_caps) != flags) |
958 | return ENODEV; |
959 | |
960 | ctl->gp_caps = sc->sc_pins[pin].pin_caps; |
961 | /* return old value */ |
962 | ctl->gp_flags = sc->sc_pins[pin].pin_flags; |
963 | if (flags > 0) { |
964 | gpiobus_pin_ctl(gc, pin, flags); |
965 | /* update current value */ |
966 | sc->sc_pins[pin].pin_flags = flags; |
967 | } |
968 | break; |
969 | case GPIODETACH50: |
970 | /* FALLTHOUGH */ |
971 | case GPIODETACH: |
972 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
973 | NULL, NULL, NULL, NULL)) |
974 | return EPERM; |
975 | |
976 | error = 0; |
977 | mutex_enter(&sc->sc_mtx); |
978 | while (sc->sc_attach_busy) { |
979 | error = cv_wait_sig(&sc->sc_attach, &sc->sc_mtx); |
980 | if (error) |
981 | break; |
982 | } |
983 | if (!error) |
984 | sc->sc_attach_busy = 1; |
985 | mutex_exit(&sc->sc_mtx); |
986 | if (error) |
987 | return EBUSY; |
988 | |
989 | attach = data; |
990 | LIST_FOREACH(gdev, &sc->sc_devs, sc_next) { |
991 | if (strcmp(device_xname(gdev->sc_dev), |
992 | attach->ga_dvname) == 0) { |
993 | mutex_enter(&sc->sc_mtx); |
994 | sc->sc_attach_busy = 0; |
995 | cv_signal(&sc->sc_attach); |
996 | mutex_exit(&sc->sc_mtx); |
997 | |
998 | if (config_detach(gdev->sc_dev, 0) == 0) |
999 | return 0; |
1000 | break; |
1001 | } |
1002 | } |
1003 | if (gdev == NULL) { |
1004 | mutex_enter(&sc->sc_mtx); |
1005 | sc->sc_attach_busy = 0; |
1006 | cv_signal(&sc->sc_attach); |
1007 | mutex_exit(&sc->sc_mtx); |
1008 | } |
1009 | return EINVAL; |
1010 | |
1011 | default: |
1012 | return ENOTTY; |
1013 | } |
1014 | return 0; |
1015 | } |
1016 | #endif /* COMPAT_50 */ |
1017 | |
1018 | MODULE(MODULE_CLASS_DRIVER, gpio, NULL); |
1019 | |
1020 | #ifdef _MODULE |
1021 | #include "ioconf.c" |
1022 | #endif |
1023 | |
1024 | static int |
1025 | gpio_modcmd(modcmd_t cmd, void *opaque) |
1026 | { |
1027 | #ifdef _MODULE |
1028 | devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; |
1029 | int error; |
1030 | #endif |
1031 | switch (cmd) { |
1032 | case MODULE_CMD_INIT: |
1033 | #ifdef _MODULE |
1034 | error = config_init_component(cfdriver_ioconf_gpio, |
1035 | cfattach_ioconf_gpio, cfdata_ioconf_gpio); |
1036 | if (error) { |
1037 | aprint_error("%s: unable to init component\n" , |
1038 | gpio_cd.cd_name); |
1039 | return error; |
1040 | } |
1041 | error = devsw_attach(gpio_cd.cd_name, NULL, &bmajor, |
1042 | &gpio_cdevsw, &cmajor); |
1043 | if (error) { |
1044 | aprint_error("%s: unable to register devsw\n" , |
1045 | gpio_cd.cd_name); |
1046 | return config_fini_component(cfdriver_ioconf_gpio, |
1047 | cfattach_ioconf_gpio, cfdata_ioconf_gpio); |
1048 | } |
1049 | #endif |
1050 | return 0; |
1051 | case MODULE_CMD_FINI: |
1052 | #ifdef _MODULE |
1053 | config_fini_component(cfdriver_ioconf_gpio, |
1054 | cfattach_ioconf_gpio, cfdata_ioconf_gpio); |
1055 | devsw_detach(NULL, &gpio_cdevsw); |
1056 | #endif |
1057 | return 0; |
1058 | default: |
1059 | return ENOTTY; |
1060 | } |
1061 | } |
1062 | |