Module Name:    src
Committed By:   bouyer
Date:           Sun Nov 26 12:16:31 UTC 2023

Modified Files:
        src/sys/dev/gpio [netbsd-10]: gpioirq.c

Log Message:
Pull up following revision(s) (requested by brad in ticket #464):
        sys/dev/gpio/gpioirq.c: revision 1.3
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.1.36.1 -r1.1.36.2 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.1.36.1 src/sys/dev/gpio/gpioirq.c:1.1.36.2
--- src/sys/dev/gpio/gpioirq.c:1.1.36.1	Sun Nov 26 11:45:16 2023
+++ src/sys/dev/gpio/gpioirq.c	Sun Nov 26 12:16:31 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: gpioirq.c,v 1.1.36.1 2023/11/26 11:45:16 bouyer Exp $ */
+/* $NetBSD: gpioirq.c,v 1.1.36.2 2023/11/26 12:16:31 bouyer 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.1.36.1 2023/11/26 11:45:16 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gpioirq.c,v 1.1.36.2 2023/11/26 12:16:31 bouyer 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);
 }

Reply via email to