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