commit 5f4e95638a4240d096c78dd739bb2381fb0db381
parent 4a0eb57baa1b67bf889bf03df2570a42ce66ab97
Author: Christos Margiolis <christos@margiolis.net>
Date: Wed, 21 Jul 2021 01:14:55 +0300
sound(4): added hans' changes
Diffstat:
4 files changed, 200 insertions(+), 64 deletions(-)
diff --git a/diff/mixer_kern.diff b/diff/mixer_kern.diff
@@ -1,10 +1,43 @@
+commit 183292e718629ceaffd37e506b226c0f65ac0e43
+Author: Hans Petter Selasky <hselasky@FreeBSD.org>
+Date: Tue Jul 20 19:02:41 2021 +0200
+
+ Implement the SOUND_MIXER_WRITE_MUTE and SOUND_MIXER_READ_MUTE ioctl(9).
+
+ These two ioctls are not part of the current version of OSS and were
+ considered obsolete. However, their behaviour is not the same as their
+ old one, so this implementation is specific to FreeBSD.
+
+ Older OSS versions had the MUTE ioctls take and return an integer with
+ a value of 0 or 1, which meant that the _whole_ mixer is unmuted or
+ muted respectively. In my implementation, the ioctl takes and returns
+ a bitmask that tells us which devices are muted.
+
+ This allows us to (un)mute only the devices we want, instead of the
+ whole mixer. The bitmask works the same way as in DEVMASK, RECMASK and
+ RECSRC.
+
+ Integrated the hardware volume feature with the new mute system.
+
+ Submitted by: Christos Margiolis <christos@freebsd.org>
+ Differential Revision: https://reviews.freebsd.org/D31130
+ MFC after: 1 week
+ Sponsored by: NVIDIA Networking
+
diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c
-index 92c5f3d613e..b84396c0b8b 100644
+index 09b0bb8ab14..89e78b036e9 100644
--- a/sys/dev/sound/pcm/mixer.c
+++ b/sys/dev/sound/pcm/mixer.c
-@@ -58,9 +58,11 @@ struct snd_mixer {
+@@ -51,16 +51,16 @@ struct snd_mixer {
+ KOBJ_FIELDS;
+ void *devinfo;
+ int busy;
+- int hwvol_muted;
+ int hwvol_mixer;
+ int hwvol_step;
+ int type;
device_t dev;
- u_int32_t hwvol_mute_level;
+- u_int32_t hwvol_mute_level;
u_int32_t devs;
+ u_int32_t mutedevs;
u_int32_t recdevs;
@@ -14,7 +47,16 @@ index 92c5f3d613e..b84396c0b8b 100644
u_int8_t parent[32];
u_int32_t child[32];
u_int8_t realdev[32];
-@@ -254,7 +256,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
+@@ -244,7 +244,7 @@ mixer_set_eq(struct snd_mixer *m, struct snddev_info *d,
+ }
+
+ static int
+-mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
++mixer_set(struct snd_mixer *m, u_int dev, u_int32_t muted, u_int lev)
+ {
+ struct snddev_info *d;
+ u_int l, r, tl, tr;
+@@ -254,7 +254,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
(0 == (m->devs & (1 << dev))))
@@ -23,7 +65,7 @@ index 92c5f3d613e..b84396c0b8b 100644
l = min((lev & 0x00ff), 100);
r = min(((lev & 0xff00) >> 8), 100);
-@@ -262,7 +264,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
+@@ -262,7 +262,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
d = device_get_softc(m->dev);
if (d == NULL)
@@ -32,21 +74,19 @@ index 92c5f3d613e..b84396c0b8b 100644
/* It is safe to drop this mutex due to Giant. */
if (!(d->flags & SD_F_MPSAFE) && mtx_owned(m->lock) != 0)
-@@ -272,6 +274,13 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
-
- MIXER_SET_UNLOCK(m, dropmtx);
+@@ -270,6 +270,11 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
+ else
+ dropmtx = 0;
+ /* Allow the volume to be "changed" while muted. */
-+ if (m->mutedevs & (1 << dev)) {
++ if (muted & (1 << dev)) {
+ m->level_muted[dev] = l | (r << 8);
-+ MIXER_SET_LOCK(m, dropmtx);
+ return (0);
+ }
-+
+ MIXER_SET_UNLOCK(m, dropmtx);
+
/* TODO: recursive handling */
- parent = m->parent[dev];
- if (parent >= SOUND_MIXER_NRDEVICES)
-@@ -287,7 +296,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
+@@ -287,7 +292,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
else if (realdev != SOUND_MIXER_NONE &&
MIXER_SET(m, realdev, tl, tr) < 0) {
MIXER_SET_LOCK(m, dropmtx);
@@ -55,7 +95,7 @@ index 92c5f3d613e..b84396c0b8b 100644
}
} else if (child != 0) {
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-@@ -305,8 +314,8 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
+@@ -305,8 +310,8 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
realdev = m->realdev[dev];
if (realdev != SOUND_MIXER_NONE &&
MIXER_SET(m, realdev, l, r) < 0) {
@@ -66,7 +106,7 @@ index 92c5f3d613e..b84396c0b8b 100644
}
} else {
if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
-@@ -317,7 +326,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
+@@ -317,7 +322,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
else if (realdev != SOUND_MIXER_NONE &&
MIXER_SET(m, realdev, l, r) < 0) {
MIXER_SET_LOCK(m, dropmtx);
@@ -75,7 +115,7 @@ index 92c5f3d613e..b84396c0b8b 100644
}
}
-@@ -326,16 +335,66 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
+@@ -326,16 +331,42 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
m->level[dev] = l | (r << 8);
m->modify_counter++;
@@ -88,65 +128,42 @@ index 92c5f3d613e..b84396c0b8b 100644
{
- if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev)))
- return mixer->level[dev];
+- else
+- return -1;
+ if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) {
+ if (mixer->mutedevs & (1 << dev))
+ return (mixer->level_muted[dev]);
+ else
+ return (mixer->level[dev]);
-+ }
- else
-- return -1;
++ } else {
+ return (-1);
++ }
+}
+
-+static int
-+mixer_setmute(struct snd_mixer *mixer, u_int32_t mutedevs)
++void
++mix_setmutedevs(struct snd_mixer *mixer, u_int32_t mutedevs)
+{
-+ struct snddev_info *d;
-+ int dropmtx, i, ret = 0, v;
-+
-+ d = device_get_softc(mixer->dev);
-+ if (d == NULL)
-+ return (-1);
-+ if (!(d->flags & SD_F_MPSAFE) && mtx_owned(mixer->lock) != 0)
-+ dropmtx = 1;
-+ else
-+ dropmtx = 0;
-+
-+ /* FIXME: lock/unlock */
++ u_int32_t delta;
+
+ /* Filter out invalid values. */
+ mutedevs &= mixer->devs;
++ delta = (mixer->mutedevs ^ mutedevs) & mixer->devs;
++ mixer->mutedevs = mutedevs;
++
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-+ if (!(mixer->devs & (1 << i)))
++ if (!(delta & (1 << i)))
+ continue;
-+ if ((mutedevs & (1 << i)) && mixer->level[i] != 0) {
++ if (mutedevs & (1 << i)) {
+ mixer->level_muted[i] = mixer->level[i];
-+ v = 0;
-+ } else if (!(mutedevs & (1 << i)) && mixer->level[i] == 0) {
-+ /*
-+ * `mixer_set` checks if the device is muted and, if
-+ * yes, assigns the volume to `level_muted` and returns.
-+ * In case of an unmute, we'll first UNSET the mute bit
-+ * so that we bypass this check.
-+ *
-+ * This is probably a dirty hack, but assigning the
-+ * flags before the loop would cause the same effect,
-+ * this time when muting.
-+ */
-+ mixer->mutedevs &= ~(1 << i);
-+ v = mixer->level_muted[i];
-+ } else
-+ continue;
-+ ret += mixer_set(mixer, i, v);
++ mixer_set(mixer, i, 0, 0);
++ } else {
++ mixer_set(mixer, i, 0, mixer->level_muted[i]);
++ }
+ }
-+ mixer->mutedevs = mutedevs;
-+
-+ return (ret);
}
static int
-@@ -598,6 +657,12 @@ mix_getdevs(struct snd_mixer *m)
+@@ -598,6 +629,12 @@ mix_getdevs(struct snd_mixer *m)
return m->devs;
}
@@ -159,7 +176,101 @@ index 92c5f3d613e..b84396c0b8b 100644
u_int32_t
mix_getrecdevs(struct snd_mixer *m)
{
-@@ -1305,10 +1370,16 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
+@@ -721,7 +758,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
+ }
+ }
+
+- mixer_set(m, i, v | (v << 8));
++ mixer_set(m, i, 0, v | (v << 8));
+ }
+
+ mixer_setrecsrc(m, 0); /* Set default input. */
+@@ -799,7 +836,7 @@ mixer_uninit(device_t dev)
+ snd_mtxlock(m->lock);
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- mixer_set(m, i, 0);
++ mixer_set(m, i, 0, 0);
+
+ mixer_setrecsrc(m, SOUND_MASK_MIC);
+
+@@ -836,8 +873,12 @@ mixer_reinit(device_t dev)
+ return i;
+ }
+
+- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+- mixer_set(m, i, m->level[i]);
++ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
++ if (m->mutedevs & (1 << i))
++ mixer_set(m, i, 0, 0);
++ else
++ mixer_set(m, i, 0, m->level[i]);
++ }
+
+ mixer_setrecsrc(m, m->recsrc);
+ snd_mtxunlock(m->lock);
+@@ -863,10 +904,8 @@ sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
+ if (dev == -1) {
+ snd_mtxunlock(m->lock);
+ return EINVAL;
+- }
+- else if (dev != m->hwvol_mixer) {
++ } else {
+ m->hwvol_mixer = dev;
+- m->hwvol_muted = 0;
+ }
+ }
+ snd_mtxunlock(m->lock);
+@@ -897,14 +936,7 @@ mixer_hwvol_init(device_t dev)
+ void
+ mixer_hwvol_mute_locked(struct snd_mixer *m)
+ {
+- if (m->hwvol_muted) {
+- m->hwvol_muted = 0;
+- mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
+- } else {
+- m->hwvol_muted++;
+- m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
+- mixer_set(m, m->hwvol_mixer, 0);
+- }
++ mix_setmutedevs(m, m->mutedevs ^ (1 << m->hwvol_mixer));
+ }
+
+ void
+@@ -925,11 +957,8 @@ mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step)
+ {
+ int level, left, right;
+
+- if (m->hwvol_muted) {
+- m->hwvol_muted = 0;
+- level = m->hwvol_mute_level;
+- } else
+- level = mixer_get(m, m->hwvol_mixer);
++ level = mixer_get(m, m->hwvol_mixer);
++
+ if (level != -1) {
+ left = level & 0xff;
+ right = (level >> 8) & 0xff;
+@@ -943,7 +972,8 @@ mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step)
+ right = 0;
+ else if (right > 100)
+ right = 100;
+- mixer_set(m, m->hwvol_mixer, left | right << 8);
++
++ mixer_set(m, m->hwvol_mixer, m->mutedevs, left | right << 8);
+ }
+ }
+
+@@ -976,7 +1006,7 @@ mix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right)
+ KASSERT(m != NULL, ("NULL snd_mixer"));
+
+ snd_mtxlock(m->lock);
+- ret = mixer_set(m, dev, left | (right << 8));
++ ret = mixer_set(m, dev, m->mutedevs, left | (right << 8));
+ snd_mtxunlock(m->lock);
+
+ return ((ret != 0) ? ENXIO : 0);
+@@ -1304,10 +1334,18 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
goto done;
}
if ((cmd & ~0xff) == MIXER_WRITE(0)) {
@@ -168,17 +279,20 @@ index 92c5f3d613e..b84396c0b8b 100644
+ case SOUND_MIXER_RECSRC:
ret = mixer_setrecsrc(m, *arg_i);
- else
+- ret = mixer_set(m, j, *arg_i);
+ break;
+ case SOUND_MIXER_MUTE:
-+ ret = mixer_setmute(m, *arg_i);
++ mix_setmutedevs(m, *arg_i);
++ ret = 0;
+ break;
+ default:
- ret = mixer_set(m, j, *arg_i);
++ ret = mixer_set(m, j, m->mutedevs, *arg_i);
++ break;
+ }
snd_mtxunlock(m->lock);
return ((ret == 0) ? 0 : ENXIO);
}
-@@ -1319,6 +1390,9 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
+@@ -1318,6 +1356,9 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
case SOUND_MIXER_STEREODEVS:
v = mix_getdevs(m);
break;
@@ -188,15 +302,30 @@ index 92c5f3d613e..b84396c0b8b 100644
case SOUND_MIXER_RECMASK:
v = mix_getrecdevs(m);
break;
+@@ -1326,6 +1367,7 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
+ break;
+ default:
+ v = mixer_get(m, j);
++ break;
+ }
+ *arg_i = v;
+ snd_mtxunlock(m->lock);
+@@ -1554,5 +1596,5 @@ mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right)
+
+ level = (left & 0xFF) | ((right & 0xFF) << 8);
+
+- return (mixer_set(m, dev, level));
++ return (mixer_set(m, dev, m->mutedevs, level));
+ }
diff --git a/sys/dev/sound/pcm/mixer.h b/sys/dev/sound/pcm/mixer.h
-index 8e11d553a3e..626282c803e 100644
+index 8e11d553a3e..7857609b289 100644
--- a/sys/dev/sound/pcm/mixer.h
+++ b/sys/dev/sound/pcm/mixer.h
@@ -60,8 +60,10 @@ device_t mix_get_dev(struct snd_mixer *m);
void mix_setdevs(struct snd_mixer *m, u_int32_t v);
void mix_setrecdevs(struct snd_mixer *m, u_int32_t v);
-+//void mix_setmutedevs(struct snd_mixer *m, u_int32_t mutedevs);
++void mix_setmutedevs(struct snd_mixer *m, u_int32_t v);
u_int32_t mix_getdevs(struct snd_mixer *m);
u_int32_t mix_getrecdevs(struct snd_mixer *m);
+u_int32_t mix_getmutedevs(struct snd_mixer *m);
diff --git a/mixer_lib/mixer.h b/mixer_lib/mixer.h
@@ -55,7 +55,7 @@ struct mix_dev {
};
struct mixer {
- TAILQ_HEAD(head, mix_dev) devs;
+ TAILQ_HEAD(, mix_dev) devs;
struct mix_dev *dev;
oss_mixerinfo mi;
oss_card_info ci;
diff --git a/mixer_prog/mixer_prog.8 b/mixer_prog/mixer_prog.8
@@ -205,6 +205,12 @@ volume by 0.05:
.It $ mixer mic.volume=+0.10:-0.05
.El
.Pp
+Toggle the mute for
+.Ar vol :
+.Bl -tag -width Ds -offset indent
+.It $ mixer vol.mute=^
+.El
+.Pp
Set
.Ar mic
and toggle
diff --git a/mixer_prog/mixer_prog.c b/mixer_prog/mixer_prog.c
@@ -205,6 +205,7 @@ printall(struct mixer *m, int oflag)
}
}
+/* TODO: print play/rec */
static void
printminfo(struct mixer *m, int oflag)
{