Re: [PATCH v2 4/4] HID: steelseries: Add support for Arctis headset lineup
From: Bastien Nocera
Date: Thu Feb 26 2026 - 05:07:07 EST
Hey,
On Thu, 2026-02-26 at 04:33 -0500, Sriman Achanta wrote:
> I agree these should be proper ALSA controls rather than sysfs files.
> I've been investigating the best way to accomplish this, since the
> challenge is that these values (chatmix, sidetone, mic volume, etc.)
> are reported/controlled via the HID vendor interface, while the USB
> audio card is owned by snd-usb-audio.
>
> There are a few approaches I've found precedent for: (1) adding
> vendor quirks in sound/usb/mixer_quirks.c that bridge back to the HID
> interface, similar to the DualSense jack detection code which uses an
> input_handler to receive events from hid-playstation; (2) creating a
> separate snd_card from the HID driver itself with custom mixer
> controls, similar to how hid-prodikeys creates its own ALSA card; or
> (3) having the HID driver find the sibling USB audio card and add
> controls to it directly (though this has no existing precedent and
> raises lifetime/ordering concerns).
>
> My inclination is toward option 2 — a dedicated snd_card owned by the
> HID driver — since the chatmix dial and sidetone are logically
> properties of the HID device rather than the audio stream, and it
> avoids fragile cross-driver coupling. However, this does mean
> userspace sees a second ALSA card for what is physically one device.
> I'd appreciate guidance on which approach the maintainers would
> prefer before I implement it.
Option 2 is definitely the way to go. I would expect widely deployed
front-ends to ALSA like Pipewire and PulseAudio to be able to make it
look like the 2 sets of mixing controls come from the same physical
device.
Cheers
>
> Best,
> Sriman Achanta
>
> On Wed, Jan 14, 2026 at 4:51 AM Bastien Nocera <hadess@xxxxxxxxxx>
> wrote:
> > On Tue, 2026-01-13 at 21:57 -0500, Sriman Achanta wrote:
> > > > As mentioned in the earlier patch, sidetone control, chatmix
> > > > level, mic
> > > > level, volume limiter and bluetooth call volume all should be
> > > > implemented as ALSA mixers/switches so they can be toggled with
> > > > stock
> > > > tools and presented in a uniform way up the stack
> > > > (Pipewire/Pulseaudio
> > > > and desktop environments).
> > >
> > > My only concern with this is that there is no ability to read the
> > > setting state from the headset so the only way to implement ALSA
> > > mixers would be to return a guessed value / default and then
> > > write-
> > > through caching for subsequently set values, creating a desync
> > > between the device and the reported state of the mixer.
> >
> > How is that different from a sysfs value that you can't read when
> > the
> > headset is off?
> >
> > > Additionally, inactive_timeout and bt_power_on should remain as
> > > Sysfs handles as they modify the power system, not audio.
> >
> > They should however be separate patches, so the maintainers have a
> > choice to take them or not, especially since adding new sysfs files
> > is
> > frowned upon, and maintainers will likely want a more generic way
> > to
> > implement that functionality for other devices as well.
> >
> > Note that you emailed me in private, you should definitely CC: the
> > mailing-list when you answer, otherwise nobody but me will see your
> > response.
> >
> > Cheers
> >
> > >
> > > On Mon, Jan 12, 2026 at 8:09 AM Bastien Nocera
> > > <hadess@xxxxxxxxxx>
> > > wrote:
> > > > On Sun, 2026-01-11 at 23:19 -0500, Sriman Achanta wrote:
> > > > > Add full support for the SteelSeries Arctis wireless gaming
> > > > > headset
> > > > > lineup, extending the driver from basic support for 2 models
> > > > > (Arctis
> > > > > 1
> > > > > and 9) to comprehensive support for 25+ models across all
> > > > > Arctis
> > > > > generations.
> > > > >
> > > > > This is a major restructure of the hid-steelseries driver
> > > > > that
> > > > > replaces
> > > > > the previous minimal implementation with a unified,
> > > > > capability-
> > > > > based
> > > > > architecture.
> > > >
> > > > This patch needs to be split up, at the very least it needs new
> > > > features to be split up from any other refactoring that might
> > > > be
> > > > needed
> > > > to support features with each new feature getting its own
> > > > commit.
> > > >
> > > > As mentioned in the earlier patch, sidetone control, chatmix
> > > > level,
> > > > mic
> > > > level, volume limiter and bluetooth call volume all should be
> > > > implemented as ALSA mixers/switches so they can be toggled with
> > > > stock
> > > > tools and presented in a uniform way up the stack
> > > > (Pipewire/Pulseaudio
> > > > and desktop environments).
> > > >
> > > > An additional comments inline.
> > > >
> > > > > <snip>
> > > > > -/* Fixed report descriptor for Steelseries SRW-S1 wheel
> > > > > controller
> > > > > - *
> > > > > - * The original descriptor hides the sensitivity and assists
> > > > > dials
> > > > > - * a custom vendor usage page. This inserts a patch to make
> > > > > them
> > > > > - * appear in the 'Generic Desktop' usage.
> > > > > - */
> > > > > -
> > > > > +/* Fixed report descriptor for Steelseries SRW-S1 wheel
> > > > > controller
> > > > > */
> > > >
> > > > There's really no need to reindent this array.
> > > >
> > > > > static const __u8 steelseries_srws1_rdesc_fixed[] = {
> > > > > -0x05, 0x01, /* Usage Page (Desktop)
> > > > > */
> > > > > -0x09, 0x08, /* Usage (MultiAxis), Changed
> > > > > */
> > > > > -0xA1, 0x01, /* Collection (Application),
> > > > > */
> > > > > -0xA1, 0x02, /* Collection (Logical),
> > > > > */
> > > > > -0x95, 0x01, /* Report Count (1),
> > > > > */
> > > > > -0x05, 0x01, /* Changed Usage Page (Desktop),
> > > > > */
> > > > > -0x09, 0x30, /* Changed Usage (X),
> > > > > */
> > > > > -0x16, 0xF8, 0xF8, /* Logical Minimum (-1800),
> > > > > */
> > > > > -0x26, 0x08, 0x07, /* Logical Maximum (1800),
> > > > > */
> > > > > -0x65, 0x14, /* Unit (Degrees),
> > > > > */
> > > > > -0x55, 0x0F, /* Unit Exponent (15),
> > > > > */
> > > > > -0x75, 0x10, /* Report Size (16),
> > > > > */
> > > > > -0x81, 0x02, /* Input (Variable),
> > > > > */
> > > > > -0x09, 0x31, /* Changed Usage (Y),
> > > > > */
> > > > > -0x15, 0x00, /* Logical Minimum (0),
> > > > > */
> > > > > -0x26, 0xFF, 0x03, /* Logical Maximum (1023),
> > > > > */
> > > > > -0x75, 0x0C, /* Report Size (12),
> > > > > */
> > > > > -0x81, 0x02, /* Input (Variable),
> > > > > */
> > > > > -0x09, 0x32, /* Changed Usage (Z),
> > > > > */
> > > > > -0x15, 0x00, /* Logical Minimum (0),
> > > > > */
> > > > > -0x26, 0xFF, 0x03, /* Logical Maximum (1023),
> > > > > */
> > > > > -0x75, 0x0C, /* Report Size (12),
> > > > > */
> > > > > -0x81, 0x02, /* Input (Variable),
> > > > > */
> > > > > -0x05, 0x01, /* Usage Page (Desktop),
> > > > > */
> > > > > -0x09, 0x39, /* Usage (Hat Switch),
> > > > > */
> > > > > -0x25, 0x07, /* Logical Maximum (7),
> > > > > */
> > > > > -0x35, 0x00, /* Physical Minimum (0),
> > > > > */
> > > > > -0x46, 0x3B, 0x01, /* Physical Maximum (315),
> > > > > */
> > > > > -0x65, 0x14, /* Unit (Degrees),
> > > > > */
> > > > > -0x75, 0x04, /* Report Size (4),
> > > > > */
> > > > > -0x95, 0x01, /* Report Count (1),
> > > > > */
> > > > > -0x81, 0x02, /* Input (Variable),
> > > > > */
> > > > > -0x25, 0x01, /* Logical Maximum (1),
> > > > > */
> > > > > -0x45, 0x01, /* Physical Maximum (1),
> > > > > */
> > > > > -0x65, 0x00, /* Unit,
> > > > > */
> > > > > -0x75, 0x01, /* Report Size (1),
> > > > > */
> > > > > -0x95, 0x03, /* Report Count (3),
> > > > > */
> > > > > -0x81, 0x01, /* Input (Constant),
> > > > > */
> > > > > -0x05, 0x09, /* Usage Page (Button),
> > > > > */
> > > > > -0x19, 0x01, /* Usage Minimum (01h),
> > > > > */
> > > > > -0x29, 0x11, /* Usage Maximum (11h),
> > > > > */
> > > > > -0x95, 0x11, /* Report Count (17),
> > > > > */
> > > > > -0x81, 0x02, /* Input (Variable),
> > > > > */
> > > > > - /* ---- Dial patch starts here ----
> > > > > */
> > > > > -0x05, 0x01, /* Usage Page (Desktop),
> > > > > */
> > > > > -0x09, 0x33, /* Usage (RX),
> > > > > */
> > > > > -0x75, 0x04, /* Report Size (4),
> > > > > */
> > > > > -0x95, 0x02, /* Report Count (2),
> > > > > */
> > > > > -0x15, 0x00, /* Logical Minimum (0),
> > > > > */
> > > > > -0x25, 0x0b, /* Logical Maximum (b),
> > > > > */
> > > > > -0x81, 0x02, /* Input (Variable),
> > > > > */
> > > > > -0x09, 0x35, /* Usage (RZ),
> > > > > */
> > > > > -0x75, 0x04, /* Report Size (4),
> > > > > */
> > > > > -0x95, 0x01, /* Report Count (1),
> > > > > */
> > > > > -0x25, 0x03, /* Logical Maximum (3),
> > > > > */
> > > > > -0x81, 0x02, /* Input (Variable),
> > > > > */
> > > > > - /* ---- Dial patch ends here ----
> > > > > */
> > > > > -0x06, 0x00, 0xFF, /* Usage Page (FF00h),
> > > > > */
> > > > > -0x09, 0x01, /* Usage (01h),
> > > > > */
> > > > > -0x75, 0x04, /* Changed Report Size (4),
> > > > > */
> > > > > -0x95, 0x0D, /* Changed Report Count (13),
> > > > > */
> > > > > -0x81, 0x02, /* Input (Variable),
> > > > > */
> > > > > -0xC0, /* End Collection,
> > > > > */
> > > > > -0xA1, 0x02, /* Collection (Logical),
> > > > > */
> > > > > -0x09, 0x02, /* Usage (02h),
> > > > > */
> > > > > -0x75, 0x08, /* Report Size (8),
> > > > > */
> > > > > -0x95, 0x10, /* Report Count (16),
> > > > > */
> > > > > -0x91, 0x02, /* Output (Variable),
> > > > > */
> > > > > -0xC0, /* End Collection,
> > > > > */
> > > > > -0xC0 /* End Collection
> > > > > */
> > > > > + 0x05, 0x01, /* Usage Page (Desktop) */
> > > > > + 0x09, 0x08, /* Usage (MultiAxis), Changed */
> > > > > + 0xA1, 0x01, /* Collection (Application), */
> > > > > + 0xA1, 0x02, /* Collection (Logical), */
> > > > > + 0x95, 0x01, /* Report Count (1), */
> > > > > + 0x05, 0x01, /* Changed Usage Page (Desktop), */
> > > > > + 0x09, 0x30, /* Changed Usage (X), */
> > > > > + 0x16, 0xF8, 0xF8, /* Logical Minimum (-
> > > > > 1800),
> > > > > */
> > > > > + 0x26, 0x08, 0x07, /* Logical Maximum
> > > > > (1800),
> > > > > */
> > > > > + 0x65, 0x14, /* Unit (Degrees), */
> > > > > + 0x55, 0x0F, /* Unit Exponent (15), */
> > > > > + 0x75, 0x10, /* Report Size (16), */
> > > > > + 0x81, 0x02, /* Input (Variable), */
> > > > > + 0x09, 0x31, /* Changed Usage (Y), */
> > > > > + 0x15, 0x00, /* Logical Minimum (0), */
> > > > > + 0x26, 0xFF, 0x03, /* Logical Maximum
> > > > > (1023),
> > > > > */
> > > > > + 0x75, 0x0C, /* Report Size (12), */
> > > > > + 0x81, 0x02, /* Input (Variable), */
> > > > > + 0x09, 0x32, /* Changed Usage (Z), */
> > > > > + 0x15, 0x00, /* Logical Minimum (0), */
> > > > > + 0x26, 0xFF, 0x03, /* Logical Maximum
> > > > > (1023),
> > > > > */
> > > > > + 0x75, 0x0C, /* Report Size (12), */
> > > > > + 0x81, 0x02, /* Input (Variable), */
> > > > > + 0x05, 0x01, /* Usage Page (Desktop), */
> > > > > + 0x09, 0x39, /* Usage (Hat Switch), */
> > > > > + 0x25, 0x07, /* Logical Maximum (7), */
> > > > > + 0x35, 0x00, /* Physical Minimum (0), */
> > > > > + 0x46, 0x3B, 0x01, /* Physical Maximum
> > > > > (315),
> > > > > */
> > > > > + 0x65, 0x14, /* Unit (Degrees), */
> > > > > + 0x75, 0x04, /* Report Size (4), */
> > > > > + 0x95, 0x01, /* Report Count (1), */
> > > > > + 0x81, 0x02, /* Input (Variable), */
> > > > > + 0x25, 0x01, /* Logical Maximum (1), */
> > > > > + 0x45, 0x01, /* Physical Maximum (1), */
> > > > > + 0x65, 0x00, /* Unit, */
> > > > > + 0x75, 0x01, /* Report Size (1), */
> > > > > + 0x95, 0x03, /* Report Count (3), */
> > > > > + 0x81, 0x01, /* Input (Constant), */
> > > > > + 0x05, 0x09, /* Usage Page (Button), */
> > > > > + 0x19, 0x01, /* Usage Minimum (01h), */
> > > > > + 0x29, 0x11, /* Usage Maximum (11h), */
> > > > > + 0x95, 0x11, /* Report Count (17), */
> > > > > + 0x81, 0x02, /* Input (Variable), */
> > > > > + /* ---- Dial patch starts here ---- */
> > > > > + 0x05, 0x01, /* Usage Page (Desktop), */
> > > > > + 0x09, 0x33, /* Usage (RX), */
> > > > > + 0x75, 0x04, /* Report Size (4), */
> > > > > + 0x95, 0x02, /* Report Count (2), */
> > > > > + 0x15, 0x00, /* Logical Minimum (0), */
> > > > > + 0x25, 0x0b, /* Logical Maximum (b), */
> > > > > + 0x81, 0x02, /* Input (Variable), */
> > > > > + 0x09, 0x35, /* Usage (RZ), */
> > > > > + 0x75, 0x04, /* Report Size (4), */
> > > > > + 0x95, 0x01, /* Report Count (1), */
> > > > > + 0x25, 0x03, /* Logical Maximum (3), */
> > > > > + 0x81, 0x02, /* Input (Variable), */
> > > > > + /* ---- Dial patch ends here ---- */
> > > > > + 0x06, 0x00, 0xFF, /* Usage Page
> > > > > (FF00h),
> > > > > */
> > > > > + 0x09, 0x01, /* Usage (01h), */
> > > > > + 0x75, 0x04, /* Changed Report Size (4), */
> > > > > + 0x95, 0x0D, /* Changed Report Count (13), */
> > > > > + 0x81, 0x02, /* Input (Variable), */
> > > > > + 0xC0, /* End Collection, */
> > > > > + 0xA1, 0x02, /* Collection (Logical), */
> > > > > + 0x09, 0x02, /* Usage (02h), */
> > > > > + 0x75, 0x08, /* Report Size (8), */
> > > > > + 0x95, 0x10, /* Report Count (16), */
> > > > > + 0x91, 0x02, /* Output (Variable), */
> > > > > + 0xC0, /* End Collection, */
> > > > > + 0xC0 /* End Collection */
> > > > > };