1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * HID driver for Corsair Void headsets 4 * 5 * Copyright (C) 2023-2024 Stuart Hayhurst 6 */ 7 8 /* -------------------------------------------------------------------------- */ 9 /* Receiver report information: (ID 100) */ 10 /* -------------------------------------------------------------------------- */ 11 /* 12 * When queried, the receiver reponds with 5 bytes to describe the battery 13 * The power button, mute button and moving the mic also trigger this report 14 * This includes power button + mic + connection + battery status and capacity 15 * The information below may not be perfect, it's been gathered through guesses 16 * 17 * 0: REPORT ID 18 * 100 for the battery packet 19 * 20 * 1: POWER BUTTON + (?) 21 * Largest bit is 1 when power button pressed 22 * 23 * 2: BATTERY CAPACITY + MIC STATUS 24 * Battery capacity: 25 * Seems to report ~54 higher than reality when charging 26 * Capped at 100, charging or not 27 * Microphone status: 28 * Largest bit is set to 1 when the mic is physically up 29 * No bits change when the mic is muted, only when physically moved 30 * This report is sent every time the mic is moved, no polling required 31 * 32 * 3: CONNECTION STATUS 33 * 16: Wired headset 34 * 38: Initialising 35 * 49: Lost connection 36 * 51: Disconnected, searching 37 * 52: Disconnected, not searching 38 * 177: Normal 39 * 40 * 4: BATTERY STATUS 41 * 0: Disconnected 42 * 1: Normal 43 * 2: Low 44 * 3: Critical - sent during shutdown 45 * 4: Fully charged 46 * 5: Charging 47 */ 48 /* -------------------------------------------------------------------------- */ 49 50 /* -------------------------------------------------------------------------- */ 51 /* Receiver report information: (ID 102) */ 52 /* -------------------------------------------------------------------------- */ 53 /* 54 * When queried, the recevier responds with 4 bytes to describe the firmware 55 * The first 2 bytes are for the receiver, the second 2 are the headset 56 * The headset firmware version will be 0 if no headset is connected 57 * 58 * 0: Recevier firmware major version 59 * Major version of the receiver's firmware 60 * 61 * 1: Recevier firmware minor version 62 * Minor version of the receiver's firmware 63 * 64 * 2: Headset firmware major version 65 * Major version of the headset's firmware 66 * 67 * 3: Headset firmware minor version 68 * Minor version of the headset's firmware 69 */ 70 /* -------------------------------------------------------------------------- */ 71 72 #include <linux/bitfield.h> 73 #include <linux/bitops.h> 74 #include <linux/device.h> 75 #include <linux/hid.h> 76 #include <linux/module.h> 77 #include <linux/power_supply.h> 78 #include <linux/usb.h> 79 #include <linux/workqueue.h> 80 #include <asm/byteorder.h> 81 82 #include "hid-ids.h" 83 84 #define CORSAIR_VOID_DEVICE(id, type) { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, (id)), \ 85 .driver_data = (type) } 86 #define CORSAIR_VOID_WIRELESS_DEVICE(id) CORSAIR_VOID_DEVICE((id), CORSAIR_VOID_WIRELESS) 87 #define CORSAIR_VOID_WIRED_DEVICE(id) CORSAIR_VOID_DEVICE((id), CORSAIR_VOID_WIRED) 88 89 #define CORSAIR_VOID_STATUS_REQUEST_ID 0xC9 90 #define CORSAIR_VOID_NOTIF_REQUEST_ID 0xCA 91 #define CORSAIR_VOID_SIDETONE_REQUEST_ID 0xFF 92 #define CORSAIR_VOID_STATUS_REPORT_ID 0x64 93 #define CORSAIR_VOID_FIRMWARE_REPORT_ID 0x66 94 95 #define CORSAIR_VOID_USB_SIDETONE_REQUEST 0x1 96 #define CORSAIR_VOID_USB_SIDETONE_REQUEST_TYPE 0x21 97 #define CORSAIR_VOID_USB_SIDETONE_VALUE 0x200 98 #define CORSAIR_VOID_USB_SIDETONE_INDEX 0xB00 99 100 #define CORSAIR_VOID_MIC_MASK GENMASK(7, 7) 101 #define CORSAIR_VOID_CAPACITY_MASK GENMASK(6, 0) 102 103 #define CORSAIR_VOID_WIRELESS_CONNECTED 177 104 105 #define CORSAIR_VOID_SIDETONE_MAX_WIRELESS 55 106 #define CORSAIR_VOID_SIDETONE_MAX_WIRED 4096 107 108 enum { 109 CORSAIR_VOID_WIRELESS, 110 CORSAIR_VOID_WIRED, 111 }; 112 113 enum { 114 CORSAIR_VOID_BATTERY_NORMAL = 1, 115 CORSAIR_VOID_BATTERY_LOW = 2, 116 CORSAIR_VOID_BATTERY_CRITICAL = 3, 117 CORSAIR_VOID_BATTERY_CHARGED = 4, 118 CORSAIR_VOID_BATTERY_CHARGING = 5, 119 }; 120 121 enum { 122 CORSAIR_VOID_ADD_BATTERY = 0, 123 CORSAIR_VOID_REMOVE_BATTERY = 1, 124 CORSAIR_VOID_UPDATE_BATTERY = 2, 125 }; 126 127 static enum power_supply_property corsair_void_battery_props[] = { 128 POWER_SUPPLY_PROP_STATUS, 129 POWER_SUPPLY_PROP_PRESENT, 130 POWER_SUPPLY_PROP_CAPACITY, 131 POWER_SUPPLY_PROP_CAPACITY_LEVEL, 132 POWER_SUPPLY_PROP_SCOPE, 133 POWER_SUPPLY_PROP_MODEL_NAME, 134 POWER_SUPPLY_PROP_MANUFACTURER, 135 }; 136 137 struct corsair_void_battery_data { 138 int status; 139 bool present; 140 int capacity; 141 int capacity_level; 142 }; 143 144 struct corsair_void_drvdata { 145 struct hid_device *hid_dev; 146 struct device *dev; 147 148 char *name; 149 bool is_wired; 150 unsigned int sidetone_max; 151 152 struct corsair_void_battery_data battery_data; 153 bool mic_up; 154 bool connected; 155 int fw_receiver_major; 156 int fw_receiver_minor; 157 int fw_headset_major; 158 int fw_headset_minor; 159 160 struct power_supply *battery; 161 struct power_supply_desc battery_desc; 162 163 struct delayed_work delayed_status_work; 164 struct delayed_work delayed_firmware_work; 165 166 unsigned long battery_work_flags; 167 struct work_struct battery_work; 168 }; 169 170 /* 171 * Functions to process receiver data 172 */ 173 174 static void corsair_void_set_wireless_status(struct corsair_void_drvdata *drvdata) 175 { 176 struct usb_interface *usb_if = to_usb_interface(drvdata->dev->parent); 177 178 if (drvdata->is_wired) 179 return; 180 181 usb_set_wireless_status(usb_if, drvdata->connected ? 182 USB_WIRELESS_STATUS_CONNECTED : 183 USB_WIRELESS_STATUS_DISCONNECTED); 184 } 185 186 static void corsair_void_set_unknown_batt(struct corsair_void_drvdata *drvdata) 187 { 188 struct corsair_void_battery_data *battery_data = &drvdata->battery_data; 189 190 battery_data->status = POWER_SUPPLY_STATUS_UNKNOWN; 191 battery_data->present = false; 192 battery_data->capacity = 0; 193 battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; 194 } 195 196 /* Reset data that may change between wireless connections */ 197 static void corsair_void_set_unknown_wireless_data(struct corsair_void_drvdata *drvdata) 198 { 199 /* Only 0 out headset, receiver is always known if relevant */ 200 drvdata->fw_headset_major = 0; 201 drvdata->fw_headset_minor = 0; 202 203 drvdata->connected = false; 204 drvdata->mic_up = false; 205 206 corsair_void_set_wireless_status(drvdata); 207 } 208 209 static void corsair_void_process_receiver(struct corsair_void_drvdata *drvdata, 210 int raw_battery_capacity, 211 int raw_connection_status, 212 int raw_battery_status) 213 { 214 struct corsair_void_battery_data *battery_data = &drvdata->battery_data; 215 struct corsair_void_battery_data orig_battery_data; 216 217 /* Save initial battery data, to compare later */ 218 orig_battery_data = *battery_data; 219 220 /* Headset not connected, or it's wired */ 221 if (raw_connection_status != CORSAIR_VOID_WIRELESS_CONNECTED) 222 goto unknown_battery; 223 224 /* Battery information unavailable */ 225 if (raw_battery_status == 0) 226 goto unknown_battery; 227 228 /* Battery must be connected then */ 229 battery_data->present = true; 230 battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 231 232 /* Set battery status */ 233 switch (raw_battery_status) { 234 case CORSAIR_VOID_BATTERY_NORMAL: 235 case CORSAIR_VOID_BATTERY_LOW: 236 case CORSAIR_VOID_BATTERY_CRITICAL: 237 battery_data->status = POWER_SUPPLY_STATUS_DISCHARGING; 238 if (raw_battery_status == CORSAIR_VOID_BATTERY_LOW) 239 battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 240 else if (raw_battery_status == CORSAIR_VOID_BATTERY_CRITICAL) 241 battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 242 243 break; 244 case CORSAIR_VOID_BATTERY_CHARGED: 245 battery_data->status = POWER_SUPPLY_STATUS_FULL; 246 break; 247 case CORSAIR_VOID_BATTERY_CHARGING: 248 battery_data->status = POWER_SUPPLY_STATUS_CHARGING; 249 break; 250 default: 251 hid_warn(drvdata->hid_dev, "unknown battery status '%d'", 252 raw_battery_status); 253 goto unknown_battery; 254 break; 255 } 256 257 battery_data->capacity = raw_battery_capacity; 258 corsair_void_set_wireless_status(drvdata); 259 260 goto success; 261 unknown_battery: 262 corsair_void_set_unknown_batt(drvdata); 263 success: 264 265 /* Inform power supply if battery values changed */ 266 if (memcmp(&orig_battery_data, battery_data, sizeof(*battery_data))) { 267 set_bit(CORSAIR_VOID_UPDATE_BATTERY, 268 &drvdata->battery_work_flags); 269 schedule_work(&drvdata->battery_work); 270 } 271 } 272 273 /* 274 * Functions to report stored data 275 */ 276 277 static int corsair_void_battery_get_property(struct power_supply *psy, 278 enum power_supply_property prop, 279 union power_supply_propval *val) 280 { 281 struct corsair_void_drvdata *drvdata = power_supply_get_drvdata(psy); 282 283 switch (prop) { 284 case POWER_SUPPLY_PROP_SCOPE: 285 val->intval = POWER_SUPPLY_SCOPE_DEVICE; 286 break; 287 case POWER_SUPPLY_PROP_MODEL_NAME: 288 if (!strncmp(drvdata->hid_dev->name, "Corsair ", 8)) 289 val->strval = drvdata->hid_dev->name + 8; 290 else 291 val->strval = drvdata->hid_dev->name; 292 break; 293 case POWER_SUPPLY_PROP_MANUFACTURER: 294 val->strval = "Corsair"; 295 break; 296 case POWER_SUPPLY_PROP_STATUS: 297 val->intval = drvdata->battery_data.status; 298 break; 299 case POWER_SUPPLY_PROP_PRESENT: 300 val->intval = drvdata->battery_data.present; 301 break; 302 case POWER_SUPPLY_PROP_CAPACITY: 303 val->intval = drvdata->battery_data.capacity; 304 break; 305 case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 306 val->intval = drvdata->battery_data.capacity_level; 307 break; 308 default: 309 return -EINVAL; 310 } 311 312 return 0; 313 } 314 315 static ssize_t microphone_up_show(struct device *dev, 316 struct device_attribute *attr, char *buf) 317 { 318 struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 319 320 if (!drvdata->connected) 321 return -ENODEV; 322 323 return sysfs_emit(buf, "%d\n", drvdata->mic_up); 324 } 325 326 static ssize_t fw_version_receiver_show(struct device *dev, 327 struct device_attribute *attr, 328 char *buf) 329 { 330 struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 331 332 if (drvdata->fw_receiver_major == 0 && drvdata->fw_receiver_minor == 0) 333 return -ENODATA; 334 335 return sysfs_emit(buf, "%d.%02d\n", drvdata->fw_receiver_major, 336 drvdata->fw_receiver_minor); 337 } 338 339 340 static ssize_t fw_version_headset_show(struct device *dev, 341 struct device_attribute *attr, 342 char *buf) 343 { 344 struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 345 346 if (drvdata->fw_headset_major == 0 && drvdata->fw_headset_minor == 0) 347 return -ENODATA; 348 349 return sysfs_emit(buf, "%d.%02d\n", drvdata->fw_headset_major, 350 drvdata->fw_headset_minor); 351 } 352 353 static ssize_t sidetone_max_show(struct device *dev, 354 struct device_attribute *attr, 355 char *buf) 356 { 357 struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 358 359 return sysfs_emit(buf, "%d\n", drvdata->sidetone_max); 360 } 361 362 /* 363 * Functions to send data to headset 364 */ 365 366 static ssize_t send_alert_store(struct device *dev, 367 struct device_attribute *attr, 368 const char *buf, size_t count) 369 { 370 struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 371 struct hid_device *hid_dev = drvdata->hid_dev; 372 unsigned char alert_id; 373 unsigned char *send_buf __free(kfree) = NULL; 374 int ret; 375 376 if (!drvdata->connected || drvdata->is_wired) 377 return -ENODEV; 378 379 /* Only accept 0 or 1 for alert ID */ 380 if (kstrtou8(buf, 10, &alert_id) || alert_id >= 2) 381 return -EINVAL; 382 383 send_buf = kmalloc(3, GFP_KERNEL); 384 if (!send_buf) 385 return -ENOMEM; 386 387 /* Packet format to send alert with ID alert_id */ 388 send_buf[0] = CORSAIR_VOID_NOTIF_REQUEST_ID; 389 send_buf[1] = 0x02; 390 send_buf[2] = alert_id; 391 392 ret = hid_hw_raw_request(hid_dev, CORSAIR_VOID_NOTIF_REQUEST_ID, 393 send_buf, 3, HID_OUTPUT_REPORT, 394 HID_REQ_SET_REPORT); 395 if (ret < 0) 396 hid_warn(hid_dev, "failed to send alert request (reason: %d)", 397 ret); 398 else 399 ret = count; 400 401 return ret; 402 } 403 404 static int corsair_void_set_sidetone_wired(struct device *dev, const char *buf, 405 unsigned int sidetone) 406 { 407 struct usb_interface *usb_if = to_usb_interface(dev->parent); 408 struct usb_device *usb_dev = interface_to_usbdev(usb_if); 409 410 /* Packet format to set sidetone for wired headsets */ 411 __le16 sidetone_le = cpu_to_le16(sidetone); 412 413 return usb_control_msg_send(usb_dev, 0, 414 CORSAIR_VOID_USB_SIDETONE_REQUEST, 415 CORSAIR_VOID_USB_SIDETONE_REQUEST_TYPE, 416 CORSAIR_VOID_USB_SIDETONE_VALUE, 417 CORSAIR_VOID_USB_SIDETONE_INDEX, 418 &sidetone_le, 2, USB_CTRL_SET_TIMEOUT, 419 GFP_KERNEL); 420 } 421 422 static int corsair_void_set_sidetone_wireless(struct device *dev, 423 const char *buf, 424 unsigned char sidetone) 425 { 426 struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 427 struct hid_device *hid_dev = drvdata->hid_dev; 428 unsigned char *send_buf __free(kfree) = NULL; 429 430 send_buf = kmalloc(12, GFP_KERNEL); 431 if (!send_buf) 432 return -ENOMEM; 433 434 /* Packet format to set sidetone for wireless headsets */ 435 send_buf[0] = CORSAIR_VOID_SIDETONE_REQUEST_ID; 436 send_buf[1] = 0x0B; 437 send_buf[2] = 0x00; 438 send_buf[3] = 0xFF; 439 send_buf[4] = 0x04; 440 send_buf[5] = 0x0E; 441 send_buf[6] = 0xFF; 442 send_buf[7] = 0x05; 443 send_buf[8] = 0x01; 444 send_buf[9] = 0x04; 445 send_buf[10] = 0x00; 446 send_buf[11] = sidetone + 200; 447 448 return hid_hw_raw_request(hid_dev, CORSAIR_VOID_SIDETONE_REQUEST_ID, 449 send_buf, 12, HID_FEATURE_REPORT, 450 HID_REQ_SET_REPORT); 451 } 452 453 static ssize_t set_sidetone_store(struct device *dev, 454 struct device_attribute *attr, 455 const char *buf, size_t count) 456 { 457 struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 458 struct hid_device *hid_dev = drvdata->hid_dev; 459 unsigned int sidetone; 460 int ret; 461 462 if (!drvdata->connected) 463 return -ENODEV; 464 465 /* sidetone must be between 0 and drvdata->sidetone_max inclusive */ 466 if (kstrtouint(buf, 10, &sidetone) || sidetone > drvdata->sidetone_max) 467 return -EINVAL; 468 469 if (drvdata->is_wired) 470 ret = corsair_void_set_sidetone_wired(dev, buf, sidetone); 471 else 472 ret = corsair_void_set_sidetone_wireless(dev, buf, sidetone); 473 474 if (ret < 0) 475 hid_warn(hid_dev, "failed to send sidetone (reason: %d)", ret); 476 else 477 ret = count; 478 479 return ret; 480 } 481 482 static int corsair_void_request_status(struct hid_device *hid_dev, int id) 483 { 484 unsigned char *send_buf __free(kfree) = NULL; 485 486 send_buf = kmalloc(2, GFP_KERNEL); 487 if (!send_buf) 488 return -ENOMEM; 489 490 /* Packet format to request data item (status / firmware) refresh */ 491 send_buf[0] = CORSAIR_VOID_STATUS_REQUEST_ID; 492 send_buf[1] = id; 493 494 /* Send request for data refresh */ 495 return hid_hw_raw_request(hid_dev, CORSAIR_VOID_STATUS_REQUEST_ID, 496 send_buf, 2, HID_OUTPUT_REPORT, 497 HID_REQ_SET_REPORT); 498 } 499 500 /* 501 * Headset connect / disconnect handlers and work handlers 502 */ 503 504 static void corsair_void_status_work_handler(struct work_struct *work) 505 { 506 struct corsair_void_drvdata *drvdata; 507 struct delayed_work *delayed_work; 508 int battery_ret; 509 510 delayed_work = to_delayed_work(work); 511 drvdata = container_of(delayed_work, struct corsair_void_drvdata, 512 delayed_status_work); 513 514 battery_ret = corsair_void_request_status(drvdata->hid_dev, 515 CORSAIR_VOID_STATUS_REPORT_ID); 516 if (battery_ret < 0) { 517 hid_warn(drvdata->hid_dev, 518 "failed to request battery (reason: %d)", battery_ret); 519 } 520 } 521 522 static void corsair_void_firmware_work_handler(struct work_struct *work) 523 { 524 struct corsair_void_drvdata *drvdata; 525 struct delayed_work *delayed_work; 526 int firmware_ret; 527 528 delayed_work = to_delayed_work(work); 529 drvdata = container_of(delayed_work, struct corsair_void_drvdata, 530 delayed_firmware_work); 531 532 firmware_ret = corsair_void_request_status(drvdata->hid_dev, 533 CORSAIR_VOID_FIRMWARE_REPORT_ID); 534 if (firmware_ret < 0) { 535 hid_warn(drvdata->hid_dev, 536 "failed to request firmware (reason: %d)", firmware_ret); 537 } 538 539 } 540 541 static void corsair_void_add_battery(struct corsair_void_drvdata *drvdata) 542 { 543 struct power_supply_config psy_cfg = {}; 544 struct power_supply *new_supply; 545 546 if (drvdata->battery) 547 return; 548 549 psy_cfg.drv_data = drvdata; 550 new_supply = power_supply_register(drvdata->dev, 551 &drvdata->battery_desc, 552 &psy_cfg); 553 554 if (IS_ERR(new_supply)) { 555 hid_err(drvdata->hid_dev, 556 "failed to register battery '%s' (reason: %pe)\n", 557 drvdata->battery_desc.name, new_supply); 558 return; 559 } 560 561 if (power_supply_powers(new_supply, drvdata->dev)) { 562 power_supply_unregister(new_supply); 563 return; 564 } 565 566 drvdata->battery = new_supply; 567 } 568 569 static void corsair_void_battery_work_handler(struct work_struct *work) 570 { 571 struct corsair_void_drvdata *drvdata = container_of(work, 572 struct corsair_void_drvdata, battery_work); 573 574 bool add_battery = test_and_clear_bit(CORSAIR_VOID_ADD_BATTERY, 575 &drvdata->battery_work_flags); 576 bool remove_battery = test_and_clear_bit(CORSAIR_VOID_REMOVE_BATTERY, 577 &drvdata->battery_work_flags); 578 bool update_battery = test_and_clear_bit(CORSAIR_VOID_UPDATE_BATTERY, 579 &drvdata->battery_work_flags); 580 581 if (add_battery && !remove_battery) { 582 corsair_void_add_battery(drvdata); 583 } else if (remove_battery && !add_battery && drvdata->battery) { 584 power_supply_unregister(drvdata->battery); 585 drvdata->battery = NULL; 586 } 587 588 if (update_battery && drvdata->battery) 589 power_supply_changed(drvdata->battery); 590 591 } 592 593 static void corsair_void_headset_connected(struct corsair_void_drvdata *drvdata) 594 { 595 set_bit(CORSAIR_VOID_ADD_BATTERY, &drvdata->battery_work_flags); 596 schedule_work(&drvdata->battery_work); 597 schedule_delayed_work(&drvdata->delayed_firmware_work, 598 msecs_to_jiffies(100)); 599 } 600 601 static void corsair_void_headset_disconnected(struct corsair_void_drvdata *drvdata) 602 { 603 set_bit(CORSAIR_VOID_REMOVE_BATTERY, &drvdata->battery_work_flags); 604 schedule_work(&drvdata->battery_work); 605 606 corsair_void_set_unknown_wireless_data(drvdata); 607 corsair_void_set_unknown_batt(drvdata); 608 } 609 610 /* 611 * Driver setup, probing and HID event handling 612 */ 613 614 static DEVICE_ATTR_RO(fw_version_receiver); 615 static DEVICE_ATTR_RO(fw_version_headset); 616 static DEVICE_ATTR_RO(microphone_up); 617 static DEVICE_ATTR_RO(sidetone_max); 618 619 static DEVICE_ATTR_WO(send_alert); 620 static DEVICE_ATTR_WO(set_sidetone); 621 622 static struct attribute *corsair_void_attrs[] = { 623 &dev_attr_fw_version_receiver.attr, 624 &dev_attr_fw_version_headset.attr, 625 &dev_attr_microphone_up.attr, 626 &dev_attr_send_alert.attr, 627 &dev_attr_set_sidetone.attr, 628 &dev_attr_sidetone_max.attr, 629 NULL, 630 }; 631 632 static const struct attribute_group corsair_void_attr_group = { 633 .attrs = corsair_void_attrs, 634 }; 635 636 static int corsair_void_probe(struct hid_device *hid_dev, 637 const struct hid_device_id *hid_id) 638 { 639 int ret; 640 struct corsair_void_drvdata *drvdata; 641 char *name; 642 643 if (!hid_is_usb(hid_dev)) 644 return -EINVAL; 645 646 drvdata = devm_kzalloc(&hid_dev->dev, sizeof(*drvdata), 647 GFP_KERNEL); 648 if (!drvdata) 649 return -ENOMEM; 650 651 hid_set_drvdata(hid_dev, drvdata); 652 dev_set_drvdata(&hid_dev->dev, drvdata); 653 654 drvdata->dev = &hid_dev->dev; 655 drvdata->hid_dev = hid_dev; 656 drvdata->is_wired = hid_id->driver_data == CORSAIR_VOID_WIRED; 657 658 drvdata->sidetone_max = CORSAIR_VOID_SIDETONE_MAX_WIRELESS; 659 if (drvdata->is_wired) 660 drvdata->sidetone_max = CORSAIR_VOID_SIDETONE_MAX_WIRED; 661 662 /* Set initial values for no wireless headset attached */ 663 /* If a headset is attached, it'll be prompted later */ 664 corsair_void_set_unknown_wireless_data(drvdata); 665 corsair_void_set_unknown_batt(drvdata); 666 667 /* Receiver version won't be reset after init */ 668 /* Headset version already set via set_unknown_wireless_data */ 669 drvdata->fw_receiver_major = 0; 670 drvdata->fw_receiver_minor = 0; 671 672 ret = hid_parse(hid_dev); 673 if (ret) { 674 hid_err(hid_dev, "parse failed (reason: %d)\n", ret); 675 return ret; 676 } 677 678 name = devm_kasprintf(drvdata->dev, GFP_KERNEL, 679 "corsair-void-%d-battery", hid_dev->id); 680 if (!name) 681 return -ENOMEM; 682 683 drvdata->battery_desc.name = name; 684 drvdata->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; 685 drvdata->battery_desc.properties = corsair_void_battery_props; 686 drvdata->battery_desc.num_properties = ARRAY_SIZE(corsair_void_battery_props); 687 drvdata->battery_desc.get_property = corsair_void_battery_get_property; 688 689 drvdata->battery = NULL; 690 INIT_WORK(&drvdata->battery_work, corsair_void_battery_work_handler); 691 692 ret = sysfs_create_group(&hid_dev->dev.kobj, &corsair_void_attr_group); 693 if (ret) 694 return ret; 695 696 /* Any failures after here will need to call hid_hw_stop */ 697 ret = hid_hw_start(hid_dev, HID_CONNECT_DEFAULT); 698 if (ret) { 699 hid_err(hid_dev, "hid_hw_start failed (reason: %d)\n", ret); 700 goto failed_after_sysfs; 701 } 702 703 /* Refresh battery data, in case wireless headset is already connected */ 704 INIT_DELAYED_WORK(&drvdata->delayed_status_work, 705 corsair_void_status_work_handler); 706 schedule_delayed_work(&drvdata->delayed_status_work, 707 msecs_to_jiffies(100)); 708 709 /* Refresh firmware versions */ 710 INIT_DELAYED_WORK(&drvdata->delayed_firmware_work, 711 corsair_void_firmware_work_handler); 712 schedule_delayed_work(&drvdata->delayed_firmware_work, 713 msecs_to_jiffies(100)); 714 715 return 0; 716 717 failed_after_sysfs: 718 sysfs_remove_group(&hid_dev->dev.kobj, &corsair_void_attr_group); 719 return ret; 720 } 721 722 static void corsair_void_remove(struct hid_device *hid_dev) 723 { 724 struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev); 725 726 hid_hw_stop(hid_dev); 727 cancel_work_sync(&drvdata->battery_work); 728 if (drvdata->battery) 729 power_supply_unregister(drvdata->battery); 730 731 cancel_delayed_work_sync(&drvdata->delayed_status_work); 732 cancel_delayed_work_sync(&drvdata->delayed_firmware_work); 733 sysfs_remove_group(&hid_dev->dev.kobj, &corsair_void_attr_group); 734 } 735 736 static int corsair_void_raw_event(struct hid_device *hid_dev, 737 struct hid_report *hid_report, 738 u8 *data, int size) 739 { 740 struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev); 741 bool was_connected = drvdata->connected; 742 743 /* Description of packets are documented at the top of this file */ 744 if (hid_report->id == CORSAIR_VOID_STATUS_REPORT_ID) { 745 drvdata->mic_up = FIELD_GET(CORSAIR_VOID_MIC_MASK, data[2]); 746 drvdata->connected = (data[3] == CORSAIR_VOID_WIRELESS_CONNECTED) || 747 drvdata->is_wired; 748 749 corsair_void_process_receiver(drvdata, 750 FIELD_GET(CORSAIR_VOID_CAPACITY_MASK, data[2]), 751 data[3], data[4]); 752 } else if (hid_report->id == CORSAIR_VOID_FIRMWARE_REPORT_ID) { 753 drvdata->fw_receiver_major = data[1]; 754 drvdata->fw_receiver_minor = data[2]; 755 drvdata->fw_headset_major = data[3]; 756 drvdata->fw_headset_minor = data[4]; 757 } 758 759 /* Handle wireless headset connect / disconnect */ 760 if ((was_connected != drvdata->connected) && !drvdata->is_wired) { 761 if (drvdata->connected) 762 corsair_void_headset_connected(drvdata); 763 else 764 corsair_void_headset_disconnected(drvdata); 765 } 766 767 return 0; 768 } 769 770 static const struct hid_device_id corsair_void_devices[] = { 771 /* Corsair Void Wireless */ 772 CORSAIR_VOID_WIRELESS_DEVICE(0x0a0c), 773 CORSAIR_VOID_WIRELESS_DEVICE(0x0a2b), 774 CORSAIR_VOID_WIRELESS_DEVICE(0x1b23), 775 CORSAIR_VOID_WIRELESS_DEVICE(0x1b25), 776 CORSAIR_VOID_WIRELESS_DEVICE(0x1b27), 777 778 /* Corsair Void USB */ 779 CORSAIR_VOID_WIRED_DEVICE(0x0a0f), 780 CORSAIR_VOID_WIRED_DEVICE(0x1b1c), 781 CORSAIR_VOID_WIRED_DEVICE(0x1b29), 782 CORSAIR_VOID_WIRED_DEVICE(0x1b2a), 783 784 /* Corsair Void Surround */ 785 CORSAIR_VOID_WIRED_DEVICE(0x0a30), 786 CORSAIR_VOID_WIRED_DEVICE(0x0a31), 787 788 /* Corsair Void Pro Wireless */ 789 CORSAIR_VOID_WIRELESS_DEVICE(0x0a14), 790 CORSAIR_VOID_WIRELESS_DEVICE(0x0a16), 791 CORSAIR_VOID_WIRELESS_DEVICE(0x0a1a), 792 793 /* Corsair Void Pro USB */ 794 CORSAIR_VOID_WIRED_DEVICE(0x0a17), 795 CORSAIR_VOID_WIRED_DEVICE(0x0a1d), 796 797 /* Corsair Void Pro Surround */ 798 CORSAIR_VOID_WIRED_DEVICE(0x0a18), 799 CORSAIR_VOID_WIRED_DEVICE(0x0a1e), 800 CORSAIR_VOID_WIRED_DEVICE(0x0a1f), 801 802 /* Corsair Void Elite Wireless */ 803 CORSAIR_VOID_WIRELESS_DEVICE(0x0a51), 804 CORSAIR_VOID_WIRELESS_DEVICE(0x0a55), 805 CORSAIR_VOID_WIRELESS_DEVICE(0x0a75), 806 807 /* Corsair Void Elite USB */ 808 CORSAIR_VOID_WIRED_DEVICE(0x0a52), 809 CORSAIR_VOID_WIRED_DEVICE(0x0a56), 810 811 /* Corsair Void Elite Surround */ 812 CORSAIR_VOID_WIRED_DEVICE(0x0a53), 813 CORSAIR_VOID_WIRED_DEVICE(0x0a57), 814 815 {} 816 }; 817 818 MODULE_DEVICE_TABLE(hid, corsair_void_devices); 819 820 static struct hid_driver corsair_void_driver = { 821 .name = "hid-corsair-void", 822 .id_table = corsair_void_devices, 823 .probe = corsair_void_probe, 824 .remove = corsair_void_remove, 825 .raw_event = corsair_void_raw_event, 826 }; 827 828 module_hid_driver(corsair_void_driver); 829 830 MODULE_LICENSE("GPL"); 831 MODULE_AUTHOR("Stuart Hayhurst <stuart.a.hayhurst@gmail.com>"); 832 MODULE_DESCRIPTION("HID driver for Corsair Void headsets"); 833