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 = container_of(work, struct 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 = container_of(work, struct 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: %ld)\n", 557 drvdata->battery_desc.name, 558 PTR_ERR(new_supply)); 559 return; 560 } 561 562 if (power_supply_powers(new_supply, drvdata->dev)) { 563 power_supply_unregister(new_supply); 564 return; 565 } 566 567 drvdata->battery = new_supply; 568 } 569 570 static void corsair_void_battery_work_handler(struct work_struct *work) 571 { 572 struct corsair_void_drvdata *drvdata = container_of(work, 573 struct corsair_void_drvdata, battery_work); 574 575 bool add_battery = test_and_clear_bit(CORSAIR_VOID_ADD_BATTERY, 576 &drvdata->battery_work_flags); 577 bool remove_battery = test_and_clear_bit(CORSAIR_VOID_REMOVE_BATTERY, 578 &drvdata->battery_work_flags); 579 bool update_battery = test_and_clear_bit(CORSAIR_VOID_UPDATE_BATTERY, 580 &drvdata->battery_work_flags); 581 582 if (add_battery && !remove_battery) { 583 corsair_void_add_battery(drvdata); 584 } else if (remove_battery && !add_battery && drvdata->battery) { 585 power_supply_unregister(drvdata->battery); 586 drvdata->battery = NULL; 587 } 588 589 if (update_battery && drvdata->battery) 590 power_supply_changed(drvdata->battery); 591 592 } 593 594 static void corsair_void_headset_connected(struct corsair_void_drvdata *drvdata) 595 { 596 set_bit(CORSAIR_VOID_ADD_BATTERY, &drvdata->battery_work_flags); 597 schedule_work(&drvdata->battery_work); 598 schedule_delayed_work(&drvdata->delayed_firmware_work, 599 msecs_to_jiffies(100)); 600 } 601 602 static void corsair_void_headset_disconnected(struct corsair_void_drvdata *drvdata) 603 { 604 set_bit(CORSAIR_VOID_REMOVE_BATTERY, &drvdata->battery_work_flags); 605 schedule_work(&drvdata->battery_work); 606 607 corsair_void_set_unknown_wireless_data(drvdata); 608 corsair_void_set_unknown_batt(drvdata); 609 } 610 611 /* 612 * Driver setup, probing and HID event handling 613 */ 614 615 static DEVICE_ATTR_RO(fw_version_receiver); 616 static DEVICE_ATTR_RO(fw_version_headset); 617 static DEVICE_ATTR_RO(microphone_up); 618 static DEVICE_ATTR_RO(sidetone_max); 619 620 static DEVICE_ATTR_WO(send_alert); 621 static DEVICE_ATTR_WO(set_sidetone); 622 623 static struct attribute *corsair_void_attrs[] = { 624 &dev_attr_fw_version_receiver.attr, 625 &dev_attr_fw_version_headset.attr, 626 &dev_attr_microphone_up.attr, 627 &dev_attr_send_alert.attr, 628 &dev_attr_set_sidetone.attr, 629 &dev_attr_sidetone_max.attr, 630 NULL, 631 }; 632 633 static const struct attribute_group corsair_void_attr_group = { 634 .attrs = corsair_void_attrs, 635 }; 636 637 static int corsair_void_probe(struct hid_device *hid_dev, 638 const struct hid_device_id *hid_id) 639 { 640 int ret; 641 struct corsair_void_drvdata *drvdata; 642 char *name; 643 644 if (!hid_is_usb(hid_dev)) 645 return -EINVAL; 646 647 drvdata = devm_kzalloc(&hid_dev->dev, sizeof(*drvdata), 648 GFP_KERNEL); 649 if (!drvdata) 650 return -ENOMEM; 651 652 hid_set_drvdata(hid_dev, drvdata); 653 dev_set_drvdata(&hid_dev->dev, drvdata); 654 655 drvdata->dev = &hid_dev->dev; 656 drvdata->hid_dev = hid_dev; 657 drvdata->is_wired = hid_id->driver_data == CORSAIR_VOID_WIRED; 658 659 drvdata->sidetone_max = CORSAIR_VOID_SIDETONE_MAX_WIRELESS; 660 if (drvdata->is_wired) 661 drvdata->sidetone_max = CORSAIR_VOID_SIDETONE_MAX_WIRED; 662 663 /* Set initial values for no wireless headset attached */ 664 /* If a headset is attached, it'll be prompted later */ 665 corsair_void_set_unknown_wireless_data(drvdata); 666 corsair_void_set_unknown_batt(drvdata); 667 668 /* Receiver version won't be reset after init */ 669 /* Headset version already set via set_unknown_wireless_data */ 670 drvdata->fw_receiver_major = 0; 671 drvdata->fw_receiver_minor = 0; 672 673 ret = hid_parse(hid_dev); 674 if (ret) { 675 hid_err(hid_dev, "parse failed (reason: %d)\n", ret); 676 return ret; 677 } 678 679 name = devm_kasprintf(drvdata->dev, GFP_KERNEL, 680 "corsair-void-%d-battery", hid_dev->id); 681 if (!name) 682 return -ENOMEM; 683 684 drvdata->battery_desc.name = name; 685 drvdata->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; 686 drvdata->battery_desc.properties = corsair_void_battery_props; 687 drvdata->battery_desc.num_properties = ARRAY_SIZE(corsair_void_battery_props); 688 drvdata->battery_desc.get_property = corsair_void_battery_get_property; 689 690 drvdata->battery = NULL; 691 INIT_WORK(&drvdata->battery_work, corsair_void_battery_work_handler); 692 693 ret = sysfs_create_group(&hid_dev->dev.kobj, &corsair_void_attr_group); 694 if (ret) 695 return ret; 696 697 /* Any failures after here will need to call hid_hw_stop */ 698 ret = hid_hw_start(hid_dev, HID_CONNECT_DEFAULT); 699 if (ret) { 700 hid_err(hid_dev, "hid_hw_start failed (reason: %d)\n", ret); 701 goto failed_after_sysfs; 702 } 703 704 /* Refresh battery data, in case wireless headset is already connected */ 705 INIT_DELAYED_WORK(&drvdata->delayed_status_work, 706 corsair_void_status_work_handler); 707 schedule_delayed_work(&drvdata->delayed_status_work, 708 msecs_to_jiffies(100)); 709 710 /* Refresh firmware versions */ 711 INIT_DELAYED_WORK(&drvdata->delayed_firmware_work, 712 corsair_void_firmware_work_handler); 713 schedule_delayed_work(&drvdata->delayed_firmware_work, 714 msecs_to_jiffies(100)); 715 716 return 0; 717 718 failed_after_sysfs: 719 sysfs_remove_group(&hid_dev->dev.kobj, &corsair_void_attr_group); 720 return ret; 721 } 722 723 static void corsair_void_remove(struct hid_device *hid_dev) 724 { 725 struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev); 726 727 hid_hw_stop(hid_dev); 728 cancel_work_sync(&drvdata->battery_work); 729 if (drvdata->battery) 730 power_supply_unregister(drvdata->battery); 731 732 cancel_delayed_work_sync(&drvdata->delayed_status_work); 733 cancel_delayed_work_sync(&drvdata->delayed_firmware_work); 734 sysfs_remove_group(&hid_dev->dev.kobj, &corsair_void_attr_group); 735 } 736 737 static int corsair_void_raw_event(struct hid_device *hid_dev, 738 struct hid_report *hid_report, 739 u8 *data, int size) 740 { 741 struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev); 742 bool was_connected = drvdata->connected; 743 744 /* Description of packets are documented at the top of this file */ 745 if (hid_report->id == CORSAIR_VOID_STATUS_REPORT_ID) { 746 drvdata->mic_up = FIELD_GET(CORSAIR_VOID_MIC_MASK, data[2]); 747 drvdata->connected = (data[3] == CORSAIR_VOID_WIRELESS_CONNECTED) || 748 drvdata->is_wired; 749 750 corsair_void_process_receiver(drvdata, 751 FIELD_GET(CORSAIR_VOID_CAPACITY_MASK, data[2]), 752 data[3], data[4]); 753 } else if (hid_report->id == CORSAIR_VOID_FIRMWARE_REPORT_ID) { 754 drvdata->fw_receiver_major = data[1]; 755 drvdata->fw_receiver_minor = data[2]; 756 drvdata->fw_headset_major = data[3]; 757 drvdata->fw_headset_minor = data[4]; 758 } 759 760 /* Handle wireless headset connect / disconnect */ 761 if ((was_connected != drvdata->connected) && !drvdata->is_wired) { 762 if (drvdata->connected) 763 corsair_void_headset_connected(drvdata); 764 else 765 corsair_void_headset_disconnected(drvdata); 766 } 767 768 return 0; 769 } 770 771 static const struct hid_device_id corsair_void_devices[] = { 772 /* Corsair Void Wireless */ 773 CORSAIR_VOID_WIRELESS_DEVICE(0x0a0c), 774 CORSAIR_VOID_WIRELESS_DEVICE(0x0a2b), 775 CORSAIR_VOID_WIRELESS_DEVICE(0x1b23), 776 CORSAIR_VOID_WIRELESS_DEVICE(0x1b25), 777 CORSAIR_VOID_WIRELESS_DEVICE(0x1b27), 778 779 /* Corsair Void USB */ 780 CORSAIR_VOID_WIRED_DEVICE(0x0a0f), 781 CORSAIR_VOID_WIRED_DEVICE(0x1b1c), 782 CORSAIR_VOID_WIRED_DEVICE(0x1b29), 783 CORSAIR_VOID_WIRED_DEVICE(0x1b2a), 784 785 /* Corsair Void Surround */ 786 CORSAIR_VOID_WIRED_DEVICE(0x0a30), 787 CORSAIR_VOID_WIRED_DEVICE(0x0a31), 788 789 /* Corsair Void Pro Wireless */ 790 CORSAIR_VOID_WIRELESS_DEVICE(0x0a14), 791 CORSAIR_VOID_WIRELESS_DEVICE(0x0a16), 792 CORSAIR_VOID_WIRELESS_DEVICE(0x0a1a), 793 794 /* Corsair Void Pro USB */ 795 CORSAIR_VOID_WIRED_DEVICE(0x0a17), 796 CORSAIR_VOID_WIRED_DEVICE(0x0a1d), 797 798 /* Corsair Void Pro Surround */ 799 CORSAIR_VOID_WIRED_DEVICE(0x0a18), 800 CORSAIR_VOID_WIRED_DEVICE(0x0a1e), 801 CORSAIR_VOID_WIRED_DEVICE(0x0a1f), 802 803 /* Corsair Void Elite Wireless */ 804 CORSAIR_VOID_WIRELESS_DEVICE(0x0a51), 805 CORSAIR_VOID_WIRELESS_DEVICE(0x0a55), 806 CORSAIR_VOID_WIRELESS_DEVICE(0x0a75), 807 808 /* Corsair Void Elite USB */ 809 CORSAIR_VOID_WIRED_DEVICE(0x0a52), 810 CORSAIR_VOID_WIRED_DEVICE(0x0a56), 811 812 /* Corsair Void Elite Surround */ 813 CORSAIR_VOID_WIRED_DEVICE(0x0a53), 814 CORSAIR_VOID_WIRED_DEVICE(0x0a57), 815 816 {} 817 }; 818 819 MODULE_DEVICE_TABLE(hid, corsair_void_devices); 820 821 static struct hid_driver corsair_void_driver = { 822 .name = "hid-corsair-void", 823 .id_table = corsair_void_devices, 824 .probe = corsair_void_probe, 825 .remove = corsair_void_remove, 826 .raw_event = corsair_void_raw_event, 827 }; 828 829 module_hid_driver(corsair_void_driver); 830 831 MODULE_LICENSE("GPL"); 832 MODULE_AUTHOR("Stuart Hayhurst <stuart.a.hayhurst@gmail.com>"); 833 MODULE_DESCRIPTION("HID driver for Corsair Void headsets"); 834