FreeBSD/Linux Kernel Cross Reference
sys/dev/gpio/gpioc.c
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/conf.h>
36 #include <sys/gpio.h>
37 #include <sys/ioccom.h>
38 #include <sys/filio.h>
39 #include <sys/fcntl.h>
40 #include <sys/sigio.h>
41 #include <sys/signalvar.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/uio.h>
45 #include <sys/poll.h>
46 #include <sys/selinfo.h>
47 #include <sys/module.h>
48
49 #include <dev/gpio/gpiobusvar.h>
50
51 #include "gpio_if.h"
52 #include "gpiobus_if.h"
53
54 #undef GPIOC_DEBUG
55 #ifdef GPIOC_DEBUG
56 #define dprintf printf
57 #define ddevice_printf device_printf
58 #else
59 #define dprintf(x, arg...)
60 #define ddevice_printf(dev, x, arg...)
61 #endif
62
63 struct gpioc_softc {
64 device_t sc_dev; /* gpiocX dev */
65 device_t sc_pdev; /* gpioX dev */
66 struct cdev *sc_ctl_dev; /* controller device */
67 int sc_unit;
68 int sc_npins;
69 struct gpioc_pin_intr *sc_pin_intr;
70 };
71
72 struct gpioc_pin_intr {
73 struct gpioc_softc *sc;
74 gpio_pin_t pin;
75 bool config_locked;
76 int intr_rid;
77 struct resource *intr_res;
78 void *intr_cookie;
79 struct mtx mtx;
80 SLIST_HEAD(gpioc_privs_list, gpioc_privs) privs;
81 };
82
83
84 struct gpioc_cdevpriv {
85 struct gpioc_softc *sc;
86 struct selinfo selinfo;
87 bool async;
88 uint8_t report_option;
89 struct sigio *sigio;
90 struct mtx mtx;
91 struct gpioc_pin_event *events;
92 int numevents;
93 int evidx_head;
94 int evidx_tail;
95 SLIST_HEAD(gpioc_pins_list, gpioc_pins) pins;
96 };
97
98 struct gpioc_privs {
99 struct gpioc_cdevpriv *priv;
100 SLIST_ENTRY(gpioc_privs) next;
101 };
102
103 struct gpioc_pins {
104 struct gpioc_pin_intr *pin;
105 int eventcount;
106 int firstevent;
107 SLIST_ENTRY(gpioc_pins) next;
108 };
109
110 struct gpioc_pin_event {
111 struct gpioc_pins *privpin;
112 sbintime_t event_time;
113 bool event_pin_state;
114 };
115
116 static MALLOC_DEFINE(M_GPIOC, "gpioc", "gpioc device data");
117
118 static int gpioc_allocate_pin_intr(struct gpioc_pin_intr*, uint32_t);
119 static int gpioc_release_pin_intr(struct gpioc_pin_intr*);
120 static int gpioc_attach_priv_pin(struct gpioc_cdevpriv*,
121 struct gpioc_pin_intr*);
122 static int gpioc_detach_priv_pin(struct gpioc_cdevpriv*,
123 struct gpioc_pin_intr*);
124 static bool gpioc_intr_reconfig_allowed(struct gpioc_cdevpriv*,
125 struct gpioc_pin_intr *intr_conf);
126 static uint32_t gpioc_get_intr_config(struct gpioc_softc*,
127 struct gpioc_cdevpriv*, uint32_t pin);
128 static int gpioc_set_intr_config(struct gpioc_softc*,
129 struct gpioc_cdevpriv*, uint32_t, uint32_t);
130 static void gpioc_interrupt_handler(void*);
131
132 static int gpioc_kqread(struct knote*, long);
133 static void gpioc_kqdetach(struct knote*);
134
135 static int gpioc_probe(device_t dev);
136 static int gpioc_attach(device_t dev);
137 static int gpioc_detach(device_t dev);
138
139 static void gpioc_cdevpriv_dtor(void*);
140
141 static d_open_t gpioc_open;
142 static d_read_t gpioc_read;
143 static d_ioctl_t gpioc_ioctl;
144 static d_poll_t gpioc_poll;
145 static d_kqfilter_t gpioc_kqfilter;
146
147 static struct cdevsw gpioc_cdevsw = {
148 .d_version = D_VERSION,
149 .d_open = gpioc_open,
150 .d_read = gpioc_read,
151 .d_ioctl = gpioc_ioctl,
152 .d_poll = gpioc_poll,
153 .d_kqfilter = gpioc_kqfilter,
154 .d_name = "gpioc",
155 };
156
157 static struct filterops gpioc_read_filterops = {
158 .f_isfd = true,
159 .f_attach = NULL,
160 .f_detach = gpioc_kqdetach,
161 .f_event = gpioc_kqread,
162 .f_touch = NULL
163 };
164
165 static struct gpioc_pin_event *
166 next_head_event(struct gpioc_cdevpriv *priv)
167 {
168 struct gpioc_pin_event *rv;
169
170 rv = &priv->events[priv->evidx_head++];
171 if (priv->evidx_head == priv->numevents)
172 priv->evidx_head = 0;
173 return (rv);
174 }
175
176 static struct gpioc_pin_event *
177 next_tail_event(struct gpioc_cdevpriv *priv)
178 {
179 struct gpioc_pin_event *rv;
180
181 rv = &priv->events[priv->evidx_tail++];
182 if (priv->evidx_tail == priv->numevents)
183 priv->evidx_tail = 0;
184 return (rv);
185 }
186
187 static size_t
188 number_of_events(struct gpioc_cdevpriv *priv)
189 {
190 if (priv->evidx_head >= priv->evidx_tail)
191 return (priv->evidx_head - priv->evidx_tail);
192 else
193 return (priv->numevents + priv->evidx_head - priv->evidx_tail);
194 }
195
196 static int
197 gpioc_allocate_pin_intr(struct gpioc_pin_intr *intr_conf, uint32_t flags)
198 {
199 int err;
200
201 intr_conf->config_locked = true;
202 mtx_unlock(&intr_conf->mtx);
203
204 intr_conf->intr_res = gpio_alloc_intr_resource(intr_conf->pin->dev,
205 &intr_conf->intr_rid, RF_ACTIVE, intr_conf->pin, flags);
206 if (intr_conf->intr_res == NULL) {
207 err = ENXIO;
208 goto error_exit;
209 }
210
211 err = bus_setup_intr(intr_conf->pin->dev, intr_conf->intr_res,
212 INTR_TYPE_MISC | INTR_MPSAFE, NULL, gpioc_interrupt_handler,
213 intr_conf, &intr_conf->intr_cookie);
214 if (err != 0)
215 goto error_exit;
216
217 intr_conf->pin->flags = flags;
218
219 error_exit:
220 mtx_lock(&intr_conf->mtx);
221 intr_conf->config_locked = false;
222 wakeup(&intr_conf->config_locked);
223
224 return (err);
225 }
226
227 static int
228 gpioc_release_pin_intr(struct gpioc_pin_intr *intr_conf)
229 {
230 int err;
231
232 intr_conf->config_locked = true;
233 mtx_unlock(&intr_conf->mtx);
234
235 if (intr_conf->intr_cookie != NULL) {
236 err = bus_teardown_intr(intr_conf->pin->dev,
237 intr_conf->intr_res, intr_conf->intr_cookie);
238 if (err != 0)
239 goto error_exit;
240 else
241 intr_conf->intr_cookie = NULL;
242 }
243
244 if (intr_conf->intr_res != NULL) {
245 err = bus_release_resource(intr_conf->pin->dev, SYS_RES_IRQ,
246 intr_conf->intr_rid, intr_conf->intr_res);
247 if (err != 0)
248 goto error_exit;
249 else {
250 intr_conf->intr_rid = 0;
251 intr_conf->intr_res = NULL;
252 }
253 }
254
255 intr_conf->pin->flags = 0;
256 err = 0;
257
258 error_exit:
259 mtx_lock(&intr_conf->mtx);
260 intr_conf->config_locked = false;
261 wakeup(&intr_conf->config_locked);
262
263 return (err);
264 }
265
266 static int
267 gpioc_attach_priv_pin(struct gpioc_cdevpriv *priv,
268 struct gpioc_pin_intr *intr_conf)
269 {
270 struct gpioc_privs *priv_link;
271 struct gpioc_pins *pin_link;
272 unsigned int consistency_a __diagused;
273 unsigned int consistency_b __diagused;
274
275 consistency_a = 0;
276 consistency_b = 0;
277 mtx_assert(&intr_conf->mtx, MA_OWNED);
278 mtx_lock(&priv->mtx);
279 SLIST_FOREACH(priv_link, &intr_conf->privs, next) {
280 if (priv_link->priv == priv)
281 consistency_a++;
282 }
283 KASSERT(consistency_a <= 1,
284 ("inconsistent links between pin config and cdevpriv"));
285 SLIST_FOREACH(pin_link, &priv->pins, next) {
286 if (pin_link->pin == intr_conf)
287 consistency_b++;
288 }
289 KASSERT(consistency_a == consistency_b,
290 ("inconsistent links between pin config and cdevpriv"));
291 if (consistency_a == 1 && consistency_b == 1) {
292 mtx_unlock(&priv->mtx);
293 return (EEXIST);
294 }
295 priv_link = malloc(sizeof(struct gpioc_privs), M_GPIOC,
296 M_NOWAIT | M_ZERO);
297 if (priv_link == NULL)
298 {
299 mtx_unlock(&priv->mtx);
300 return (ENOMEM);
301 }
302 pin_link = malloc(sizeof(struct gpioc_pins), M_GPIOC,
303 M_NOWAIT | M_ZERO);
304 if (pin_link == NULL) {
305 mtx_unlock(&priv->mtx);
306 return (ENOMEM);
307 }
308 priv_link->priv = priv;
309 pin_link->pin = intr_conf;
310 SLIST_INSERT_HEAD(&intr_conf->privs, priv_link, next);
311 SLIST_INSERT_HEAD(&priv->pins, pin_link, next);
312 mtx_unlock(&priv->mtx);
313
314 return (0);
315 }
316
317 static int
318 gpioc_detach_priv_pin(struct gpioc_cdevpriv *priv,
319 struct gpioc_pin_intr *intr_conf)
320 {
321 struct gpioc_privs *priv_link, *priv_link_temp;
322 struct gpioc_pins *pin_link, *pin_link_temp;
323 unsigned int consistency_a __diagused;
324 unsigned int consistency_b __diagused;
325
326 consistency_a = 0;
327 consistency_b = 0;
328 mtx_assert(&intr_conf->mtx, MA_OWNED);
329 mtx_lock(&priv->mtx);
330 SLIST_FOREACH_SAFE(priv_link, &intr_conf->privs, next, priv_link_temp) {
331 if (priv_link->priv == priv) {
332 SLIST_REMOVE(&intr_conf->privs, priv_link, gpioc_privs,
333 next);
334 free(priv_link, M_GPIOC);
335 consistency_a++;
336 }
337 }
338 KASSERT(consistency_a <= 1,
339 ("inconsistent links between pin config and cdevpriv"));
340 SLIST_FOREACH_SAFE(pin_link, &priv->pins, next, pin_link_temp) {
341 if (pin_link->pin == intr_conf) {
342 /*
343 * If the pin we're removing has events in the priv's
344 * event fifo, we can't leave dangling pointers from
345 * those events to the gpioc_pins struct we're about to
346 * free. We also can't remove random items and leave
347 * holes in the events fifo, so just empty it out.
348 */
349 if (pin_link->eventcount > 0) {
350 priv->evidx_head = priv->evidx_tail = 0;
351 }
352 SLIST_REMOVE(&priv->pins, pin_link, gpioc_pins, next);
353 free(pin_link, M_GPIOC);
354 consistency_b++;
355 }
356 }
357 KASSERT(consistency_a == consistency_b,
358 ("inconsistent links between pin config and cdevpriv"));
359 mtx_unlock(&priv->mtx);
360
361 return (0);
362 }
363
364 static bool
365 gpioc_intr_reconfig_allowed(struct gpioc_cdevpriv *priv,
366 struct gpioc_pin_intr *intr_conf)
367 {
368 struct gpioc_privs *priv_link;
369
370 mtx_assert(&intr_conf->mtx, MA_OWNED);
371
372 if (SLIST_EMPTY(&intr_conf->privs))
373 return (true);
374
375 SLIST_FOREACH(priv_link, &intr_conf->privs, next) {
376 if (priv_link->priv != priv)
377 return (false);
378 }
379
380 return (true);
381 }
382
383
384 static uint32_t
385 gpioc_get_intr_config(struct gpioc_softc *sc, struct gpioc_cdevpriv *priv,
386 uint32_t pin)
387 {
388 struct gpioc_pin_intr *intr_conf = &sc->sc_pin_intr[pin];
389 struct gpioc_privs *priv_link;
390 uint32_t flags;
391
392 flags = intr_conf->pin->flags;
393
394 if (flags == 0)
395 return (0);
396
397 mtx_lock(&intr_conf->mtx);
398 SLIST_FOREACH(priv_link, &intr_conf->privs, next) {
399 if (priv_link->priv == priv) {
400 flags |= GPIO_INTR_ATTACHED;
401 break;
402 }
403 }
404 mtx_unlock(&intr_conf->mtx);
405
406 return (flags);
407 }
408
409 static int
410 gpioc_set_intr_config(struct gpioc_softc *sc, struct gpioc_cdevpriv *priv,
411 uint32_t pin, uint32_t flags)
412 {
413 struct gpioc_pin_intr *intr_conf = &sc->sc_pin_intr[pin];
414 int res;
415
416 res = 0;
417 if (intr_conf->pin->flags == 0 && flags == 0) {
418 /* No interrupt configured and none requested: Do nothing. */
419 return (0);
420 }
421 mtx_lock(&intr_conf->mtx);
422 while (intr_conf->config_locked == true)
423 mtx_sleep(&intr_conf->config_locked, &intr_conf->mtx, 0,
424 "gpicfg", 0);
425 if (intr_conf->pin->flags == 0 && flags != 0) {
426 /*
427 * No interrupt is configured, but one is requested: Allocate
428 * and setup interrupt on the according pin.
429 */
430 res = gpioc_allocate_pin_intr(intr_conf, flags);
431 if (res == 0)
432 res = gpioc_attach_priv_pin(priv, intr_conf);
433 if (res == EEXIST)
434 res = 0;
435 } else if (intr_conf->pin->flags == flags) {
436 /*
437 * Same interrupt requested as already configured: Attach the
438 * cdevpriv to the corresponding pin.
439 */
440 res = gpioc_attach_priv_pin(priv, intr_conf);
441 if (res == EEXIST)
442 res = 0;
443 } else if (intr_conf->pin->flags != 0 && flags == 0) {
444 /*
445 * Interrupt configured, but none requested: Teardown and
446 * release the pin when no other cdevpriv is attached. Otherwise
447 * just detach pin and cdevpriv from each other.
448 */
449 if (gpioc_intr_reconfig_allowed(priv, intr_conf)) {
450 res = gpioc_release_pin_intr(intr_conf);
451 }
452 if (res == 0)
453 res = gpioc_detach_priv_pin(priv, intr_conf);
454 } else {
455 /*
456 * Other flag requested than configured: Reconfigure when no
457 * other cdevpriv is are attached to the pin.
458 */
459 if (!gpioc_intr_reconfig_allowed(priv, intr_conf))
460 res = EBUSY;
461 else {
462 res = gpioc_release_pin_intr(intr_conf);
463 if (res == 0)
464 res = gpioc_allocate_pin_intr(intr_conf, flags);
465 if (res == 0)
466 res = gpioc_attach_priv_pin(priv, intr_conf);
467 if (res == EEXIST)
468 res = 0;
469 }
470 }
471 mtx_unlock(&intr_conf->mtx);
472
473 return (res);
474 }
475
476 static void
477 gpioc_interrupt_handler(void *arg)
478 {
479 struct gpioc_pin_intr *intr_conf;
480 struct gpioc_privs *privs;
481 struct gpioc_softc *sc;
482 sbintime_t evtime;
483 uint32_t pin_state;
484
485 intr_conf = arg;
486 sc = intr_conf->sc;
487
488 /* Capture time and pin state first. */
489 evtime = sbinuptime();
490 if (intr_conf->pin->flags & GPIO_INTR_EDGE_BOTH)
491 GPIO_PIN_GET(sc->sc_pdev, intr_conf->pin->pin, &pin_state);
492 else if (intr_conf->pin->flags & GPIO_INTR_EDGE_RISING)
493 pin_state = true;
494 else
495 pin_state = false;
496
497 mtx_lock(&intr_conf->mtx);
498
499 if (intr_conf->config_locked == true) {
500 ddevice_printf(sc->sc_dev, "Interrupt configuration in "
501 "progress. Discarding interrupt on pin %d.\n",
502 intr_conf->pin->pin);
503 mtx_unlock(&intr_conf->mtx);
504 return;
505 }
506
507 if (SLIST_EMPTY(&intr_conf->privs)) {
508 ddevice_printf(sc->sc_dev, "No file descriptor associated with "
509 "occurred interrupt on pin %d.\n", intr_conf->pin->pin);
510 mtx_unlock(&intr_conf->mtx);
511 return;
512 }
513
514 SLIST_FOREACH(privs, &intr_conf->privs, next) {
515 struct gpioc_cdevpriv *priv = privs->priv;
516 struct gpioc_pins *privpin;
517 struct gpioc_pin_event *event;
518 mtx_lock(&priv->mtx);
519 SLIST_FOREACH(privpin, &priv->pins, next) {
520 if (privpin->pin == intr_conf)
521 break;
522 }
523 if (privpin == NULL) {
524 /* Should be impossible. */
525 ddevice_printf(sc->sc_dev, "Cannot find privpin\n");
526 mtx_unlock(&priv->mtx);
527 continue;
528 }
529
530 if (priv->report_option == GPIO_EVENT_REPORT_DETAIL) {
531 event = next_head_event(priv);
532 /* If head is overtaking tail, advance tail. */
533 if (priv->evidx_head == priv->evidx_tail)
534 next_tail_event(priv);
535 } else {
536 if (privpin->eventcount > 0)
537 event = &priv->events[privpin->firstevent + 1];
538 else {
539 privpin->firstevent = priv->evidx_head;
540 event = next_head_event(priv);
541 event->privpin = privpin;
542 event->event_time = evtime;
543 event->event_pin_state = pin_state;
544 event = next_head_event(priv);
545 }
546 ++privpin->eventcount;
547 }
548 event->privpin = privpin;
549 event->event_time = evtime;
550 event->event_pin_state = pin_state;
551 wakeup(priv);
552 selwakeup(&priv->selinfo);
553 KNOTE_LOCKED(&priv->selinfo.si_note, 0);
554 if (priv->async == true && priv->sigio != NULL)
555 pgsigio(&priv->sigio, SIGIO, 0);
556 mtx_unlock(&priv->mtx);
557 }
558
559 mtx_unlock(&intr_conf->mtx);
560 }
561
562 static int
563 gpioc_probe(device_t dev)
564 {
565 device_set_desc(dev, "GPIO controller");
566 return (0);
567 }
568
569 static int
570 gpioc_attach(device_t dev)
571 {
572 int err;
573 struct gpioc_softc *sc;
574 struct make_dev_args devargs;
575
576 sc = device_get_softc(dev);
577 sc->sc_dev = dev;
578 sc->sc_pdev = device_get_parent(dev);
579 sc->sc_unit = device_get_unit(dev);
580
581 err = GPIO_PIN_MAX(sc->sc_pdev, &sc->sc_npins);
582 sc->sc_npins++; /* Number of pins is one more than max pin number. */
583 if (err != 0)
584 return (err);
585 sc->sc_pin_intr = malloc(sizeof(struct gpioc_pin_intr) * sc->sc_npins,
586 M_GPIOC, M_WAITOK | M_ZERO);
587 for (int i = 0; i <= sc->sc_npins; i++) {
588 sc->sc_pin_intr[i].pin = malloc(sizeof(struct gpiobus_pin),
589 M_GPIOC, M_WAITOK | M_ZERO);
590 sc->sc_pin_intr[i].sc = sc;
591 sc->sc_pin_intr[i].pin->pin = i;
592 sc->sc_pin_intr[i].pin->dev = sc->sc_pdev;
593 mtx_init(&sc->sc_pin_intr[i].mtx, "gpioc pin", NULL, MTX_DEF);
594 SLIST_INIT(&sc->sc_pin_intr[i].privs);
595 }
596
597 make_dev_args_init(&devargs);
598 devargs.mda_devsw = &gpioc_cdevsw;
599 devargs.mda_uid = UID_ROOT;
600 devargs.mda_gid = GID_WHEEL;
601 devargs.mda_mode = 0600;
602 devargs.mda_si_drv1 = sc;
603 err = make_dev_s(&devargs, &sc->sc_ctl_dev, "gpioc%d", sc->sc_unit);
604 if (err != 0) {
605 device_printf(dev, "Failed to create gpioc%d", sc->sc_unit);
606 return (ENXIO);
607 }
608
609 return (0);
610 }
611
612 static int
613 gpioc_detach(device_t dev)
614 {
615 struct gpioc_softc *sc = device_get_softc(dev);
616 int err;
617
618 if (sc->sc_ctl_dev)
619 destroy_dev(sc->sc_ctl_dev);
620
621 for (int i = 0; i <= sc->sc_npins; i++) {
622 mtx_destroy(&sc->sc_pin_intr[i].mtx);
623 free(sc->sc_pin_intr[i].pin, M_GPIOC);
624 }
625 free(sc->sc_pin_intr, M_GPIOC);
626
627 if ((err = bus_generic_detach(dev)) != 0)
628 return (err);
629
630 return (0);
631 }
632
633 static void
634 gpioc_cdevpriv_dtor(void *data)
635 {
636 struct gpioc_cdevpriv *priv;
637 struct gpioc_privs *priv_link, *priv_link_temp;
638 struct gpioc_pins *pin_link, *pin_link_temp;
639 unsigned int consistency __diagused;
640
641 priv = data;
642
643 SLIST_FOREACH_SAFE(pin_link, &priv->pins, next, pin_link_temp) {
644 consistency = 0;
645 mtx_lock(&pin_link->pin->mtx);
646 while (pin_link->pin->config_locked == true)
647 mtx_sleep(&pin_link->pin->config_locked,
648 &pin_link->pin->mtx, 0, "gpicfg", 0);
649 SLIST_FOREACH_SAFE(priv_link, &pin_link->pin->privs, next,
650 priv_link_temp) {
651 if (priv_link->priv == priv) {
652 SLIST_REMOVE(&pin_link->pin->privs, priv_link,
653 gpioc_privs, next);
654 free(priv_link, M_GPIOC);
655 consistency++;
656 }
657 }
658 KASSERT(consistency == 1,
659 ("inconsistent links between pin config and cdevpriv"));
660 if (gpioc_intr_reconfig_allowed(priv, pin_link->pin)) {
661 gpioc_release_pin_intr(pin_link->pin);
662 }
663 mtx_unlock(&pin_link->pin->mtx);
664 SLIST_REMOVE(&priv->pins, pin_link, gpioc_pins, next);
665 free(pin_link, M_GPIOC);
666 }
667
668 wakeup(&priv);
669 knlist_clear(&priv->selinfo.si_note, 0);
670 seldrain(&priv->selinfo);
671 knlist_destroy(&priv->selinfo.si_note);
672 funsetown(&priv->sigio);
673
674 mtx_destroy(&priv->mtx);
675 free(priv->events, M_GPIOC);
676 free(data, M_GPIOC);
677 }
678
679 static int
680 gpioc_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
681 {
682 struct gpioc_cdevpriv *priv;
683 int err;
684
685 priv = malloc(sizeof(*priv), M_GPIOC, M_WAITOK | M_ZERO);
686 priv->sc = dev->si_drv1;
687 priv->report_option = GPIO_EVENT_REPORT_DETAIL;
688 err = devfs_set_cdevpriv(priv, gpioc_cdevpriv_dtor);
689 if (err != 0) {
690 gpioc_cdevpriv_dtor(priv);
691 return (err);
692 }
693 mtx_init(&priv->mtx, "gpioc priv", NULL, MTX_DEF);
694 knlist_init_mtx(&priv->selinfo.si_note, &priv->mtx);
695
696 /*
697 * Allocate a circular buffer for events. The scheme we use for summary
698 * reporting assumes there will always be a pair of events available to
699 * record the first/last events on any pin, so we allocate 2 * npins.
700 * Even though we actually default to detailed event reporting, 2 *
701 * npins isn't a horrible fifo size for that either.
702 */
703 priv->numevents = priv->sc->sc_npins * 2;
704 priv->events = malloc(priv->numevents * sizeof(struct gpio_event_detail),
705 M_GPIOC, M_WAITOK | M_ZERO);
706
707 return (0);
708 }
709
710 static int
711 gpioc_read(struct cdev *dev, struct uio *uio, int ioflag)
712 {
713 struct gpioc_cdevpriv *priv;
714 struct gpioc_pin_event *event;
715 union {
716 struct gpio_event_summary sum;
717 struct gpio_event_detail evt;
718 uint8_t data[1];
719 } recbuf;
720 size_t recsize;
721 int err;
722
723 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
724 return (err);
725
726 if (priv->report_option == GPIO_EVENT_REPORT_SUMMARY)
727 recsize = sizeof(struct gpio_event_summary);
728 else
729 recsize = sizeof(struct gpio_event_detail);
730
731 if (uio->uio_resid < recsize)
732 return (EINVAL);
733
734 mtx_lock(&priv->mtx);
735 while (priv->evidx_head == priv->evidx_tail) {
736 if (SLIST_EMPTY(&priv->pins)) {
737 err = ENXIO;
738 break;
739 } else if (ioflag & O_NONBLOCK) {
740 err = EWOULDBLOCK;
741 break;
742 } else {
743 err = mtx_sleep(priv, &priv->mtx, PCATCH, "gpintr", 0);
744 if (err != 0)
745 break;
746 }
747 }
748
749 while (err == 0 && uio->uio_resid >= recsize &&
750 priv->evidx_tail != priv->evidx_head) {
751 event = next_tail_event(priv);
752 if (priv->report_option == GPIO_EVENT_REPORT_SUMMARY) {
753 recbuf.sum.gp_first_time = event->event_time;
754 recbuf.sum.gp_pin = event->privpin->pin->pin->pin;
755 recbuf.sum.gp_count = event->privpin->eventcount;
756 recbuf.sum.gp_first_state = event->event_pin_state;
757 event = next_tail_event(priv);
758 recbuf.sum.gp_last_time = event->event_time;
759 recbuf.sum.gp_last_state = event->event_pin_state;
760 event->privpin->eventcount = 0;
761 event->privpin->firstevent = 0;
762 } else {
763 recbuf.evt.gp_time = event->event_time;
764 recbuf.evt.gp_pin = event->privpin->pin->pin->pin;
765 recbuf.evt.gp_pinstate = event->event_pin_state;
766 }
767 mtx_unlock(&priv->mtx);
768 err = uiomove(recbuf.data, recsize, uio);
769 mtx_lock(&priv->mtx);
770 }
771 mtx_unlock(&priv->mtx);
772 return (err);
773 }
774
775 static int
776 gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
777 struct thread *td)
778 {
779 device_t bus;
780 int max_pin, res;
781 struct gpioc_softc *sc = cdev->si_drv1;
782 struct gpioc_cdevpriv *priv;
783 struct gpio_pin pin;
784 struct gpio_req req;
785 struct gpio_access_32 *a32;
786 struct gpio_config_32 *c32;
787 struct gpio_event_config *evcfg;
788 uint32_t caps, intrflags;
789
790 bus = GPIO_GET_BUS(sc->sc_pdev);
791 if (bus == NULL)
792 return (EINVAL);
793 switch (cmd) {
794 case GPIOMAXPIN:
795 max_pin = -1;
796 res = GPIO_PIN_MAX(sc->sc_pdev, &max_pin);
797 bcopy(&max_pin, arg, sizeof(max_pin));
798 break;
799 case GPIOGETCONFIG:
800 bcopy(arg, &pin, sizeof(pin));
801 dprintf("get config pin %d\n", pin.gp_pin);
802 res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin,
803 &pin.gp_flags);
804 /* Fail early */
805 if (res)
806 break;
807 res = devfs_get_cdevpriv((void **)&priv);
808 if (res)
809 break;
810 pin.gp_flags |= gpioc_get_intr_config(sc, priv,
811 pin.gp_pin);
812 GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps);
813 GPIOBUS_PIN_GETNAME(bus, pin.gp_pin, pin.gp_name);
814 bcopy(&pin, arg, sizeof(pin));
815 break;
816 case GPIOSETCONFIG:
817 bcopy(arg, &pin, sizeof(pin));
818 dprintf("set config pin %d\n", pin.gp_pin);
819 res = devfs_get_cdevpriv((void **)&priv);
820 if (res != 0)
821 break;
822 res = GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &caps);
823 if (res != 0)
824 break;
825 res = gpio_check_flags(caps, pin.gp_flags);
826 if (res != 0)
827 break;
828 intrflags = pin.gp_flags & GPIO_INTR_MASK;
829 /*
830 * We can do only edge interrupts, and only if the
831 * hardware supports that interrupt type on that pin.
832 */
833 switch (intrflags) {
834 case GPIO_INTR_NONE:
835 break;
836 case GPIO_INTR_EDGE_RISING:
837 case GPIO_INTR_EDGE_FALLING:
838 case GPIO_INTR_EDGE_BOTH:
839 if ((intrflags & caps) == 0)
840 res = EOPNOTSUPP;
841 break;
842 default:
843 res = EINVAL;
844 break;
845 }
846 if (res != 0)
847 break;
848 res = GPIO_PIN_SETFLAGS(sc->sc_pdev, pin.gp_pin,
849 (pin.gp_flags & ~GPIO_INTR_MASK));
850 if (res != 0)
851 break;
852 res = gpioc_set_intr_config(sc, priv, pin.gp_pin,
853 intrflags);
854 break;
855 case GPIOGET:
856 bcopy(arg, &req, sizeof(req));
857 res = GPIO_PIN_GET(sc->sc_pdev, req.gp_pin,
858 &req.gp_value);
859 dprintf("read pin %d -> %d\n",
860 req.gp_pin, req.gp_value);
861 bcopy(&req, arg, sizeof(req));
862 break;
863 case GPIOSET:
864 bcopy(arg, &req, sizeof(req));
865 res = GPIO_PIN_SET(sc->sc_pdev, req.gp_pin,
866 req.gp_value);
867 dprintf("write pin %d -> %d\n",
868 req.gp_pin, req.gp_value);
869 break;
870 case GPIOTOGGLE:
871 bcopy(arg, &req, sizeof(req));
872 dprintf("toggle pin %d\n",
873 req.gp_pin);
874 res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin);
875 break;
876 case GPIOSETNAME:
877 bcopy(arg, &pin, sizeof(pin));
878 dprintf("set name on pin %d\n", pin.gp_pin);
879 res = GPIOBUS_PIN_SETNAME(bus, pin.gp_pin,
880 pin.gp_name);
881 break;
882 case GPIOACCESS32:
883 a32 = (struct gpio_access_32 *)arg;
884 res = GPIO_PIN_ACCESS_32(sc->sc_pdev, a32->first_pin,
885 a32->clear_pins, a32->change_pins, &a32->orig_pins);
886 break;
887 case GPIOCONFIG32:
888 c32 = (struct gpio_config_32 *)arg;
889 res = GPIO_PIN_CONFIG_32(sc->sc_pdev, c32->first_pin,
890 c32->num_pins, c32->pin_flags);
891 break;
892 case GPIOCONFIGEVENTS:
893 evcfg = (struct gpio_event_config *)arg;
894 res = devfs_get_cdevpriv((void **)&priv);
895 if (res != 0)
896 break;
897 /* If any pins have been configured, changes aren't allowed. */
898 if (!SLIST_EMPTY(&priv->pins)) {
899 res = EINVAL;
900 break;
901 }
902 if (evcfg->gp_report_type != GPIO_EVENT_REPORT_DETAIL &&
903 evcfg->gp_report_type != GPIO_EVENT_REPORT_SUMMARY) {
904 res = EINVAL;
905 break;
906 }
907 priv->report_option = evcfg->gp_report_type;
908 /* Reallocate the events buffer if the user wants it bigger. */
909 if (priv->report_option == GPIO_EVENT_REPORT_DETAIL &&
910 priv->numevents < evcfg->gp_fifo_size) {
911 free(priv->events, M_GPIOC);
912 priv->numevents = evcfg->gp_fifo_size;
913 priv->events = malloc(priv->numevents *
914 sizeof(struct gpio_event_detail), M_GPIOC,
915 M_WAITOK | M_ZERO);
916 priv->evidx_head = priv->evidx_tail = 0;
917 }
918 break;
919 case FIONBIO:
920 /*
921 * This dummy handler is necessary to prevent fcntl()
922 * from failing. The actual handling of non-blocking IO
923 * is done using the O_NONBLOCK ioflag passed to the
924 * read() syscall.
925 */
926 res = 0;
927 break;
928 case FIOASYNC:
929 res = devfs_get_cdevpriv((void **)&priv);
930 if (res == 0) {
931 if (*(int *)arg == FASYNC)
932 priv->async = true;
933 else
934 priv->async = false;
935 }
936 break;
937 case FIOGETOWN:
938 res = devfs_get_cdevpriv((void **)&priv);
939 if (res == 0)
940 *(int *)arg = fgetown(&priv->sigio);
941 break;
942 case FIOSETOWN:
943 res = devfs_get_cdevpriv((void **)&priv);
944 if (res == 0)
945 res = fsetown(*(int *)arg, &priv->sigio);
946 break;
947 default:
948 return (ENOTTY);
949 break;
950 }
951
952 return (res);
953 }
954
955 static int
956 gpioc_poll(struct cdev *dev, int events, struct thread *td)
957 {
958 struct gpioc_cdevpriv *priv;
959 int err;
960 int revents;
961
962 revents = 0;
963
964 err = devfs_get_cdevpriv((void **)&priv);
965 if (err != 0) {
966 revents = POLLERR;
967 return (revents);
968 }
969
970 if (SLIST_EMPTY(&priv->pins)) {
971 revents = POLLHUP;
972 return (revents);
973 }
974
975 if (events & (POLLIN | POLLRDNORM)) {
976 if (priv->evidx_head != priv->evidx_tail)
977 revents |= events & (POLLIN | POLLRDNORM);
978 else
979 selrecord(td, &priv->selinfo);
980 }
981
982 return (revents);
983 }
984
985 static int
986 gpioc_kqfilter(struct cdev *dev, struct knote *kn)
987 {
988 struct gpioc_cdevpriv *priv;
989 struct knlist *knlist;
990 int err;
991
992 err = devfs_get_cdevpriv((void **)&priv);
993 if (err != 0)
994 return err;
995
996 if (SLIST_EMPTY(&priv->pins))
997 return (ENXIO);
998
999 switch(kn->kn_filter) {
1000 case EVFILT_READ:
1001 kn->kn_fop = &gpioc_read_filterops;
1002 kn->kn_hook = (void *)priv;
1003 break;
1004 default:
1005 return (EOPNOTSUPP);
1006 }
1007
1008 knlist = &priv->selinfo.si_note;
1009 knlist_add(knlist, kn, 0);
1010
1011 return (0);
1012 }
1013
1014 static int
1015 gpioc_kqread(struct knote *kn, long hint)
1016 {
1017 struct gpioc_cdevpriv *priv = kn->kn_hook;
1018 size_t recsize;
1019
1020
1021 if (SLIST_EMPTY(&priv->pins)) {
1022 kn->kn_flags |= EV_EOF;
1023 return (1);
1024 } else {
1025 if (priv->evidx_head != priv->evidx_tail) {
1026 if (priv->report_option == GPIO_EVENT_REPORT_SUMMARY)
1027 recsize = sizeof(struct gpio_event_summary);
1028 else
1029 recsize = sizeof(struct gpio_event_detail);
1030 kn->kn_data = recsize * number_of_events(priv);
1031 return (1);
1032 }
1033 }
1034 return (0);
1035 }
1036
1037 static void
1038 gpioc_kqdetach(struct knote *kn)
1039 {
1040 struct gpioc_cdevpriv *priv = kn->kn_hook;
1041 struct knlist *knlist = &priv->selinfo.si_note;
1042
1043 knlist_remove(knlist, kn, 0);
1044 }
1045
1046 static device_method_t gpioc_methods[] = {
1047 /* Device interface */
1048 DEVMETHOD(device_probe, gpioc_probe),
1049 DEVMETHOD(device_attach, gpioc_attach),
1050 DEVMETHOD(device_detach, gpioc_detach),
1051 DEVMETHOD(device_shutdown, bus_generic_shutdown),
1052 DEVMETHOD(device_suspend, bus_generic_suspend),
1053 DEVMETHOD(device_resume, bus_generic_resume),
1054
1055 DEVMETHOD_END
1056 };
1057
1058 driver_t gpioc_driver = {
1059 "gpioc",
1060 gpioc_methods,
1061 sizeof(struct gpioc_softc)
1062 };
1063
1064 devclass_t gpioc_devclass;
1065
1066 DRIVER_MODULE(gpioc, gpio, gpioc_driver, gpioc_devclass, 0, 0);
1067 MODULE_VERSION(gpioc, 1);
Cache object: 1cfc0d32a4ad94ac2e07054327b2c036
|