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                      */
> > > > >  };