git: 6378079427be - stable/14 - sound: Improve simplex handling in dsp_open()

From: Christos Margiolis <christos_at_FreeBSD.org>
Date: Wed, 10 Jul 2024 16:49:05 UTC
The branch stable/14 has been updated by christos:

URL: https://cgit.FreeBSD.org/src/commit/?id=6378079427be35962d36a8e9b587eb63b1159e99

commit 6378079427be35962d36a8e9b587eb63b1159e99
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2024-07-06 18:22:45 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2024-07-10 16:48:13 +0000

    sound: Improve simplex handling in dsp_open()
    
    If we are in simplex mode, make sure we do not open in both directions
    (read/write) and also that we do not open in a direction opposite of
    what is already opened. For example, if the device is already doing
    playback, we cannot open the device for recording at the same time, and
    vice-versa.
    
    While here, remove dsp_cdevpriv->simplex as it's no longer needed.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      2 days
    Reviewed by:    dev_submerge.ch
    Differential Revision:  https://reviews.freebsd.org/D45835
    
    (cherry picked from commit be04a9d9387f6b5d4e83fc4976d8d83bb03fe5af)
---
 sys/dev/sound/pcm/dsp.c | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index f2cead08783c..26a2919ed1da 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -52,7 +52,6 @@ struct dsp_cdevpriv {
 	struct pcm_channel *rdch;
 	struct pcm_channel *wrch;
 	struct pcm_channel *volch;
-	int simplex;
 };
 
 static int dsp_mmap_allow_prot_exec = 0;
@@ -301,10 +300,10 @@ static int
 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)
@@ -319,7 +318,6 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
 	priv->rdch = NULL;
 	priv->wrch = NULL;
 	priv->volch = NULL;
-	priv->simplex = (pcm_getflags(d->dev) & SD_F_SIMPLEX) ? 1 : 0;
 
 	error = devfs_set_cdevpriv(priv, dsp_close);
 	if (error != 0)
@@ -333,6 +331,36 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
 
 	error = 0;
 	DSP_FIXUP_ERROR();
+	if (pcm_getflags(d->dev) & SD_F_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)) {
+				if (d->playcount > 0)
+					flags &= ~FREAD;
+				else if (d->reccount > 0)
+					flags &= ~FWRITE;
+			} 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);