git: 54df18cbb400 - main - uvideo: add kqueue support

From: Baptiste Daroussin <bapt_at_FreeBSD.org>
Date: Tue, 16 Jun 2026 11:23:03 UTC
The branch main has been updated by bapt:

URL: https://cgit.FreeBSD.org/src/commit/?id=54df18cbb400e6394edad8abab0e5cb3a97e4df3

commit 54df18cbb400e6394edad8abab0e5cb3a97e4df3
Author:     Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2026-05-06 16:22:07 +0000
Commit:     Baptiste Daroussin <bapt@FreeBSD.org>
CommitDate: 2026-06-16 11:20:57 +0000

    uvideo: add kqueue support
    
    Add EVFILT_READ kqueue filter so applications using kqueue/kevent
    can efficiently wait for video frames instead of polling.
    
    Reviewed by:    manu
    Differential Revision:  https://reviews.freebsd.org/D56961
---
 sys/dev/usb/video/uvideo.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/sys/dev/usb/video/uvideo.c b/sys/dev/usb/video/uvideo.c
index 310c66db2846..a33b3ac31ea6 100644
--- a/sys/dev/usb/video/uvideo.c
+++ b/sys/dev/usb/video/uvideo.c
@@ -38,6 +38,7 @@
 #include <sys/mutex.h>
 #include <sys/poll.h>
 #include <sys/proc.h>
+#include <sys/event.h>
 #include <sys/selinfo.h>
 #include <sys/limits.h>
 #include <sys/sysctl.h>
@@ -155,6 +156,7 @@ static d_close_t	uvideo_cdev_close;
 static d_read_t		uvideo_cdev_read;
 static d_ioctl_t	uvideo_cdev_ioctl;
 static d_poll_t		uvideo_cdev_poll;
+static d_kqfilter_t	uvideo_cdev_kqfilter;
 static d_mmap_t		uvideo_cdev_mmap;
 
 static int	uvideo_querycap(struct uvideo_softc *, struct v4l2_capability *);
@@ -540,6 +542,7 @@ static struct cdevsw uvideo_cdevsw = {
 	.d_read = uvideo_cdev_read,
 	.d_ioctl = uvideo_cdev_ioctl,
 	.d_poll = uvideo_cdev_poll,
+	.d_kqfilter = uvideo_cdev_kqfilter,
 	.d_mmap = uvideo_cdev_mmap,
 	.d_name = "video",
 };
@@ -2433,6 +2436,7 @@ uvideo_mmap_queue(struct uvideo_softc *sc, int len, int err)
 
 	wakeup(sc);
 	selwakeup(&sc->sc_selinfo);
+	KNOTE_LOCKED(&sc->sc_selinfo.si_note, 0);
 }
 
 static void
@@ -2453,6 +2457,7 @@ uvideo_read_frame(struct uvideo_softc *sc, uint8_t *buf, int len)
 
 	wakeup(sc);
 	selwakeup(&sc->sc_selinfo);
+	KNOTE_LOCKED(&sc->sc_selinfo.si_note, 0);
 }
 
 /* ---------------------------------------------------------------- */
@@ -2690,6 +2695,49 @@ uvideo_cdev_poll(struct cdev *dev, int events, struct thread *td)
 	return (revents);
 }
 
+static void
+uvideo_kqfilter_detach(struct knote *kn)
+{
+	struct uvideo_softc *sc = kn->kn_hook;
+
+	knlist_remove(&sc->sc_selinfo.si_note, kn, 0);
+}
+
+static int
+uvideo_kqfilter_read(struct knote *kn, long hint __unused)
+{
+	struct uvideo_softc *sc = kn->kn_hook;
+
+	if (sc->sc_mmap_flag)
+		return (!STAILQ_EMPTY(&sc->sc_mmap_q));
+	return (sc->sc_frames_ready > 0);
+}
+
+static struct filterops uvideo_filtops_read = {
+	.f_isfd = 1,
+	.f_detach = uvideo_kqfilter_detach,
+	.f_event = uvideo_kqfilter_read,
+};
+
+static int
+uvideo_cdev_kqfilter(struct cdev *dev, struct knote *kn)
+{
+	struct uvideo_softc *sc = dev->si_drv1;
+
+	if (sc == NULL || sc->sc_dying)
+		return (ENXIO);
+
+	switch (kn->kn_filter) {
+	case EVFILT_READ:
+		kn->kn_fop = &uvideo_filtops_read;
+		kn->kn_hook = sc;
+		knlist_add(&sc->sc_selinfo.si_note, kn, 0);
+		return (0);
+	default:
+		return (EINVAL);
+	}
+}
+
 static int
 uvideo_cdev_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
     int nprot, vm_memattr_t *memattr)