Line data Source code
1 : /* $OpenBSD: gpio.c,v 1.15 2017/08/18 12:15:35 jsg Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
5 : * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org>
6 : *
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
9 : * copyright notice and this permission notice appear in all copies.
10 : *
11 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
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
17 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 : */
19 :
20 : /*
21 : * General Purpose Input/Output framework.
22 : */
23 :
24 : #include <sys/param.h>
25 : #include <sys/systm.h>
26 : #include <sys/conf.h>
27 : #include <sys/device.h>
28 : #include <sys/fcntl.h>
29 : #include <sys/ioctl.h>
30 : #include <sys/gpio.h>
31 : #include <sys/vnode.h>
32 : #include <sys/malloc.h>
33 : #include <sys/queue.h>
34 :
35 : #include <dev/gpio/gpiovar.h>
36 :
37 : struct gpio_softc {
38 : struct device sc_dev;
39 :
40 : gpio_chipset_tag_t sc_gc; /* GPIO controller */
41 : gpio_pin_t *sc_pins; /* pins array */
42 : int sc_npins; /* number of pins */
43 :
44 : int sc_opened;
45 : LIST_HEAD(, gpio_dev) sc_devs; /* devices */
46 : LIST_HEAD(, gpio_name) sc_names; /* named pins */
47 : };
48 :
49 : int gpio_match(struct device *, void *, void *);
50 : int gpio_submatch(struct device *, void *, void *);
51 : void gpio_attach(struct device *, struct device *, void *);
52 : int gpio_detach(struct device *, int);
53 : int gpio_search(struct device *, void *, void *);
54 : int gpio_print(void *, const char *);
55 : int gpio_pinbyname(struct gpio_softc *, char *gp_name);
56 :
57 : struct cfattach gpio_ca = {
58 : sizeof (struct gpio_softc),
59 : gpio_match,
60 : gpio_attach,
61 : gpio_detach
62 : };
63 :
64 : struct cfdriver gpio_cd = {
65 : NULL, "gpio", DV_DULL
66 : };
67 :
68 : int
69 0 : gpio_match(struct device *parent, void *match, void *aux)
70 : {
71 0 : struct cfdata *cf = match;
72 0 : struct gpiobus_attach_args *gba = aux;
73 :
74 0 : return (strcmp(gba->gba_name, cf->cf_driver->cd_name) == 0);
75 : }
76 :
77 : int
78 0 : gpio_submatch(struct device *parent, void *match, void *aux)
79 : {
80 0 : struct cfdata *cf = match;
81 0 : struct gpio_attach_args *ga = aux;
82 :
83 0 : if (strcmp(ga->ga_dvname, cf->cf_driver->cd_name) != 0)
84 0 : return (0);
85 :
86 0 : return ((*cf->cf_attach->ca_match)(parent, match, aux));
87 0 : }
88 :
89 : void
90 0 : gpio_attach(struct device *parent, struct device *self, void *aux)
91 : {
92 0 : struct gpio_softc *sc = (struct gpio_softc *)self;
93 0 : struct gpiobus_attach_args *gba = aux;
94 :
95 0 : sc->sc_gc = gba->gba_gc;
96 0 : sc->sc_pins = gba->gba_pins;
97 0 : sc->sc_npins = gba->gba_npins;
98 :
99 0 : printf(": %d pins\n", sc->sc_npins);
100 :
101 : /*
102 : * Attach all devices that can be connected to the GPIO pins
103 : * described in the kernel configuration file.
104 : */
105 0 : config_search(gpio_search, self, sc);
106 0 : }
107 :
108 : int
109 0 : gpio_detach(struct device *self, int flags)
110 : {
111 : int maj, mn;
112 :
113 : /* Locate the major number */
114 0 : for (maj = 0; maj < nchrdev; maj++)
115 0 : if (cdevsw[maj].d_open == gpioopen)
116 : break;
117 :
118 : /* Nuke the vnodes for any open instances (calls close) */
119 0 : mn = self->dv_unit;
120 0 : vdevgone(maj, mn, mn, VCHR);
121 :
122 0 : return (0);
123 : }
124 :
125 : int
126 0 : gpio_search(struct device *parent, void *arg, void *aux)
127 : {
128 0 : struct cfdata *cf = arg;
129 0 : struct gpio_attach_args ga;
130 :
131 0 : ga.ga_gpio = aux;
132 0 : ga.ga_offset = cf->cf_loc[0];
133 0 : ga.ga_mask = cf->cf_loc[1];
134 0 : ga.ga_flags = cf->cf_loc[2];
135 :
136 0 : if (cf->cf_attach->ca_match(parent, cf, &ga) > 0)
137 0 : config_attach(parent, cf, &ga, gpio_print);
138 :
139 0 : return (0);
140 0 : }
141 :
142 : int
143 0 : gpio_print(void *aux, const char *pnp)
144 : {
145 0 : struct gpio_attach_args *ga = aux;
146 : int i;
147 :
148 0 : printf(" pins");
149 0 : for (i = 0; i < 32; i++)
150 0 : if (ga->ga_mask & (1 << i))
151 0 : printf(" %d", ga->ga_offset + i);
152 :
153 0 : return (UNCONF);
154 : }
155 :
156 : int
157 0 : gpiobus_print(void *aux, const char *pnp)
158 : {
159 0 : struct gpiobus_attach_args *gba = aux;
160 :
161 0 : if (pnp != NULL)
162 0 : printf("%s at %s", gba->gba_name, pnp);
163 :
164 0 : return (UNCONF);
165 : }
166 :
167 : int
168 0 : gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map)
169 : {
170 0 : struct gpio_softc *sc = gpio;
171 : int npins, pin, i;
172 :
173 0 : npins = gpio_npins(mask);
174 0 : if (npins > sc->sc_npins)
175 0 : return (1);
176 :
177 0 : for (npins = 0, i = 0; i < 32; i++)
178 0 : if (mask & (1 << i)) {
179 0 : pin = offset + i;
180 0 : if (pin < 0 || pin >= sc->sc_npins)
181 0 : return (1);
182 0 : if (sc->sc_pins[pin].pin_mapped)
183 0 : return (1);
184 0 : sc->sc_pins[pin].pin_mapped = 1;
185 0 : map->pm_map[npins++] = pin;
186 0 : }
187 0 : map->pm_size = npins;
188 :
189 0 : return (0);
190 0 : }
191 :
192 : void
193 0 : gpio_pin_unmap(void *gpio, struct gpio_pinmap *map)
194 : {
195 0 : struct gpio_softc *sc = gpio;
196 : int pin, i;
197 :
198 0 : for (i = 0; i < map->pm_size; i++) {
199 0 : pin = map->pm_map[i];
200 0 : sc->sc_pins[pin].pin_mapped = 0;
201 : }
202 0 : }
203 :
204 : int
205 0 : gpio_pin_read(void *gpio, struct gpio_pinmap *map, int pin)
206 : {
207 0 : struct gpio_softc *sc = gpio;
208 :
209 0 : return (gpiobus_pin_read(sc->sc_gc, map->pm_map[pin]));
210 : }
211 :
212 : void
213 0 : gpio_pin_write(void *gpio, struct gpio_pinmap *map, int pin, int value)
214 : {
215 0 : struct gpio_softc *sc = gpio;
216 :
217 0 : return (gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value));
218 0 : }
219 :
220 : void
221 0 : gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags)
222 : {
223 0 : struct gpio_softc *sc = gpio;
224 :
225 0 : return (gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags));
226 0 : }
227 :
228 : int
229 0 : gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin)
230 : {
231 0 : struct gpio_softc *sc = gpio;
232 :
233 0 : return (sc->sc_pins[map->pm_map[pin]].pin_caps);
234 : }
235 :
236 : int
237 0 : gpio_npins(u_int32_t mask)
238 : {
239 : int npins, i;
240 :
241 0 : for (npins = 0, i = 0; i < 32; i++)
242 0 : if (mask & (1 << i))
243 0 : npins++;
244 :
245 0 : return (npins);
246 : }
247 :
248 : int
249 0 : gpioopen(dev_t dev, int flag, int mode, struct proc *p)
250 : {
251 : struct gpio_softc *sc;
252 :
253 0 : sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
254 0 : if (sc == NULL)
255 0 : return (ENXIO);
256 :
257 0 : if (sc->sc_opened)
258 0 : return (EBUSY);
259 0 : sc->sc_opened = 1;
260 :
261 0 : return (0);
262 0 : }
263 :
264 : int
265 0 : gpioclose(dev_t dev, int flag, int mode, struct proc *p)
266 : {
267 : struct gpio_softc *sc;
268 :
269 0 : sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
270 0 : if (sc == NULL)
271 0 : return (ENXIO);
272 :
273 0 : sc->sc_opened = 0;
274 :
275 0 : return (0);
276 0 : }
277 :
278 : int
279 0 : gpio_pinbyname(struct gpio_softc *sc, char *gp_name)
280 : {
281 : struct gpio_name *nm;
282 :
283 0 : LIST_FOREACH(nm, &sc->sc_names, gp_next)
284 0 : if (!strcmp(nm->gp_name, gp_name))
285 0 : return (nm->gp_pin);
286 0 : return (-1);
287 0 : }
288 :
289 : int
290 0 : gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
291 : {
292 : struct gpio_softc *sc;
293 : gpio_chipset_tag_t gc;
294 : struct gpio_info *info;
295 : struct gpio_pin_op *op;
296 : struct gpio_attach *attach;
297 0 : struct gpio_attach_args ga;
298 : struct gpio_dev *gdev;
299 : struct gpio_name *nm;
300 : struct gpio_pin_set *set;
301 : struct device *dv;
302 : int pin, value, flags, npins, found;
303 :
304 0 : sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
305 0 : if (sc == NULL)
306 0 : return (ENXIO);
307 :
308 0 : gc = sc->sc_gc;
309 :
310 0 : switch (cmd) {
311 : case GPIOINFO:
312 0 : info = (struct gpio_info *)data;
313 0 : if (securelevel < 1)
314 0 : info->gpio_npins = sc->sc_npins;
315 : else {
316 0 : for (pin = npins = 0; pin < sc->sc_npins; pin++)
317 0 : if (sc->sc_pins[pin].pin_flags & GPIO_PIN_SET)
318 0 : ++npins;
319 0 : info->gpio_npins = npins;
320 : }
321 : break;
322 : case GPIOPINREAD:
323 0 : op = (struct gpio_pin_op *)data;
324 :
325 0 : if (op->gp_name[0] != '\0') {
326 0 : pin = gpio_pinbyname(sc, op->gp_name);
327 0 : if (pin == -1)
328 0 : return (EINVAL);
329 : } else
330 0 : pin = op->gp_pin;
331 :
332 0 : if (pin < 0 || pin >= sc->sc_npins)
333 0 : return (EINVAL);
334 :
335 0 : if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
336 0 : securelevel > 0)
337 0 : return (EPERM);
338 :
339 : /* return read value */
340 0 : op->gp_value = gpiobus_pin_read(gc, pin);
341 0 : break;
342 : case GPIOPINWRITE:
343 0 : if ((flag & FWRITE) == 0)
344 0 : return (EBADF);
345 :
346 0 : op = (struct gpio_pin_op *)data;
347 :
348 0 : if (op->gp_name[0] != '\0') {
349 0 : pin = gpio_pinbyname(sc, op->gp_name);
350 0 : if (pin == -1)
351 0 : return (EINVAL);
352 : } else
353 0 : pin = op->gp_pin;
354 :
355 0 : if (pin < 0 || pin >= sc->sc_npins)
356 0 : return (EINVAL);
357 :
358 0 : if (sc->sc_pins[pin].pin_mapped)
359 0 : return (EBUSY);
360 :
361 0 : if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
362 0 : securelevel > 0)
363 0 : return (EPERM);
364 :
365 0 : value = op->gp_value;
366 0 : if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH)
367 0 : return (EINVAL);
368 :
369 0 : gpiobus_pin_write(gc, pin, value);
370 : /* return old value */
371 0 : op->gp_value = sc->sc_pins[pin].pin_state;
372 : /* update current value */
373 0 : sc->sc_pins[pin].pin_state = value;
374 0 : break;
375 : case GPIOPINTOGGLE:
376 0 : if ((flag & FWRITE) == 0)
377 0 : return (EBADF);
378 :
379 0 : op = (struct gpio_pin_op *)data;
380 :
381 0 : if (op->gp_name[0] != '\0') {
382 0 : pin = gpio_pinbyname(sc, op->gp_name);
383 0 : if (pin == -1)
384 0 : return (EINVAL);
385 : } else
386 0 : pin = op->gp_pin;
387 :
388 0 : if (pin < 0 || pin >= sc->sc_npins)
389 0 : return (EINVAL);
390 :
391 0 : if (sc->sc_pins[pin].pin_mapped)
392 0 : return (EBUSY);
393 :
394 0 : if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
395 0 : securelevel > 0)
396 0 : return (EPERM);
397 :
398 0 : value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ?
399 : GPIO_PIN_HIGH : GPIO_PIN_LOW);
400 0 : gpiobus_pin_write(gc, pin, value);
401 : /* return old value */
402 0 : op->gp_value = sc->sc_pins[pin].pin_state;
403 : /* update current value */
404 0 : sc->sc_pins[pin].pin_state = value;
405 0 : break;
406 : case GPIOATTACH:
407 0 : if (securelevel > 0)
408 0 : return (EPERM);
409 :
410 0 : attach = (struct gpio_attach *)data;
411 0 : bzero(&ga, sizeof(ga));
412 0 : ga.ga_gpio = sc;
413 0 : ga.ga_dvname = attach->ga_dvname;
414 0 : ga.ga_offset = attach->ga_offset;
415 0 : ga.ga_mask = attach->ga_mask;
416 0 : ga.ga_flags = attach->ga_flags;
417 0 : dv = config_found_sm((struct device *)sc, &ga, gpiobus_print,
418 : gpio_submatch);
419 0 : if (dv != NULL) {
420 0 : gdev = malloc(sizeof(*gdev), M_DEVBUF,
421 : M_WAITOK);
422 0 : gdev->sc_dev = dv;
423 0 : LIST_INSERT_HEAD(&sc->sc_devs, gdev, sc_next);
424 0 : }
425 : break;
426 : case GPIODETACH:
427 0 : if (securelevel > 0)
428 0 : return (EPERM);
429 :
430 0 : attach = (struct gpio_attach *)data;
431 0 : LIST_FOREACH(gdev, &sc->sc_devs, sc_next) {
432 0 : if (strcmp(gdev->sc_dev->dv_xname, attach->ga_dvname)
433 0 : == 0) {
434 0 : if (config_detach(gdev->sc_dev, 0) == 0) {
435 0 : LIST_REMOVE(gdev, sc_next);
436 0 : free(gdev, M_DEVBUF, sizeof(*gdev));
437 0 : }
438 : break;
439 : }
440 : }
441 : break;
442 : case GPIOPINSET:
443 0 : if (securelevel > 0)
444 0 : return (EPERM);
445 :
446 0 : set = (struct gpio_pin_set *)data;
447 :
448 0 : if (set->gp_name[0] != '\0') {
449 0 : pin = gpio_pinbyname(sc, set->gp_name);
450 0 : if (pin == -1)
451 0 : return (EINVAL);
452 : } else
453 0 : pin = set->gp_pin;
454 0 : if (pin < 0 || pin >= sc->sc_npins)
455 0 : return (EINVAL);
456 0 : flags = set->gp_flags;
457 : /* check that the controller supports all requested flags */
458 0 : if ((flags & sc->sc_pins[pin].pin_caps) != flags)
459 0 : return (ENODEV);
460 0 : flags = set->gp_flags | GPIO_PIN_SET;
461 :
462 0 : set->gp_caps = sc->sc_pins[pin].pin_caps;
463 : /* return old value */
464 0 : set->gp_flags = sc->sc_pins[pin].pin_flags;
465 0 : if (flags > 0) {
466 0 : gpiobus_pin_ctl(gc, pin, flags);
467 : /* update current value */
468 0 : sc->sc_pins[pin].pin_flags = flags;
469 0 : }
470 :
471 : /* rename pin or new pin? */
472 0 : if (set->gp_name2[0] != '\0') {
473 : found = 0;
474 0 : LIST_FOREACH(nm, &sc->sc_names, gp_next)
475 0 : if (nm->gp_pin == pin) {
476 0 : strlcpy(nm->gp_name, set->gp_name2,
477 : sizeof(nm->gp_name));
478 : found = 1;
479 0 : break;
480 : }
481 0 : if (!found) {
482 0 : nm = malloc(sizeof(*nm), M_DEVBUF, M_WAITOK);
483 0 : strlcpy(nm->gp_name, set->gp_name2,
484 : sizeof(nm->gp_name));
485 0 : nm->gp_pin = set->gp_pin;
486 0 : LIST_INSERT_HEAD(&sc->sc_names, nm, gp_next);
487 0 : }
488 : }
489 : break;
490 : case GPIOPINUNSET:
491 0 : if (securelevel > 0)
492 0 : return (EPERM);
493 :
494 0 : set = (struct gpio_pin_set *)data;
495 0 : if (set->gp_name[0] != '\0') {
496 0 : pin = gpio_pinbyname(sc, set->gp_name);
497 0 : if (pin == -1)
498 0 : return (EINVAL);
499 : } else
500 0 : pin = set->gp_pin;
501 :
502 0 : if (pin < 0 || pin >= sc->sc_npins)
503 0 : return (EINVAL);
504 0 : if (sc->sc_pins[pin].pin_mapped)
505 0 : return (EBUSY);
506 0 : if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET))
507 0 : return (EINVAL);
508 :
509 0 : LIST_FOREACH(nm, &sc->sc_names, gp_next) {
510 0 : if (nm->gp_pin == pin) {
511 0 : LIST_REMOVE(nm, gp_next);
512 0 : free(nm, M_DEVBUF, sizeof(*nm));
513 0 : break;
514 : }
515 : }
516 0 : sc->sc_pins[pin].pin_flags &= ~GPIO_PIN_SET;
517 0 : break;
518 : default:
519 0 : return (ENOTTY);
520 : }
521 :
522 0 : return (0);
523 0 : }
|