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