diff --git a/sys/dev/sound/dummy.c b/sys/dev/sound/dummy.c index 9013fd023a7e..b637171d82e4 100644 --- a/sys/dev/sound/dummy.c +++ b/sys/dev/sound/dummy.c @@ -67,6 +67,24 @@ struct dummy_softc { struct mtx *lock; }; +static bool +dummy_active(struct dummy_softc *sc) +{ + struct dummy_chan *ch; + int i; + + snd_mtxassert(sc->lock); + + for (i = 0; i < sc->chnum; i++) { + ch = &sc->chans[i]; + if (ch->run) + return (true); + } + + /* No channel is running at the moment. */ + return (false); +} + static void dummy_chan_io(void *arg) { @@ -74,7 +92,9 @@ dummy_chan_io(void *arg) struct dummy_chan *ch; int i = 0; - snd_mtxlock(sc->lock); + /* Do not reschedule if no channel is running. */ + if (!dummy_active(sc)) + return; for (i = 0; i < sc->chnum; i++) { ch = &sc->chans[i]; @@ -89,8 +109,6 @@ dummy_chan_io(void *arg) snd_mtxlock(sc->lock); } callout_schedule(&sc->callout, 1); - - snd_mtxunlock(sc->lock); } static int @@ -179,15 +197,15 @@ dummy_chan_trigger(kobj_t obj, void *data, int go) switch (go) { case PCMTRIG_START: - if (!callout_active(&sc->callout)) - callout_reset(&sc->callout, 1, dummy_chan_io, sc); ch->ptr = 0; ch->run = 1; + callout_reset(&sc->callout, 1, dummy_chan_io, sc); break; case PCMTRIG_STOP: case PCMTRIG_ABORT: ch->run = 0; - if (callout_active(&sc->callout)) + /* If all channels are stopped, stop the callout as well. */ + if (!dummy_active(sc)) callout_stop(&sc->callout); default: break; @@ -292,6 +310,7 @@ dummy_attach(device_t dev) sc = device_get_softc(dev); sc->dev = dev; sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_dummy softc"); + callout_init_mtx(&sc->callout, sc->lock, 0); sc->cap_fmts[0] = SND_FORMAT(AFMT_S32_LE, 2, 0); sc->cap_fmts[1] = SND_FORMAT(AFMT_S24_LE, 2, 0); @@ -316,7 +335,6 @@ dummy_attach(device_t dev) if (pcm_register(dev, status)) return (ENXIO); mixer_init(dev, &dummy_mixer_class, sc); - callout_init(&sc->callout, 1); return (0); } @@ -327,8 +345,8 @@ dummy_detach(device_t dev) struct dummy_softc *sc = device_get_softc(dev); int err; - callout_drain(&sc->callout); err = pcm_unregister(dev); + callout_drain(&sc->callout); snd_mtxfree(sc->lock); return (err);