* Re: USB device with more than 32 channels
2026-02-26 11:02 USB device with more than 32 channels Phil Willoughby
@ 2026-02-26 12:17 ` Takashi Iwai
2026-03-27 13:42 ` Phil Willoughby
0 siblings, 1 reply; 3+ messages in thread
From: Takashi Iwai @ 2026-02-26 12:17 UTC (permalink / raw)
To: Phil Willoughby; +Cc: linux-sound@vger.kernel.org
[-- Attachment #1: Type: text/plain, Size: 2422 bytes --]
On Thu, 26 Feb 2026 12:02:10 +0100,
Phil Willoughby wrote:
>
> There's a check at sound/usb/mixer.c:2024 introduced by patch
> 2f38cf730caedaeacdefb7ff35b0a3c1168117f9 which filters out any device
> with more than 32 channels.
>
> My audio interface has 34 channels in and 34 channels out, which
> therefore takes this branch, and means that this interface doesn't work
> on Linux. As I have nothing plugged in to channels 33 and 34 I am
> locally experimenting with changing the body of this check like:
>
> - return -EINVAL;
> + channels = 32;
>
> Which is obviously not a change I want to suggest for general
> consumption. I would like to fix it properly.
>
> Judging by the commit message for
> 2f38cf730caedaeacdefb7ff35b0a3c1168117f9 the only reason for more than
> 32 channels existing that seems to have been considered at the time was
> a malformed USB descriptor. Is that something that actually exists in
> the wild or was this scenario purely theoretical?
The number 32 there is just because of bit operations. Some checks
are done with 32bit int.
> In either case I think the core of the correct fix is going to be to
> make the 32-bit variable we're shifting a 64-bit variable and change the
> hard check to > 64. If there are real concerns with malformed
> descriptors we can either add an allow-list or reject-list based on vid/pid.
>
> Should I expect any ABI problems here? Are we exposing a 32-bit channel
> bitfield outside of kernel-space anywhere?
>
> Some background:
>
> The interface I have is an Arturia Audiofuse 16Rig. Yes it really has
> that many channels.
>
> There are a few threads on sites like
> https://linuxmusicians.com/viewtopic.php?t=28759 where others have
> encountered this problem so it's not just me.
>
> You will find some threads which say it worked at some point in time but
> then stopped working - this very roughly tracks with the timing of the
> 2f38cf730caedaeacdefb7ff35b0a3c1168117f9 commit getting merged into
> mainstream distros.
>
> I think I'm the first person to try tweaking this piece of code. I'm
> still building my patched kernel as I type this so I can't yet say
> whether it works.
The current code has even a lower MAX_CHANNELS (= 16), and I guess
more than 16 channels don't work perfectly for now. The 32 limitation
above was merely for fixing UBSAN warning.
Below are ad hoc fixes. let me know if this works.
thanks,
Takashi
[-- Attachment #2: 0001-ALSA-usb-audio-Replace-hard-coded-number-with-MAX_CH.patch --]
[-- Type: application/octet-stream, Size: 946 bytes --]
From aa293c3772adf874242962a8dd50d5c011184dd3 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 26 Feb 2026 13:01:42 +0100
Subject: [PATCH 1/2] ALSA: usb-audio: Replace hard-coded number with
MAX_CHANNELS
One place in mixer.c still used a hard-coded number 16 instead of
MAX_CHANNELS. Replace with it, so that we can extend the max number
of channels gracefully.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/usb/mixer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index ac8c71ba9483..09c42300fb48 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1707,7 +1707,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer,
cval->master_readonly = readonly_mask;
} else {
int i, c = 0;
- for (i = 0; i < 16; i++)
+ for (i = 0; i < MAX_CHANNELS; i++)
if (ctl_mask & BIT(i))
c++;
cval->channels = c;
--
2.53.0
[-- Attachment #3: 0002-ALSA-usb-audio-Extend-max-number-of-channels-to-64.patch --]
[-- Type: application/octet-stream, Size: 4164 bytes --]
From c5b4df77405111c2883fe9164ce1a696ddb9189b Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 26 Feb 2026 13:11:56 +0100
Subject: [PATCH 2/2] ALSA: usb-audio: Extend max number of channels to 64
The current limitation of 16 as MAX_CHANNELS is rather historical at
the time of UAC1 definition. As there seem already devices with a
higher number of mixer channels, we should extend it too. As an ad
hoc update, let's raise it to 64 so that it can still fit in a single
long-long integer.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/usb/mixer.c | 14 +++++++-------
sound/usb/mixer.h | 4 ++--
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 09c42300fb48..2490f0c4ddbd 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1662,7 +1662,7 @@ static const struct usb_feature_control_info *get_feature_control_info(int contr
static void __build_feature_ctl(struct usb_mixer_interface *mixer,
const struct usbmix_name_map *imap,
- unsigned int ctl_mask, int control,
+ u64 ctl_mask, int control,
struct usb_audio_term *iterm,
struct usb_audio_term *oterm,
int unitid, int nameid, int readonly_mask)
@@ -1833,7 +1833,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer,
}
static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
- unsigned int ctl_mask, int control,
+ u64 ctl_mask, int control,
struct usb_audio_term *iterm, int unitid,
int readonly_mask)
{
@@ -1845,7 +1845,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
}
static void build_feature_ctl_badd(struct usb_mixer_interface *mixer,
- unsigned int ctl_mask, int control, int unitid,
+ u64 ctl_mask, int control, int unitid,
const struct usbmix_name_map *badd_map)
{
__build_feature_ctl(mixer, badd_map, ctl_mask, control,
@@ -2021,7 +2021,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
bmaControls = ftr->bmaControls;
}
- if (channels > 32) {
+ if (channels > MAX_CHANNELS) {
usb_audio_info(state->chip,
"usbmixer: too many channels (%d) in unit %d\n",
channels, unitid);
@@ -2059,7 +2059,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
if (state->mixer->protocol == UAC_VERSION_1) {
/* check all control types */
for (i = 0; i < 10; i++) {
- unsigned int ch_bits = 0;
+ u64 ch_bits = 0;
int control = audio_feature_info[i].control;
for (j = 0; j < channels; j++) {
@@ -2085,7 +2085,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
}
} else { /* UAC_VERSION_2/3 */
for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) {
- unsigned int ch_bits = 0;
+ u64 ch_bits = 0;
unsigned int ch_read_only = 0;
int control = audio_feature_info[i].control;
@@ -3398,7 +3398,7 @@ static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer,
[USB_MIXER_U32] = "U32",
[USB_MIXER_BESPOKEN] = "BESPOKEN",
};
- snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, "
+ snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%llx, "
"channels=%i, type=\"%s\"\n", cval->head.id,
cval->control, cval->cmask, cval->channels,
val_types[cval->val_type]);
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 167fbfcf01ac..afbb3dd9f177 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -44,7 +44,7 @@ struct usb_mixer_interface {
void (*private_suspend)(struct usb_mixer_interface *mixer);
};
-#define MAX_CHANNELS 16 /* max logical channels */
+#define MAX_CHANNELS 64 /* max logical channels */
enum {
USB_MIXER_BOOLEAN,
@@ -81,7 +81,7 @@ struct usb_mixer_elem_list {
struct usb_mixer_elem_info {
struct usb_mixer_elem_list head;
unsigned int control; /* CS or ICN (high byte) */
- unsigned int cmask; /* channel mask bitmap: 0 = master */
+ u64 cmask; /* channel mask bitmap: 0 = master */
unsigned int idx_off; /* Control index offset */
unsigned int ch_readonly;
unsigned int master_readonly;
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread