From: "Geoffrey D. Bennett" <g@b4.vu>
To: Takashi Iwai <tiwai@suse.de>
Cc: Takashi Iwai <tiwai@suse.com>,
linux-sound@vger.kernel.org, Alexander Tsoy <alexander@tsoy.me>,
Tina Wuest <tina@wuest.me>
Subject: [PATCH 0/4] ALSA: usb-audio: Fix Focusrite probe-time side effects
Date: Sat, 21 Feb 2026 02:33:11 +1030 [thread overview]
Message-ID: <cover.1771594828.git.g@b4.vu> (raw)
Hi all,
This series fixes two problems caused by probe-time testing of
altsettings and sample rates on Focusrite devices. When a sample rate
of 192kHz is selected during the probe's trial and error, the internal
mixer and Air and Safe modes are disabled. I.e. no audio passes
through the mixer, and Air and Safe modes cannot be selected until an
application opens the PCM and sets a lower rate. This results in user
annoyance and bug reports of unexpected silence and mode changes.
I tested 20 Focusrite devices (Scarlett 2nd, 3rd, 4th Gen, Clarett+,
and Vocaster) and found that the valid sample rates can be determined
from USB descriptors alone, without the QUIRK_FLAG_VALIDATE_RATES
trial-and-error testing of each rate and altsetting. I also added a
quirk to skip the redundant interface setup and enabled the quirk to
skip the clock selector write-back (reading the current value then
writing it back unchanged triggers a ~300ms delay per altsetting).
The result of all this: the probe time drops from ~4 seconds to ~4ms,
there is no interruption to audio, and the mode settings do not
inadvertently get reset. The contents of /proc/asound/card*/stream0 is
identical before and after on all tested devices.
Background
----------
Focusrite interfaces with digital I/O use multiple altsettings for
different channel counts at different sample rates (more channels at
48kHz, fewer at 192kHz). The clock source reports all rates for every
altsetting, so rates need filtering.
Two mechanisms currently do this:
1. focusrite_valid_sample_rate() reads a non-standard Format Type
descriptor (bLength=10, vs standard UAC2 bLength=6) with a max_rate
in bytes 6-9.
2. validate_sample_rate_table_v2v3() (QUIRK_FLAG_VALIDATE_RATES) sets
each rate on the device and queries UAC2_AS_VAL_ALT_SETTINGS to
check validity. Prunes rates that fail.
Mechanism #1 currently uses fallthrough logic (commit cc8e91054c0a):
an altsetting with max_rate=192000 accepts all rates down to 44100.
This is correct for Clarett+ but wrong for Scarlett 3rd/4th Gen, where
only the matching rate pair should be accepted. Mechanism #2 gets the
right answer but has the USB side effects above.
Commit 05f254a6369a had strict 1:1 mapping, correct for Scarlett but
wrong for Clarett+. Neither approach alone works for all devices.
The UAC2_AS_VAL_ALT_SETTINGS readable bit in the AS header bmControls
predicts which behaviour the device needs:
- val_alt readable: strict — each altsetting only accepts its own rate
pair
- val_alt not readable: fallthrough — all rates up to max_rate
Device test matrix:
Device Playback Capture val_alt
-------------------------------------------------------------------
Scarlett 6i6 2nd Gen 1 alt, bLen=6 1 alt, bLen=6 no
Scarlett 18i8 2nd Gen 1 alt, bLen=6 3 alts, bLen=10 no
Scarlett 18i20 2nd Gen 3 alts, bLen=10 3 alts, bLen=10 no
Scarlett Solo 3rd Gen 1 alt, bLen=6 1 alt, bLen=6 yes
Scarlett 2i2 3rd Gen 1 alt, bLen=6 1 alt, bLen=6 yes
Scarlett 4i4 3rd Gen 1 alt, bLen=6 1 alt, bLen=6 yes
Scarlett 8i6 3rd Gen 1 alt, bLen=6 1 alt, bLen=6 yes
Scarlett 18i8 3rd Gen 3 alts, bLen=6 3 alts, bLen=10 yes
Scarlett 18i20 3rd Gen 3 alts, bLen=10 3 alts, bLen=10 yes
Scarlett Solo 4th Gen 1 alt, bLen=6 1 alt, bLen=6 yes
Scarlett 2i2 4th Gen 1 alt, bLen=6 1 alt, bLen=6 yes
Scarlett 4i4 4th Gen 1 alt, bLen=6 1 alt, bLen=6 yes
Scarlett 16i16 4th Gen 3 alts, bLen=10 3 alts, bLen=10 yes
Scarlett 18i16 4th Gen 3 alts, bLen=10 3 alts, bLen=10 yes
Scarlett 18i20 4th Gen 3 alts, bLen=10 3 alts, bLen=10 yes
Clarett+ 2Pre 1 alt, bLen=6 3 alts, bLen=10 mixed*
Clarett+ 4Pre 3 alts, bLen=6 3 alts, bLen=10 no
Clarett+ 8Pre 3 alts, bLen=10 3 alts, bLen=10 no
Vocaster One 1 alt, bLen=6 1 alt, bLen=6 yes
Vocaster Two 1 alt, bLen=6 1 alt, bLen=6 yes
* Clarett+ 2Pre: playback val_alt=no (single alt),
capture val_alt=yes
bLen=10: non-standard Focusrite Format Type descriptor with max_rate
in bytes 6-9 (LE u32). Standard UAC2 is bLen=6. Single-altsetting
devices need no rate filtering. Vocaster only supports 48kHz.
For val_alt=yes multi-alt devices, the old VALIDATE_RATES probing
agreed with the new strict filtering. For val_alt=no (2nd Gen,
Clarett+), the device accepts all rates up to max_rate on any
altsetting. I confirmed this on the Scarlett 18i20 2nd Gen and
Clarett+ 8Pre with speaker-test running 10 channels at 48kHz on the
up-to-192kHz altsetting.
Patches
-------
1/4: Improve focusrite_valid_sample_rate() to check bmControls for
UAC2_AS_VAL_ALT_SETTINGS:
- val_alt readable + bLength=10: strict mapping
- val_alt not readable + bLength=10: fallthrough (unchanged)
- val_alt readable + bLength!=10 + multi-alt: use the Focusrite
altsetting convention (alt 1=48k, 2=96k, 3=192k)
- otherwise: no filtering
The third case handles the Scarlett 18i8 3rd Gen, which has bLength=6
on playback (no max_rate) but 3 altsettings with val_alt=yes,
requiring strict mapping.
2/4: Remove QUIRK_FLAG_VALIDATE_RATES for Focusrite. With patch 1,
descriptor-based filtering gets the right rates without USB probing.
3/4: Add QUIRK_FLAG_SKIP_IFACE_SETUP. Skips the probe-time interface
setup (usb_set_interface, init_pitch, init_sample_rate) in
__snd_usb_parse_audio_interface() which is redundant with
snd_usb_endpoint_prepare() at stream-open time. Enabled this quirk for
Focusrite devices. This is similar to commit ac5e2fb4 ("ALSA:
usb-audio: Drop superfluous interface setup at parsing") but gated as
a quirk. It's a worthwhile optimisation and is the second half of
fixing the problem with the sample rate being changed.
4/4: Enable QUIRK_FLAG_SKIP_CLOCK_SELECTOR for Focusrite devices.
snd_usb_clock_find_source() reads the clock selector value then writes
it back unchanged. On Focusrite devices this triggers an unnecessary
~300ms delay per altsetting.
Tested on all devices listed above: /proc/asound/card*/stream0
identical before and after.
Regards,
Geoffrey
Geoffrey D. Bennett (4):
ALSA: usb-audio: Improve Focusrite sample rate filtering
ALSA: usb-audio: Remove VALIDATE_RATES quirk for Focusrite devices
ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP
ALSA: usb-audio: Skip clock selector for Focusrite devices
sound/usb/format.c | 70 ++++++++++++++++++++++++++++++++++++++++----
sound/usb/quirks.c | 4 ++-
sound/usb/stream.c | 3 ++
sound/usb/usbaudio.h | 6 ++++
4 files changed, 77 insertions(+), 6 deletions(-)
--
2.53.0
next reply other threads:[~2026-02-20 16:03 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-20 16:03 Geoffrey D. Bennett [this message]
2026-02-20 16:03 ` [PATCH 1/4] ALSA: usb-audio: Improve Focusrite sample rate filtering Geoffrey D. Bennett
2026-02-20 16:04 ` [PATCH 2/4] ALSA: usb-audio: Remove VALIDATE_RATES quirk for Focusrite devices Geoffrey D. Bennett
2026-02-20 16:06 ` [PATCH 3/4] ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP Geoffrey D. Bennett
2026-02-20 16:06 ` [PATCH 4/4] ALSA: usb-audio: Skip clock selector for Focusrite devices Geoffrey D. Bennett
2026-02-23 8:58 ` [PATCH 0/4] ALSA: usb-audio: Fix Focusrite probe-time side effects Takashi Iwai
2026-02-23 23:58 ` Geoffrey D. Bennett
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cover.1771594828.git.g@b4.vu \
--to=g@b4.vu \
--cc=alexander@tsoy.me \
--cc=linux-sound@vger.kernel.org \
--cc=tina@wuest.me \
--cc=tiwai@suse.com \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox