diff --git a/sys/dev/sound/midi/midi.c b/sys/dev/sound/midi/midi.c --- a/sys/dev/sound/midi/midi.c +++ b/sys/dev/sound/midi/midi.c @@ -82,6 +82,7 @@ static d_read_t midi_read; static d_write_t midi_write; static d_poll_t midi_poll; +static d_kqfilter_t midi_kqfilter; static struct cdevsw midi_cdevsw = { .d_version = D_VERSION, @@ -91,6 +92,7 @@ .d_write = midi_write, .d_ioctl = midi_ioctl, .d_poll = midi_poll, + .d_kqfilter = midi_kqfilter, .d_name = "midi", }; @@ -138,6 +140,9 @@ m->channel = alloc_unr(chn_unr); m->cookie = cookie; + knlist_init_mtx(&m->rsel.si_note, &m->lock); + knlist_init_mtx(&m->wsel.si_note, &m->lock); + if (MPU_INIT(m, cookie)) goto err2; @@ -172,6 +177,10 @@ m->wchan = 0; } mtx_unlock(&m->lock); + knlist_clear(&m->rsel.si_note, 1); + knlist_destroy(&m->rsel.si_note); + knlist_clear(&m->wsel.si_note, 1); + knlist_destroy(&m->wsel.si_note); MPU_UNINIT(m, m->cookie); destroy_dev(m->dev); free_unr(dev_unr, m->unit); @@ -216,6 +225,7 @@ wakeup(&m->rchan); m->rchan = 0; } + KNOTE_LOCKED(&m->rsel.si_note, 0); selwakeup(&m->rsel); mtx_unlock(&m->lock); return used; @@ -248,6 +258,7 @@ wakeup(&m->wchan); m->wchan = 0; } + KNOTE_LOCKED(&m->wsel.si_note, 0); selwakeup(&m->wsel); } mtx_unlock(&m->lock); @@ -516,6 +527,65 @@ return (revents); } +static void +midi_kqdetach(struct knote *kn) +{ + struct snd_midi *m = kn->kn_hook; + if (kn->kn_filter == EVFILT_READ) + knlist_remove(&m->rsel.si_note, kn, 0); + else if (kn->kn_filter == EVFILT_WRITE) + knlist_remove(&m->wsel.si_note, kn, 0); +} + +static int +midi_kqfilter_event(struct knote *kn, long hint) +{ + struct snd_midi *m = kn->kn_hook; + if (/* there's something wrong */ false) { + kn->kn_data = EBADF; + kn->kn_flags |= EV_ERROR; + return (1); + } + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_data = MIDIQ_AVAIL(m->inq); + break; + case EVFILT_WRITE: + kn->kn_data = MIDIQ_AVAIL(m->outq); + break; + } + return (1); +} + +static const struct filterops midi_kqfilter_ops = { + .f_isfd = 1, + .f_detach = midi_kqdetach, + .f_event = midi_kqfilter_event, +}; + +static int +midi_kqfilter(struct cdev *dev, struct knote *kn) +{ + int error = 0; + struct snd_midi *m = dev->si_drv1; + + kn->kn_hook = m; + kn->kn_fop = &midi_kqfilter_ops; + + switch (kn->kn_filter) { + case EVFILT_READ: + knlist_add(&m->rsel.si_note, kn, 1); + break; + case EVFILT_WRITE: + knlist_add(&m->wsel.si_note, kn, 1); + break; + default: + error = EINVAL; + break; + } + return (error); +} + static void midi_sysinit(void *data __unused) {