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