Re: [PATCH v3 06/18] HID: steelseries: Add ALSA sound card infrastructure
From: Bastien Nocera
Date: Tue Mar 03 2026 - 06:09:17 EST
On Fri, 2026-02-27 at 18:50 -0500, Sriman Achanta wrote:
> Register an ALSA sound card for each supported Arctis headset to
> expose
> headset-specific audio controls to userspace. The card is created in
> steelseries_snd_register() and freed in steelseries_snd_unregister(),
> both guarded by a module compatibility check so that registration
> only
> occurs when both SND and HID_STEELSERIES are built-in or are both
> modules, avoiding a dependency mismatch.
This seems pretty weird, are there examples of that pattern somewhere
else in the kernel source tree?
As we're adding new sound devices, it would probably be nice to CC: the
linux-sound@ mailing-list for their opinion.
>
> The Kconfig entry is updated to add SND as a dependency. Subsequent
> commits build on this infrastructure to register mixer controls.
>
> Signed-off-by: Sriman Achanta <srimanachanta@xxxxxxxxx>
> ---
> drivers/hid/Kconfig | 2 +-
> drivers/hid/hid-steelseries.c | 52
> +++++++++++++++++++++++++++++++++++
> 2 files changed, 53 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 29f05d4b7e30..fcdb5406159a 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -1139,7 +1139,7 @@ config STEAM_FF
>
> config HID_STEELSERIES
> tristate "Steelseries devices support"
> - depends on USB_HID
> + depends on USB_HID && SND
> help
> Support for Steelseries SRW-S1 steering wheel, and the
> Steelseries
> Arctis headset family (Arctis 1, Arctis 7, Arctis 7+, Arctis
> 9,
> diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-
> steelseries.c
> index d8ece8449255..b7f932cde98d 100644
> --- a/drivers/hid/hid-steelseries.c
> +++ b/drivers/hid/hid-steelseries.c
> @@ -16,6 +16,7 @@
> #include <linux/power_supply.h>
> #include <linux/workqueue.h>
> #include <linux/spinlock.h>
> +#include <sound/core.h>
>
> #include "hid-ids.h"
>
> @@ -50,6 +51,8 @@ struct steelseries_device {
> u8 battery_capacity;
> bool battery_charging;
>
> + struct snd_card *card;
> +
> spinlock_t lock;
> bool removed;
> };
> @@ -830,6 +833,43 @@ static int steelseries_battery_register(struct
> steelseries_device *sd)
> return 0;
> }
>
> +#if IS_BUILTIN(CONFIG_SND) || \
> + (IS_MODULE(CONFIG_SND) && IS_MODULE(CONFIG_HID_STEELSERIES))
> +
> +static int steelseries_snd_register(struct steelseries_device *sd)
> +{
> + struct hid_device *hdev = sd->hdev;
> + int ret;
> +
> + ret = snd_card_new(&hdev->dev, -1, "SteelSeries",
> THIS_MODULE,
> + 0, &sd->card);
> + if (ret < 0)
> + return ret;
> +
> + sd->card->private_data = sd;
> + strscpy(sd->card->driver, "SteelSeries");
> + strscpy(sd->card->shortname, hdev->name);
> + snprintf(sd->card->longname, sizeof(sd->card->longname),
> + "%s at USB %s", hdev->name, dev_name(&hdev->dev));
> +
> + ret = snd_card_register(sd->card);
> + if (ret < 0) {
> + snd_card_free(sd->card);
> + sd->card = NULL;
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static void steelseries_snd_unregister(struct steelseries_device
> *sd)
> +{
> + if (sd->card)
> + snd_card_free(sd->card);
> +}
> +
> +#endif
> +
> static int steelseries_raw_event(struct hid_device *hdev,
> struct hid_report *report, u8
> *data, int size)
> {
> @@ -975,6 +1015,13 @@ static int steelseries_probe(struct hid_device
> *hdev,
> hid_warn(hdev, "Failed to register
> battery: %d\n", ret);
> }
>
> +#if IS_BUILTIN(CONFIG_SND) || \
> + (IS_MODULE(CONFIG_SND) && IS_MODULE(CONFIG_HID_STEELSERIES))
> + ret = steelseries_snd_register(sd);
> + if (ret < 0)
> + hid_warn(hdev, "Failed to register sound
> card: %d\n", ret);
> +#endif
> +
> INIT_DELAYED_WORK(&sd->status_work,
> steelseries_status_timer_work_handler);
> schedule_delayed_work(&sd->status_work,
> msecs_to_jiffies(100));
>
> @@ -1048,6 +1095,11 @@ static void steelseries_remove(struct
> hid_device *hdev)
> hid_set_drvdata(sibling, NULL);
> }
>
> +#if IS_BUILTIN(CONFIG_SND) || \
> + (IS_MODULE(CONFIG_SND) && IS_MODULE(CONFIG_HID_STEELSERIES))
> + steelseries_snd_unregister(sd);
> +#endif
> +
> spin_lock_irqsave(&sd->lock, flags);
> sd->removed = true;
> spin_unlock_irqrestore(&sd->lock, flags);