Thread (1 message) 1 message, 1 author, 2026-02-26

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.

Cheers
quoted
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                      */
 };
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help