The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=54df18cbb400e6394edad8abab0e5cb3a97e4df3
commit 54df18cbb400e6394edad8abab0e5cb3a97e4df3 Author: Baptiste Daroussin <[email protected]> AuthorDate: 2026-05-06 16:22:07 +0000 Commit: Baptiste Daroussin <[email protected]> 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)
