git: e4c0d796141b - stable/14 - sound: Fix vchanrate and vchanformat

From: Christos Margiolis <christos_at_FreeBSD.org>
Date: Sun, 06 Apr 2025 00:28:27 UTC
The branch stable/14 has been updated by christos:

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

commit e4c0d796141b6611780fdff3063f744bbd49b282
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2025-03-30 17:45:34 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2025-04-06 00:28:14 +0000

    sound: Fix vchanrate and vchanformat
    
    Make vchanrate and vchanformat reflect the primary channel's software
    buffer's rate and format respectively. Fix previous inconsistencies.
    
    Get rid of the initializations in vchan_create() and move them to
    chn_init().
    
    Without the feeder_rate_round check in sysctl_dev_pcm_vchanrate(), we
    can set the software rate to anything between feeder_rate_min and
    feeder_rate_max. If we keep the check, however, the rate is limited to
    whatever the driver's min/max is, which can be a problem if, for
    example, the driver supports only a single rate, in which case we won't
    be able to set anything other than the driver rate.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D48961
    
    (cherry picked from commit e372211be5c56e218e974a4478be9aa80bfca064)
---
 sys/dev/sound/pcm/channel.c | 12 +++++--
 sys/dev/sound/pcm/vchan.c   | 82 ++-------------------------------------------
 2 files changed, 13 insertions(+), 81 deletions(-)

diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index 287e2f07d8a1..4a96505ada66 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -1176,7 +1176,7 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
 	struct feeder_class *fc;
 	struct snd_dbuf *b, *bs;
 	char buf[CHN_NAMELEN];
-	int err, i, direction;
+	int err, i, direction, *vchanrate, *vchanformat;
 
 	PCM_BUSYASSERT(d);
 	PCM_LOCKASSERT(d);
@@ -1189,6 +1189,8 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
 		if (dir == PCMDIR_PLAY_VIRTUAL)
 			d->pvchancount++;
 		direction = PCMDIR_PLAY;
+		vchanrate = &d->pvchanrate;
+		vchanformat = &d->pvchanformat;
 		break;
 	case PCMDIR_REC:
 		d->reccount++;
@@ -1197,6 +1199,8 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
 		if (dir == PCMDIR_REC_VIRTUAL)
 			d->rvchancount++;
 		direction = PCMDIR_REC;
+		vchanrate = &d->rvchanrate;
+		vchanformat = &d->rvchanformat;
 		break;
 	default:
 		device_printf(d->dev,
@@ -1301,8 +1305,12 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
 
 	PCM_LOCK(d);
 	CHN_INSERT_SORT_ASCEND(d, c, channels.pcm);
-	if ((c->flags & CHN_F_VIRTUAL) == 0)
+	if ((c->flags & CHN_F_VIRTUAL) == 0) {
 		CHN_INSERT_SORT_ASCEND(d, c, channels.pcm.primary);
+		/* Initialize the *vchanrate/vchanformat parameters. */
+		*vchanrate = sndbuf_getspd(c->bufsoft);
+		*vchanformat = sndbuf_getfmt(c->bufsoft);
+	}
 
 	return (c);
 
diff --git a/sys/dev/sound/pcm/vchan.c b/sys/dev/sound/pcm/vchan.c
index 7064f1e51125..1f184f21807e 100644
--- a/sys/dev/sound/pcm/vchan.c
+++ b/sys/dev/sound/pcm/vchan.c
@@ -405,7 +405,6 @@ sysctl_dev_pcm_vchanrate(SYSCTL_HANDLER_ARGS)
 {
 	struct snddev_info *d;
 	struct pcm_channel *c, *ch;
-	struct pcmchan_caps *caps;
 	int *vchanrate, direction, ret, newspd, restart;
 
 	d = devclass_get_softc(pcm_devclass, VCHAN_SYSCTL_UNIT(oidp->oid_arg1));
@@ -467,13 +466,6 @@ sysctl_dev_pcm_vchanrate(SYSCTL_HANDLER_ARGS)
 			} else
 				restart = 0;
 
-			if (feeder_rate_round) {
-				caps = chn_getcaps(c);
-				RANGE(newspd, caps->minspeed, caps->maxspeed);
-				newspd = CHANNEL_SETSPEED(c->methods,
-				    c->devinfo, newspd);
-			}
-
 			ret = chn_reset(c, c->format, newspd);
 			if (ret == 0) {
 				if (restart != 0) {
@@ -488,7 +480,7 @@ sysctl_dev_pcm_vchanrate(SYSCTL_HANDLER_ARGS)
 				}
 			}
 		}
-		*vchanrate = c->speed;
+		*vchanrate = sndbuf_getspd(c->bufsoft);
 
 		CHN_UNLOCK(c);
 	}
@@ -583,7 +575,7 @@ sysctl_dev_pcm_vchanformat(SYSCTL_HANDLER_ARGS)
 				}
 			}
 		}
-		*vchanformat = c->format;
+		*vchanformat = sndbuf_getfmt(c->bufsoft);
 
 		CHN_UNLOCK(c);
 	}
@@ -607,11 +599,9 @@ vchan_create(struct pcm_channel *parent, struct pcm_channel **child)
 	struct pcm_channel *ch;
 	struct pcmchan_caps *parent_caps;
 	uint32_t vchanfmt, vchanspd;
-	int ret, direction, r;
-	bool save;
+	int ret, direction;
 
 	ret = 0;
-	save = false;
 	d = parent->parentsnddev;
 
 	PCM_BUSYASSERT(d);
@@ -659,75 +649,9 @@ vchan_create(struct pcm_channel *parent, struct pcm_channel **child)
 		goto fail;
 	}
 
-	if (vchanfmt == 0) {
-		const char *vfmt;
-
-		CHN_UNLOCK(parent);
-		r = resource_string_value(device_get_name(parent->dev),
-		    device_get_unit(parent->dev), VCHAN_FMT_HINT(direction),
-		    &vfmt);
-		CHN_LOCK(parent);
-		if (r != 0)
-			vfmt = NULL;
-		if (vfmt != NULL) {
-			vchanfmt = snd_str2afmt(vfmt);
-			if (vchanfmt != 0 && !(vchanfmt & AFMT_VCHAN))
-				vchanfmt = 0;
-		}
-		if (vchanfmt == 0)
-			vchanfmt = VCHAN_DEFAULT_FORMAT;
-		save = true;
-	}
-
-	if (vchanspd == 0) {
-		/*
-		 * This is very sad. Few soundcards advertised as being
-		 * able to do (insanely) higher/lower speed, but in
-		 * reality, they simply can't. At least, we give user chance
-		 * to set sane value via kernel hints or sysctl.
-		 */
-		CHN_UNLOCK(parent);
-		r = resource_int_value(device_get_name(parent->dev),
-		    device_get_unit(parent->dev), VCHAN_SPD_HINT(direction),
-		    &vchanspd);
-		CHN_LOCK(parent);
-		if (r != 0) {
-			/* No saved value, no hint, NOTHING. */
-			vchanspd = VCHAN_DEFAULT_RATE;
-			RANGE(vchanspd, parent_caps->minspeed,
-			    parent_caps->maxspeed);
-		}
-		save = true;
-	}
-
-	/*
-	 * Limit the speed between feeder_rate_min <-> feeder_rate_max.
-	 */
-	RANGE(vchanspd, feeder_rate_min, feeder_rate_max);
-
-	if (feeder_rate_round) {
-		RANGE(vchanspd, parent_caps->minspeed,
-		    parent_caps->maxspeed);
-		vchanspd = CHANNEL_SETSPEED(parent->methods,
-		    parent->devinfo, vchanspd);
-	}
-
 	if ((ret = chn_reset(parent, vchanfmt, vchanspd)) != 0)
 		goto fail;
 
-	if (save) {
-		/*
-		 * Save new value.
-		 */
-		if (direction == PCMDIR_PLAY_VIRTUAL) {
-			d->pvchanformat = parent->format;
-			d->pvchanrate = parent->speed;
-		} else {
-			d->rvchanformat = parent->format;
-			d->rvchanrate = parent->speed;
-		}
-	}
-
 	/*
 	 * If the parent channel supports digital format,
 	 * enable passthrough mode.