* [PATCH v2 0/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN for Sennheiser MOMENTUM 3
@ 2026-05-27 18:56 Rong Zhang
2026-05-27 18:56 ` [PATCH v2 1/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN Rong Zhang
2026-05-27 18:56 ` [PATCH v2 2/2] ALSA: usb-audio: Add quirk flag for Sennheiser MOMENTUM 3 Rong Zhang
0 siblings, 2 replies; 4+ messages in thread
From: Rong Zhang @ 2026-05-27 18:56 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai, Jonathan Corbet, Shuah Khan
Cc: Rong Zhang, linux-sound, linux-doc, linux-kernel
Since commit 86aa1ea1f15c ("ALSA: usb-audio: Do not expose sticky
mixers"), the UAC mixer core utilizes volume SET_CUR and GET_CUR to
identify devices with sticky mixers. Unfortunately, even though most
devices with sticky GET_CUR also have corresponding sticky SET_CUR,
which I actually met more since the commit had been merged, there is
also a rare case that some devices may have volume mixers that responds
to SET_CUR properly but with its GET_CUR stubbed. This cause the sticky
check to consider the mixer to be sticky and unnecessarily disable it.
As the sticky check can't distinguish between sticky mixers and working
SET_CUR but broken GET_CUR, add QUIRK_FLAG_MIXER_GET_CUR_BROKEN to tell
that the device should fall into the second category when GET_CUR
returns a constant value. In this case, the sticky check becomes
non-fatal and only disables GET_CUR instead of the whole mixer. The
current volume will then be provided by the internal cache that stores
the last set volume.
The Sennheiser MOMENTUM 3 needs the quirk flag. Though its UAC mixer
works fine and precisely corresponds to the reported dB range, the
mixer's volume GET_CUR method is somehow stubbed and returns a constant
value (15dB), resulting in it being disabled by the sticky check.
Signed-off-by: Rong Zhang <i@rong.moe>
---
Changes in v2:
- Turn the approach into a less radical one
- Rename the quirk flag to QUIRK_FLAG_MIXER_GET_CUR_BROKEN
- Add a flag `get_cur_broken' to `struct usb_mixer_elem_info'
- When the sticky check fails, check quirk flags. Gate further GET_CUR
by setting `cval->get_cur_broken' if QUIRK_FLAG_MIXER_GET_CUR_BROKEN
is set, otherwise disable the mixer as usual
- The quirk flag still applies to all mixers, but as long as a mixer
makes the sticky check happy, it won't be affected at all. Only
those mixers with constant GET_CUR values will have their GET_CUR
gated. I assume the impact is minimal, since it's very unlikely a
device would have sticky mixers (broken SET_CUR) along with mixers
with working SET_CUR but broken GET_CUR at the same time
- Link to v1: https://patch.msgid.link/20260527-uac-quirk-get-cur-vol-v1-0-e9362b712e5e@rong.moe
To: Jaroslav Kysela <perex@perex.cz>
To: Takashi Iwai <tiwai@suse.com>
To: Jonathan Corbet <corbet@lwn.net>
To: Shuah Khan <skhan@linuxfoundation.org>
Cc: linux-sound@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Rong Zhang (2):
ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN
ALSA: usb-audio: Add quirk flag for Sennheiser MOMENTUM 3
Documentation/sound/alsa-configuration.rst | 12 ++++++++++++
sound/usb/mixer.c | 17 +++++++++++++++--
sound/usb/mixer.h | 1 +
sound/usb/quirks.c | 3 +++
sound/usb/usbaudio.h | 13 +++++++++++++
5 files changed, 44 insertions(+), 2 deletions(-)
---
base-commit: 72d8bf668954678bfae8f7296b4b1c01990bcdc2
change-id: 20260527-uac-quirk-get-cur-vol-d0b292c3e796
Thanks,
Rong
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN
2026-05-27 18:56 [PATCH v2 0/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN for Sennheiser MOMENTUM 3 Rong Zhang
@ 2026-05-27 18:56 ` Rong Zhang
2026-05-28 7:44 ` Takashi Iwai
2026-05-27 18:56 ` [PATCH v2 2/2] ALSA: usb-audio: Add quirk flag for Sennheiser MOMENTUM 3 Rong Zhang
1 sibling, 1 reply; 4+ messages in thread
From: Rong Zhang @ 2026-05-27 18:56 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai, Jonathan Corbet, Shuah Khan
Cc: Rong Zhang, linux-sound, linux-doc, linux-kernel
Since commit 86aa1ea1f15c ("ALSA: usb-audio: Do not expose sticky
mixers"), the UAC mixer core utilizes volume SET_CUR and GET_CUR to
identify devices with sticky mixers. Unfortunately, even though most
devices with sticky GET_CUR also have corresponding sticky SET_CUR,
which I actually met more since the commit had been merged, there is
also a rare case that some devices may have volume mixers that responds
to SET_CUR properly but with its GET_CUR stubbed. This cause the sticky
check to consider the mixer to be sticky and unnecessarily disable it.
As the sticky check can't distinguish between sticky mixers and working
SET_CUR but broken GET_CUR, add QUIRK_FLAG_MIXER_GET_CUR_BROKEN to tell
that the device should fall into the second category when GET_CUR
returns a constant value. In this case, the sticky check becomes
non-fatal and only disables GET_CUR instead of the whole mixer. The
current volume will then be provided by the internal cache that stores
the last set volume.
Signed-off-by: Rong Zhang <i@rong.moe>
---
Documentation/sound/alsa-configuration.rst | 12 ++++++++++++
sound/usb/mixer.c | 17 +++++++++++++++--
sound/usb/mixer.h | 1 +
sound/usb/quirks.c | 1 +
sound/usb/usbaudio.h | 13 +++++++++++++
5 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst
index 4b30cd63c5a5..78fb484e8b04 100644
--- a/Documentation/sound/alsa-configuration.rst
+++ b/Documentation/sound/alsa-configuration.rst
@@ -2389,6 +2389,18 @@ quirk_flags
from snd_usb_handle_sync_urb. Instead fall through and enqueue a
packet_info containing only size-0 packets, so the OUT ring keeps
moving (emits silence). Needed by Behringer Flow 8 (1397:050c).
+ * bit 30: ``mixer_get_cur_broken``
+ Some mixers are sticky, which means that setting their current volume
+ is a no-op, and reading the current volume returns a constant value.
+ The sticky check disables these mixers to prevent confusing userspace.
+ However, some devices do have a tunable volume despite the reported
+ current volume being constant. As the sticky check can't distinguish
+ between the two categories, setting this flag tells that the device
+ should fall into the second category when GET_CUR returns a constant
+ value, resulting in the sticky check being non-fatal and only
+ disabling GET_CUR instead of the whole mixer. The current volume will
+ then be provided by the internal cache that stores the last set
+ volume
This module supports multiple devices, autoprobe and hotplugging.
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index d61bde654219..27d6445cc319 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -420,6 +420,9 @@ static int get_cur_ctl_value(struct usb_mixer_elem_info *cval,
static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
int channel, int *value)
{
+ if (cval->get_cur_broken)
+ return -ENXIO;
+
return get_ctl_value(cval, UAC_GET_CUR,
(cval->control << 8) | channel,
value);
@@ -1258,6 +1261,16 @@ static int check_sticky_volume_control(struct usb_mixer_elem_info *cval,
return 0;
}
+ if (cval->head.mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_GET_CUR_BROKEN) {
+ usb_audio_warn(cval->head.mixer->chip,
+ "%d:%d: broken mixer GET_CUR (%d/%d/%d => %d)\n",
+ cval->head.id, mixer_ctrl_intf(cval->head.mixer),
+ cval->min, cval->max, cval->res, saved);
+
+ cval->get_cur_broken = 1;
+ return -ENXIO;
+ }
+
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),
@@ -1360,12 +1373,12 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
goto no_checks;
ret = check_sticky_volume_control(cval, minchn, saved);
- if (ret < 0) {
+ if (ret == -ENODEV) {
snd_usb_set_cur_mix_value(cval, minchn, 0, saved);
return ret;
}
- if (cval->min + cval->res < cval->max)
+ if (!ret && cval->min + cval->res < cval->max)
check_volume_control_res(cval, minchn, saved);
snd_usb_set_cur_mix_value(cval, minchn, 0, saved);
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index afbb3dd9f177..3fa1bd96f858 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -94,6 +94,7 @@ struct usb_mixer_elem_info {
int cache_val[MAX_CHANNELS];
u8 initialized;
u8 min_mute;
+ u8 get_cur_broken;
void *private_data;
};
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index e2c95be38aca..ac2f0f6039be 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2605,6 +2605,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
QUIRK_STRING_ENTRY(MIXER_PLAYBACK_LINEAR_VOL),
QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL),
QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY),
+ QUIRK_STRING_ENTRY(MIXER_GET_CUR_BROKEN),
NULL
};
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 9afcad8f143a..e472aef6eb87 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -242,6 +242,17 @@ extern bool snd_usb_skip_validation;
* from snd_usb_handle_sync_urb. Instead fall through and enqueue a
* packet_info containing only size-0 packets, so the OUT ring keeps
* moving (emits silence). Needed by Behringer Flow 8 (1397:050c).
+ * QUIRK_FLAG_MIXER_GET_CUR_BROKEN
+ * Some mixers are sticky, which means that setting their current volume is a
+ * no-op, and reading the current volume returns a constant value. The sticky
+ * check disables these mixers to prevent confusing userspace. However, some
+ * devices do have a tunable volume despite the reported current volume being
+ * constant. As the sticky check can't distinguish between the two categories,
+ * setting this flag tells that the device should fall into the second
+ * category when GET_CUR returns a constant value, resulting in the sticky
+ * check being non-fatal and only disabling GET_CUR instead of the whole mixer.
+ * The current volume will then be provided by the internal cache that stores
+ * the last set volume
*/
enum {
@@ -275,6 +286,7 @@ enum {
QUIRK_TYPE_MIXER_PLAYBACK_LINEAR_VOL = 27,
QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28,
QUIRK_TYPE_IFB_SILENCE_ON_EMPTY = 29,
+ QUIRK_TYPE_MIXER_GET_CUR_BROKEN = 30,
/* Please also edit snd_usb_audio_quirk_flag_names */
};
@@ -310,5 +322,6 @@ enum {
#define QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL QUIRK_FLAG(MIXER_PLAYBACK_LINEAR_VOL)
#define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL)
#define QUIRK_FLAG_IFB_SILENCE_ON_EMPTY QUIRK_FLAG(IFB_SILENCE_ON_EMPTY)
+#define QUIRK_FLAG_MIXER_GET_CUR_BROKEN QUIRK_FLAG(MIXER_GET_CUR_BROKEN)
#endif /* __USBAUDIO_H */
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] ALSA: usb-audio: Add quirk flag for Sennheiser MOMENTUM 3
2026-05-27 18:56 [PATCH v2 0/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN for Sennheiser MOMENTUM 3 Rong Zhang
2026-05-27 18:56 ` [PATCH v2 1/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN Rong Zhang
@ 2026-05-27 18:56 ` Rong Zhang
1 sibling, 0 replies; 4+ messages in thread
From: Rong Zhang @ 2026-05-27 18:56 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai, Jonathan Corbet, Shuah Khan
Cc: Rong Zhang, linux-sound, linux-doc, linux-kernel
The Sennheiser MOMENTUM 3 is a wireless around-ear headphones featuring
ANC, which can be connected via Bluetooth or USB-C.
When connecting via USB-C, its UAC mixer works fine and precisely
corresponds to the reported dB range. However, the mixer's volume
GET_CUR method is somehow stubbed and returns a constant value (15dB).
Since commit 86aa1ea1f15c ("ALSA: usb-audio: Do not expose sticky
mixers"), the sticky check considers the mixer to be sticky and
unnecessarily disables the mixer.
Add a quirk table entry matching VID/PID=0x1377/0x6004 and applying
the MIXER_GET_CUR_BROKEN quirk flag, so that the mixer is usable again.
Quirky device sample:
usb 7-1.4.4.1.1.1: new full-speed USB device number 30 using xhci_hcd
usb 7-1.4.4.1.1.1: New USB device found, idVendor=1377, idProduct=6004, bcdDevice=38.85
usb 7-1.4.4.1.1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 7-1.4.4.1.1.1: Product: MOMENTUM 3
usb 7-1.4.4.1.1.1: Manufacturer: Sennheiser electronic GmbH & Co. KG
usb 7-1.4.4.1.1.1: SerialNumber: <REDACTED>
usb 7-1.4.4.1.1.1: Found last interface = 0
usb 7-1.4.4.1.1.1: 1:1: add audio endpoint 0x3
usb 7-1.4.4.1.1.1: Creating new data endpoint #3
usb 7-1.4.4.1.1.1: 1:1 Set sample rate 48000, clock 0
usb 7-1.4.4.1.1.1: 6:0: sticky mixer values (0/11520/768 => 3840), disabling
usb 7-1.4.4.1.1.1: [6] FU [PCM Playback Volume] skipped due to invalid volume
input: Sennheiser electronic GmbH & Co. KG MOMENTUM 3 as /devices/pci0000:00/0000:00:08.3/0000:67:00.4/usb7/7-1/7-1.4/7-1.4.4/7-1.4.4.1/7-1.4.4.1.1/7-1.4.4.1.1.1/7-1.4.4.1.1.1:1.2/0003:1377:6004.002B/input/input208
input: Sennheiser electronic GmbH & Co. KG MOMENTUM 3 Consumer Control as /devices/pci0000:00/0000:00:08.3/0000:67:00.4/usb7/7-1/7-1.4/7-1.4.4/7-1.4.4.1/7-1.4.4.1.1/7-1.4.4.1.1.1/7-1.4.4.1.1.1:1.2/0003:1377:6004.002B/input/input209
hid-generic 0003:1377:6004.002B: input,hiddev99,hidraw12: USB HID v1.11 Device [Sennheiser electronic GmbH & Co. KG MOMENTUM 3] on usb-0000:67:00.4-1.4.4.1.1.1/input2
Signed-off-by: Rong Zhang <i@rong.moe>
---
sound/usb/quirks.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index ac2f0f6039be..149f2009df12 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2357,6 +2357,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
+ DEVICE_FLG(0x1377, 0x6004, /* Sennheiser MOMENTUM 3 */
+ QUIRK_FLAG_MIXER_GET_CUR_BROKEN),
DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x1397, 0x0507, /* Behringer UMC202HD */
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 1/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN
2026-05-27 18:56 ` [PATCH v2 1/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN Rong Zhang
@ 2026-05-28 7:44 ` Takashi Iwai
0 siblings, 0 replies; 4+ messages in thread
From: Takashi Iwai @ 2026-05-28 7:44 UTC (permalink / raw)
To: Rong Zhang
Cc: Jaroslav Kysela, Takashi Iwai, Jonathan Corbet, Shuah Khan,
linux-sound, linux-doc, linux-kernel
On Wed, 27 May 2026 20:56:27 +0200,
Rong Zhang wrote:
>
> @@ -1258,6 +1261,16 @@ static int check_sticky_volume_control(struct usb_mixer_elem_info *cval,
> return 0;
> }
>
> + if (cval->head.mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_GET_CUR_BROKEN) {
> + usb_audio_warn(cval->head.mixer->chip,
> + "%d:%d: broken mixer GET_CUR (%d/%d/%d => %d)\n",
> + cval->head.id, mixer_ctrl_intf(cval->head.mixer),
> + cval->min, cval->max, cval->res, saved);
> +
IMO, it's better to be usb_audio_info(). Otherwise it leads to an
unnecessary caution. Basically the behavior is expected, so there is
nothing to worry about that.
thanks,
Takashi
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-05-28 7:44 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-27 18:56 [PATCH v2 0/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN for Sennheiser MOMENTUM 3 Rong Zhang
2026-05-27 18:56 ` [PATCH v2 1/2] ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN Rong Zhang
2026-05-28 7:44 ` Takashi Iwai
2026-05-27 18:56 ` [PATCH v2 2/2] ALSA: usb-audio: Add quirk flag for Sennheiser MOMENTUM 3 Rong Zhang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox