Annotation of src/sys/dev/gpio/gpio.c, Revision 1.15.4.4
1.15.4.4! yamt 1: /* $NetBSD: gpio.c,v 1.15.4.3 2009/08/19 18:47:05 yamt Exp $ */
1.5 riz 2: /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */
3:
1.1 jmcneill 4: /*
1.15.4.3 yamt 5: * Copyright (c) 2008, 2009 Marc Balmer <marc@msys.ch>
1.5 riz 6: * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org>
1.1 jmcneill 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:
1.2 cube 21: #include <sys/cdefs.h>
1.15.4.4! yamt 22: __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.15.4.3 2009/08/19 18:47:05 yamt Exp $");
1.2 cube 23:
1.1 jmcneill 24: /*
25: * General Purpose Input/Output framework.
26: */
27:
28: #include <sys/param.h>
29: #include <sys/systm.h>
30: #include <sys/conf.h>
31: #include <sys/device.h>
1.15.4.3 yamt 32: #include <sys/fcntl.h>
1.1 jmcneill 33: #include <sys/ioctl.h>
34: #include <sys/gpio.h>
35: #include <sys/vnode.h>
1.15.4.3 yamt 36: #include <sys/kmem.h>
37: #include <sys/queue.h>
38: #include <sys/kauth.h>
1.1 jmcneill 39:
40: #include <dev/gpio/gpiovar.h>
41:
1.3 drochner 42: #include "locators.h"
43:
1.15.4.3 yamt 44: #ifdef GPIO_DEBUG
45: #define DPRINTFN(n, x) do { if (gpiodebug > (n)) printf x; } while (0)
46: int gpiodebug = 0;
47: #else
48: #define DPRINTFN(n, x)
49: #endif
50: #define DPRINTF(x) DPRINTFN(0, x)
1.1 jmcneill 51:
1.15.4.3 yamt 52: struct gpio_softc {
53: device_t sc_dev;
1.1 jmcneill 54:
1.15.4.3 yamt 55: gpio_chipset_tag_t sc_gc; /* GPIO controller */
56: gpio_pin_t *sc_pins; /* pins array */
57: int sc_npins; /* number of pins */
58:
59: int sc_opened;
60: LIST_HEAD(, gpio_dev) sc_devs; /* devices */
61: LIST_HEAD(, gpio_name) sc_names; /* named pins */
1.1 jmcneill 62: };
63:
1.15.4.1 yamt 64: int gpio_match(device_t, cfdata_t, void *);
1.15.4.3 yamt 65: int gpio_submatch(device_t, cfdata_t, const int *, void *);
1.14 dyoung 66: void gpio_attach(device_t, device_t, void *);
1.15 dyoung 67: bool gpio_resume(device_t PMF_FN_PROTO);
1.14 dyoung 68: int gpio_detach(device_t, int);
69: int gpio_activate(device_t, enum devact);
1.15.4.1 yamt 70: int gpio_search(device_t, cfdata_t, const int *, void *);
1.1 jmcneill 71: int gpio_print(void *, const char *);
1.15.4.3 yamt 72: int gpio_pinbyname(struct gpio_softc *, char *);
73:
74: /* Old API */
75: int gpio_ioctl_oapi(struct gpio_softc *, u_long, void *, int, kauth_cred_t);
1.1 jmcneill 76:
1.15.4.2 yamt 77: CFATTACH_DECL3_NEW(gpio, sizeof(struct gpio_softc),
78: gpio_match, gpio_attach, gpio_detach, gpio_activate, NULL, NULL,
79: DVF_DETACH_SHUTDOWN);
1.1 jmcneill 80:
81: dev_type_open(gpioopen);
82: dev_type_close(gpioclose);
83: dev_type_ioctl(gpioioctl);
84:
85: const struct cdevsw gpio_cdevsw = {
86: gpioopen, gpioclose, noread, nowrite, gpioioctl,
1.9 christos 87: nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
1.1 jmcneill 88: };
89:
90: extern struct cfdriver gpio_cd;
91:
92: int
1.15.4.1 yamt 93: gpio_match(device_t parent, cfdata_t cf, void *aux)
1.1 jmcneill 94: {
1.15.4.3 yamt 95: return 1;
96: }
97:
98: int
99: gpio_submatch(device_t parent, cfdata_t cf, const int *ip, void *aux)
100: {
101: struct gpio_attach_args *ga = aux;
1.1 jmcneill 102:
1.15.4.3 yamt 103: if (ga->ga_offset == -1)
104: return 0;
105:
106: return strcmp(ga->ga_dvname, cf->cf_name) == 0;
1.1 jmcneill 107: }
108:
1.13 dyoung 109: bool
1.15 dyoung 110: gpio_resume(device_t self PMF_FN_ARGS)
1.13 dyoung 111: {
112: struct gpio_softc *sc = device_private(self);
113: int pin;
114:
115: for (pin = 0; pin < sc->sc_npins; pin++) {
116: gpiobus_pin_ctl(sc->sc_gc, pin, sc->sc_pins[pin].pin_flags);
117: gpiobus_pin_write(sc->sc_gc, pin, sc->sc_pins[pin].pin_state);
118: }
119: return true;
120: }
121:
1.1 jmcneill 122: void
1.14 dyoung 123: gpio_attach(device_t parent, device_t self, void *aux)
1.1 jmcneill 124: {
1.7 thorpej 125: struct gpio_softc *sc = device_private(self);
1.1 jmcneill 126: struct gpiobus_attach_args *gba = aux;
127:
1.15.4.1 yamt 128: sc->sc_dev = self;
1.1 jmcneill 129: sc->sc_gc = gba->gba_gc;
130: sc->sc_pins = gba->gba_pins;
131: sc->sc_npins = gba->gba_npins;
132:
133: printf(": %d pins\n", sc->sc_npins);
134:
1.13 dyoung 135: if (!pmf_device_register(self, NULL, gpio_resume))
136: aprint_error_dev(self, "couldn't establish power handler\n");
137:
1.1 jmcneill 138: /*
139: * Attach all devices that can be connected to the GPIO pins
140: * described in the kernel configuration file.
141: */
1.5 riz 142: config_search_ia(gpio_search, self, "gpio", sc);
1.1 jmcneill 143: }
144:
145: int
1.14 dyoung 146: gpio_detach(device_t self, int flags)
1.1 jmcneill 147: {
148: #if 0
149: int maj, mn;
150:
151: /* Locate the major number */
152: for (maj = 0; maj < nchrdev; maj++)
153: if (cdevsw[maj].d_open == gpioopen)
154: break;
155:
156: /* Nuke the vnodes for any open instances (calls close) */
1.6 thorpej 157: mn = device_unit(self);
1.1 jmcneill 158: vdevgone(maj, mn, mn, VCHR);
159: #endif
1.15.4.3 yamt 160: return 0;
1.1 jmcneill 161: }
162:
163: int
1.14 dyoung 164: gpio_activate(device_t self, enum devact act)
1.1 jmcneill 165: {
1.15.4.3 yamt 166: printf("gpio_active: ");
1.1 jmcneill 167: switch (act) {
168: case DVACT_ACTIVATE:
1.15.4.3 yamt 169: DPRINTF(("ACTIVATE\n"));
170: return EOPNOTSUPP;
1.1 jmcneill 171: case DVACT_DEACTIVATE:
1.15.4.3 yamt 172: DPRINTF(("DEACTIVATE\n"));
1.1 jmcneill 173: break;
174: }
1.15.4.3 yamt 175: return 0;
1.1 jmcneill 176: }
177:
178: int
1.15.4.1 yamt 179: gpio_search(device_t parent, cfdata_t cf,
1.11 christos 180: const int *ldesc, void *aux)
1.1 jmcneill 181: {
182: struct gpio_attach_args ga;
183:
1.5 riz 184: ga.ga_gpio = aux;
185: ga.ga_offset = cf->cf_loc[GPIOCF_OFFSET];
1.3 drochner 186: ga.ga_mask = cf->cf_loc[GPIOCF_MASK];
1.1 jmcneill 187:
188: if (config_match(parent, cf, &ga) > 0)
189: config_attach(parent, cf, &ga, gpio_print);
190:
1.15.4.3 yamt 191: return 0;
1.1 jmcneill 192: }
193:
194: int
1.11 christos 195: gpio_print(void *aux, const char *pnp)
1.1 jmcneill 196: {
197: struct gpio_attach_args *ga = aux;
198: int i;
199:
200: printf(" pins");
201: for (i = 0; i < 32; i++)
202: if (ga->ga_mask & (1 << i))
1.5 riz 203: printf(" %d", ga->ga_offset + i);
1.1 jmcneill 204:
1.15.4.3 yamt 205: return UNCONF;
1.1 jmcneill 206: }
207:
208: int
1.11 christos 209: gpiobus_print(void *aux, const char *pnp)
1.1 jmcneill 210: {
1.3 drochner 211: #if 0
1.1 jmcneill 212: struct gpiobus_attach_args *gba = aux;
1.3 drochner 213: #endif
1.1 jmcneill 214: if (pnp != NULL)
1.15.4.3 yamt 215: printf("gpiobus at %s", pnp);
1.1 jmcneill 216:
1.15.4.3 yamt 217: return UNCONF;
1.1 jmcneill 218: }
219:
1.15.4.4! yamt 220: /* return 1 if all pins can be mapped, 0 if not */
! 221:
! 222: int
! 223: gpio_pin_can_map(void *gpio, int offset, u_int32_t mask)
! 224: {
! 225: struct gpio_softc *sc = gpio;
! 226: int npins, pin, i;
! 227:
! 228: npins = gpio_npins(mask);
! 229: if (npins > sc->sc_npins)
! 230: return 0;
! 231:
! 232: for (npins = 0, i = 0; i < 32; i++)
! 233: if (mask & (1 << i)) {
! 234: pin = offset + i;
! 235: if (pin < 0 || pin >= sc->sc_npins)
! 236: return 0;
! 237: if (sc->sc_pins[pin].pin_mapped)
! 238: return 0;
! 239: }
! 240:
! 241: return 1;
! 242: }
! 243:
1.8 uwe 244: int
1.5 riz 245: gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map)
246: {
247: struct gpio_softc *sc = gpio;
248: int npins, pin, i;
249:
250: npins = gpio_npins(mask);
251: if (npins > sc->sc_npins)
1.15.4.3 yamt 252: return 1;
1.5 riz 253:
254: for (npins = 0, i = 0; i < 32; i++)
255: if (mask & (1 << i)) {
256: pin = offset + i;
257: if (pin < 0 || pin >= sc->sc_npins)
1.15.4.3 yamt 258: return 1;
1.5 riz 259: if (sc->sc_pins[pin].pin_mapped)
1.15.4.3 yamt 260: return 1;
1.5 riz 261: sc->sc_pins[pin].pin_mapped = 1;
262: map->pm_map[npins++] = pin;
263: }
264: map->pm_size = npins;
265:
1.15.4.3 yamt 266: return 0;
1.5 riz 267: }
268:
269: void
270: gpio_pin_unmap(void *gpio, struct gpio_pinmap *map)
271: {
272: struct gpio_softc *sc = gpio;
273: int pin, i;
274:
275: for (i = 0; i < map->pm_size; i++) {
276: pin = map->pm_map[i];
277: sc->sc_pins[pin].pin_mapped = 0;
278: }
279: }
280:
281: int
282: gpio_pin_read(void *gpio, struct gpio_pinmap *map, int pin)
283: {
284: struct gpio_softc *sc = gpio;
285:
1.15.4.3 yamt 286: return gpiobus_pin_read(sc->sc_gc, map->pm_map[pin]);
1.5 riz 287: }
288:
289: void
290: gpio_pin_write(void *gpio, struct gpio_pinmap *map, int pin, int value)
291: {
292: struct gpio_softc *sc = gpio;
293:
1.13 dyoung 294: gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value);
295: sc->sc_pins[map->pm_map[pin]].pin_state = value;
1.5 riz 296: }
297:
298: void
299: gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags)
300: {
301: struct gpio_softc *sc = gpio;
302:
1.15.4.3 yamt 303: return gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags);
1.5 riz 304: }
305:
306: int
307: gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin)
308: {
309: struct gpio_softc *sc = gpio;
310:
1.15.4.3 yamt 311: return sc->sc_pins[map->pm_map[pin]].pin_caps;
1.5 riz 312: }
313:
314: int
315: gpio_npins(u_int32_t mask)
316: {
317: int npins, i;
318:
319: for (npins = 0, i = 0; i < 32; i++)
320: if (mask & (1 << i))
321: npins++;
322:
1.15.4.3 yamt 323: return npins;
1.5 riz 324: }
325:
1.1 jmcneill 326: int
1.15.4.3 yamt 327: gpioopen(dev_t dev, int flag, int mode, struct lwp *l)
1.1 jmcneill 328: {
329: struct gpio_softc *sc;
1.15.4.1 yamt 330: int ret;
1.1 jmcneill 331:
1.15.4.1 yamt 332: sc = device_lookup_private(&gpio_cd, minor(dev));
1.1 jmcneill 333: if (sc == NULL)
1.15.4.3 yamt 334: return ENXIO;
335: DPRINTF(("%s: opening\n", device_xname(sc->sc_dev)));
336: if (sc->sc_opened) {
337: DPRINTF(("%s: already opened\n", device_xname(sc->sc_dev)));
338: return EBUSY;
339: }
1.15.4.1 yamt 340:
1.15.4.3 yamt 341: if ((ret = gpiobus_open(sc->sc_gc, sc->sc_dev))) {
342: DPRINTF(("%s: gpiobus_open returned %d\n",
343: device_xname(sc->sc_dev),
344: ret));
1.15.4.1 yamt 345: return ret;
1.15.4.3 yamt 346: }
1.15.4.1 yamt 347:
1.1 jmcneill 348: sc->sc_opened = 1;
349:
1.15.4.3 yamt 350: return 0;
1.1 jmcneill 351: }
352:
353: int
1.15.4.3 yamt 354: gpioclose(dev_t dev, int flag, int mode, struct lwp *l)
1.1 jmcneill 355: {
356: struct gpio_softc *sc;
357:
1.15.4.1 yamt 358: sc = device_lookup_private(&gpio_cd, minor(dev));
1.15.4.3 yamt 359: DPRINTF(("%s: closing\n", device_xname(sc->sc_dev)));
1.15.4.1 yamt 360: gpiobus_close(sc->sc_gc, sc->sc_dev);
1.1 jmcneill 361: sc->sc_opened = 0;
362:
1.15.4.3 yamt 363: return 0;
364: }
365:
366: int
367: gpio_pinbyname(struct gpio_softc *sc, char *gp_name)
368: {
369: struct gpio_name *nm;
370:
371: LIST_FOREACH(nm, &sc->sc_names, gp_next)
372: if (!strcmp(nm->gp_name, gp_name))
373: return nm->gp_pin;
374: return -1;
1.1 jmcneill 375: }
376:
377: int
1.15.4.3 yamt 378: gpioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1.1 jmcneill 379: {
380: struct gpio_softc *sc;
381: gpio_chipset_tag_t gc;
382: struct gpio_info *info;
1.15.4.3 yamt 383: struct gpio_attach *attach;
384: struct gpio_attach_args ga;
385: struct gpio_dev *gdev;
386: struct gpio_req *req;
387: struct gpio_name *nm;
388: struct gpio_set *set;
389: device_t dv;
390: cfdata_t cf;
391: kauth_cred_t cred;
392: int locs[GPIOCF_NLOCS];
1.15.4.4! yamt 393: int pin, value, flags, npins;
1.1 jmcneill 394:
1.15.4.1 yamt 395: sc = device_lookup_private(&gpio_cd, minor(dev));
1.1 jmcneill 396: gc = sc->sc_gc;
397:
1.15.4.3 yamt 398: if (cmd != GPIOINFO && !device_is_active(sc->sc_dev)) {
399: DPRINTF(("%s: device is not active\n",
400: device_xname(sc->sc_dev)));
1.13 dyoung 401: return EBUSY;
1.15.4.3 yamt 402: }
403:
404: cred = kauth_cred_get();
1.13 dyoung 405:
1.1 jmcneill 406: switch (cmd) {
407: case GPIOINFO:
408: info = (struct gpio_info *)data;
1.15.4.3 yamt 409: if (!kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
410: NULL, NULL, NULL, NULL))
411: info->gpio_npins = sc->sc_npins;
412: else {
413: for (pin = npins = 0; pin < sc->sc_npins; pin++)
414: if (sc->sc_pins[pin].pin_flags & GPIO_PIN_SET)
415: ++npins;
416: info->gpio_npins = npins;
417: }
418: break;
419: case GPIOREAD:
420: req = (struct gpio_req *)data;
421:
422: if (req->gp_name[0] != '\0') {
423: pin = gpio_pinbyname(sc, req->gp_name);
424: if (pin == -1)
425: return EINVAL;
426: } else
427: pin = req->gp_pin;
428:
429: if (pin < 0 || pin >= sc->sc_npins)
430: return EINVAL;
431:
432: if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
433: kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
434: NULL, NULL, NULL, NULL))
435: return EPERM;
436:
437: /* return read value */
438: req->gp_value = gpiobus_pin_read(gc, pin);
439: break;
440: case GPIOWRITE:
441: if ((flag & FWRITE) == 0)
442: return EBADF;
443:
444: req = (struct gpio_req *)data;
445:
446: if (req->gp_name[0] != '\0') {
447: pin = gpio_pinbyname(sc, req->gp_name);
448: if (pin == -1)
449: return EINVAL;
450: } else
451: pin = req->gp_pin;
452:
453: if (pin < 0 || pin >= sc->sc_npins)
454: return EINVAL;
455:
456: if (sc->sc_pins[pin].pin_mapped)
457: return EBUSY;
458:
459: if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
460: kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
461: NULL, NULL, NULL, NULL))
462: return EPERM;
1.1 jmcneill 463:
1.15.4.3 yamt 464: value = req->gp_value;
465: if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH)
466: return EINVAL;
467:
468: gpiobus_pin_write(gc, pin, value);
469: /* return old value */
470: req->gp_value = sc->sc_pins[pin].pin_state;
471: /* update current value */
472: sc->sc_pins[pin].pin_state = value;
1.1 jmcneill 473: break;
1.15.4.3 yamt 474: case GPIOTOGGLE:
475: if ((flag & FWRITE) == 0)
476: return EBADF;
477:
478: req = (struct gpio_req *)data;
479:
480: if (req->gp_name[0] != '\0') {
481: pin = gpio_pinbyname(sc, req->gp_name);
482: if (pin == -1)
483: return EINVAL;
484: } else
485: pin = req->gp_pin;
486:
487: if (pin < 0 || pin >= sc->sc_npins)
488: return EINVAL;
489:
490: if (sc->sc_pins[pin].pin_mapped)
491: return EBUSY;
492:
493: if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
494: kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
495: NULL, NULL, NULL, NULL))
496: return EPERM;
497:
498: value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ?
499: GPIO_PIN_HIGH : GPIO_PIN_LOW);
500: gpiobus_pin_write(gc, pin, value);
501: /* return old value */
502: req->gp_value = sc->sc_pins[pin].pin_state;
503: /* update current value */
504: sc->sc_pins[pin].pin_state = value;
505: break;
506: case GPIOATTACH:
507: if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
508: NULL, NULL, NULL, NULL))
509: return EPERM;
1.15.4.4! yamt 510:
1.15.4.3 yamt 511: attach = (struct gpio_attach *)data;
1.15.4.4! yamt 512:
! 513: /* do not try to attach if the pins are already mapped */
! 514: if (!gpio_pin_can_map(sc, attach->ga_offset, attach->ga_mask))
! 515: return EBUSY;
! 516:
1.15.4.3 yamt 517: ga.ga_gpio = sc;
518: ga.ga_dvname = attach->ga_dvname;
519: ga.ga_offset = attach->ga_offset;
520: ga.ga_mask = attach->ga_mask;
521: DPRINTF(("%s: attach %s with offset %d and mask 0x%02x\n",
522: device_xname(sc->sc_dev), ga.ga_dvname, ga.ga_offset,
523: ga.ga_mask));
524:
525: locs[GPIOCF_OFFSET] = ga.ga_offset;
526: locs[GPIOCF_MASK] = ga.ga_mask;
527:
528: cf = config_search_loc(NULL, sc->sc_dev, "gpio", locs, &ga);
529: if (cf != NULL) {
530: dv = config_attach_loc(sc->sc_dev, cf, locs, &ga,
531: gpiobus_print);
532: if (dv != NULL) {
533: gdev = kmem_alloc(sizeof(struct gpio_dev),
534: KM_SLEEP);
535: gdev->sc_dev = dv;
536: LIST_INSERT_HEAD(&sc->sc_devs, gdev, sc_next);
537: } else
538: return EINVAL;
539: } else
540: return EINVAL;
541: break;
542: case GPIODETACH:
543: if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
544: NULL, NULL, NULL, NULL))
545: return EPERM;
546:
547: attach = (struct gpio_attach *)data;
548: LIST_FOREACH(gdev, &sc->sc_devs, sc_next) {
549: if (strcmp(device_xname(gdev->sc_dev),
550: attach->ga_dvname) == 0) {
551: if (config_detach(gdev->sc_dev, 0) == 0) {
552: LIST_REMOVE(gdev, sc_next);
553: kmem_free(gdev,
554: sizeof(struct gpio_dev));
555: return 0;
556: }
557: break;
558: }
559: }
560: return EINVAL;
561: break;
562: case GPIOSET:
563: if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
564: NULL, NULL, NULL, NULL))
565: return EPERM;
566:
567: set = (struct gpio_set *)data;
568:
569: if (set->gp_name[0] != '\0') {
570: pin = gpio_pinbyname(sc, set->gp_name);
571: if (pin == -1)
572: return EINVAL;
573: } else
574: pin = set->gp_pin;
575: if (pin < 0 || pin >= sc->sc_npins)
576: return EINVAL;
577: flags = set->gp_flags;
578:
579: /* check that the controller supports all requested flags */
580: if ((flags & sc->sc_pins[pin].pin_caps) != flags)
581: return ENODEV;
582: flags = set->gp_flags | GPIO_PIN_SET;
583:
584: set->gp_caps = sc->sc_pins[pin].pin_caps;
585: /* return old value */
586: set->gp_flags = sc->sc_pins[pin].pin_flags;
587: if (flags > 0) {
588: gpiobus_pin_ctl(gc, pin, flags);
589: /* update current value */
590: sc->sc_pins[pin].pin_flags = flags;
591: }
592:
593: /* rename pin or new pin? */
594: if (set->gp_name2[0] != '\0') {
1.15.4.4! yamt 595: struct gpio_name *gnm;
! 596:
! 597: gnm = NULL;
! 598: LIST_FOREACH(nm, &sc->sc_names, gp_next) {
! 599: if (!strcmp(nm->gp_name, set->gp_name2) &&
! 600: nm->gp_pin != pin)
! 601: return EINVAL; /* duplicate name */
! 602: if (nm->gp_pin == pin)
! 603: gnm = nm;
! 604: }
! 605: if (gnm != NULL)
! 606: strlcpy(gnm->gp_name, set->gp_name2,
! 607: sizeof(gnm->gp_name));
! 608: else {
1.15.4.3 yamt 609: nm = kmem_alloc(sizeof(struct gpio_name),
610: KM_SLEEP);
611: strlcpy(nm->gp_name, set->gp_name2,
612: sizeof(nm->gp_name));
613: nm->gp_pin = set->gp_pin;
614: LIST_INSERT_HEAD(&sc->sc_names, nm, gp_next);
615: }
616: }
617: break;
618: case GPIOUNSET:
619: if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
620: NULL, NULL, NULL, NULL))
621: return EPERM;
622:
623: set = (struct gpio_set *)data;
624: if (set->gp_name[0] != '\0') {
625: pin = gpio_pinbyname(sc, set->gp_name);
626: if (pin == -1)
627: return EINVAL;
628: } else
629: pin = set->gp_pin;
630:
631: if (pin < 0 || pin >= sc->sc_npins)
632: return EINVAL;
633: if (sc->sc_pins[pin].pin_mapped)
634: return EBUSY;
635: if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET))
636: return EINVAL;
637:
638: LIST_FOREACH(nm, &sc->sc_names, gp_next) {
639: if (nm->gp_pin == pin) {
640: LIST_REMOVE(nm, gp_next);
641: kmem_free(nm, sizeof(struct gpio_name));
642: break;
643: }
644: }
645: sc->sc_pins[pin].pin_flags &= ~GPIO_PIN_SET;
646: break;
647: default:
648: /* Try the old API */
649: DPRINTF(("%s: trying the old API\n", device_xname(sc->sc_dev)));
650: return gpio_ioctl_oapi(sc, cmd, data, flag, cred);
651: }
652: return 0;
653: }
654:
655: int
656: gpio_ioctl_oapi(struct gpio_softc *sc, u_long cmd, void *data, int flag,
657: kauth_cred_t cred)
658: {
659: gpio_chipset_tag_t gc;
660: struct gpio_pin_op *op;
661: struct gpio_pin_ctl *ctl;
662: int pin, value, flags;
663:
664: gc = sc->sc_gc;
665:
666: switch (cmd) {
1.1 jmcneill 667: case GPIOPINREAD:
668: op = (struct gpio_pin_op *)data;
669:
670: pin = op->gp_pin;
1.15.4.3 yamt 671:
1.1 jmcneill 672: if (pin < 0 || pin >= sc->sc_npins)
1.15.4.3 yamt 673: return EINVAL;
674:
675: if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
676: kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
677: NULL, NULL, NULL, NULL))
678: return EPERM;
1.1 jmcneill 679:
680: /* return read value */
681: op->gp_value = gpiobus_pin_read(gc, pin);
682: break;
683: case GPIOPINWRITE:
1.15.4.3 yamt 684: if ((flag & FWRITE) == 0)
685: return EBADF;
686:
1.1 jmcneill 687: op = (struct gpio_pin_op *)data;
688:
689: pin = op->gp_pin;
1.15.4.3 yamt 690:
1.1 jmcneill 691: if (pin < 0 || pin >= sc->sc_npins)
1.15.4.3 yamt 692: return EINVAL;
693:
1.5 riz 694: if (sc->sc_pins[pin].pin_mapped)
1.15.4.3 yamt 695: return EBUSY;
696:
697: if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
698: kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
699: NULL, NULL, NULL, NULL))
700: return EPERM;
1.1 jmcneill 701:
702: value = op->gp_value;
703: if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH)
1.15.4.3 yamt 704: return EINVAL;
1.1 jmcneill 705:
706: gpiobus_pin_write(gc, pin, value);
707: /* return old value */
708: op->gp_value = sc->sc_pins[pin].pin_state;
709: /* update current value */
710: sc->sc_pins[pin].pin_state = value;
711: break;
712: case GPIOPINTOGGLE:
1.15.4.3 yamt 713: if ((flag & FWRITE) == 0)
714: return EBADF;
715:
1.1 jmcneill 716: op = (struct gpio_pin_op *)data;
717:
718: pin = op->gp_pin;
1.15.4.3 yamt 719:
1.1 jmcneill 720: if (pin < 0 || pin >= sc->sc_npins)
1.15.4.3 yamt 721: return EINVAL;
722:
1.5 riz 723: if (sc->sc_pins[pin].pin_mapped)
1.15.4.3 yamt 724: return EBUSY;
725:
726: if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
727: kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
728: NULL, NULL, NULL, NULL))
729: return EPERM;
1.1 jmcneill 730:
731: value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ?
732: GPIO_PIN_HIGH : GPIO_PIN_LOW);
733: gpiobus_pin_write(gc, pin, value);
734: /* return old value */
735: op->gp_value = sc->sc_pins[pin].pin_state;
736: /* update current value */
737: sc->sc_pins[pin].pin_state = value;
738: break;
739: case GPIOPINCTL:
1.15.4.3 yamt 740: ctl = (struct gpio_pin_ctl *) data;
741:
742: if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
743: NULL, NULL, NULL, NULL))
744: return EPERM;
1.1 jmcneill 745:
746: pin = ctl->gp_pin;
1.15.4.3 yamt 747:
1.1 jmcneill 748: if (pin < 0 || pin >= sc->sc_npins)
1.15.4.3 yamt 749: return EINVAL;
1.5 riz 750: if (sc->sc_pins[pin].pin_mapped)
1.15.4.3 yamt 751: return EBUSY;
1.1 jmcneill 752: flags = ctl->gp_flags;
1.15.4.3 yamt 753:
1.1 jmcneill 754: /* check that the controller supports all requested flags */
755: if ((flags & sc->sc_pins[pin].pin_caps) != flags)
1.15.4.3 yamt 756: return ENODEV;
1.1 jmcneill 757:
758: ctl->gp_caps = sc->sc_pins[pin].pin_caps;
759: /* return old value */
760: ctl->gp_flags = sc->sc_pins[pin].pin_flags;
761: if (flags > 0) {
762: gpiobus_pin_ctl(gc, pin, flags);
763: /* update current value */
764: sc->sc_pins[pin].pin_flags = flags;
765: }
766: break;
767: default:
1.15.4.3 yamt 768: return ENOTTY;
1.1 jmcneill 769: }
1.15.4.3 yamt 770: return 0;
1.1 jmcneill 771: }
CVSweb <webmaster@jp.NetBSD.org>