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