[PATCH] ALSA: usb-audio: add QUIRK_FLAG_ALWAYS_SET_RATE for Mackie DLZ Creator XS

JJ Macalinao <[email protected]>
Newsgroups org.alsa-project.alsa-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-sound
Message-ID <[email protected]>
set_sample_rate_v2v3() returns early when the clock already reports the
requested rate:

	prev_rate = get_sample_rate_v2v3(chip, fmt->iface,
					 fmt->altsetting, clock);
	if (prev_rate == rate)
		goto validation;

A device advertising exactly one sample rate always takes this branch, so
it never receives a SET_CUR for CS_SAM_FREQ_CONTROL at all.

The Mackie DLZ Creator XS (0a73:003a, 14 in / 4 out, 48 kHz only) requires
that write.  Without it the device drops off the USB bus roughly 0.2-1.8 s
into any stream, clearing its port CONNECTION bit; captured audio is
byte-correct until the instant it vanishes.

USBPcap traces of a cold-booted device on Windows show SET_CUR 48000 issued
unconditionally on every stream start, followed by clean streaming.  The
device is otherwise driven with plain class-compliant UAC2 - it also works
on iOS, which cannot load a vendor driver - so no vendor-specific
initialisation is involved.

The device is self-powered, so the resulting state survives a USB replug:
initialising it on any host that issues the write leaves it working on
Linux until it is power-cycled, which made the failure look intermittent.

Add a quirk flag rather than dropping the early exit, since the opposite
requirement also exists in-tree: QUIRK_FLAG_FIXED_RATE suppresses rate
setting for single-rate devices (JBL Quantum610/810).  The two behaviours
are device-dependent and cannot both be the default.

A/B on identically cold-booted hardware, same kernel, same port, repeated
twice:

  without the flag  device dropped after 5-6 s, then again after 3-4 s
  with the flag     20 s playback followed by 20 s of 14-channel capture,
                    960000 frames, zero re-enumerations

This change was developed with an AI coding assistant.  The assistant did
the trace analysis that located the bug and wrote the patch and this
changelog; the hardware testing, the cold-boot cycles and the decision to
submit were the author's.  Several earlier hypotheses it proposed - URB
queue depth, isochronous packet under-allocation, endpoint start ordering -
were disproven by measurement before this one.

The bug was located with usbmon on Linux and USBPcap on Windows, by
diffing an enumeration capture of a cold-booted device on each host.
Verified on physical hardware by the A/B above.

Assisted-by: Claude-Code:claude-opus-5
Signed-off-by: JJ Macalinao <[email protected]>
---
 sound/usb/clock.c    | 3 ++-
 sound/usb/quirks.c   | 3 +++
 sound/usb/usbaudio.h | 6 ++++++
 3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 2e0c18e352..647bf55b1b 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -626,7 +626,8 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip,
 	}
 
 	prev_rate = get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock);
-	if (prev_rate == rate)
+	if (prev_rate == rate &&
+	    !(chip->quirk_flags & QUIRK_FLAG_ALWAYS_SET_RATE))
 		goto validation;
 
 	cur_rate = snd_usb_set_sample_rate_v2v3(chip, fmt, clock, rate);
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 3330eb6049..d00d6a543a 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2333,6 +2333,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
 		   QUIRK_FLAG_IGNORE_CTL_ERROR),
 	DEVICE_FLG(0x0951, 0x16ad, /* Kingston HyperX */
 		   QUIRK_FLAG_CTL_MSG_DELAY_1M),
+	DEVICE_FLG(0x0a73, 0x003a, /* Mackie DLZ Creator XS */
+		   QUIRK_FLAG_ALWAYS_SET_RATE),
 	DEVICE_FLG(0x0b05, 0x18a6, /* ASUSTek Computer, Inc. */
 		   QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE),
 	DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */
@@ -2638,6 +2640,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
 	QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY),
 	QUIRK_STRING_ENTRY(MIXER_GET_CUR_BROKEN),
 	QUIRK_STRING_ENTRY(PLAYBACK_URB_FIXUP),
+	QUIRK_STRING_ENTRY(ALWAYS_SET_RATE),
 	NULL
 };
 
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 31e6125000..c49709d7ad 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -260,6 +260,10 @@ extern bool snd_usb_skip_validation;
  *  to insufficient buffer depth combined with xHCI scheduling variability.
  *  The larger buffer (MAX_URBS = 12, ~64ms) absorbs system scheduling
  *  jitter during boot, while URB_ISO_ASAP ensures consistent xHCI scheduling.
+ * QUIRK_FLAG_ALWAYS_SET_RATE:
+ *  Issue SET_CUR for the sample rate even when the clock already reports the
+ *  requested rate.  A device advertising a single rate is otherwise never sent
+ *  the request at all, and some require it before streaming will start.
  */
 
 enum {
@@ -295,6 +299,7 @@ enum {
 	QUIRK_TYPE_IFB_SILENCE_ON_EMPTY		= 29,
 	QUIRK_TYPE_MIXER_GET_CUR_BROKEN		= 30,
 	QUIRK_TYPE_PLAYBACK_URB_FIXUP		= 31,
+	QUIRK_TYPE_ALWAYS_SET_RATE		= 32,
 /* Please also edit snd_usb_audio_quirk_flag_names */
 };
 
@@ -332,5 +337,6 @@ enum {
 #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)
 #define QUIRK_FLAG_PLAYBACK_URB_FIXUP		QUIRK_FLAG(PLAYBACK_URB_FIXUP)
+#define QUIRK_FLAG_ALWAYS_SET_RATE		QUIRK_FLAG(ALWAYS_SET_RATE)
 
 #endif /* __USBAUDIO_H */
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.