diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -301,10 +301,10 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td) { struct dsp_cdevpriv *priv; - struct pcm_channel *rdch, *wrch; + struct pcm_channel *rdch, *wrch, *ch; struct snddev_info *d; uint32_t fmt, spd; - int error, rderror, wrerror; + int error, rderror, wrerror, dir; /* Kind of impossible.. */ if (i_dev == NULL || td == NULL) @@ -333,6 +333,33 @@ error = 0; DSP_FIXUP_ERROR(); + if (priv->simplex) { + if (DSP_F_DUPLEX(flags)) { + /* + * If no channels are opened yet, and we request + * DUPLEX, limit to playback only, otherwise open one + * channel in a direction that already exists. + */ + if (CHN_EMPTY(d, channels.pcm.opened)) + flags &= ~FREAD; + else { + ch = CHN_FIRST(d, channels.pcm.opened); + if (ch->direction == PCMDIR_PLAY) + flags &= ~FREAD; + else if (ch->direction == PCMDIR_REC) + flags &= ~FWRITE; + } + } else if (!CHN_EMPTY(d, channels.pcm.opened)) { + /* + * If we requested SIMPLEX, make sure we do not open a + * channel in the opposite direction. + */ + ch = CHN_FIRST(d, channels.pcm.opened); + dir = DSP_F_READ(flags) ? PCMDIR_REC : PCMDIR_PLAY; + if (ch->direction != dir) + error = ENOTSUP; + } + } if (error != 0) { PCM_UNLOCK(d); PCM_GIANT_EXIT(d);