mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-28 01:43:47 -04:00
HID: steelseries: Add support for Arctis Nova 5X and Nova 7 families
The Arctis Nova 5X, Nova 7 Gen2, and Nova 7 2026 refresh headsets answer status polls, but also send unsolicited battery and connection updates on a second HID interface (interface 5). Use that interface through async_interface so the driver does not have to poll. Add request and parse helpers for the Nova status format (0xb0/0xb7/0xb9/0xbb opcodes). The original (pre-Gen2) Arctis Nova 7 family answers the same status opcodes on the same interfaces, but reports battery capacity as a discrete 0-4 level instead of a raw percentage. Add a second parse function that maps that level through steelseries_map_capacity(), and a separate device_info so the two capacity encodings cannot get mixed up. Add the fourteen USB product IDs that share these protocols: 0x2253 Arctis Nova 5X 0x2202 Arctis Nova 7 0x2206 Arctis Nova 7X 0x22a4 Arctis Nova 7X (alternate PID) 0x223a Arctis Nova 7 Diablo 0x227a Arctis Nova 7 World of Warcraft Edition 0x22a1 Arctis Nova 7 2026 0x22a7 Arctis Nova 7P 2026 0x22a5 Arctis Nova 7X 2026 0x22a9 Arctis Nova 7 Diablo 2026 0x227e Arctis Nova 7 Gen 2 0x2258 Arctis Nova 7X Gen 2 0x229e Arctis Nova 7X Gen 2 (alternate PID) 0x22ad Arctis Nova 7X Gen 2 (alternate PID) Signed-off-by: Sriman Achanta <srimanachanta@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
This commit is contained in:
committed by
Jiri Kosina
parent
bebeca20ab
commit
83e70ced0d
@@ -1379,6 +1379,20 @@
|
||||
#define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_1_X 0x12b6
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_9 0x12c2
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_5_X 0x2253
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7 0x2202
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X 0x2206
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_2 0x22a4
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_DIABLO 0x223a
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_WOW 0x227a
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_2026 0x22a1
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_P_2026 0x22a7
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_2026 0x22a5
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_DIABLO_2026 0x22a9
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_GEN2 0x227e
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2 0x2258
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2_2 0x229e
|
||||
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2_3 0x22ad
|
||||
#define USB_DEVICE_ID_STEELSERIES_MSI_KLC 0x1122
|
||||
#define USB_DEVICE_ID_STEELSERIES_MSI_ALC 0x1161
|
||||
|
||||
|
||||
@@ -749,6 +749,20 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_1_X) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_9) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_5_X) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_DIABLO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_WOW) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_2026) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_P_2026) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_2026) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_DIABLO_2026) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_GEN2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2_3) },
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_HID_SUNPLUS)
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
|
||||
|
||||
@@ -108,6 +108,13 @@ static int steelseries_arctis_9_request_status(struct hid_device *hdev)
|
||||
return steelseries_send_output_report(hdev, data, sizeof(data));
|
||||
}
|
||||
|
||||
static int steelseries_arctis_nova_request_status(struct hid_device *hdev)
|
||||
{
|
||||
const u8 data[] = { 0x00, 0xb0 };
|
||||
|
||||
return steelseries_send_output_report(hdev, data, sizeof(data));
|
||||
}
|
||||
|
||||
/*
|
||||
* Headset battery helpers
|
||||
*/
|
||||
@@ -162,6 +169,58 @@ static void steelseries_arctis_9_parse_status(struct steelseries_device *sd,
|
||||
}
|
||||
}
|
||||
|
||||
static void steelseries_arctis_nova_parse_status(struct steelseries_device *sd,
|
||||
u8 *data, int size)
|
||||
{
|
||||
if (size < 2)
|
||||
return;
|
||||
|
||||
switch (data[0]) {
|
||||
case 0xb0:
|
||||
if (size < 4)
|
||||
return;
|
||||
sd->headset_connected = (data[1] == 0x03);
|
||||
sd->battery_capacity = data[2];
|
||||
sd->battery_charging = (data[3] == 0x01);
|
||||
break;
|
||||
case 0xb7:
|
||||
sd->battery_capacity = data[1];
|
||||
break;
|
||||
case 0xb9:
|
||||
sd->headset_connected = (data[1] == 0x03);
|
||||
break;
|
||||
case 0xbb:
|
||||
sd->battery_charging = (data[1] == 0x01);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void steelseries_arctis_nova_7_parse_status(struct steelseries_device *sd,
|
||||
u8 *data, int size)
|
||||
{
|
||||
if (size < 2)
|
||||
return;
|
||||
|
||||
switch (data[0]) {
|
||||
case 0xb0:
|
||||
if (size < 4)
|
||||
return;
|
||||
sd->headset_connected = (data[1] == 0x03);
|
||||
sd->battery_capacity = steelseries_map_capacity(data[2], 0, 4);
|
||||
sd->battery_charging = (data[3] == 0x01);
|
||||
break;
|
||||
case 0xb7:
|
||||
sd->battery_capacity = steelseries_map_capacity(data[1], 0, 4);
|
||||
break;
|
||||
case 0xb9:
|
||||
sd->headset_connected = (data[1] == 0x03);
|
||||
break;
|
||||
case 0xbb:
|
||||
sd->battery_charging = (data[1] == 0x01);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Device info definitions
|
||||
*/
|
||||
@@ -180,6 +239,22 @@ static const struct steelseries_device_info arctis_9_info = {
|
||||
.parse_status = steelseries_arctis_9_parse_status,
|
||||
};
|
||||
|
||||
static const struct steelseries_device_info arctis_nova_info = {
|
||||
.sync_interface = 3,
|
||||
.async_interface = 5,
|
||||
.capabilities = SS_CAP_BATTERY,
|
||||
.request_status = steelseries_arctis_nova_request_status,
|
||||
.parse_status = steelseries_arctis_nova_parse_status,
|
||||
};
|
||||
|
||||
static const struct steelseries_device_info arctis_nova_7_info = {
|
||||
.sync_interface = 3,
|
||||
.async_interface = 5,
|
||||
.capabilities = SS_CAP_BATTERY,
|
||||
.request_status = steelseries_arctis_nova_request_status,
|
||||
.parse_status = steelseries_arctis_nova_7_parse_status,
|
||||
};
|
||||
|
||||
/*
|
||||
* Headset wireless status and battery infrastructure
|
||||
*/
|
||||
@@ -581,6 +656,48 @@ static const struct hid_device_id steelseries_arctis_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_9),
|
||||
.driver_data = (unsigned long)&arctis_9_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_5_X),
|
||||
.driver_data = (unsigned long)&arctis_nova_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7),
|
||||
.driver_data = (unsigned long)&arctis_nova_7_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X),
|
||||
.driver_data = (unsigned long)&arctis_nova_7_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_2),
|
||||
.driver_data = (unsigned long)&arctis_nova_7_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_DIABLO),
|
||||
.driver_data = (unsigned long)&arctis_nova_7_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_WOW),
|
||||
.driver_data = (unsigned long)&arctis_nova_7_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_2026),
|
||||
.driver_data = (unsigned long)&arctis_nova_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_P_2026),
|
||||
.driver_data = (unsigned long)&arctis_nova_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_2026),
|
||||
.driver_data = (unsigned long)&arctis_nova_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_DIABLO_2026),
|
||||
.driver_data = (unsigned long)&arctis_nova_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_GEN2),
|
||||
.driver_data = (unsigned long)&arctis_nova_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2),
|
||||
.driver_data = (unsigned long)&arctis_nova_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2_2),
|
||||
.driver_data = (unsigned long)&arctis_nova_info },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
|
||||
USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2_3),
|
||||
.driver_data = (unsigned long)&arctis_nova_info },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, steelseries_arctis_devices);
|
||||
|
||||
Reference in New Issue
Block a user