xref: /linux/drivers/hid/hid-steelseries-arctis.c (revision 148ab873d8194cb44f29474da3b4428fa2e100d1)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  HID driver for Steelseries arctis headsets
4  *
5  *  Copyright (c) 2023 Bastien Nocera
6  *  Copyright (c) 2026 Sriman Achanta
7  */
8 
9 #include <linux/device.h>
10 #include <linux/hid.h>
11 #include <linux/kref.h>
12 #include <linux/slab.h>
13 #include <linux/module.h>
14 #include <linux/power_supply.h>
15 #include <linux/spinlock.h>
16 #include <linux/usb.h>
17 #include <linux/workqueue.h>
18 
19 #include "hid-ids.h"
20 
21 #define SS_CAP_BATTERY			BIT(0)
22 
23 struct steelseries_device;
24 
25 struct steelseries_device_info {
26 	unsigned long capabilities;
27 
28 	u8 sync_interface;
29 	u8 async_interface;
30 
31 	int (*request_status)(struct hid_device *hdev);
32 	void (*parse_status)(struct steelseries_device *sd, u8 *data, int size);
33 };
34 
35 struct steelseries_device {
36 	struct kref refcnt;
37 
38 	struct hid_device *hdev;
39 	const struct steelseries_device_info *info;
40 
41 	struct delayed_work status_work;
42 
43 	struct power_supply_desc battery_desc;
44 	struct power_supply *battery;
45 	bool headset_connected;
46 	u8 battery_capacity;
47 	bool battery_charging;
48 
49 	spinlock_t lock;
50 	bool removed;
51 };
52 
53 static void steelseries_device_release(struct kref *ref)
54 {
55 	struct steelseries_device *sd =
56 		container_of(ref, struct steelseries_device, refcnt);
57 
58 	kfree(sd);
59 }
60 
61 /*
62  * Headset report helpers
63  */
64 
65 static int steelseries_send_report(struct hid_device *hdev, const u8 *data,
66 				    int len, enum hid_report_type type)
67 {
68 	u8 *buf;
69 	int ret;
70 
71 	buf = kmemdup(data, len, GFP_KERNEL);
72 	if (!buf)
73 		return -ENOMEM;
74 
75 	ret = hid_hw_raw_request(hdev, data[0], buf, len, type,
76 				 HID_REQ_SET_REPORT);
77 	kfree(buf);
78 
79 	if (ret < 0)
80 		return ret;
81 	if (ret < len)
82 		return -EIO;
83 
84 	return 0;
85 }
86 
87 static inline int steelseries_send_output_report(struct hid_device *hdev,
88 						  const u8 *data, int len)
89 {
90 	return steelseries_send_report(hdev, data, len, HID_OUTPUT_REPORT);
91 }
92 
93 /*
94  * Headset status request functions
95  */
96 
97 static int steelseries_arctis_1_request_status(struct hid_device *hdev)
98 {
99 	const u8 data[] = { 0x06, 0x12 };
100 
101 	return steelseries_send_output_report(hdev, data, sizeof(data));
102 }
103 
104 static int steelseries_arctis_7_2018_request_status(struct hid_device *hdev)
105 {
106 	const u8 connection[] = { 0x06, 0x14 };
107 	const u8 battery[] = { 0x06, 0x18 };
108 	int ret;
109 
110 	ret = steelseries_send_output_report(hdev, connection, sizeof(connection));
111 	if (ret)
112 		return ret;
113 
114 	return steelseries_send_output_report(hdev, battery, sizeof(battery));
115 }
116 
117 static int steelseries_arctis_9_request_status(struct hid_device *hdev)
118 {
119 	const u8 data[] = { 0x00, 0x20 };
120 
121 	return steelseries_send_output_report(hdev, data, sizeof(data));
122 }
123 
124 static int steelseries_arctis_nova_request_status(struct hid_device *hdev)
125 {
126 	const u8 data[] = { 0x00, 0xb0 };
127 
128 	return steelseries_send_output_report(hdev, data, sizeof(data));
129 }
130 
131 /*
132  * Headset battery helpers
133  */
134 
135 static int battery_capacity_to_level(int capacity)
136 {
137 	if (capacity >= 50)
138 		return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
139 	if (capacity >= 20)
140 		return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
141 	return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
142 }
143 
144 static u8 steelseries_map_capacity(u8 capacity, u8 min_in, u8 max_in)
145 {
146 	if (capacity >= max_in)
147 		return 100;
148 	if (capacity <= min_in)
149 		return 0;
150 	return (capacity - min_in) * 100 / (max_in - min_in);
151 }
152 
153 /*
154  * Headset status parse functions
155  */
156 
157 static void steelseries_arctis_1_parse_status(struct steelseries_device *sd,
158 					      u8 *data, int size)
159 {
160 	/* Only the battery status report echoes the request header. */
161 	if (size < 8 || data[0] != 0x06 || data[1] != 0x12)
162 		return;
163 
164 	sd->headset_connected = (data[2] != 0x01);
165 	sd->battery_capacity = data[3];
166 }
167 
168 static void steelseries_arctis_7_2018_parse_status(struct steelseries_device *sd,
169 						      u8 *data, int size)
170 {
171 	if (size < 3 || data[0] != 0x06)
172 		return;
173 
174 	switch (data[1]) {
175 	case 0x14:
176 		/* 0x03 means that the headset is connected to the transmitter. */
177 		sd->headset_connected = data[2] == 0x03;
178 		break;
179 	case 0x18:
180 		if (!sd->headset_connected)
181 			break;
182 
183 		/* The Arctis 7 sometimes overreports battery. Cap to 100. */
184 		sd->battery_capacity = steelseries_map_capacity(data[2], 0, 100);
185 		break;
186 	}
187 }
188 
189 static void steelseries_arctis_9_parse_status(struct steelseries_device *sd,
190 					      u8 *data, int size)
191 {
192 	if (size < 5)
193 		return;
194 
195 	if (data[0] == 0xaa && data[1] == 0x01) {
196 		sd->headset_connected = true;
197 		sd->battery_charging = (data[4] == 0x01);
198 		sd->battery_capacity = steelseries_map_capacity(data[3], 0x64, 0x9a);
199 	} else {
200 		/* Device off: 0x55 (no status) or 0x03 (stale status). */
201 		sd->headset_connected = false;
202 		sd->battery_charging = false;
203 	}
204 }
205 
206 static void steelseries_arctis_nova_parse_status(struct steelseries_device *sd,
207 						 u8 *data, int size)
208 {
209 	if (size < 2)
210 		return;
211 
212 	switch (data[0]) {
213 	case 0xb0:
214 		if (size < 4)
215 			return;
216 		sd->headset_connected = (data[1] == 0x03);
217 		sd->battery_capacity = data[2];
218 		sd->battery_charging = (data[3] == 0x01);
219 		break;
220 	case 0xb7:
221 		sd->battery_capacity = data[1];
222 		break;
223 	case 0xb9:
224 		sd->headset_connected = (data[1] == 0x03);
225 		break;
226 	case 0xbb:
227 		sd->battery_charging = (data[1] == 0x01);
228 		break;
229 	}
230 }
231 
232 static void steelseries_arctis_nova_7_parse_status(struct steelseries_device *sd,
233 						   u8 *data, int size)
234 {
235 	if (size < 2)
236 		return;
237 
238 	switch (data[0]) {
239 	case 0xb0:
240 		if (size < 4)
241 			return;
242 		sd->headset_connected = (data[1] == 0x03);
243 		sd->battery_capacity = steelseries_map_capacity(data[2], 0, 4);
244 		sd->battery_charging = (data[3] == 0x01);
245 		break;
246 	case 0xb7:
247 		sd->battery_capacity = steelseries_map_capacity(data[1], 0, 4);
248 		break;
249 	case 0xb9:
250 		sd->headset_connected = (data[1] == 0x03);
251 		break;
252 	case 0xbb:
253 		sd->battery_charging = (data[1] == 0x01);
254 		break;
255 	}
256 }
257 
258 /*
259  * Device info definitions
260  */
261 
262 static const struct steelseries_device_info arctis_1_info = {
263 	.sync_interface = 3,
264 	.capabilities = SS_CAP_BATTERY,
265 	.request_status = steelseries_arctis_1_request_status,
266 	.parse_status = steelseries_arctis_1_parse_status,
267 };
268 
269 static const struct steelseries_device_info arctis_7_2018_info = {
270 	.sync_interface = 5,
271 	.capabilities = SS_CAP_BATTERY,
272 	.request_status = steelseries_arctis_7_2018_request_status,
273 	.parse_status = steelseries_arctis_7_2018_parse_status,
274 };
275 
276 static const struct steelseries_device_info arctis_9_info = {
277 	.sync_interface = 0,
278 	.capabilities = SS_CAP_BATTERY,
279 	.request_status = steelseries_arctis_9_request_status,
280 	.parse_status = steelseries_arctis_9_parse_status,
281 };
282 
283 static const struct steelseries_device_info arctis_nova_info = {
284 	.sync_interface = 3,
285 	.async_interface = 5,
286 	.capabilities = SS_CAP_BATTERY,
287 	.request_status = steelseries_arctis_nova_request_status,
288 	.parse_status = steelseries_arctis_nova_parse_status,
289 };
290 
291 static const struct steelseries_device_info arctis_nova_7_info = {
292 	.sync_interface = 3,
293 	.async_interface = 5,
294 	.capabilities = SS_CAP_BATTERY,
295 	.request_status = steelseries_arctis_nova_request_status,
296 	.parse_status = steelseries_arctis_nova_7_parse_status,
297 };
298 
299 /*
300  * Headset wireless status and battery infrastructure
301  */
302 
303 #define STEELSERIES_HEADSET_STATUS_TIMEOUT_MS	3000
304 
305 static void
306 steelseries_headset_set_wireless_status(struct hid_device *hdev,
307 					bool connected)
308 {
309 	struct usb_interface *intf;
310 
311 	if (!hid_is_usb(hdev))
312 		return;
313 
314 	intf = to_usb_interface(hdev->dev.parent);
315 	usb_set_wireless_status(intf, connected ?
316 				USB_WIRELESS_STATUS_CONNECTED :
317 				USB_WIRELESS_STATUS_DISCONNECTED);
318 }
319 
320 #define STEELSERIES_PREFIX "SteelSeries "
321 
322 static int steelseries_battery_get_property(struct power_supply *psy,
323 				enum power_supply_property psp,
324 				union power_supply_propval *val)
325 {
326 	struct steelseries_device *sd = power_supply_get_drvdata(psy);
327 	size_t prefix_len;
328 	int ret = 0;
329 
330 	switch (psp) {
331 	case POWER_SUPPLY_PROP_MODEL_NAME:
332 		val->strval = sd->hdev->name;
333 		while ((prefix_len = str_has_prefix(val->strval, STEELSERIES_PREFIX)))
334 			val->strval += prefix_len;
335 		break;
336 	case POWER_SUPPLY_PROP_MANUFACTURER:
337 		val->strval = "SteelSeries";
338 		break;
339 	case POWER_SUPPLY_PROP_PRESENT:
340 		val->intval = 1;
341 		break;
342 	case POWER_SUPPLY_PROP_STATUS:
343 		if (!sd->headset_connected)
344 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
345 		else if (sd->battery_charging)
346 			val->intval = sd->battery_capacity >= 100 ?
347 				POWER_SUPPLY_STATUS_FULL :
348 				POWER_SUPPLY_STATUS_CHARGING;
349 		else
350 			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
351 		break;
352 	case POWER_SUPPLY_PROP_SCOPE:
353 		val->intval = POWER_SUPPLY_SCOPE_DEVICE;
354 		break;
355 	case POWER_SUPPLY_PROP_CAPACITY:
356 		val->intval = sd->battery_capacity;
357 		break;
358 	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
359 		val->intval = battery_capacity_to_level(sd->battery_capacity);
360 		break;
361 	default:
362 		ret = -EINVAL;
363 		break;
364 	}
365 	return ret;
366 }
367 
368 static enum power_supply_property steelseries_battery_props[] = {
369 	POWER_SUPPLY_PROP_MODEL_NAME,
370 	POWER_SUPPLY_PROP_MANUFACTURER,
371 	POWER_SUPPLY_PROP_PRESENT,
372 	POWER_SUPPLY_PROP_STATUS,
373 	POWER_SUPPLY_PROP_SCOPE,
374 	POWER_SUPPLY_PROP_CAPACITY,
375 	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
376 };
377 
378 /*
379  * Delayed work handlers for status polling
380  */
381 
382 static void steelseries_status_timer_work_handler(struct work_struct *work)
383 {
384 	struct steelseries_device *sd = container_of(
385 		work, struct steelseries_device, status_work.work);
386 	unsigned long flags;
387 
388 	sd->info->request_status(sd->hdev);
389 
390 	spin_lock_irqsave(&sd->lock, flags);
391 	/* Async devices push status events themselves; only poll once. */
392 	if (!sd->removed && !sd->info->async_interface)
393 		schedule_delayed_work(&sd->status_work,
394 				msecs_to_jiffies(STEELSERIES_HEADSET_STATUS_TIMEOUT_MS));
395 	spin_unlock_irqrestore(&sd->lock, flags);
396 }
397 
398 static int steelseries_battery_register(struct steelseries_device *sd)
399 {
400 	struct power_supply_config battery_cfg = { .drv_data = sd, };
401 	struct power_supply *battery;
402 	int ret;
403 
404 	sd->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
405 	sd->battery_desc.properties = steelseries_battery_props;
406 	sd->battery_desc.num_properties = ARRAY_SIZE(steelseries_battery_props);
407 	sd->battery_desc.get_property = steelseries_battery_get_property;
408 	sd->battery_desc.use_for_apm = 0;
409 	sd->battery_desc.name = devm_kasprintf(&sd->hdev->dev, GFP_KERNEL,
410 					       "steelseries_headset_battery_%s",
411 					       sd->hdev->uniq[0] ? sd->hdev->uniq :
412 					       dev_name(&sd->hdev->dev));
413 	if (!sd->battery_desc.name)
414 		return -ENOMEM;
415 
416 	/* avoid the warning of 0% battery while waiting for the first info */
417 	sd->battery_capacity = 100;
418 	sd->battery_charging = false;
419 	sd->headset_connected = false;
420 	steelseries_headset_set_wireless_status(sd->hdev, false);
421 
422 	battery = power_supply_register(&sd->hdev->dev,
423 			&sd->battery_desc, &battery_cfg);
424 	if (IS_ERR(battery)) {
425 		ret = PTR_ERR(battery);
426 		hid_err(sd->hdev,
427 				"%s:power_supply_register failed with error %d\n",
428 				__func__, ret);
429 		return ret;
430 	}
431 	power_supply_powers(battery, &sd->hdev->dev);
432 
433 	/* Assign on success only, so a concurrent raw_event never sees an ERR_PTR. */
434 	sd->battery = battery;
435 
436 	return 0;
437 }
438 
439 static struct hid_driver steelseries_arctis_driver;
440 
441 static struct steelseries_device *
442 steelseries_get_sibling_sd(struct hid_device *hdev, int interface_num)
443 {
444 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
445 	struct usb_device *usb_dev = interface_to_usbdev(intf);
446 	struct usb_interface *sibling_intf;
447 	struct hid_device *sibling_hdev;
448 	struct steelseries_device *sd = NULL;
449 
450 	sibling_intf = usb_ifnum_to_if(usb_dev, interface_num);
451 	if (!sibling_intf)
452 		return NULL;
453 
454 	/*
455 	 * usb_get_intfdata() only yields a hid_device when usbhid is bound;
456 	 * gate on the descriptor class so a non-HID sibling (e.g. a crafted
457 	 * device exposing storage or audio here) is never treated as one.
458 	 */
459 	if (sibling_intf->cur_altsetting->desc.bInterfaceClass != USB_INTERFACE_CLASS_HID)
460 		return NULL;
461 
462 	/*
463 	 * Take the sibling's device lock across the intfdata read and the
464 	 * kref_get so a concurrent unbind cannot free the hid_device underneath
465 	 * us; usbhid leaves intfdata dangling on disconnect, so dev.driver is
466 	 * the reliable "still bound" test under this lock. Use device_trylock()
467 	 * to stay off the lockdep chain of the interface being probed and let
468 	 * the caller retry via -EPROBE_DEFER if the sibling is momentarily busy.
469 	 */
470 	if (!device_trylock(&sibling_intf->dev))
471 		return NULL;
472 	if (sibling_intf->dev.driver) {
473 		sibling_hdev = usb_get_intfdata(sibling_intf);
474 		if (sibling_hdev &&
475 		    sibling_hdev->driver == &steelseries_arctis_driver) {
476 			sd = hid_get_drvdata(sibling_hdev);
477 			if (sd)
478 				kref_get(&sd->refcnt);
479 		}
480 	}
481 	device_unlock(&sibling_intf->dev);
482 
483 	return sd;
484 }
485 
486 static int steelseries_arctis_probe(struct hid_device *hdev,
487 				    const struct hid_device_id *id)
488 {
489 	const struct steelseries_device_info *info =
490 		(const struct steelseries_device_info *)id->driver_data;
491 	struct steelseries_device *sd;
492 	struct usb_interface *intf;
493 	u8 interface_num;
494 	int ret;
495 
496 	if (hid_is_usb(hdev)) {
497 		intf = to_usb_interface(hdev->dev.parent);
498 		interface_num = intf->cur_altsetting->desc.bInterfaceNumber;
499 	} else {
500 		return -ENODEV;
501 	}
502 
503 	ret = hid_parse(hdev);
504 	if (ret)
505 		return ret;
506 
507 	/* Let hid-generic handle non-vendor or unknown interfaces */
508 	if (interface_num != info->sync_interface &&
509 	    (!info->async_interface || interface_num != info->async_interface))
510 		return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
511 
512 	if (interface_num == info->sync_interface) {
513 		sd = kzalloc_obj(*sd);
514 		if (!sd)
515 			return -ENOMEM;
516 
517 		kref_init(&sd->refcnt);
518 		sd->hdev = hdev;
519 		sd->info = info;
520 		spin_lock_init(&sd->lock);
521 		INIT_DELAYED_WORK(&sd->status_work, steelseries_status_timer_work_handler);
522 
523 		ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
524 		if (ret)
525 			goto err_free;
526 
527 		ret = hid_hw_open(hdev);
528 		if (ret)
529 			goto err_stop;
530 
531 		if (info->capabilities & SS_CAP_BATTERY) {
532 			ret = steelseries_battery_register(sd);
533 			if (ret < 0)
534 				hid_warn(hdev, "Failed to register battery: %d\n", ret);
535 		}
536 
537 		/*
538 		 * Publish drvdata only once fully initialised: the async sibling
539 		 * attaches by reading it, so it must never observe a half-built or
540 		 * failed instance. A failed probe never gets here, so the error
541 		 * path below has nothing to unpublish.
542 		 */
543 		hid_set_drvdata(hdev, sd);
544 		schedule_delayed_work(&sd->status_work, msecs_to_jiffies(100));
545 
546 		return 0;
547 	}
548 
549 	/*
550 	 * The async interface shares the steelseries_device created by the
551 	 * sync interface. Defer until the sync interface has probed and
552 	 * published its drvdata.
553 	 */
554 	if (info->async_interface && interface_num == info->async_interface) {
555 		sd = steelseries_get_sibling_sd(hdev, info->sync_interface);
556 		if (!sd)
557 			return -EPROBE_DEFER;
558 
559 		hid_set_drvdata(hdev, sd);
560 
561 		ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
562 		if (ret) {
563 			kref_put(&sd->refcnt, steelseries_device_release);
564 			return ret;
565 		}
566 
567 		ret = hid_hw_open(hdev);
568 		if (ret) {
569 			hid_hw_stop(hdev);
570 			kref_put(&sd->refcnt, steelseries_device_release);
571 			return ret;
572 		}
573 		return 0;
574 	}
575 
576 	return -ENODEV;
577 
578 err_stop:
579 	hid_hw_stop(hdev);
580 err_free:
581 	/* drvdata is unpublished until full success, so no sibling can hold sd. */
582 	kref_put(&sd->refcnt, steelseries_device_release);
583 	return ret;
584 }
585 
586 static void steelseries_arctis_remove(struct hid_device *hdev)
587 {
588 	struct steelseries_device *sd;
589 	struct power_supply *battery;
590 	unsigned long flags;
591 	struct usb_interface *intf;
592 	u8 interface_num;
593 
594 	if (hid_is_usb(hdev)) {
595 		intf = to_usb_interface(hdev->dev.parent);
596 		interface_num = intf->cur_altsetting->desc.bInterfaceNumber;
597 	} else {
598 		return;
599 	}
600 
601 	sd = hid_get_drvdata(hdev);
602 
603 	if (!sd) {
604 		hid_hw_stop(hdev);
605 		return;
606 	}
607 
608 	if (interface_num == sd->info->sync_interface) {
609 		spin_lock_irqsave(&sd->lock, flags);
610 		sd->removed = true;
611 		battery = sd->battery;
612 		sd->battery = NULL;
613 		spin_unlock_irqrestore(&sd->lock, flags);
614 
615 		cancel_delayed_work_sync(&sd->status_work);
616 
617 		if (battery)
618 			power_supply_unregister(battery);
619 	}
620 
621 	hid_hw_close(hdev);
622 	hid_hw_stop(hdev);
623 
624 	kref_put(&sd->refcnt, steelseries_device_release);
625 }
626 
627 static int steelseries_arctis_raw_event(struct hid_device *hdev,
628 				 struct hid_report *report, u8 *data, int size)
629 {
630 	struct steelseries_device *sd = hid_get_drvdata(hdev);
631 	u8 old_capacity;
632 	bool old_connected;
633 	bool old_charging;
634 	bool is_async_interface;
635 	unsigned long flags;
636 
637 	if (!sd)
638 		return 0;
639 
640 	is_async_interface = (hdev != sd->hdev);
641 
642 	spin_lock_irqsave(&sd->lock, flags);
643 
644 	if (sd->removed) {
645 		spin_unlock_irqrestore(&sd->lock, flags);
646 		return 0;
647 	}
648 
649 	old_capacity = sd->battery_capacity;
650 	old_connected = sd->headset_connected;
651 	old_charging = sd->battery_charging;
652 
653 	sd->info->parse_status(sd, data, size);
654 
655 	if (sd->headset_connected != old_connected) {
656 		hid_dbg(hdev,
657 			"Connected status changed from %sconnected to %sconnected\n",
658 			old_connected ? "" : "not ",
659 			sd->headset_connected ? "" : "not ");
660 
661 		if (sd->headset_connected && !old_connected &&
662 		    sd->info->async_interface && is_async_interface)
663 			schedule_delayed_work(&sd->status_work, 0);
664 
665 		if (sd->battery) {
666 			steelseries_headset_set_wireless_status(sd->hdev,
667 							       sd->headset_connected);
668 			power_supply_changed(sd->battery);
669 		}
670 	}
671 
672 	if (sd->battery_capacity != old_capacity) {
673 		hid_dbg(hdev, "Battery capacity changed from %d%% to %d%%\n",
674 			old_capacity, sd->battery_capacity);
675 		if (sd->battery)
676 			power_supply_changed(sd->battery);
677 	}
678 
679 	if (sd->battery_charging != old_charging) {
680 		hid_dbg(hdev,
681 			"Battery charging status changed from %scharging to %scharging\n",
682 			old_charging ? "" : "not ",
683 			sd->battery_charging ? "" : "not ");
684 		if (sd->battery)
685 			power_supply_changed(sd->battery);
686 	}
687 
688 	spin_unlock_irqrestore(&sd->lock, flags);
689 
690 	return 0;
691 }
692 
693 static const struct hid_device_id steelseries_arctis_devices[] = {
694 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
695 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_1_X),
696 	  .driver_data = (unsigned long)&arctis_1_info },
697 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
698 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_7_2018),
699 	  .driver_data = (unsigned long)&arctis_7_2018_info },
700 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
701 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_9),
702 	  .driver_data = (unsigned long)&arctis_9_info },
703 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
704 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_5_X),
705 	  .driver_data = (unsigned long)&arctis_nova_info },
706 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
707 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7),
708 	  .driver_data = (unsigned long)&arctis_nova_7_info },
709 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
710 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X),
711 	  .driver_data = (unsigned long)&arctis_nova_7_info },
712 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
713 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_2),
714 	  .driver_data = (unsigned long)&arctis_nova_7_info },
715 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
716 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_DIABLO),
717 	  .driver_data = (unsigned long)&arctis_nova_7_info },
718 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
719 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_WOW),
720 	  .driver_data = (unsigned long)&arctis_nova_7_info },
721 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
722 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_2026),
723 	  .driver_data = (unsigned long)&arctis_nova_info },
724 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
725 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_P_2026),
726 	  .driver_data = (unsigned long)&arctis_nova_info },
727 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
728 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_2026),
729 	  .driver_data = (unsigned long)&arctis_nova_info },
730 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
731 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_DIABLO_2026),
732 	  .driver_data = (unsigned long)&arctis_nova_info },
733 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
734 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_GEN2),
735 	  .driver_data = (unsigned long)&arctis_nova_info },
736 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
737 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2),
738 	  .driver_data = (unsigned long)&arctis_nova_info },
739 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
740 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2_2),
741 	  .driver_data = (unsigned long)&arctis_nova_info },
742 	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES,
743 			 USB_DEVICE_ID_STEELSERIES_ARCTIS_NOVA_7_X_GEN2_3),
744 	  .driver_data = (unsigned long)&arctis_nova_info },
745 	{}
746 };
747 MODULE_DEVICE_TABLE(hid, steelseries_arctis_devices);
748 
749 static struct hid_driver steelseries_arctis_driver = {
750 	.name = "hid-steelseries-arctis",
751 	.id_table = steelseries_arctis_devices,
752 	.probe = steelseries_arctis_probe,
753 	.remove = steelseries_arctis_remove,
754 	.raw_event = steelseries_arctis_raw_event,
755 };
756 
757 module_hid_driver(steelseries_arctis_driver);
758 MODULE_DESCRIPTION("HID driver for Steelseries arctis headsets");
759 MODULE_LICENSE("GPL");
760 MODULE_AUTHOR("Christian Mayer <git@mayer-bgk.de>");
761 MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
762 MODULE_AUTHOR("Sriman Achanta <srimanachanta@gmail.com>");
763