git: ab7c01f9e82c - stable/14 - sound: Move vchan-related code to pcm/vchan.*

From: Christos Margiolis <christos_at_FreeBSD.org>
Date: Fri, 17 May 2024 19:31:07 UTC
The branch stable/14 has been updated by christos:

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

commit ab7c01f9e82cbf63d3b51d392ebfa1112bea14ef
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2024-05-06 18:32:46 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2024-05-17 19:30:35 +0000

    sound: Move vchan-related code to pcm/vchan.*
    
    pcm/sound.* contains code that should be part of pcm/vchan.*.
    
    Changes:
    - pcm_setvchans() -> vchan_setnew()
    - pcm_setmaxautovchans() -> vchan_setmaxauto()
    - hw.snd.maxautovchans moved to pcm/vchan.c
    - snd_maxautovchans declaration moved to pcm/vchan.h and definition to
      pcm/vchan.c
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Reviewed by:    dev_submerge.ch, markj
    Differential Revision:  https://reviews.freebsd.org/D45015
    
    (cherry picked from commit 7ad5f383fcb507482d5606c8eb7a324b3621a9db)
---
 sys/dev/sound/pcm/feeder.c |   1 +
 sys/dev/sound/pcm/sound.c  | 176 +--------------------------------------------
 sys/dev/sound/pcm/sound.h  |   2 -
 sys/dev/sound/pcm/vchan.c  | 173 +++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/sound/pcm/vchan.h  |   5 ++
 5 files changed, 180 insertions(+), 177 deletions(-)

diff --git a/sys/dev/sound/pcm/feeder.c b/sys/dev/sound/pcm/feeder.c
index 78443ad76140..0113299bd0d4 100644
--- a/sys/dev/sound/pcm/feeder.c
+++ b/sys/dev/sound/pcm/feeder.c
@@ -32,6 +32,7 @@
 #endif
 
 #include <dev/sound/pcm/sound.h>
+#include <dev/sound/pcm/vchan.h>
 
 #include "feeder_if.h"
 
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index afa19f9f0624..971054261030 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -56,8 +56,6 @@ static int snd_unit_auto = -1;
 SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RWTUN,
     &snd_unit_auto, 0, "assign default unit to a newly attached device");
 
-int snd_maxautovchans = 16;
-
 SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
     "Sound driver");
 
@@ -111,126 +109,6 @@ snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand
 	return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep);
 }
 
-int
-pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num)
-{
-	struct pcm_channel *c, *ch, *nch;
-	struct pcmchan_caps *caps;
-	int i, err, vcnt;
-
-	PCM_BUSYASSERT(d);
-
-	if ((direction == PCMDIR_PLAY && d->playcount < 1) ||
-	    (direction == PCMDIR_REC && d->reccount < 1))
-		return (ENODEV);
-
-	if (!(d->flags & SD_F_AUTOVCHAN))
-		return (EINVAL);
-
-	if (newcnt < 0 || newcnt > SND_MAXVCHANS)
-		return (E2BIG);
-
-	if (direction == PCMDIR_PLAY)
-		vcnt = d->pvchancount;
-	else if (direction == PCMDIR_REC)
-		vcnt = d->rvchancount;
-	else
-		return (EINVAL);
-
-	if (newcnt > vcnt) {
-		KASSERT(num == -1 ||
-		    (num >= 0 && num < SND_MAXVCHANS && (newcnt - 1) == vcnt),
-		    ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d",
-		    num, newcnt, vcnt));
-		/* add new vchans - find a parent channel first */
-		ch = NULL;
-		CHN_FOREACH(c, d, channels.pcm) {
-			CHN_LOCK(c);
-			if (c->direction == direction &&
-			    ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 &&
-			    c->refcount < 1 &&
-			    !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) {
-				/* 
-				 * Reuse hw channel with vchans already
-				 * created.
-				 */
-				if (c->flags & CHN_F_HAS_VCHAN) {
-					ch = c;
-					break;
-				}
-				/*
-				 * No vchans ever created, look for
-				 * channels with supported formats.
-				 */
-				caps = chn_getcaps(c);
-				if (caps == NULL) {
-					CHN_UNLOCK(c);
-					continue;
-				}
-				for (i = 0; caps->fmtlist[i] != 0; i++) {
-					if (caps->fmtlist[i] & AFMT_CONVERTIBLE)
-						break;
-				}
-				if (caps->fmtlist[i] != 0) {
-					ch = c;
-				    	break;
-				}
-			}
-			CHN_UNLOCK(c);
-		}
-		if (ch == NULL)
-			return (EBUSY);
-		ch->flags |= CHN_F_BUSY;
-		err = 0;
-		while (err == 0 && newcnt > vcnt) {
-			err = vchan_create(ch, num);
-			if (err == 0)
-				vcnt++;
-			else if (err == E2BIG && newcnt > vcnt)
-				device_printf(d->dev,
-				    "%s: err=%d Maximum channel reached.\n",
-				    __func__, err);
-		}
-		if (vcnt == 0)
-			ch->flags &= ~CHN_F_BUSY;
-		CHN_UNLOCK(ch);
-		if (err != 0)
-			return (err);
-	} else if (newcnt < vcnt) {
-		KASSERT(num == -1,
-		    ("bogus vchan_destroy() request num=%d", num));
-		CHN_FOREACH(c, d, channels.pcm) {
-			CHN_LOCK(c);
-			if (c->direction != direction ||
-			    CHN_EMPTY(c, children) ||
-			    !(c->flags & CHN_F_HAS_VCHAN)) {
-				CHN_UNLOCK(c);
-				continue;
-			}
-			CHN_FOREACH_SAFE(ch, c, nch, children) {
-				CHN_LOCK(ch);
-				if (vcnt == 1 && c->refcount > 0) {
-					CHN_UNLOCK(ch);
-					break;
-				}
-				if (!(ch->flags & CHN_F_BUSY) &&
-				    ch->refcount < 1) {
-					err = vchan_destroy(ch);
-					if (err == 0)
-						vcnt--;
-				} else
-					CHN_UNLOCK(ch);
-				if (vcnt == newcnt)
-					break;
-			}
-			CHN_UNLOCK(c);
-			break;
-		}
-	}
-
-	return (0);
-}
-
 /* return error status and a locked channel */
 int
 pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
@@ -287,7 +165,7 @@ vchan_alloc:
 	/* no channel available */
 	if (!(vchancount > 0 && vchancount < snd_maxautovchans))
 		return (err);
-	err = pcm_setvchans(d, direction, vchancount + 1, -1);
+	err = vchan_setnew(d, direction, vchancount + 1, -1);
 	if (err == 0) {
 		retry = true;
 		goto retry_chnalloc;
@@ -296,25 +174,6 @@ vchan_alloc:
 	return (err);
 }
 
-static void
-pcm_setmaxautovchans(struct snddev_info *d, int num)
-{
-	PCM_BUSYASSERT(d);
-
-	if (num < 0)
-		return;
-
-	if (num >= 0 && d->pvchancount > num)
-		(void)pcm_setvchans(d, PCMDIR_PLAY, num, -1);
-	else if (num > 0 && d->pvchancount == 0)
-		(void)pcm_setvchans(d, PCMDIR_PLAY, 1, -1);
-
-	if (num >= 0 && d->rvchancount > num)
-		(void)pcm_setvchans(d, PCMDIR_REC, num, -1);
-	else if (num > 0 && d->rvchancount == 0)
-		(void)pcm_setvchans(d, PCMDIR_REC, 1, -1);
-}
-
 static int
 sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS)
 {
@@ -338,37 +197,6 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit,
     sizeof(int), sysctl_hw_snd_default_unit, "I",
     "default sound device");
 
-static int
-sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS)
-{
-	struct snddev_info *d;
-	int i, v, error;
-
-	v = snd_maxautovchans;
-	error = sysctl_handle_int(oidp, &v, 0, req);
-	if (error == 0 && req->newptr != NULL) {
-		if (v < 0)
-			v = 0;
-		if (v > SND_MAXVCHANS)
-			v = SND_MAXVCHANS;
-		snd_maxautovchans = v;
-		for (i = 0; pcm_devclass != NULL &&
-		    i < devclass_get_maxunit(pcm_devclass); i++) {
-			d = devclass_get_softc(pcm_devclass, i);
-			if (!PCM_REGISTERED(d))
-				continue;
-			PCM_ACQUIRE_QUICK(d);
-			pcm_setmaxautovchans(d, v);
-			PCM_RELEASE_QUICK(d);
-		}
-	}
-	return (error);
-}
-SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans,
-    CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int),
-    sysctl_hw_snd_maxautovchans, "I",
-    "maximum virtual channel");
-
 void
 pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
 {
@@ -549,7 +377,7 @@ pcm_setstatus(device_t dev, char *str)
 	if (d->playcount > 0 || d->reccount > 0)
 		d->flags |= SD_F_AUTOVCHAN;
 
-	pcm_setmaxautovchans(d, snd_maxautovchans);
+	vchan_setmaxauto(d, snd_maxautovchans);
 
 	strlcpy(d->status, str, SND_STATUSLEN);
 
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index 5a750440cbea..e4a3ba41ee7f 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -247,7 +247,6 @@ enum {
 
 extern int pcm_veto_load;
 extern int snd_unit;
-extern int snd_maxautovchans;
 extern int snd_verbose;
 extern devclass_t pcm_devclass;
 extern struct unrhdr *pcmsg_unrhdr;
@@ -265,7 +264,6 @@ extern struct unrhdr *pcmsg_unrhdr;
 
 SYSCTL_DECL(_hw_snd);
 
-int pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num);
 int pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
     pid_t pid, char *comm);
 
diff --git a/sys/dev/sound/pcm/vchan.c b/sys/dev/sound/pcm/vchan.c
index 1a21b7049b77..9df23298b742 100644
--- a/sys/dev/sound/pcm/vchan.c
+++ b/sys/dev/sound/pcm/vchan.c
@@ -57,6 +57,8 @@ struct vchan_info {
 	int trigger;
 };
 
+int snd_maxautovchans = 16;
+
 static void *
 vchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
     struct pcm_channel *c, int dir)
@@ -337,7 +339,7 @@ sysctl_dev_pcm_vchans(SYSCTL_HANDLER_ARGS)
 			cnt = 0;
 		if (cnt > SND_MAXVCHANS)
 			cnt = SND_MAXVCHANS;
-		err = pcm_setvchans(d, direction, cnt, -1);
+		err = vchan_setnew(d, direction, cnt, -1);
 	}
 
 	PCM_RELEASE_QUICK(d);
@@ -930,6 +932,175 @@ vchan_sync(struct pcm_channel *c)
 	return (ret);
 }
 
+int
+vchan_setnew(struct snddev_info *d, int direction, int newcnt, int num)
+{
+	struct pcm_channel *c, *ch, *nch;
+	struct pcmchan_caps *caps;
+	int i, err, vcnt;
+
+	PCM_BUSYASSERT(d);
+
+	if ((direction == PCMDIR_PLAY && d->playcount < 1) ||
+	    (direction == PCMDIR_REC && d->reccount < 1))
+		return (ENODEV);
+
+	if (!(d->flags & SD_F_AUTOVCHAN))
+		return (EINVAL);
+
+	if (newcnt < 0 || newcnt > SND_MAXVCHANS)
+		return (E2BIG);
+
+	if (direction == PCMDIR_PLAY)
+		vcnt = d->pvchancount;
+	else if (direction == PCMDIR_REC)
+		vcnt = d->rvchancount;
+	else
+		return (EINVAL);
+
+	if (newcnt > vcnt) {
+		KASSERT(num == -1 ||
+		    (num >= 0 && num < SND_MAXVCHANS && (newcnt - 1) == vcnt),
+		    ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d",
+		    num, newcnt, vcnt));
+		/* add new vchans - find a parent channel first */
+		ch = NULL;
+		CHN_FOREACH(c, d, channels.pcm) {
+			CHN_LOCK(c);
+			if (c->direction == direction &&
+			    ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 &&
+			    c->refcount < 1 &&
+			    !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) {
+				/*
+				 * Reuse hw channel with vchans already
+				 * created.
+				 */
+				if (c->flags & CHN_F_HAS_VCHAN) {
+					ch = c;
+					break;
+				}
+				/*
+				 * No vchans ever created, look for
+				 * channels with supported formats.
+				 */
+				caps = chn_getcaps(c);
+				if (caps == NULL) {
+					CHN_UNLOCK(c);
+					continue;
+				}
+				for (i = 0; caps->fmtlist[i] != 0; i++) {
+					if (caps->fmtlist[i] & AFMT_CONVERTIBLE)
+						break;
+				}
+				if (caps->fmtlist[i] != 0) {
+					ch = c;
+					break;
+				}
+			}
+			CHN_UNLOCK(c);
+		}
+		if (ch == NULL)
+			return (EBUSY);
+		ch->flags |= CHN_F_BUSY;
+		err = 0;
+		while (err == 0 && newcnt > vcnt) {
+			err = vchan_create(ch, num);
+			if (err == 0)
+				vcnt++;
+			else if (err == E2BIG && newcnt > vcnt)
+				device_printf(d->dev,
+				    "%s: err=%d Maximum channel reached.\n",
+				    __func__, err);
+		}
+		if (vcnt == 0)
+			ch->flags &= ~CHN_F_BUSY;
+		CHN_UNLOCK(ch);
+		if (err != 0)
+			return (err);
+	} else if (newcnt < vcnt) {
+		KASSERT(num == -1,
+		    ("bogus vchan_destroy() request num=%d", num));
+		CHN_FOREACH(c, d, channels.pcm) {
+			CHN_LOCK(c);
+			if (c->direction != direction ||
+			    CHN_EMPTY(c, children) ||
+			    !(c->flags & CHN_F_HAS_VCHAN)) {
+				CHN_UNLOCK(c);
+				continue;
+			}
+			CHN_FOREACH_SAFE(ch, c, nch, children) {
+				CHN_LOCK(ch);
+				if (vcnt == 1 && c->refcount > 0) {
+					CHN_UNLOCK(ch);
+					break;
+				}
+				if (!(ch->flags & CHN_F_BUSY) &&
+				    ch->refcount < 1) {
+					err = vchan_destroy(ch);
+					if (err == 0)
+						vcnt--;
+				} else
+					CHN_UNLOCK(ch);
+				if (vcnt == newcnt)
+					break;
+			}
+			CHN_UNLOCK(c);
+			break;
+		}
+	}
+
+	return (0);
+}
+
+void
+vchan_setmaxauto(struct snddev_info *d, int num)
+{
+	PCM_BUSYASSERT(d);
+
+	if (num < 0)
+		return;
+
+	if (num >= 0 && d->pvchancount > num)
+		(void)vchan_setnew(d, PCMDIR_PLAY, num, -1);
+	else if (num > 0 && d->pvchancount == 0)
+		(void)vchan_setnew(d, PCMDIR_PLAY, 1, -1);
+
+	if (num >= 0 && d->rvchancount > num)
+		(void)vchan_setnew(d, PCMDIR_REC, num, -1);
+	else if (num > 0 && d->rvchancount == 0)
+		(void)vchan_setnew(d, PCMDIR_REC, 1, -1);
+}
+
+static int
+sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS)
+{
+	struct snddev_info *d;
+	int i, v, error;
+
+	v = snd_maxautovchans;
+	error = sysctl_handle_int(oidp, &v, 0, req);
+	if (error == 0 && req->newptr != NULL) {
+		if (v < 0)
+			v = 0;
+		if (v > SND_MAXVCHANS)
+			v = SND_MAXVCHANS;
+		snd_maxautovchans = v;
+		for (i = 0; pcm_devclass != NULL &&
+		    i < devclass_get_maxunit(pcm_devclass); i++) {
+			d = devclass_get_softc(pcm_devclass, i);
+			if (!PCM_REGISTERED(d))
+				continue;
+			PCM_ACQUIRE_QUICK(d);
+			vchan_setmaxauto(d, v);
+			PCM_RELEASE_QUICK(d);
+		}
+	}
+	return (error);
+}
+SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans,
+    CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int),
+    sysctl_hw_snd_maxautovchans, "I", "maximum virtual channel");
+
 void
 vchan_initsys(device_t dev)
 {
diff --git a/sys/dev/sound/pcm/vchan.h b/sys/dev/sound/pcm/vchan.h
index e2dcc9761261..dcc1d6e9ff32 100644
--- a/sys/dev/sound/pcm/vchan.h
+++ b/sys/dev/sound/pcm/vchan.h
@@ -30,6 +30,8 @@
 #ifndef _SND_VCHAN_H_
 #define _SND_VCHAN_H_
 
+extern int snd_maxautovchans;
+
 int vchan_create(struct pcm_channel *, int);
 int vchan_destroy(struct pcm_channel *);
 
@@ -45,6 +47,9 @@ int vchan_sync(struct pcm_channel *);
 	sndbuf_getfmt((c)->bufhard) != (c)->parentchannel->format ||	\
 	sndbuf_getspd((c)->bufhard) != (c)->parentchannel->speed))
 
+int vchan_setnew(struct snddev_info *, int, int, int);
+void vchan_setmaxauto(struct snddev_info *, int);
+
 void vchan_initsys(device_t);
 
 /*