xref: /linux/drivers/hid/hid-corsair-void.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
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