Module Name: src Committed By: brad Date: Fri Nov 10 13:17:17 UTC 2023
Modified Files: src/sys/dev/gpio: gpioirq.c Log Message: For /dev/ reads against gpioirq(4) implement the following: o O_NONBLOCK on reads o Add a d_poll function and associated sel[init|notify|record|destroy] calls to the driver so that select(2) and poll(2) work as expected. With these in place async use cases work against /dev/gpioirqN To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/dev/gpio/gpioirq.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/gpio/gpioirq.c diff -u src/sys/dev/gpio/gpioirq.c:1.2 src/sys/dev/gpio/gpioirq.c:1.3 --- src/sys/dev/gpio/gpioirq.c:1.2 Mon Nov 6 00:35:05 2023 +++ src/sys/dev/gpio/gpioirq.c Fri Nov 10 13:17:17 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: gpioirq.c,v 1.2 2023/11/06 00:35:05 brad Exp $ */ +/* $NetBSD: gpioirq.c,v 1.3 2023/11/10 13:17:17 brad Exp $ */ /* * Copyright (c) 2016, 2023 Brad Spencer <b...@anduin.eldar.org> @@ -17,7 +17,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: gpioirq.c,v 1.2 2023/11/06 00:35:05 brad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: gpioirq.c,v 1.3 2023/11/10 13:17:17 brad Exp $"); /* * GPIO driver that uses interrupts and can send that fact to userland. @@ -34,6 +34,9 @@ __KERNEL_RCSID(0, "$NetBSD: gpioirq.c,v #include <sys/pool.h> #include <sys/kmem.h> #include <sys/condvar.h> +#include <sys/vnode.h> +#include <sys/select.h> +#include <sys/poll.h> #include <dev/gpio/gpiovar.h> @@ -67,6 +70,7 @@ struct gpioirq_softc { kcondvar_t sc_cond_dying; pool_cache_t sc_readpool; char *sc_readpoolname; + struct selinfo sc_rsel; SIMPLEQ_HEAD(,gpioirq_read_q) sc_read_queue; }; @@ -97,6 +101,7 @@ extern struct cfdriver gpioirq_cd; static dev_type_open(gpioirq_open); static dev_type_read(gpioirq_read); static dev_type_close(gpioirq_close); +static dev_type_poll(gpioirq_poll); const struct cdevsw gpioirq_cdevsw = { .d_open = gpioirq_open, .d_close = gpioirq_close, @@ -105,7 +110,7 @@ const struct cdevsw gpioirq_cdevsw = { .d_ioctl = noioctl, .d_stop = nostop, .d_tty = notty, - .d_poll = nopoll, + .d_poll = gpioirq_poll, .d_mmap = nommap, .d_kqfilter = nokqfilter, .d_discard = nodiscard, @@ -189,6 +194,7 @@ gpioirq_attach(device_t parent, device_t sc->sc_readpool = pool_cache_init(sizeof(struct gpioirq_read_q),0,0,0,sc->sc_readpoolname,NULL,IPL_VM,NULL,NULL,NULL); pool_cache_sethiwat(sc->sc_readpool,100); SIMPLEQ_INIT(&sc->sc_read_queue); + selinit(&sc->sc_rsel); for(int apin = 0; apin < sc->sc_npins; apin++) { if (!gpio_intr_str(sc->sc_gpio, &sc->sc_map, apin, irqmode, @@ -263,6 +269,7 @@ gpioirq_intr(void *arg) q->parentunit = is->i_parentunit; q->theval = val; SIMPLEQ_INSERT_TAIL(&sc->sc_read_queue,q,read_q); + selnotify(&sc->sc_rsel, POLLIN|POLLRDNORM, NOTE_SUBMIT); cv_signal(&sc->sc_condreadready); } else { aprint_error("Could not allocate memory for read pool\n"); @@ -304,6 +311,10 @@ gpioirq_read(dev_t dev, struct uio *uio, if (!sc) return (ENXIO); + if (sc->sc_dying) { + return EIO; + } + while (uio->uio_resid > 0) { any = 0; error = 0; @@ -316,7 +327,11 @@ gpioirq_read(dev_t dev, struct uio *uio, any = 1; break; } else { - error = cv_wait_sig(&sc->sc_condreadready,&sc->sc_read_mutex); + if (flags & IO_NDELAY) { + error = EWOULDBLOCK; + } else { + error = cv_wait_sig(&sc->sc_condreadready,&sc->sc_read_mutex); + } if (sc->sc_dying) error = EIO; if (error == 0) @@ -358,6 +373,10 @@ gpioirq_close(dev_t dev, int flags, int sc = device_lookup_private(&gpioirq_cd, minor(dev)); + if (sc->sc_dying) { + return(0); + } + mutex_enter(&sc->sc_lock); while ((q = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) { SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q); @@ -369,6 +388,31 @@ gpioirq_close(dev_t dev, int flags, int return(0); } +static int +gpioirq_poll(dev_t dev, int events, struct lwp *l) +{ + struct gpioirq_softc *sc; + int revents = 0; + + sc = device_lookup_private(&gpioirq_cd, minor(dev)); + + mutex_enter(&sc->sc_read_mutex); + if (sc->sc_dying) { + mutex_exit(&sc->sc_read_mutex); + return POLLHUP; + } + + if ((events & (POLLIN | POLLRDNORM)) != 0) { + if (!SIMPLEQ_EMPTY(&sc->sc_read_queue)) + revents |= events & (POLLIN | POLLRDNORM); + else + selrecord(l, &sc->sc_rsel); + } + + mutex_exit(&sc->sc_read_mutex); + return revents; +} + int gpioirq_detach(device_t self, int flags) { @@ -413,6 +457,7 @@ gpioirq_detach(device_t self, int flags) mutex_destroy(&sc->sc_read_mutex); mutex_destroy(&sc->sc_lock); + seldestroy(&sc->sc_rsel); return (0); }