Re: [PATCH v2 4/4] HID: steelseries: Add support for Arctis headset lineup
From: Bastien Nocera <hadess@hadess.net>
Date: 2026-02-26 10:02:02
Also in:
lkml
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 [off-list ref] wrote:quoted
On Tue, 2026-01-13 at 21:57 -0500, Sriman Achanta wrote:quoted
quoted
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?quoted
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. Cheersquoted
On Mon, Jan 12, 2026 at 8:09 AM Bastien Nocera [off-list ref] wrote:quoted
On Sun, 2026-01-11 at 23:19 -0500, Sriman Achanta wrote:quoted
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.quoted
<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.quoted
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 */ };