All of lore.kernel.org
 help / color / mirror / Atom feed
* [REGRESSION] ALSA: usb-audio: Logitech PRO X Wireless 046d:0aba playback volume rejected as sticky
@ 2026-08-14 10:41 Alexander N.
  2026-08-14 11:53 ` Takashi Iwai
  2026-08-14 13:17 ` Rong Zhang
  0 siblings, 2 replies; 4+ messages in thread
From: Alexander N. @ 2026-08-14 10:41 UTC (permalink / raw)
  To: linux-sound; +Cc: regressions, tiwai, perex, i

[-- Attachment #1: Type: text/plain, Size: 4710 bytes --]

Hello,

I found a regression in snd-usb-audio affecting the Logitech PRO X
Wireless Gaming Headset (USB ID 046d:0aba).

The device has a valid UAC1 playback volume control, but the sticky mixer
detection introduced by commit 86aa1ea1f15c ("ALSA: usb-audio: Do not
expose sticky mixers") rejects it.

Hardware
========

   Logitech PRO X Wireless Gaming Headset
   USB ID: 046d:0aba

Observed kernel
===============

   7.1.5-ogc5.1.fc44.x86_64
   Bazzite/Fedora 44 OGC kernel

The OGC patch for this kernel does not modify sound/usb, and the relevant
mixer.c code matches upstream Linux 7.1.5.

I have not hardware-tested current mainline 7.2-rc7, but current upstream
mixer.c still contains the same immediate SET_CUR -> GET_CUR sticky mixer
test and I could not find a device quirk for 046d:0aba.

Symptom
=======

Without a workaround, ALSA only exposes:

   Simple mixer control 'PCM',0
     Capabilities: pswitch pswitch-joined

There is no PCM Playback Volume control.

The kernel logs:

   usb 1-10: 2:0: sticky mixer values (-16384/0/256 => -3840), disabling

I have also observed the same message ending in "=> 0", depending on the
hardware volume at probe time.

Because the playback volume control is removed, the physical volume wheel
changes the headset's hardware volume independently of the PipeWire/KDE
system volume.

USB Audio control behavior
==========================

The device is UAC1.

Feature Unit 2 exposes a master playback volume control.

Direct control requests, after temporarily unbinding AudioControl
interface 0 from snd-usb-audio, report:

   GET_MIN = -16384  (-64.00 dB)
   GET_MAX =      0  (  0.00 dB)
   GET_RES =    256  (  1.00 dB)

GET_CUR and SET_CUR both work, but the device has two quirks relevant to
the new sticky detection.

1. GET_CUR reflects normal SET_CUR changes with a delay of roughly 50 ms.

Measured from 0 dB:

   target     result   first visible GET_CUR change

    -1 dB     OK       81.3 ms
    -2 dB     OK       51.9 ms
    -4 dB     OK       47.3 ms
    -8 dB     OK       47.1 ms
   -16 dB     OK       51.7 ms
   -32 dB     OK       47.2 ms

2. The advertised minimum value -64 dB is not functional.

A direct SET_CUR to -64 dB returns success, but GET_CUR remains at 0 dB
even after 1000 ms.

This appears to cause a false positive in check_sticky_volume_control():

- cval->min is -16384 (-64 dB)
- cval->max is 0
- if the saved value is 0, max is skipped
- SET_CUR(min) returns success
- an immediate GET_CUR still returns the saved value
- the mixer is classified as sticky and is not registered

mixer_get_cur_broken is not appropriate
=======================================

I tested the mixer_get_cur_broken quirk.

GET_CUR on this device is not broken or constant. It correctly reports
host SET_CUR changes after the device delay, and it also reports volume
changes caused by the physical headset wheel.

Using an internal-only cached value would therefore lose useful hardware
state.

Local proof-of-concept fix
==========================

I built a local snd-usb-audio.ko against the running 7.1.5 kernel.

For this specific device, Feature Unit 2, UAC_FU_VOLUME, I:

- clamp the unusable minimum from -64 dB to -63 dB
- skip the probe-time sticky/resolution checks for this control

With that module, ALSA exposes:

   Simple mixer control 'PCM',0
     Capabilities: pvolume pvolume-joined pswitch pswitch-joined
     Playback channels: Mono
     Limits: Playback 0 - 63

/proc/asound/card*/usbmixer shows:

   Unit: 2
     Control: name="PCM Playback Volume", index=0
     Info: id=2, control=2, cmask=0x0, channels=1, type="S16"
     Volume: min=-16128, max=0, dBmin=-6300, dBmax=0

Most importantly, no userspace workaround is required once the mixer
control is restored.

Example before rotating the physical headset wheel:

   ALSA:     -27 dB / 57%
   PipeWire: 0.35

After rotating the headset wheel:

   ALSA:     -11 dB / 83%
   PipeWire: 0.65

KDE system volume follows the physical wheel as expected.

I attached the proof-of-concept diff and the measured results. I am happy
to test a maintainer-preferred implementation or additional diagnostics.

My suspicion is that this device exposes two assumptions in the sticky
mixer probe that are not universally safe:

1. GET_CUR is assumed to reflect SET_CUR immediately.
2. advertised min/max values are assumed to be usable test values.

Thanks.

#regzbot introduced: 86aa1ea1f15ce6b56ac1b4c0d9b88a07a5b9bf03

[-- Attachment #2: measurements.txt --]
[-- Type: text/plain, Size: 1619 bytes --]

Logitech PRO X Wireless Gaming Headset
USB ID: 046d:0aba

UAC1 playback control
---------------------
Feature Unit: 2
Control: UAC_FU_VOLUME
Channel: master (0)

GET_MIN: -16384 = -64.00 dB
GET_MAX:      0 =   0.00 dB
GET_RES:    256 =   1.00 dB

SET_CUR / GET_CUR timing
------------------------
Start: 0 dB

Target   Result   First visible GET_CUR change
 -1 dB   OK       81.3 ms
 -2 dB   OK       51.9 ms
 -4 dB   OK       47.3 ms
 -8 dB   OK       47.1 ms
-16 dB   OK       51.7 ms
-32 dB   OK       47.2 ms
-64 dB   FAIL     GET_CUR stayed at 0 dB after 1000 ms

Observed stock kernel message
-----------------------------
usb 1-10: 2:0: sticky mixer values (-16384/0/256 => -3840), disabling

Also observed depending on current hardware volume:
usb 1-10: 2:0: sticky mixer values (-16384/0/256 => 0), disabling

Stock ALSA mixer
----------------
Simple mixer control 'PCM',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [on]

Patched ALSA mixer
------------------
Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback 0 - 63

/proc/asound/card*/usbmixer:
Unit: 2
  Control: name="PCM Playback Volume", index=0
  Info: id=2, control=2, cmask=0x0, channels=1, type="S16"
  Volume: min=-16128, max=0, dBmin=-6300, dBmax=0

Physical volume wheel integration after PoC fix
-----------------------------------------------
Before:
  ALSA:     -27 dB / 57%
  PipeWire: 0.35

After wheel rotation:
  ALSA:     -11 dB / 83%
  PipeWire: 0.65

KDE follows the headset wheel after the control is restored.

[-- Attachment #3: poc-fix.diff --]
[-- Type: text/x-patch, Size: 888 bytes --]

Proof-of-concept only; not proposed as the final upstream implementation.

--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1,3 +1,3 @@
@@
 		if (cval->res == 0)
 			cval->res = 1;

+		/*
+		 * Logitech PRO X Wireless volume quirk (046d:0aba)
+		 *
+		 * The device advertises -64 dB as minimum playback volume, but
+		 * SET_CUR(-64 dB) is ineffective. Working values are reflected by
+		 * GET_CUR only after roughly 50 ms, so the probe-time sticky and
+		 * resolution tests can mis-detect this valid control.
+		 */
+		if (cval->head.mixer->chip->usb_id == USB_ID(0x046d, 0x0aba) &&
+		    cval->head.id == 2 &&
+		    cval->control == UAC_FU_VOLUME) {
+			usb_audio_info(cval->head.mixer->chip,
+				       "Logitech PRO X Wireless: applying playback volume quirk\n");
+			cval->min = -16128; /* -63 dB */
+			goto no_checks;
+		}
+
 		if (cval->min < cval->max) {
 			int saved;

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-14 14:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-14 10:41 [REGRESSION] ALSA: usb-audio: Logitech PRO X Wireless 046d:0aba playback volume rejected as sticky Alexander N.
2026-08-14 11:53 ` Takashi Iwai
2026-08-14 13:17 ` Rong Zhang
2026-08-14 14:02   ` Alexander Niemeyer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.