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