* [PATCH 1/3] ALSA: usb-audio: Add error checks against get_min_max*()
2026-04-10 17:49 [PATCH 0/3] ALSA: usb-audio: Refactor mixer checks and add check for sticky mixers Rong Zhang
@ 2026-04-10 17:49 ` Rong Zhang
2026-04-10 17:49 ` [PATCH 2/3] ALSA: usb-audio: Move volume control resolution check into a function Rong Zhang
` (2 subsequent siblings)
3 siblings, 0 replies; 9+ messages in thread
From: Rong Zhang @ 2026-04-10 17:49 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: Icenowy Zheng, linux-sound, linux-kernel, Rong Zhang,
Takashi Iwai
All callers of get_min_max*() ignore the latter's return code
completely. This means to ignore temporary errors at the probe time.
However, it is not optimal and leads to some maintenance burdens.
Return -EAGAIN for temporary errors, and check against it in the callers
of get_min_max*(). If any other error occurs, bail out of the caller
early.
Suggested-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/87ldewi4j8.wl-tiwai@suse.de
Signed-off-by: Rong Zhang <i@rong.moe>
---
sound/usb/mixer.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index a25e8145af67..e5993364c825 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1264,7 +1264,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
"%d:%d: cannot get min/max values for control %d (id %d)\n",
cval->head.id, mixer_ctrl_intf(cval->head.mixer),
cval->control, cval->head.id);
- return -EINVAL;
+ return -EAGAIN;
}
if (get_ctl_value(cval, UAC_GET_RES,
(cval->control << 8) | minchn,
@@ -1388,6 +1388,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
+ int ret;
if (cval->val_type == USB_MIXER_BOOLEAN ||
cval->val_type == USB_MIXER_INV_BOOLEAN)
@@ -1398,8 +1399,9 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
if (cval->val_type != USB_MIXER_BOOLEAN &&
cval->val_type != USB_MIXER_INV_BOOLEAN) {
if (!cval->initialized) {
- get_min_max_with_quirks(cval, 0, kcontrol);
- if (cval->initialized && cval->dBmin >= cval->dBmax) {
+ ret = get_min_max_with_quirks(cval, 0, kcontrol);
+ if ((ret >= 0 || ret == -EAGAIN) &&
+ cval->initialized && cval->dBmin >= cval->dBmax) {
kcontrol->vd[0].access &=
~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
@@ -1743,6 +1745,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer,
struct snd_kcontrol *kctl;
struct usb_mixer_elem_info *cval;
const struct usbmix_name_map *map;
+ int ret;
if (control == UAC_FU_GRAPHIC_EQUALIZER) {
/* FIXME: not supported yet */
@@ -1856,10 +1859,10 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer,
}
/* get min/max values */
- get_min_max_with_quirks(cval, 0, kctl);
+ ret = get_min_max_with_quirks(cval, 0, kctl);
/* skip a bogus volume range */
- if (cval->max <= cval->min) {
+ if ((ret < 0 && ret != -EAGAIN) || cval->max <= cval->min) {
usb_audio_dbg(mixer->chip,
"[%d] FU [%s] skipped due to invalid volume\n",
cval->head.id, kctl->id.name);
@@ -2233,6 +2236,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
unsigned int i, len;
struct snd_kcontrol *kctl;
const struct usbmix_name_map *map;
+ int ret;
map = find_map(state->map, unitid, 0);
if (check_ignored_ctl(map))
@@ -2255,7 +2259,11 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
}
/* get min/max values */
- get_min_max(cval, 0);
+ ret = get_min_max(cval, 0);
+ if (ret < 0 && ret != -EAGAIN) {
+ usb_mixer_elem_info_free(cval);
+ return;
+ }
kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
if (!kctl) {
@@ -2627,7 +2635,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
break;
}
- get_min_max(cval, valinfo->min_value);
+ err = get_min_max(cval, valinfo->min_value);
break;
}
case USB_XU_CLOCK_RATE:
@@ -2639,11 +2647,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
cval->max = 5;
cval->res = 1;
cval->initialized = 1;
+ err = 0;
break;
default:
- get_min_max(cval, valinfo->min_value);
+ err = get_min_max(cval, valinfo->min_value);
break;
}
+ if (err < 0 && err != -EAGAIN) {
+ usb_mixer_elem_info_free(cval);
+ return err;
+ }
err = get_cur_ctl_value(cval, cval->control << 8, &val);
if (err < 0) {
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 2/3] ALSA: usb-audio: Move volume control resolution check into a function
2026-04-10 17:49 [PATCH 0/3] ALSA: usb-audio: Refactor mixer checks and add check for sticky mixers Rong Zhang
2026-04-10 17:49 ` [PATCH 1/3] ALSA: usb-audio: Add error checks against get_min_max*() Rong Zhang
@ 2026-04-10 17:49 ` Rong Zhang
2026-04-10 17:49 ` [PATCH 3/3] ALSA: usb-audio: Do not expose sticky mixers Rong Zhang
2026-04-11 8:03 ` [PATCH 0/3] ALSA: usb-audio: Refactor mixer checks and add check for " Takashi Iwai
3 siblings, 0 replies; 9+ messages in thread
From: Rong Zhang @ 2026-04-10 17:49 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: Icenowy Zheng, linux-sound, linux-kernel, Rong Zhang,
Takashi Iwai
get_min_max_with_quirks() is too lengthy and hard to read.
Move the volume control resolution check code into a function as it's
relatively self-contained.
Suggested-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/87o6jsk3vs.wl-tiwai@suse.de
Signed-off-by: Rong Zhang <i@rong.moe>
---
sound/usb/mixer.c | 65 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 39 insertions(+), 26 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index e5993364c825..e77c2d78a782 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1232,6 +1232,38 @@ static void init_cur_mix_raw(struct usb_mixer_elem_info *cval, int ch, int idx)
snd_usb_set_cur_mix_value(cval, ch, idx, cval->min);
}
+/*
+ * Additional checks for the proper resolution
+ *
+ * Some devices report smaller resolutions than actually reacting.
+ * They don't return errors but simply clip to the lower aligned value.
+ */
+static void check_volume_control_res(struct usb_mixer_elem_info *cval,
+ int channel, int saved)
+{
+ int last_valid_res = cval->res;
+ int test, check;
+
+ for (;;) {
+ test = saved;
+ if (test < cval->max)
+ test += cval->res;
+ else
+ test -= cval->res;
+
+ if (test < cval->min || test > cval->max ||
+ snd_usb_set_cur_mix_value(cval, channel, 0, test) ||
+ get_cur_mix_raw(cval, channel, &check)) {
+ cval->res = last_valid_res;
+ break;
+ }
+ if (test == check)
+ break;
+
+ cval->res *= 2;
+ }
+}
+
/*
* retrieve the minimum and maximum values for the specified control
*/
@@ -1287,37 +1319,18 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
if (cval->res == 0)
cval->res = 1;
- /* Additional checks for the proper resolution
- *
- * Some devices report smaller resolutions than actually
- * reacting. They don't return errors but simply clip
- * to the lower aligned value.
- */
if (cval->min + cval->res < cval->max) {
- int last_valid_res = cval->res;
- int saved, test, check;
+ int saved;
+
if (get_cur_mix_raw(cval, minchn, &saved) < 0)
- goto no_res_check;
- for (;;) {
- test = saved;
- if (test < cval->max)
- test += cval->res;
- else
- test -= cval->res;
- if (test < cval->min || test > cval->max ||
- snd_usb_set_cur_mix_value(cval, minchn, 0, test) ||
- get_cur_mix_raw(cval, minchn, &check)) {
- cval->res = last_valid_res;
- break;
- }
- if (test == check)
- break;
- cval->res *= 2;
- }
+ goto no_checks;
+
+ check_volume_control_res(cval, minchn, saved);
+
snd_usb_set_cur_mix_value(cval, minchn, 0, saved);
}
-no_res_check:
+no_checks:
cval->initialized = 1;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 3/3] ALSA: usb-audio: Do not expose sticky mixers
2026-04-10 17:49 [PATCH 0/3] ALSA: usb-audio: Refactor mixer checks and add check for sticky mixers Rong Zhang
2026-04-10 17:49 ` [PATCH 1/3] ALSA: usb-audio: Add error checks against get_min_max*() Rong Zhang
2026-04-10 17:49 ` [PATCH 2/3] ALSA: usb-audio: Move volume control resolution check into a function Rong Zhang
@ 2026-04-10 17:49 ` Rong Zhang
2026-08-04 21:55 ` Michal Pecio
2026-04-11 8:03 ` [PATCH 0/3] ALSA: usb-audio: Refactor mixer checks and add check for " Takashi Iwai
3 siblings, 1 reply; 9+ messages in thread
From: Rong Zhang @ 2026-04-10 17:49 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: Icenowy Zheng, linux-sound, linux-kernel, Rong Zhang
Some devices' mixers are sticky, which accept SET_CUR but do absolutely
nothing. Registering these mixers confuses userspace and results in
ineffective volume control.
Check if a mixer is sticky by setting the volume to the maximum or
minimum value and checking for effectiveness afterward. Prevent the
mixer from being registered if it turns out to be sticky.
Quirky device sample:
usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 7-1: Product: Feaulle Rainbow
usb 7-1: Manufacturer: Generic
usb 7-1: SerialNumber: 20210726905926
(Mic Capture Volume)
Signed-off-by: Rong Zhang <i@rong.moe>
---
sound/usb/mixer.c | 48 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 45 insertions(+), 3 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index e77c2d78a782..d4ef45bf53d7 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1232,6 +1232,41 @@ static void init_cur_mix_raw(struct usb_mixer_elem_info *cval, int ch, int idx)
snd_usb_set_cur_mix_value(cval, ch, idx, cval->min);
}
+/*
+ * Additional checks for sticky mixers
+ *
+ * Some devices' volume control mixers are sticky, which accept SET_CUR but
+ * do absolutely nothing.
+ *
+ * Prevent sticky mixers from being registered, otherwise they confuses
+ * userspace and results in ineffective volume control.
+ */
+static int check_sticky_volume_control(struct usb_mixer_elem_info *cval,
+ int channel, int saved)
+{
+ int sticky_test_values[] = { cval->min, cval->max };
+ int test, check, i;
+
+ for (i = 0; i < ARRAY_SIZE(sticky_test_values); i++) {
+ test = sticky_test_values[i];
+ if (test == saved)
+ continue;
+
+ /* Assume non-sticky on failure. */
+ if (snd_usb_set_cur_mix_value(cval, channel, 0, test) ||
+ get_cur_mix_raw(cval, channel, &check) ||
+ check != saved) /* SET_CUR effective, non-sticky. */
+ return 0;
+ }
+
+ usb_audio_err(cval->head.mixer->chip,
+ "%d:%d: sticky mixer values (%d/%d/%d => %d), disabling\n",
+ cval->head.id, mixer_ctrl_intf(cval->head.mixer),
+ cval->min, cval->max, cval->res, saved);
+
+ return -ENODEV;
+}
+
/*
* Additional checks for the proper resolution
*
@@ -1270,7 +1305,7 @@ static void check_volume_control_res(struct usb_mixer_elem_info *cval,
static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
int default_min, struct snd_kcontrol *kctl)
{
- int i, idx;
+ int i, idx, ret;
/* for failsafe */
cval->min = default_min;
@@ -1319,13 +1354,20 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
if (cval->res == 0)
cval->res = 1;
- if (cval->min + cval->res < cval->max) {
+ if (cval->min < cval->max) {
int saved;
if (get_cur_mix_raw(cval, minchn, &saved) < 0)
goto no_checks;
- check_volume_control_res(cval, minchn, saved);
+ ret = check_sticky_volume_control(cval, minchn, saved);
+ if (ret < 0) {
+ snd_usb_set_cur_mix_value(cval, minchn, 0, saved);
+ return ret;
+ }
+
+ if (cval->min + cval->res < cval->max)
+ check_volume_control_res(cval, minchn, saved);
snd_usb_set_cur_mix_value(cval, minchn, 0, saved);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 3/3] ALSA: usb-audio: Do not expose sticky mixers
2026-04-10 17:49 ` [PATCH 3/3] ALSA: usb-audio: Do not expose sticky mixers Rong Zhang
@ 2026-08-04 21:55 ` Michal Pecio
2026-08-05 14:32 ` Rong Zhang
0 siblings, 1 reply; 9+ messages in thread
From: Michal Pecio @ 2026-08-04 21:55 UTC (permalink / raw)
To: Rong Zhang
Cc: Jaroslav Kysela, Takashi Iwai, Icenowy Zheng, linux-sound,
linux-kernel
On Sat, 11 Apr 2026 01:49:04 +0800, Rong Zhang wrote:
> Some devices' mixers are sticky, which accept SET_CUR but do absolutely
> nothing. Registering these mixers confuses userspace and results in
> ineffective volume control.
>
> Check if a mixer is sticky by setting the volume to the maximum or
> minimum value and checking for effectiveness afterward. Prevent the
> mixer from being registered if it turns out to be sticky.
>
> Quirky device sample:
>
> usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> usb 7-1: Product: Feaulle Rainbow
> usb 7-1: Manufacturer: Generic
> usb 7-1: SerialNumber: 20210726905926
> (Mic Capture Volume)
>
> Signed-off-by: Rong Zhang <i@rong.moe>
This appears to break (yet another) device, as reported below.
Not 100% sure because both affected users ran away to -lts and
appear to be of the "won't compile kernel patches" variety.
https://bbs.archlinux.org/viewtopic.php?id=314220
My $.02 - was there no way to deal with this in userspace,
or to make it opt-in rather than opt-out?
Regards,
Michal
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] ALSA: usb-audio: Do not expose sticky mixers
2026-08-04 21:55 ` Michal Pecio
@ 2026-08-05 14:32 ` Rong Zhang
2026-08-05 15:32 ` Takashi Iwai
0 siblings, 1 reply; 9+ messages in thread
From: Rong Zhang @ 2026-08-05 14:32 UTC (permalink / raw)
To: Michal Pecio
Cc: Jaroslav Kysela, Takashi Iwai, Icenowy Zheng, linux-sound,
linux-kernel
Hi Michal,
Thanks for the report.
On Tue, 2026-08-04 at 23:55 +0200, Michal Pecio wrote:
> On Sat, 11 Apr 2026 01:49:04 +0800, Rong Zhang wrote:
> > Some devices' mixers are sticky, which accept SET_CUR but do absolutely
> > nothing. Registering these mixers confuses userspace and results in
> > ineffective volume control.
> >
> > Check if a mixer is sticky by setting the volume to the maximum or
> > minimum value and checking for effectiveness afterward. Prevent the
> > mixer from being registered if it turns out to be sticky.
> >
> > Quirky device sample:
> >
> > usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> > usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> > usb 7-1: Product: Feaulle Rainbow
> > usb 7-1: Manufacturer: Generic
> > usb 7-1: SerialNumber: 20210726905926
> > (Mic Capture Volume)
> >
> > Signed-off-by: Rong Zhang <i@rong.moe>
>
> This appears to break (yet another) device, as reported below.
> Not 100% sure because both affected users ran away to -lts and
> appear to be of the "won't compile kernel patches" variety.
>
> https://bbs.archlinux.org/viewtopic.php?id=314220
Let me quote some words below:
> After updating, my headset output was halved (or so) despite the same mixer levels and sounds weird/bassy/distorted during fading audio. Previously my volume was set to 25%, but now i need 40-50% for the same volume, and the quality seems worse.
>
The new 100% still maps to the original 100% as the sticky check sets the
mixer value to max before bailing out. IOW, it won't result in always-
halved physical volume.
If the dB reporting is correct, both a hardware mixer and a soft mixer
should map to similar physical volume on the same device. That is, volume
other than 100% behaving differently usually implies broken dB reporting.
So the difference in volume mapping isn't really an issue caused by soft
mixer. Instead, it exposes yet another device quirk.
Distortion at low volume is a side effect of soft mixers on some devices.
Usually it's hardly audible. I guess the SteelSeries Arctis Nova 5 uses a
poorly-performed lossy 2.4GHz codec, making the distortion worse.
>
> [...]
>
> Broken kernel output:
>
> Jul 09 17:06:05 <HOSTNAME> kernel: usb 3-1: Product: SteelSeries Arctis Nova 5
> Jul 09 17:06:05 <HOSTNAME> kernel: usb 3-1: Manufacturer: SteelSeries
> Jul 09 17:06:05 <HOSTNAME> kernel: hid-generic 0003:1038:2232.0008: hiddev99,hidraw7: USB HID v1.11 Device [SteelSeries SteelSeries Arctis Nova 5] on usb-0000:13:00.3-1/input3
> Jul 09 17:06:05 <HOSTNAME> kernel: input: SteelSeries SteelSeries Arctis Nova 5 as /devices/pci0000:00/0000:00:08.1/0000:13:00.3/usb3/3-1/3-1:1.4/0003:1038:2232.0009/input/input12
> Jul 09 17:06:06 <HOSTNAME> kernel: hid-generic 0003:1038:2232.0009: input,hidraw8: USB HID v1.11 Device [SteelSeries SteelSeries Arctis Nova 5] on usb-0000:13:00.3-1/input4
> Jul 09 17:06:06 <HOSTNAME> kernel: hid-generic 0003:1038:2232.000A: hiddev100,hidraw9: USB HID v1.11 Device [SteelSeries SteelSeries Arctis Nova 5] on usb-0000:13:00.3-1/input5
> Jul 09 17:06:07 <HOSTNAME> kernel: usb 3-1: 9:0: sticky mixer values (-19712/0/256 => 0), disabling
> Jul 09 17:06:07 <HOSTNAME> kernel: usb 3-1: 10:0: sticky mixer values (-21248/0/256 => 0), disabling
With the kmsg dump, as well as the user confirming that the UAC mixer
responds to SET_CUR, I can confirm the device has broken GET_CUR mixers
instead of sticky ones.
I will submit a patch to add QUIRK_FLAG_MIXER_GET_CUR_BROKEN for the
device, so that the UAC mixer can be reenabled.
>
> My $.02 - was there no way to deal with this in userspace,
> or to make it opt-in rather than opt-out?
While userspace can ignore hardware mixers via some configurations, the
current opt-out model is really about:
When we can't distinguish between both, will the extra advantages of
exposing a broken GET_CUR mixer outweigh the disadvantages of exposing
a sticky one?
My answer is no.
A sticky hardware mixer breaks volume control completely. If a user
doesn't know how to tell the audio stack to ignore it, it will be a
terrible out-of-box experience.
In contrast, exposing a broken GET_CUR mixer is more like an optimization
for slightly better volume control quality (if the mixer is otherwise
implemented properly) compared to a soft mixer.
Other than the unfortunate combination with lossy codecs, usually the
distortion caused by a soft mixer is only audible on a device with high
gain, but such a device should also come with a gain control knob anyway
-- the user really should use the knob to tune the volume.
Thanks,
Rong
>
> Regards,
> Michal
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] ALSA: usb-audio: Do not expose sticky mixers
2026-08-05 14:32 ` Rong Zhang
@ 2026-08-05 15:32 ` Takashi Iwai
2026-08-05 16:52 ` Rong Zhang
0 siblings, 1 reply; 9+ messages in thread
From: Takashi Iwai @ 2026-08-05 15:32 UTC (permalink / raw)
To: Rong Zhang
Cc: Michal Pecio, Jaroslav Kysela, Takashi Iwai, Icenowy Zheng,
linux-sound, linux-kernel
On Wed, 05 Aug 2026 16:32:00 +0200,
Rong Zhang wrote:
>
> Hi Michal,
>
> Thanks for the report.
>
> On Tue, 2026-08-04 at 23:55 +0200, Michal Pecio wrote:
> > On Sat, 11 Apr 2026 01:49:04 +0800, Rong Zhang wrote:
> > > Some devices' mixers are sticky, which accept SET_CUR but do absolutely
> > > nothing. Registering these mixers confuses userspace and results in
> > > ineffective volume control.
> > >
> > > Check if a mixer is sticky by setting the volume to the maximum or
> > > minimum value and checking for effectiveness afterward. Prevent the
> > > mixer from being registered if it turns out to be sticky.
> > >
> > > Quirky device sample:
> > >
> > > usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> > > usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> > > usb 7-1: Product: Feaulle Rainbow
> > > usb 7-1: Manufacturer: Generic
> > > usb 7-1: SerialNumber: 20210726905926
> > > (Mic Capture Volume)
> > >
> > > Signed-off-by: Rong Zhang <i@rong.moe>
> >
> > This appears to break (yet another) device, as reported below.
> > Not 100% sure because both affected users ran away to -lts and
> > appear to be of the "won't compile kernel patches" variety.
> >
> > https://bbs.archlinux.org/viewtopic.php?id=314220
>
> Let me quote some words below:
>
> > After updating, my headset output was halved (or so) despite the same mixer levels and sounds weird/bassy/distorted during fading audio. Previously my volume was set to 25%, but now i need 40-50% for the same volume, and the quality seems worse.
> >
>
> The new 100% still maps to the original 100% as the sticky check sets the
> mixer value to max before bailing out. IOW, it won't result in always-
> halved physical volume.
>
> If the dB reporting is correct, both a hardware mixer and a soft mixer
> should map to similar physical volume on the same device. That is, volume
> other than 100% behaving differently usually implies broken dB reporting.
> So the difference in volume mapping isn't really an issue caused by soft
> mixer. Instead, it exposes yet another device quirk.
>
> Distortion at low volume is a side effect of soft mixers on some devices.
> Usually it's hardly audible. I guess the SteelSeries Arctis Nova 5 uses a
> poorly-performed lossy 2.4GHz codec, making the distortion worse.
>
> >
> > [...]
> >
> > Broken kernel output:
> >
> > Jul 09 17:06:05 <HOSTNAME> kernel: usb 3-1: Product: SteelSeries Arctis Nova 5
> > Jul 09 17:06:05 <HOSTNAME> kernel: usb 3-1: Manufacturer: SteelSeries
> > Jul 09 17:06:05 <HOSTNAME> kernel: hid-generic 0003:1038:2232.0008: hiddev99,hidraw7: USB HID v1.11 Device [SteelSeries SteelSeries Arctis Nova 5] on usb-0000:13:00.3-1/input3
> > Jul 09 17:06:05 <HOSTNAME> kernel: input: SteelSeries SteelSeries Arctis Nova 5 as /devices/pci0000:00/0000:00:08.1/0000:13:00.3/usb3/3-1/3-1:1.4/0003:1038:2232.0009/input/input12
> > Jul 09 17:06:06 <HOSTNAME> kernel: hid-generic 0003:1038:2232.0009: input,hidraw8: USB HID v1.11 Device [SteelSeries SteelSeries Arctis Nova 5] on usb-0000:13:00.3-1/input4
> > Jul 09 17:06:06 <HOSTNAME> kernel: hid-generic 0003:1038:2232.000A: hiddev100,hidraw9: USB HID v1.11 Device [SteelSeries SteelSeries Arctis Nova 5] on usb-0000:13:00.3-1/input5
> > Jul 09 17:06:07 <HOSTNAME> kernel: usb 3-1: 9:0: sticky mixer values (-19712/0/256 => 0), disabling
> > Jul 09 17:06:07 <HOSTNAME> kernel: usb 3-1: 10:0: sticky mixer values (-21248/0/256 => 0), disabling
>
> With the kmsg dump, as well as the user confirming that the UAC mixer
> responds to SET_CUR, I can confirm the device has broken GET_CUR mixers
> instead of sticky ones.
>
> I will submit a patch to add QUIRK_FLAG_MIXER_GET_CUR_BROKEN for the
> device, so that the UAC mixer can be reenabled.
>
> >
> > My $.02 - was there no way to deal with this in userspace,
> > or to make it opt-in rather than opt-out?
>
> While userspace can ignore hardware mixers via some configurations, the
> current opt-out model is really about:
>
> When we can't distinguish between both, will the extra advantages of
> exposing a broken GET_CUR mixer outweigh the disadvantages of exposing
> a sticky one?
>
> My answer is no.
>
> A sticky hardware mixer breaks volume control completely. If a user
> doesn't know how to tell the audio stack to ignore it, it will be a
> terrible out-of-box experience.
>
> In contrast, exposing a broken GET_CUR mixer is more like an optimization
> for slightly better volume control quality (if the mixer is otherwise
> implemented properly) compared to a soft mixer.
>
> Other than the unfortunate combination with lossy codecs, usually the
> distortion caused by a soft mixer is only audible on a device with high
> gain, but such a device should also come with a gain control knob anyway
> -- the user really should use the knob to tune the volume.
>
> Thanks,
> Rong
Well, this is getting more troublesome than expected, as it seems;
there have been a few more bug reports, too (I forgot places), and I'm
afraid that the tendency will remain.
My impression is that Windows drivers don't care about the GET_CUR, so
often the device firmware doesn't treat it at all. If that's the
case, it'd be also fine just to take the given mixer value as-is.
OTOH, if we want to be more strict, keeping the high default is also
logical -- which is our current behavior. That is, there is no
perfect answer to this, and it purely depends on our decision.
At least, for 7.3 kernel, I'll keep the current code and take
BROKEN_GET_CUR quirks for the reported devices. But if the reports
keeping flooding, we'd have to reconsider. Let's see.
thanks,
Takashi
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] ALSA: usb-audio: Do not expose sticky mixers
2026-08-05 15:32 ` Takashi Iwai
@ 2026-08-05 16:52 ` Rong Zhang
0 siblings, 0 replies; 9+ messages in thread
From: Rong Zhang @ 2026-08-05 16:52 UTC (permalink / raw)
To: Takashi Iwai
Cc: Michal Pecio, Jaroslav Kysela, Takashi Iwai, Icenowy Zheng,
linux-sound, linux-kernel
Hi Takashi,
Thanks for your opinion.
On Wed, 2026-08-05 at 17:32 +0200, Takashi Iwai wrote:
> On Wed, 05 Aug 2026 16:32:00 +0200,
> Rong Zhang wrote:
> >
> > Hi Michal,
> >
> > Thanks for the report.
> >
> > On Tue, 2026-08-04 at 23:55 +0200, Michal Pecio wrote:
> > > On Sat, 11 Apr 2026 01:49:04 +0800, Rong Zhang wrote:
> > > > Some devices' mixers are sticky, which accept SET_CUR but do absolutely
> > > > nothing. Registering these mixers confuses userspace and results in
> > > > ineffective volume control.
> > > >
> > > > Check if a mixer is sticky by setting the volume to the maximum or
> > > > minimum value and checking for effectiveness afterward. Prevent the
> > > > mixer from being registered if it turns out to be sticky.
> > > >
> > > > Quirky device sample:
> > > >
> > > > usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> > > > usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> > > > usb 7-1: Product: Feaulle Rainbow
> > > > usb 7-1: Manufacturer: Generic
> > > > usb 7-1: SerialNumber: 20210726905926
> > > > (Mic Capture Volume)
> > > >
> > > > Signed-off-by: Rong Zhang <i@rong.moe>
> > >
> > > This appears to break (yet another) device, as reported below.
> > > Not 100% sure because both affected users ran away to -lts and
> > > appear to be of the "won't compile kernel patches" variety.
> > >
> > > https://bbs.archlinux.org/viewtopic.php?id=314220
> >
> > Let me quote some words below:
> >
> > > After updating, my headset output was halved (or so) despite the same mixer levels and sounds weird/bassy/distorted during fading audio. Previously my volume was set to 25%, but now i need 40-50% for the same volume, and the quality seems worse.
> > >
> >
> > The new 100% still maps to the original 100% as the sticky check sets the
> > mixer value to max before bailing out. IOW, it won't result in always-
> > halved physical volume.
> >
> > If the dB reporting is correct, both a hardware mixer and a soft mixer
> > should map to similar physical volume on the same device. That is, volume
> > other than 100% behaving differently usually implies broken dB reporting.
> > So the difference in volume mapping isn't really an issue caused by soft
> > mixer. Instead, it exposes yet another device quirk.
> >
> > Distortion at low volume is a side effect of soft mixers on some devices.
> > Usually it's hardly audible. I guess the SteelSeries Arctis Nova 5 uses a
> > poorly-performed lossy 2.4GHz codec, making the distortion worse.
> >
> > >
> > > [...]
> > >
> > > Broken kernel output:
> > >
> > > Jul 09 17:06:05 <HOSTNAME> kernel: usb 3-1: Product: SteelSeries Arctis Nova 5
> > > Jul 09 17:06:05 <HOSTNAME> kernel: usb 3-1: Manufacturer: SteelSeries
> > > Jul 09 17:06:05 <HOSTNAME> kernel: hid-generic 0003:1038:2232.0008: hiddev99,hidraw7: USB HID v1.11 Device [SteelSeries SteelSeries Arctis Nova 5] on usb-0000:13:00.3-1/input3
> > > Jul 09 17:06:05 <HOSTNAME> kernel: input: SteelSeries SteelSeries Arctis Nova 5 as /devices/pci0000:00/0000:00:08.1/0000:13:00.3/usb3/3-1/3-1:1.4/0003:1038:2232.0009/input/input12
> > > Jul 09 17:06:06 <HOSTNAME> kernel: hid-generic 0003:1038:2232.0009: input,hidraw8: USB HID v1.11 Device [SteelSeries SteelSeries Arctis Nova 5] on usb-0000:13:00.3-1/input4
> > > Jul 09 17:06:06 <HOSTNAME> kernel: hid-generic 0003:1038:2232.000A: hiddev100,hidraw9: USB HID v1.11 Device [SteelSeries SteelSeries Arctis Nova 5] on usb-0000:13:00.3-1/input5
> > > Jul 09 17:06:07 <HOSTNAME> kernel: usb 3-1: 9:0: sticky mixer values (-19712/0/256 => 0), disabling
> > > Jul 09 17:06:07 <HOSTNAME> kernel: usb 3-1: 10:0: sticky mixer values (-21248/0/256 => 0), disabling
> >
> > With the kmsg dump, as well as the user confirming that the UAC mixer
> > responds to SET_CUR, I can confirm the device has broken GET_CUR mixers
> > instead of sticky ones.
> >
> > I will submit a patch to add QUIRK_FLAG_MIXER_GET_CUR_BROKEN for the
> > device, so that the UAC mixer can be reenabled.
> >
> > >
> > > My $.02 - was there no way to deal with this in userspace,
> > > or to make it opt-in rather than opt-out?
> >
> > While userspace can ignore hardware mixers via some configurations, the
> > current opt-out model is really about:
> >
> > When we can't distinguish between both, will the extra advantages of
> > exposing a broken GET_CUR mixer outweigh the disadvantages of exposing
> > a sticky one?
> >
> > My answer is no.
> >
> > A sticky hardware mixer breaks volume control completely. If a user
> > doesn't know how to tell the audio stack to ignore it, it will be a
> > terrible out-of-box experience.
> >
> > In contrast, exposing a broken GET_CUR mixer is more like an optimization
> > for slightly better volume control quality (if the mixer is otherwise
> > implemented properly) compared to a soft mixer.
> >
> > Other than the unfortunate combination with lossy codecs, usually the
> > distortion caused by a soft mixer is only audible on a device with high
> > gain, but such a device should also come with a gain control knob anyway
> > -- the user really should use the knob to tune the volume.
> >
> > Thanks,
> > Rong
>
> Well, this is getting more troublesome than expected, as it seems;
> there have been a few more bug reports, too (I forgot places), and I'm
> afraid that the tendency will remain.
>
> My impression is that Windows drivers don't care about the GET_CUR, so
> often the device firmware doesn't treat it at all. If that's the
> case, it'd be also fine just to take the given mixer value as-is.
> OTOH, if we want to be more strict, keeping the high default is also
> logical -- which is our current behavior. That is, there is no
> perfect answer to this, and it purely depends on our decision.
My decision was based on a frequent phenomenon that many PipeWire users
mistakenly select the "Digital Stereo (IEC958)" profile instead of the
"Analog Stereo" one when the UAC device really produces analog output,
simply because they have a wrong belief that "digital is better than
analog." Selecting the former bypasses hardware mixers in the hardware
and forces the use of soft mixer. If their ears can't tell the difference
between the two profile, keeping the high default and falling back
userspace soft mixer is probably a fair choice for broken GET_CUR mixers
without prior knowledge.
>
> At least, for 7.3 kernel, I'll keep the current code and take
> BROKEN_GET_CUR quirks for the reported devices. But if the reports
> keeping flooding, we'd have to reconsider. Let's see.
Agreed. If it eventually turns out to be a rabbit hole, converting the
check failure action into a pure warning might be a better choice.
Thanks,
Rong
>
>
> thanks,
>
> Takashi
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/3] ALSA: usb-audio: Refactor mixer checks and add check for sticky mixers
2026-04-10 17:49 [PATCH 0/3] ALSA: usb-audio: Refactor mixer checks and add check for sticky mixers Rong Zhang
` (2 preceding siblings ...)
2026-04-10 17:49 ` [PATCH 3/3] ALSA: usb-audio: Do not expose sticky mixers Rong Zhang
@ 2026-04-11 8:03 ` Takashi Iwai
3 siblings, 0 replies; 9+ messages in thread
From: Takashi Iwai @ 2026-04-11 8:03 UTC (permalink / raw)
To: Rong Zhang
Cc: Jaroslav Kysela, Takashi Iwai, Icenowy Zheng, linux-sound,
linux-kernel, Takashi Iwai
On Fri, 10 Apr 2026 19:49:01 +0200,
Rong Zhang wrote:
>
> All callers of get_min_max*() ignore the latter's return code
> completely. This means to ignore temporary errors at the probe time.
> However, it is not optimal and leads to some maintenance burdens.
> Besides, get_min_max_with_quirks() is too lengthy and hard to read.
>
> Some devices' mixers are sticky, which accept SET_CUR but do absolutely
> nothing. Registering these mixers confuses userspace and results in
> ineffective volume control.
>
> Patch 1 makes get_min_max*() return -EAGAIN for temporary errors, and
> check against it in the callers of get_min_max*(). If any other error
> occurs, bail out of the caller early.
>
> Patch 2 moves the volume control resolution check code into a function
> as it's relatively self-contained.
>
> Patch 3 checks if a mixer is sticky by setting the volume to the maximum
> or minimum value and checking for effectiveness afterward, and prevents
> the mixer from being registered if it turns out to be sticky.
>
> Quirky device sample:
>
> usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> usb 7-1: Product: Feaulle Rainbow
> usb 7-1: Manufacturer: Generic
> usb 7-1: SerialNumber: 20210726905926
> (Mic Capture Volume)
>
> This series is separated from https://lore.kernel.org/r/20260409-feaulle-rainbow-v1-2-09179e09000d@rong.moe
>
> Signed-off-by: Rong Zhang <i@rong.moe>
> ---
> Rong Zhang (3):
> ALSA: usb-audio: Add error checks against get_min_max*()
> ALSA: usb-audio: Move volume control resolution check into a function
> ALSA: usb-audio: Do not expose sticky mixers
Applied all three patches now. Thanks.
Takashi
^ permalink raw reply [flat|nested] 9+ messages in thread