The branch main has been updated by christos:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=4181bf9d18166c4061bfa137b8a46972a5a55f67

commit 4181bf9d18166c4061bfa137b8a46972a5a55f67
Author:     Christos Margiolis <[email protected]>
AuthorDate: 2025-11-11 12:04:45 +0000
Commit:     Christos Margiolis <[email protected]>
CommitDate: 2025-11-11 12:04:45 +0000

    sound: Add kqueue support
    
    Co-authored by: [email protected]
    Sponsored by:   The FreeBSD Foundation
    MFC after:      2 weeks
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D53029
---
 sys/dev/sound/pcm/channel.c |  9 +++--
 sys/dev/sound/pcm/channel.h |  1 +
 sys/dev/sound/pcm/dsp.c     | 82 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index 4d13f20a5262..062eeb251a5b 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -271,7 +271,7 @@ chn_lockdestroy(struct pcm_channel *c)
  * @retval 1 = ready for I/O
  * @retval 0 = not ready for I/O
  */
-static int
+int
 chn_polltrigger(struct pcm_channel *c)
 {
        struct snd_dbuf *bs = c->bufsoft;
@@ -313,6 +313,7 @@ chn_wakeup(struct pcm_channel *c)
        bs = c->bufsoft;
 
        if (CHN_EMPTY(c, children.busy)) {
+               KNOTE_LOCKED(&bs->sel.si_note, 0);
                if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
                        selwakeuppri(sndbuf_getsel(bs), PRIBIO);
                CHN_BROADCAST(&c->intr_cv);
@@ -1277,6 +1278,7 @@ chn_init(struct snddev_info *d, struct pcm_channel 
*parent, kobj_class_t cls,
        }
        c->bufhard = b;
        c->bufsoft = bs;
+       knlist_init_mtx(&bs->sel.si_note, c->lock);
 
        c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction);
        if (c->devinfo == NULL) {
@@ -1373,8 +1375,11 @@ chn_kill(struct pcm_channel *c)
        feeder_remove(c);
        if (c->devinfo && CHANNEL_FREE(c->methods, c->devinfo))
                sndbuf_free(b);
-       if (bs)
+       if (bs) {
+               knlist_clear(&bs->sel.si_note, 0);
+               knlist_destroy(&bs->sel.si_note);
                sndbuf_destroy(bs);
+       }
        if (b)
                sndbuf_destroy(b);
        CHN_LOCK(c);
diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h
index 9ad21d219001..15180bc8f0b6 100644
--- a/sys/dev/sound/pcm/channel.h
+++ b/sys/dev/sound/pcm/channel.h
@@ -261,6 +261,7 @@ int chn_read(struct pcm_channel *c, struct uio *buf);
 u_int32_t chn_start(struct pcm_channel *c, int force);
 int chn_sync(struct pcm_channel *c, int threshold);
 int chn_flush(struct pcm_channel *c);
+int chn_polltrigger(struct pcm_channel *c);
 int chn_poll(struct pcm_channel *c, int ev, struct thread *td);
 
 char *chn_mkname(char *buf, size_t len, struct pcm_channel *c);
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index 27d5b740b90b..1b205d7229fc 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -81,6 +81,7 @@ static d_ioctl_t dsp_ioctl;
 static d_poll_t dsp_poll;
 static d_mmap_t dsp_mmap;
 static d_mmap_single_t dsp_mmap_single;
+static d_kqfilter_t dsp_kqfilter;
 
 struct cdevsw dsp_cdevsw = {
        .d_version      = D_VERSION,
@@ -89,6 +90,7 @@ struct cdevsw dsp_cdevsw = {
        .d_write        = dsp_write,
        .d_ioctl        = dsp_ioctl,
        .d_poll         = dsp_poll,
+       .d_kqfilter     = dsp_kqfilter,
        .d_mmap         = dsp_mmap,
        .d_mmap_single  = dsp_mmap_single,
        .d_name         = "dsp",
@@ -2962,6 +2964,86 @@ dsp_oss_getchannelmask(struct pcm_channel *wrch, struct 
pcm_channel *rdch,
        return (ret);
 }
 
+static void
+dsp_kqdetach(struct knote *kn)
+{
+       struct pcm_channel *ch = kn->kn_hook;
+
+       if (ch == NULL)
+               return;
+       CHN_LOCK(ch);
+       knlist_remove(&ch->bufsoft->sel.si_note, kn, 1);
+       CHN_UNLOCK(ch);
+}
+
+static int
+dsp_kqevent(struct knote *kn, long hint)
+{
+       struct pcm_channel *ch = kn->kn_hook;
+
+       CHN_LOCKASSERT(ch);
+       if (ch->flags & CHN_F_DEAD) {
+               kn->kn_flags |= EV_EOF;
+               return (1);
+       }
+       kn->kn_data = 0;
+       if (chn_polltrigger(ch)) {
+               if (kn->kn_filter == EVFILT_READ)
+                       kn->kn_data = sndbuf_getready(ch->bufsoft);
+               else
+                       kn->kn_data = sndbuf_getfree(ch->bufsoft);
+       }
+
+       return (kn->kn_data > 0);
+}
+
+static const struct filterops dsp_filtops = {
+       .f_isfd = 1,
+       .f_detach = dsp_kqdetach,
+       .f_event = dsp_kqevent,
+};
+
+static int
+dsp_kqfilter(struct cdev *dev, struct knote *kn)
+{
+       struct dsp_cdevpriv *priv;
+       struct snddev_info *d;
+       struct pcm_channel *ch;
+       int err = 0;
+
+       if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
+               return (err);
+
+       d = priv->sc;
+       if (!DSP_REGISTERED(d))
+               return (EBADF);
+       PCM_GIANT_ENTER(d);
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               ch = priv->rdch;
+               break;
+       case EVFILT_WRITE:
+               ch = priv->wrch;
+               break;
+       default:
+               kn->kn_hook = NULL;
+               err = EINVAL;
+               ch = NULL;
+               break;
+       }
+       if (ch != NULL) {
+               kn->kn_fop = &dsp_filtops;
+               CHN_LOCK(ch);
+               knlist_add(&ch->bufsoft->sel.si_note, kn, 1);
+               CHN_UNLOCK(ch);
+               kn->kn_hook = ch;
+       } else
+               err = EINVAL;
+       PCM_GIANT_LEAVE(d);
+
+       return (err);
+}
+
 #ifdef OSSV4_EXPERIMENT
 /**
  * @brief Retrieve an audio device's label

Reply via email to