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