diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -2330,13 +2330,21 @@ "prev=0x%08x\n", __func__, c->name, go, c->trigger); if (c->trigger != PCMTRIG_START) { - c->trigger = go; CHN_UNLOCK(c); PCM_LOCK(d); - CHN_INSERT_HEAD(d, c, channels.pcm.busy); - PCM_UNLOCK(d); CHN_LOCK(c); - chn_syncstate(c); + /* + * Do nothing if another thread started the channel + * already while we had dropped the mutex. + */ + if (c->trigger == PCMTRIG_START) + PCM_UNLOCK(d); + else { + c->trigger = go; + CHN_INSERT_HEAD(d, c, channels.pcm.busy); + PCM_UNLOCK(d); + chn_syncstate(c); + } } break; case PCMTRIG_STOP: @@ -2347,12 +2355,17 @@ "prev=0x%08x\n", __func__, c->name, go, c->trigger); if (c->trigger == PCMTRIG_START) { - c->trigger = go; CHN_UNLOCK(c); PCM_LOCK(d); - CHN_REMOVE(d, c, channels.pcm.busy); - PCM_UNLOCK(d); CHN_LOCK(c); + /* See comment above. */ + if (c->trigger != PCMTRIG_START) + PCM_UNLOCK(d); + else { + c->trigger = go; + CHN_REMOVE(d, c, channels.pcm.busy); + PCM_UNLOCK(d); + } } break; default: diff --git a/sys/dev/sound/pcm/vchan.c b/sys/dev/sound/pcm/vchan.c --- a/sys/dev/sound/pcm/vchan.c +++ b/sys/dev/sound/pcm/vchan.c @@ -146,20 +146,19 @@ int ret, otrigger; info = data; - - if (!PCMTRIG_COMMON(go) || go == info->trigger) - return (0); - c = info->channel; p = c->parentchannel; - otrigger = info->trigger; - info->trigger = go; CHN_LOCKASSERT(c); + if (!PCMTRIG_COMMON(go) || go == info->trigger) + return (0); CHN_UNLOCK(c); CHN_LOCK(p); + otrigger = info->trigger; + info->trigger = go; + switch (go) { case PCMTRIG_START: if (otrigger != PCMTRIG_START)