xref: /linux/drivers/hid/hid-lenovo-go-s.c (revision d3c157b4cdffd14604c2d8435e279761c511bac2)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  HID driver for Lenovo Legion Go S devices.
4  *
5  *  Copyright (c) 2026 Derek J. Clark <derekjohn.clark@gmail.com>
6  *  Copyright (c) 2026 Valve Corporation
7  */
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 
10 #include <linux/array_size.h>
11 #include <linux/cleanup.h>
12 #include <linux/completion.h>
13 #include <linux/container_of.h>
14 #include <linux/delay.h>
15 #include <linux/dev_printk.h>
16 #include <linux/device.h>
17 #include <linux/hid.h>
18 #include <linux/jiffies.h>
19 #include <linux/kstrtox.h>
20 #include <linux/led-class-multicolor.h>
21 #include <linux/mutex.h>
22 #include <linux/printk.h>
23 #include <linux/string.h>
24 #include <linux/sysfs.h>
25 #include <linux/types.h>
26 #include <linux/unaligned.h>
27 #include <linux/usb.h>
28 #include <linux/workqueue.h>
29 #include <linux/workqueue_types.h>
30 
31 #include "hid-ids.h"
32 
33 #define GO_S_CFG_INTF_IN	0x84
34 #define GO_S_PACKET_SIZE	64
35 
36 struct gos_cfg_drvdata {
37 	/* MCU General Variables */
38 	struct completion send_cmd_complete;
39 	struct delayed_work gos_cfg_setup;
40 	struct hid_device *hdev;
41 	bool orphan_ack_pending;
42 	struct mutex cfg_mutex; /*ensure single synchronous output report*/
43 	int cmd_status;
44 
45 	/* Gamepad Variables */
46 	u8 gp_auto_sleep_time;
47 	u8 imu_manufacturer;
48 	bool gp_registered;
49 	u8 tp_windows_mode;
50 	u8 tp_manufacturer;
51 	u8 tp_linux_mode;
52 	u8 imu_bypass_en;
53 	u8 imu_sensor_en;
54 	u8 gp_dpad_mode;
55 	u8 gp_poll_rate;
56 	u8 mcu_id[12];
57 	u8 mouse_step;
58 	u8 tp_version;
59 	u8 gp_mode;
60 	u8 os_mode;
61 	u8 tp_en;
62 
63 	/* RGB Variables */
64 	struct led_classdev_mc led_mc;
65 	bool rgb_registered;
66 	u8 rgb_profile;
67 	u8 rgb_effect;
68 	u8 rgb_speed;
69 	u8 rgb_mode;
70 	u8 rgb_en;
71 };
72 
73 struct gos_cfg_attr {
74 	u8 index;
75 };
76 
77 struct command_report {
78 	u8 cmd;
79 	u8 sub_cmd;
80 	u8 data[63];
81 } __packed;
82 
83 struct version_report {
84 	u8 cmd;
85 	u32 version;
86 	u8 reserved[59];
87 } __packed;
88 
89 enum mcu_command_index {
90 	GET_VERSION = 0x01,
91 	GET_MCU_ID,
92 	GET_GAMEPAD_CFG,
93 	SET_GAMEPAD_CFG,
94 	GET_TP_PARAM,
95 	SET_TP_PARAM,
96 	GET_RGB_CFG = 0x0f,
97 	SET_RGB_CFG,
98 	GET_PL_TEST = 0xdf,
99 };
100 
101 enum feature_enabled_index {
102 	FEATURE_DISABLED,
103 	FEATURE_ENABLED,
104 };
105 
106 static const char *const feature_enabled_text[] = {
107 	[FEATURE_DISABLED] = "false",
108 	[FEATURE_ENABLED] = "true",
109 };
110 
111 enum feature_status_index {
112 	FEATURE_NONE = 0x00,
113 	FEATURE_GAMEPAD_MODE = 0x01,
114 	FEATURE_AUTO_SLEEP_TIME = 0x04,
115 	FEATURE_IMU_BYPASS,
116 	FEATURE_RGB_ENABLE,
117 	FEATURE_IMU_ENABLE,
118 	FEATURE_TOUCHPAD_ENABLE,
119 	FEATURE_OS_MODE = 0x0A,
120 	FEATURE_POLL_RATE = 0x10,
121 	FEATURE_DPAD_MODE,
122 	FEATURE_MOUSE_WHEEL_STEP,
123 };
124 
125 enum gamepad_mode_index {
126 	XINPUT,
127 	DINPUT,
128 };
129 
130 static const char *const gamepad_mode_text[] = {
131 	[XINPUT] = "xinput",
132 	[DINPUT] = "dinput",
133 };
134 
135 enum os_type_index {
136 	WINDOWS,
137 	LINUX,
138 };
139 
140 static const char *const os_type_text[] = {
141 	[WINDOWS] = "windows",
142 	[LINUX] = "linux",
143 };
144 
145 enum poll_rate_index {
146 	HZ125,
147 	HZ250,
148 	HZ500,
149 	HZ1000,
150 };
151 
152 static const char *const poll_rate_text[] = {
153 	[HZ125] = "125",
154 	[HZ250] = "250",
155 	[HZ500] = "500",
156 	[HZ1000] = "1000",
157 };
158 
159 enum dpad_mode_index {
160 	DIR8,
161 	DIR4,
162 };
163 
164 static const char *const dpad_mode_text[] = {
165 	[DIR8] = "8-way",
166 	[DIR4] = "4-way",
167 };
168 
169 enum touchpad_mode_index {
170 	TP_REL,
171 	TP_ABS,
172 };
173 
174 static const char *const touchpad_mode_text[] = {
175 	[TP_REL] = "relative",
176 	[TP_ABS] = "absolute",
177 };
178 
179 enum touchpad_config_index {
180 	CFG_WINDOWS_MODE = 0x03,
181 	CFG_LINUX_MODE,
182 
183 };
184 
185 enum rgb_mode_index {
186 	RGB_MODE_DYNAMIC,
187 	RGB_MODE_CUSTOM,
188 };
189 
190 static const char *const rgb_mode_text[] = {
191 	[RGB_MODE_DYNAMIC] = "dynamic",
192 	[RGB_MODE_CUSTOM] = "custom",
193 };
194 
195 enum rgb_effect_index {
196 	RGB_EFFECT_MONO,
197 	RGB_EFFECT_BREATHE,
198 	RGB_EFFECT_CHROMA,
199 	RGB_EFFECT_RAINBOW,
200 };
201 
202 static const char *const rgb_effect_text[] = {
203 	[RGB_EFFECT_MONO] = "monocolor",
204 	[RGB_EFFECT_BREATHE] = "breathe",
205 	[RGB_EFFECT_CHROMA] = "chroma",
206 	[RGB_EFFECT_RAINBOW] = "rainbow",
207 };
208 
209 enum rgb_config_index {
210 	LIGHT_MODE_SEL = 0x01,
211 	LIGHT_PROFILE_SEL,
212 	USR_LIGHT_PROFILE_1,
213 	USR_LIGHT_PROFILE_2,
214 	USR_LIGHT_PROFILE_3,
215 };
216 
217 enum test_command_index {
218 	TEST_TP_MFR = 0x02,
219 	TEST_IMU_MFR,
220 	TEST_TP_VER,
221 };
222 
223 enum tp_mfr_index {
224 	TP_NONE,
225 	TP_BETTERLIFE,
226 	TP_SIPO,
227 };
228 
229 static const char *const touchpad_manufacturer_text[] = {
230 	[TP_NONE] = "none",
231 	[TP_BETTERLIFE] = "BetterLife",
232 	[TP_SIPO] = "SIPO",
233 };
234 
235 enum imu_mfr_index {
236 	IMU_NONE,
237 	IMU_BOSCH,
238 	IMU_ST,
239 };
240 
241 static const char *const imu_manufacturer_text[] = {
242 	[IMU_NONE] = "none",
243 	[IMU_BOSCH] = "Bosch",
244 	[IMU_ST] = "ST",
245 };
246 
247 static int hid_gos_version_event(struct gos_cfg_drvdata *drvdata, u8 *data)
248 {
249 	struct version_report *ver_rep = (struct version_report *)data;
250 
251 	drvdata->hdev->firmware_version = get_unaligned_le32(&ver_rep->version);
252 	return 0;
253 }
254 
255 static int hid_gos_mcu_id_event(struct gos_cfg_drvdata *drvdata, struct command_report *cmd_rep)
256 {
257 	drvdata->mcu_id[0] = cmd_rep->sub_cmd;
258 	memcpy(&drvdata->mcu_id[1], cmd_rep->data, 11);
259 
260 	return 0;
261 }
262 
263 static int hid_gos_gamepad_cfg_event(struct gos_cfg_drvdata *drvdata,
264 				     struct command_report *cmd_rep)
265 {
266 	int ret = 0;
267 
268 	switch (cmd_rep->sub_cmd) {
269 	case FEATURE_GAMEPAD_MODE:
270 		drvdata->gp_mode = cmd_rep->data[0];
271 		break;
272 	case FEATURE_AUTO_SLEEP_TIME:
273 		drvdata->gp_auto_sleep_time = cmd_rep->data[0];
274 		break;
275 	case FEATURE_IMU_BYPASS:
276 		drvdata->imu_bypass_en = cmd_rep->data[0];
277 		break;
278 	case FEATURE_RGB_ENABLE:
279 		drvdata->rgb_en = cmd_rep->data[0];
280 		break;
281 	case FEATURE_IMU_ENABLE:
282 		drvdata->imu_sensor_en = cmd_rep->data[0];
283 		break;
284 	case FEATURE_TOUCHPAD_ENABLE:
285 		drvdata->tp_en = cmd_rep->data[0];
286 		break;
287 	case FEATURE_OS_MODE:
288 		drvdata->os_mode = cmd_rep->data[0];
289 		break;
290 	case FEATURE_POLL_RATE:
291 		drvdata->gp_poll_rate = cmd_rep->data[0];
292 		break;
293 	case FEATURE_DPAD_MODE:
294 		drvdata->gp_dpad_mode = cmd_rep->data[0];
295 		break;
296 	case FEATURE_MOUSE_WHEEL_STEP:
297 		drvdata->mouse_step = cmd_rep->data[0];
298 		break;
299 	default:
300 		ret = -EINVAL;
301 		break;
302 	}
303 
304 	return ret;
305 }
306 
307 static int hid_gos_touchpad_event(struct gos_cfg_drvdata *drvdata, struct command_report *cmd_rep)
308 {
309 	int ret = 0;
310 
311 	switch (cmd_rep->sub_cmd) {
312 	case CFG_LINUX_MODE:
313 		drvdata->tp_linux_mode = cmd_rep->data[0];
314 		break;
315 	case CFG_WINDOWS_MODE:
316 		drvdata->tp_windows_mode = cmd_rep->data[0];
317 		break;
318 	default:
319 		ret = -EINVAL;
320 		break;
321 	}
322 
323 	return ret;
324 }
325 
326 static int hid_gos_pl_test_event(struct gos_cfg_drvdata *drvdata, struct command_report *cmd_rep)
327 {
328 	int ret = 0;
329 
330 	switch (cmd_rep->sub_cmd) {
331 	case TEST_TP_MFR:
332 		drvdata->tp_manufacturer = cmd_rep->data[0];
333 		ret = 0;
334 		break;
335 	case TEST_IMU_MFR:
336 		drvdata->imu_manufacturer = cmd_rep->data[0];
337 		ret = 0;
338 		break;
339 	case TEST_TP_VER:
340 		drvdata->tp_version = cmd_rep->data[0];
341 		ret = 0;
342 		break;
343 	default:
344 		ret = -EINVAL;
345 		break;
346 	}
347 	return ret;
348 }
349 
350 static int hid_gos_light_event(struct gos_cfg_drvdata *drvdata, struct command_report *cmd_rep)
351 {
352 	struct led_classdev_mc *led_mc;
353 	int ret = 0;
354 
355 	switch (cmd_rep->sub_cmd) {
356 	case LIGHT_MODE_SEL:
357 		drvdata->rgb_mode = cmd_rep->data[0];
358 		ret = 0;
359 		break;
360 	case LIGHT_PROFILE_SEL:
361 		drvdata->rgb_profile = cmd_rep->data[0];
362 		ret = 0;
363 		break;
364 	case USR_LIGHT_PROFILE_1:
365 	case USR_LIGHT_PROFILE_2:
366 	case USR_LIGHT_PROFILE_3:
367 		led_mc = &drvdata->led_mc;
368 		drvdata->rgb_effect = cmd_rep->data[0];
369 		led_mc->subled_info[0].intensity = cmd_rep->data[1];
370 		led_mc->subled_info[1].intensity = cmd_rep->data[2];
371 		led_mc->subled_info[2].intensity = cmd_rep->data[3];
372 		led_mc->led_cdev.brightness = cmd_rep->data[4];
373 		drvdata->rgb_speed = cmd_rep->data[5];
374 		ret = 0;
375 		break;
376 	default:
377 		ret = -EINVAL;
378 		break;
379 	}
380 	return ret;
381 }
382 
383 static int hid_gos_set_event_return(struct command_report *cmd_rep)
384 {
385 	if (cmd_rep->data[0] != 0)
386 		return -EIO;
387 
388 	return 0;
389 }
390 
391 static int get_endpoint_address(struct hid_device *hdev)
392 {
393 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
394 	struct usb_host_endpoint *ep;
395 
396 	ep = intf->cur_altsetting->endpoint;
397 	if (ep)
398 		return ep->desc.bEndpointAddress;
399 
400 	return -ENODEV;
401 }
402 
403 static int hid_gos_raw_event(struct hid_device *hdev, struct hid_report *report,
404 			     u8 *data, int size)
405 {
406 	struct gos_cfg_drvdata *drvdata = hid_get_drvdata(hdev);
407 	struct command_report *cmd_rep;
408 	int ep, ret;
409 
410 	ep = get_endpoint_address(hdev);
411 	if (ep != GO_S_CFG_INTF_IN)
412 		return 0;
413 
414 	if (!drvdata)
415 		return -ENODEV;
416 
417 	if (size != GO_S_PACKET_SIZE)
418 		return -EINVAL;
419 
420 	cmd_rep = (struct command_report *)data;
421 
422 	switch (cmd_rep->cmd) {
423 	case GET_VERSION:
424 		ret = hid_gos_version_event(drvdata, data);
425 		break;
426 	case GET_MCU_ID:
427 		ret = hid_gos_mcu_id_event(drvdata, cmd_rep);
428 		break;
429 	case GET_GAMEPAD_CFG:
430 		ret = hid_gos_gamepad_cfg_event(drvdata, cmd_rep);
431 		break;
432 	case GET_TP_PARAM:
433 		ret = hid_gos_touchpad_event(drvdata, cmd_rep);
434 		break;
435 	case GET_PL_TEST:
436 		ret = hid_gos_pl_test_event(drvdata, cmd_rep);
437 		break;
438 	case GET_RGB_CFG:
439 		ret = hid_gos_light_event(drvdata, cmd_rep);
440 		break;
441 	case SET_GAMEPAD_CFG:
442 	case SET_RGB_CFG:
443 	case SET_TP_PARAM:
444 		ret = hid_gos_set_event_return(cmd_rep);
445 		break;
446 	default:
447 		ret = -EINVAL;
448 		break;
449 	}
450 	dev_dbg(&hdev->dev, "Rx data as raw input report: [%*ph]\n",
451 		GO_S_PACKET_SIZE, data);
452 
453 	drvdata->cmd_status = ret;
454 	complete(&drvdata->send_cmd_complete);
455 
456 	return ret;
457 }
458 
459 static int mcu_property_out(struct hid_device *hdev, u8 command, u8 index,
460 			    u8 *data, size_t len)
461 {
462 	struct gos_cfg_drvdata *drvdata = hid_get_drvdata(hdev);
463 	unsigned char *dmabuf __free(kfree) = NULL;
464 	u8 header[] = { command, index };
465 	size_t header_size = ARRAY_SIZE(header);
466 	int timeout, ret;
467 
468 	if (!drvdata)
469 		return -ENODEV;
470 
471 	if (header_size + len > GO_S_PACKET_SIZE)
472 		return -EINVAL;
473 
474 	guard(mutex)(&drvdata->cfg_mutex);
475 
476 	/*
477 	 * A reply to the previous command may still be in flight. Give it a
478 	 * short window to arrive and be consumed before this call reinits the
479 	 * completion, so a late reply can't be mistaken for this command's.
480 	 */
481 	if (drvdata->orphan_ack_pending) {
482 		wait_for_completion_timeout(&drvdata->send_cmd_complete, msecs_to_jiffies(25));
483 		drvdata->orphan_ack_pending = false;
484 		drvdata->cmd_status = -ETIMEDOUT;
485 	}
486 	reinit_completion(&drvdata->send_cmd_complete);
487 
488 	/* We can't use a devm_alloc reusable buffer without side effects during suspend */
489 	dmabuf = kzalloc(GO_S_PACKET_SIZE, GFP_KERNEL);
490 	if (!dmabuf)
491 		return -ENOMEM;
492 
493 	memcpy(dmabuf, header, header_size);
494 	memcpy(dmabuf + header_size, data, len);
495 
496 	dev_dbg(&hdev->dev, "Send data as raw output report: [%*ph]\n",
497 		GO_S_PACKET_SIZE, dmabuf);
498 
499 	ret = hid_hw_output_report(hdev, dmabuf, GO_S_PACKET_SIZE);
500 	if (ret < 0)
501 		return ret;
502 
503 	ret = ret == GO_S_PACKET_SIZE ? 0 : -EINVAL;
504 	if (ret)
505 		return ret;
506 
507 	/* PL_TEST commands can take longer because they go out to another device */
508 	timeout = (command == GET_PL_TEST) ? 200 : 5;
509 	ret = wait_for_completion_interruptible_timeout(&drvdata->send_cmd_complete,
510 							msecs_to_jiffies(timeout));
511 	ret = ret > 0 ? drvdata->cmd_status : ret ?: -EBUSY;
512 
513 	if (ret)
514 		drvdata->orphan_ack_pending = true;
515 
516 	return ret;
517 }
518 
519 static ssize_t gamepad_property_store(struct device *dev,
520 				      struct device_attribute *attr,
521 				      const char *buf, size_t count,
522 				      enum feature_status_index index)
523 {
524 	struct gos_cfg_drvdata *drvdata;
525 	struct led_classdev_mc *led_mc;
526 	struct led_classdev *led_cdev;
527 	struct hid_device *hdev;
528 	bool dev_registered;
529 	size_t size = 1;
530 	u8 val = 0;
531 	int ret;
532 
533 	/* rgb_enabled is attached to led_classdev, not hid_device */
534 	if (index == FEATURE_RGB_ENABLE) {
535 		led_cdev = dev_get_drvdata(dev);
536 		led_mc = lcdev_to_mccdev(led_cdev);
537 		drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
538 		hdev = drvdata->hdev;
539 	/* Pairs with smp_store_release from gos_cfg_setup */
540 		dev_registered = smp_load_acquire(&drvdata->rgb_registered);
541 
542 	} else {
543 		hdev = to_hid_device(dev);
544 		drvdata = hid_get_drvdata(hdev);
545 	/* Pairs with smp_store_release from gos_cfg_setup */
546 		dev_registered = smp_load_acquire(&drvdata->gp_registered);
547 	}
548 
549 	if (!dev_registered)
550 		return -ENODEV;
551 
552 	switch (index) {
553 	case FEATURE_GAMEPAD_MODE:
554 		ret = sysfs_match_string(gamepad_mode_text, buf);
555 		if (ret < 0)
556 			return ret;
557 		val = ret;
558 		break;
559 	case FEATURE_AUTO_SLEEP_TIME:
560 		ret = kstrtou8(buf, 10, &val);
561 		if (ret)
562 			return ret;
563 		break;
564 	case FEATURE_IMU_ENABLE:
565 		ret = sysfs_match_string(feature_enabled_text, buf);
566 		if (ret < 0)
567 			return ret;
568 		val = ret;
569 		break;
570 	case FEATURE_IMU_BYPASS:
571 		ret = sysfs_match_string(feature_enabled_text, buf);
572 		if (ret < 0)
573 			return ret;
574 		val = ret;
575 		break;
576 	case FEATURE_RGB_ENABLE:
577 		ret = sysfs_match_string(feature_enabled_text, buf);
578 		if (ret < 0)
579 			return ret;
580 		val = ret;
581 		break;
582 	case FEATURE_TOUCHPAD_ENABLE:
583 		ret = sysfs_match_string(feature_enabled_text, buf);
584 		if (ret < 0)
585 			return ret;
586 		val = ret;
587 		break;
588 	case FEATURE_OS_MODE:
589 		ret = sysfs_match_string(os_type_text, buf);
590 		if (ret < 0)
591 			return ret;
592 		val = ret;
593 		break;
594 	case FEATURE_POLL_RATE:
595 		ret = sysfs_match_string(poll_rate_text, buf);
596 		if (ret < 0)
597 			return ret;
598 		val = ret;
599 		break;
600 	case FEATURE_DPAD_MODE:
601 		ret = sysfs_match_string(dpad_mode_text, buf);
602 		if (ret < 0)
603 			return ret;
604 		val = ret;
605 		break;
606 	case FEATURE_MOUSE_WHEEL_STEP:
607 		ret = kstrtou8(buf, 10, &val);
608 		if (ret)
609 			return ret;
610 		if (val < 1 || val > 127)
611 			return -EINVAL;
612 		break;
613 	default:
614 		return -EINVAL;
615 	}
616 
617 	if (!val)
618 		size = 0;
619 
620 	ret = mcu_property_out(hdev, SET_GAMEPAD_CFG, index, &val,
621 			       size);
622 	if (ret < 0)
623 		return ret;
624 
625 	return count;
626 }
627 
628 static ssize_t gamepad_property_show(struct device *dev,
629 				     struct device_attribute *attr, char *buf,
630 				     enum feature_status_index index)
631 {
632 	struct gos_cfg_drvdata *drvdata;
633 	struct led_classdev_mc *led_mc;
634 	struct led_classdev *led_cdev;
635 	struct hid_device *hdev;
636 	bool dev_registered;
637 
638 	ssize_t count = 0;
639 	u8 i;
640 
641 	/* rgb_enabled is attached to led_classdev, not hid_device */
642 	if (index == FEATURE_RGB_ENABLE) {
643 		led_cdev = dev_get_drvdata(dev);
644 		led_mc = lcdev_to_mccdev(led_cdev);
645 		drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
646 		hdev = drvdata->hdev;
647 	/* Pairs with smp_store_release from gos_cfg_setup */
648 		dev_registered = smp_load_acquire(&drvdata->rgb_registered);
649 
650 	} else {
651 		hdev = to_hid_device(dev);
652 		drvdata = hid_get_drvdata(hdev);
653 	/* Pairs with smp_store_release from gos_cfg_setup */
654 		dev_registered = smp_load_acquire(&drvdata->gp_registered);
655 	}
656 
657 	if (!dev_registered)
658 		return -ENODEV;
659 
660 	count = mcu_property_out(hdev, GET_GAMEPAD_CFG, index, NULL, 0);
661 	if (count < 0)
662 		return count;
663 
664 	switch (index) {
665 	case FEATURE_GAMEPAD_MODE:
666 		i = drvdata->gp_mode;
667 		if (i >= ARRAY_SIZE(gamepad_mode_text))
668 			return -EINVAL;
669 		count = sysfs_emit(buf, "%s\n", gamepad_mode_text[i]);
670 		break;
671 	case FEATURE_AUTO_SLEEP_TIME:
672 		count = sysfs_emit(buf, "%u\n", drvdata->gp_auto_sleep_time);
673 		break;
674 	case FEATURE_IMU_ENABLE:
675 		i = drvdata->imu_sensor_en;
676 		if (i >= ARRAY_SIZE(feature_enabled_text))
677 			return -EINVAL;
678 		count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]);
679 		break;
680 	case FEATURE_IMU_BYPASS:
681 		i = drvdata->imu_bypass_en;
682 		if (i >= ARRAY_SIZE(feature_enabled_text))
683 			return -EINVAL;
684 		count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]);
685 		break;
686 	case FEATURE_RGB_ENABLE:
687 		i = drvdata->rgb_en;
688 		if (i >= ARRAY_SIZE(feature_enabled_text))
689 			return -EINVAL;
690 		count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]);
691 		break;
692 	case FEATURE_TOUCHPAD_ENABLE:
693 		i = drvdata->tp_en;
694 		if (i >= ARRAY_SIZE(feature_enabled_text))
695 			return -EINVAL;
696 		count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]);
697 		break;
698 	case FEATURE_OS_MODE:
699 		i = drvdata->os_mode;
700 		if (i >= ARRAY_SIZE(os_type_text))
701 			return -EINVAL;
702 		count = sysfs_emit(buf, "%s\n", os_type_text[i]);
703 		break;
704 	case FEATURE_POLL_RATE:
705 		i = drvdata->gp_poll_rate;
706 		if (i >= ARRAY_SIZE(poll_rate_text))
707 			return -EINVAL;
708 		count = sysfs_emit(buf, "%s\n", poll_rate_text[i]);
709 		break;
710 	case FEATURE_DPAD_MODE:
711 		i = drvdata->gp_dpad_mode;
712 		if (i >= ARRAY_SIZE(dpad_mode_text))
713 			return -EINVAL;
714 		count = sysfs_emit(buf, "%s\n", dpad_mode_text[i]);
715 		break;
716 	case FEATURE_MOUSE_WHEEL_STEP:
717 		i = drvdata->mouse_step;
718 		if (i < 1 || i > 127)
719 			return -EINVAL;
720 		count = sysfs_emit(buf, "%u\n", i);
721 		break;
722 	default:
723 		return -EINVAL;
724 	}
725 
726 	return count;
727 }
728 
729 static ssize_t gamepad_property_options(struct device *dev,
730 					struct device_attribute *attr,
731 					char *buf,
732 					enum feature_status_index index)
733 {
734 	size_t count = 0;
735 	unsigned int i;
736 
737 	switch (index) {
738 	case FEATURE_GAMEPAD_MODE:
739 		for (i = 0; i < ARRAY_SIZE(gamepad_mode_text); i++) {
740 			count += sysfs_emit_at(buf, count, "%s ",
741 					       gamepad_mode_text[i]);
742 		}
743 		break;
744 	case FEATURE_AUTO_SLEEP_TIME:
745 		return sysfs_emit(buf, "0-255\n");
746 	case FEATURE_IMU_ENABLE:
747 		for (i = 0; i < ARRAY_SIZE(feature_enabled_text); i++) {
748 			count += sysfs_emit_at(buf, count, "%s ",
749 					       feature_enabled_text[i]);
750 		}
751 		break;
752 	case FEATURE_IMU_BYPASS:
753 	case FEATURE_RGB_ENABLE:
754 	case FEATURE_TOUCHPAD_ENABLE:
755 		for (i = 0; i < ARRAY_SIZE(feature_enabled_text); i++) {
756 			count += sysfs_emit_at(buf, count, "%s ",
757 					       feature_enabled_text[i]);
758 		}
759 		break;
760 	case FEATURE_OS_MODE:
761 		for (i = 0; i < ARRAY_SIZE(os_type_text); i++) {
762 			count += sysfs_emit_at(buf, count, "%s ",
763 					       os_type_text[i]);
764 		}
765 		break;
766 	case FEATURE_POLL_RATE:
767 		for (i = 0; i < ARRAY_SIZE(poll_rate_text); i++) {
768 			count += sysfs_emit_at(buf, count, "%s ",
769 					       poll_rate_text[i]);
770 		}
771 		break;
772 	case FEATURE_DPAD_MODE:
773 		for (i = 0; i < ARRAY_SIZE(dpad_mode_text); i++) {
774 			count += sysfs_emit_at(buf, count, "%s ",
775 					       dpad_mode_text[i]);
776 		}
777 		break;
778 	case FEATURE_MOUSE_WHEEL_STEP:
779 		return sysfs_emit(buf, "1-127\n");
780 	default:
781 		return count;
782 	}
783 
784 	if (count)
785 		buf[count - 1] = '\n';
786 
787 	return count;
788 }
789 
790 static ssize_t touchpad_property_store(struct device *dev,
791 				       struct device_attribute *attr,
792 				       const char *buf, size_t count,
793 				       enum touchpad_config_index index)
794 {
795 	struct hid_device *hdev = to_hid_device(dev);
796 	struct gos_cfg_drvdata *drvdata = hid_get_drvdata(hdev);
797 	bool gp_registered;
798 	size_t size = 1;
799 	u8 val = 0;
800 	int ret;
801 
802 	if (!drvdata)
803 		return -ENODEV;
804 
805 /* Pairs with smp_store_release from gos_cfg_setup */
806 	gp_registered = smp_load_acquire(&drvdata->gp_registered);
807 	if (!gp_registered)
808 		return -ENODEV;
809 
810 	switch (index) {
811 	case CFG_WINDOWS_MODE:
812 		ret = sysfs_match_string(touchpad_mode_text, buf);
813 		if (ret < 0)
814 			return ret;
815 		val = ret;
816 		break;
817 	case CFG_LINUX_MODE:
818 		ret = sysfs_match_string(touchpad_mode_text, buf);
819 		if (ret < 0)
820 			return ret;
821 		val = ret;
822 		break;
823 	default:
824 		return -EINVAL;
825 	}
826 	if (!val)
827 		size = 0;
828 
829 	ret = mcu_property_out(hdev, SET_TP_PARAM, index, &val, size);
830 	if (ret < 0)
831 		return ret;
832 
833 	return count;
834 }
835 
836 static ssize_t touchpad_property_show(struct device *dev,
837 				      struct device_attribute *attr, char *buf,
838 				      enum touchpad_config_index index)
839 {
840 	struct hid_device *hdev = to_hid_device(dev);
841 	struct gos_cfg_drvdata *drvdata = hid_get_drvdata(hdev);
842 	bool gp_registered;
843 	int ret = 0;
844 	u8 i;
845 
846 	if (!drvdata)
847 		return -ENODEV;
848 
849 /* Pairs with smp_store_release from gos_cfg_setup */
850 	gp_registered = smp_load_acquire(&drvdata->gp_registered);
851 	if (!gp_registered)
852 		return -ENODEV;
853 
854 	ret = mcu_property_out(hdev, GET_TP_PARAM, index, NULL, 0);
855 	if (ret < 0)
856 		return ret;
857 
858 	switch (index) {
859 	case CFG_WINDOWS_MODE:
860 		i = drvdata->tp_windows_mode;
861 		break;
862 	case CFG_LINUX_MODE:
863 		i = drvdata->tp_linux_mode;
864 		break;
865 	default:
866 		return -EINVAL;
867 	}
868 
869 	if (i >= ARRAY_SIZE(touchpad_mode_text))
870 		return -EINVAL;
871 
872 	return sysfs_emit(buf, "%s\n", touchpad_mode_text[i]);
873 }
874 
875 static ssize_t touchpad_property_options(struct device *dev,
876 					 struct device_attribute *attr,
877 					 char *buf,
878 					 enum touchpad_config_index index)
879 {
880 	size_t count = 0;
881 	unsigned int i;
882 
883 	switch (index) {
884 	case CFG_WINDOWS_MODE:
885 	case CFG_LINUX_MODE:
886 		for (i = 0; i < ARRAY_SIZE(touchpad_mode_text); i++) {
887 			count += sysfs_emit_at(buf, count, "%s ",
888 					       touchpad_mode_text[i]);
889 		}
890 		break;
891 	default:
892 		return count;
893 	}
894 
895 	if (count)
896 		buf[count - 1] = '\n';
897 
898 	return count;
899 }
900 
901 static ssize_t test_property_show(struct device *dev,
902 				  struct device_attribute *attr, char *buf,
903 				  enum test_command_index index)
904 {
905 	struct hid_device *hdev = to_hid_device(dev);
906 	struct gos_cfg_drvdata *drvdata = hid_get_drvdata(hdev);
907 	bool gp_registered;
908 	size_t count = 0;
909 	u8 i;
910 
911 	if (!drvdata)
912 		return -ENODEV;
913 
914 /* Pairs with smp_store_release from gos_cfg_setup */
915 	gp_registered = smp_load_acquire(&drvdata->gp_registered);
916 	if (!gp_registered)
917 		return -ENODEV;
918 
919 	switch (index) {
920 	case TEST_TP_MFR:
921 		i = drvdata->tp_manufacturer;
922 		if (i >= ARRAY_SIZE(touchpad_manufacturer_text))
923 			return -EINVAL;
924 		count = sysfs_emit(buf, "%s\n", touchpad_manufacturer_text[i]);
925 		break;
926 	case TEST_IMU_MFR:
927 		i = drvdata->imu_manufacturer;
928 		if (i >= ARRAY_SIZE(imu_manufacturer_text))
929 			return -EINVAL;
930 		count = sysfs_emit(buf, "%s\n", imu_manufacturer_text[i]);
931 		break;
932 	case TEST_TP_VER:
933 		count = sysfs_emit(buf, "%u\n", drvdata->tp_version);
934 		break;
935 	default:
936 		count = -EINVAL;
937 		break;
938 	}
939 
940 	return count;
941 }
942 
943 static ssize_t mcu_id_show(struct device *dev, struct device_attribute *attr,
944 			   char *buf)
945 {
946 	struct hid_device *hdev = to_hid_device(dev);
947 	struct gos_cfg_drvdata *drvdata = hid_get_drvdata(hdev);
948 
949 	if (!drvdata)
950 		return -ENODEV;
951 
952 	return sysfs_emit(buf, "%*phN\n", 12, &drvdata->mcu_id);
953 }
954 
955 static int rgb_cfg_call(struct hid_device *hdev, enum mcu_command_index cmd,
956 			enum rgb_config_index index, u8 *val, size_t size)
957 {
958 	if (cmd != SET_RGB_CFG && cmd != GET_RGB_CFG)
959 		return -EINVAL;
960 
961 	if (index < LIGHT_MODE_SEL || index > USR_LIGHT_PROFILE_3)
962 		return -EINVAL;
963 
964 	return mcu_property_out(hdev, cmd, index, val, size);
965 }
966 
967 static int rgb_attr_show(struct gos_cfg_drvdata *drvdata)
968 {
969 	enum rgb_config_index index;
970 
971 	index = drvdata->rgb_profile + 2;
972 
973 	return rgb_cfg_call(drvdata->hdev, GET_RGB_CFG, index, NULL, 0);
974 };
975 
976 static ssize_t rgb_effect_store(struct device *dev,
977 				struct device_attribute *attr, const char *buf,
978 				size_t count)
979 {
980 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
981 	struct led_classdev_mc *led_mc = lcdev_to_mccdev(led_cdev);
982 	struct gos_cfg_drvdata *drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
983 	enum rgb_config_index index;
984 	bool rgb_registered;
985 	u8 effect;
986 	int ret;
987 
988 /* Pairs with smp_store_release from gos_cfg_setup */
989 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
990 	if (!rgb_registered)
991 		return -ENODEV;
992 
993 	ret = sysfs_match_string(rgb_effect_text, buf);
994 	if (ret < 0)
995 		return ret;
996 
997 	effect = ret;
998 	index = drvdata->rgb_profile + 2;
999 	u8 rgb_profile[6] = { effect,
1000 			      led_mc->subled_info[0].intensity,
1001 			      led_mc->subled_info[1].intensity,
1002 			      led_mc->subled_info[2].intensity,
1003 			      led_mc->led_cdev.brightness,
1004 			      drvdata->rgb_speed };
1005 
1006 	ret = rgb_cfg_call(drvdata->hdev, SET_RGB_CFG, index, rgb_profile, 6);
1007 	if (ret)
1008 		return ret;
1009 
1010 	drvdata->rgb_effect = effect;
1011 	return count;
1012 };
1013 
1014 static ssize_t rgb_effect_show(struct device *dev,
1015 			       struct device_attribute *attr, char *buf)
1016 {
1017 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
1018 	struct led_classdev_mc *led_mc = lcdev_to_mccdev(led_cdev);
1019 	struct gos_cfg_drvdata *drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
1020 	bool rgb_registered;
1021 	int ret;
1022 
1023 /* Pairs with smp_store_release from gos_cfg_setup */
1024 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1025 	if (!rgb_registered)
1026 		return -ENODEV;
1027 
1028 	ret = rgb_attr_show(drvdata);
1029 	if (ret)
1030 		return ret;
1031 
1032 	if (drvdata->rgb_effect >= ARRAY_SIZE(rgb_effect_text))
1033 		return -EINVAL;
1034 
1035 	return sysfs_emit(buf, "%s\n", rgb_effect_text[drvdata->rgb_effect]);
1036 }
1037 
1038 static ssize_t rgb_effect_index_show(struct device *dev,
1039 				     struct device_attribute *attr, char *buf)
1040 {
1041 	ssize_t count = 0;
1042 	unsigned int i;
1043 
1044 	for (i = 0; i < ARRAY_SIZE(rgb_effect_text); i++)
1045 		count += sysfs_emit_at(buf, count, "%s ", rgb_effect_text[i]);
1046 
1047 	if (count)
1048 		buf[count - 1] = '\n';
1049 
1050 	return count;
1051 }
1052 
1053 static ssize_t rgb_speed_store(struct device *dev,
1054 			       struct device_attribute *attr, const char *buf,
1055 			       size_t count)
1056 {
1057 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
1058 	struct led_classdev_mc *led_mc = lcdev_to_mccdev(led_cdev);
1059 	struct gos_cfg_drvdata *drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
1060 	enum rgb_config_index index;
1061 	bool rgb_registered;
1062 	int val = 0;
1063 	int ret;
1064 
1065 /* Pairs with smp_store_release from gos_cfg_setup */
1066 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1067 	if (!rgb_registered)
1068 		return -ENODEV;
1069 
1070 	ret = kstrtoint(buf, 10, &val);
1071 	if (ret)
1072 		return ret;
1073 
1074 	if (val < 0 || val > 100)
1075 		return -EINVAL;
1076 
1077 	index = drvdata->rgb_profile + 2;
1078 	u8 rgb_profile[6] = { drvdata->rgb_effect,
1079 			      led_mc->subled_info[0].intensity,
1080 			      led_mc->subled_info[1].intensity,
1081 			      led_mc->subled_info[2].intensity,
1082 			      led_mc->led_cdev.brightness,
1083 			      val };
1084 
1085 	ret = rgb_cfg_call(drvdata->hdev, SET_RGB_CFG, index, rgb_profile, 6);
1086 	if (ret)
1087 		return ret;
1088 
1089 	drvdata->rgb_speed = val;
1090 
1091 	return count;
1092 };
1093 
1094 static ssize_t rgb_speed_show(struct device *dev, struct device_attribute *attr,
1095 			      char *buf)
1096 {
1097 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
1098 	struct led_classdev_mc *led_mc = lcdev_to_mccdev(led_cdev);
1099 	struct gos_cfg_drvdata *drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
1100 	bool rgb_registered;
1101 	int ret;
1102 
1103 /* Pairs with smp_store_release from gos_cfg_setup */
1104 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1105 	if (!rgb_registered)
1106 		return -ENODEV;
1107 
1108 	ret = rgb_attr_show(drvdata);
1109 	if (ret)
1110 		return ret;
1111 
1112 	if (drvdata->rgb_speed > 100)
1113 		return -EINVAL;
1114 
1115 	return sysfs_emit(buf, "%hhu\n", drvdata->rgb_speed);
1116 }
1117 
1118 static ssize_t rgb_speed_range_show(struct device *dev,
1119 				    struct device_attribute *attr, char *buf)
1120 {
1121 	return sysfs_emit(buf, "0-100\n");
1122 }
1123 
1124 static ssize_t rgb_mode_store(struct device *dev, struct device_attribute *attr,
1125 			      const char *buf, size_t count)
1126 {
1127 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
1128 	struct led_classdev_mc *led_mc = lcdev_to_mccdev(led_cdev);
1129 	struct gos_cfg_drvdata *drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
1130 	bool rgb_registered;
1131 	int ret;
1132 	u8 val;
1133 
1134 /* Pairs with smp_store_release from gos_cfg_setup */
1135 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1136 	if (!rgb_registered)
1137 		return -ENODEV;
1138 
1139 	ret = sysfs_match_string(rgb_mode_text, buf);
1140 	if (ret <= 0)
1141 		return ret;
1142 
1143 	val = ret;
1144 
1145 	ret = rgb_cfg_call(drvdata->hdev, SET_RGB_CFG, LIGHT_MODE_SEL, &val,
1146 			   1);
1147 	if (ret)
1148 		return ret;
1149 
1150 	drvdata->rgb_mode = val;
1151 
1152 	return count;
1153 };
1154 
1155 static ssize_t rgb_mode_show(struct device *dev, struct device_attribute *attr,
1156 			     char *buf)
1157 {
1158 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
1159 	struct led_classdev_mc *led_mc = lcdev_to_mccdev(led_cdev);
1160 	struct gos_cfg_drvdata *drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
1161 	bool rgb_registered;
1162 	int ret;
1163 
1164 /* Pairs with smp_store_release from gos_cfg_setup */
1165 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1166 	if (!rgb_registered)
1167 		return -ENODEV;
1168 
1169 	ret = rgb_cfg_call(drvdata->hdev, GET_RGB_CFG, LIGHT_MODE_SEL, NULL, 0);
1170 	if (ret)
1171 		return ret;
1172 
1173 	if (drvdata->rgb_mode >= ARRAY_SIZE(rgb_mode_text))
1174 		return -EINVAL;
1175 
1176 	return sysfs_emit(buf, "%s\n", rgb_mode_text[drvdata->rgb_mode]);
1177 };
1178 
1179 static ssize_t rgb_mode_index_show(struct device *dev,
1180 				   struct device_attribute *attr, char *buf)
1181 {
1182 	ssize_t count = 0;
1183 	unsigned int i;
1184 
1185 	for (i = 1; i < ARRAY_SIZE(rgb_mode_text); i++)
1186 		count += sysfs_emit_at(buf, count, "%s ", rgb_mode_text[i]);
1187 
1188 	if (count)
1189 		buf[count - 1] = '\n';
1190 
1191 	return count;
1192 }
1193 
1194 static ssize_t rgb_profile_store(struct device *dev,
1195 				 struct device_attribute *attr, const char *buf,
1196 				 size_t count)
1197 {
1198 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
1199 	struct led_classdev_mc *led_mc = lcdev_to_mccdev(led_cdev);
1200 	struct gos_cfg_drvdata *drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
1201 	bool rgb_registered;
1202 	size_t size = 1;
1203 	int ret;
1204 	u8 val;
1205 
1206 /* Pairs with smp_store_release from gos_cfg_setup */
1207 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1208 	if (!rgb_registered)
1209 		return -ENODEV;
1210 
1211 	ret = kstrtou8(buf, 10, &val);
1212 	if (ret < 0)
1213 		return ret;
1214 
1215 	if (val < 1 || val > 3)
1216 		return -EINVAL;
1217 
1218 	ret = rgb_cfg_call(drvdata->hdev, SET_RGB_CFG, LIGHT_PROFILE_SEL, &val, size);
1219 	if (ret)
1220 		return ret;
1221 
1222 	drvdata->rgb_profile = val;
1223 
1224 	return count;
1225 };
1226 
1227 static ssize_t rgb_profile_show(struct device *dev,
1228 				struct device_attribute *attr, char *buf)
1229 {
1230 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
1231 	struct led_classdev_mc *led_mc = lcdev_to_mccdev(led_cdev);
1232 	struct gos_cfg_drvdata *drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
1233 	bool rgb_registered;
1234 	int ret;
1235 
1236 /* Pairs with smp_store_release from gos_cfg_setup */
1237 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1238 	if (!rgb_registered)
1239 		return -ENODEV;
1240 
1241 	ret = rgb_cfg_call(drvdata->hdev, GET_RGB_CFG, LIGHT_PROFILE_SEL, NULL, 0);
1242 	if (ret)
1243 		return ret;
1244 
1245 	if (drvdata->rgb_profile < 1 || drvdata->rgb_profile > 3)
1246 		return -EINVAL;
1247 
1248 	return sysfs_emit(buf, "%hhu\n", drvdata->rgb_profile);
1249 };
1250 
1251 static ssize_t rgb_profile_range_show(struct device *dev,
1252 				      struct device_attribute *attr, char *buf)
1253 {
1254 	return sysfs_emit(buf, "1-3\n");
1255 }
1256 
1257 static void hid_gos_brightness_set(struct led_classdev *led_cdev,
1258 				   enum led_brightness brightness)
1259 {
1260 	struct led_classdev_mc *led_mc = lcdev_to_mccdev(led_cdev);
1261 	struct gos_cfg_drvdata *drvdata = container_of(led_mc, struct gos_cfg_drvdata, led_mc);
1262 	enum rgb_config_index index;
1263 	bool rgb_registered;
1264 	int ret;
1265 
1266 /* Pairs with smp_store_release from gos_cfg_setup */
1267 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1268 	if (!rgb_registered)
1269 		return;
1270 
1271 	if (brightness > led_cdev->max_brightness) {
1272 		dev_err(led_cdev->dev, "Invalid argument\n");
1273 		return;
1274 	}
1275 
1276 	index = drvdata->rgb_profile + 2;
1277 	u8 rgb_profile[6] = { drvdata->rgb_effect,
1278 			      led_mc->subled_info[0].intensity,
1279 			      led_mc->subled_info[1].intensity,
1280 			      led_mc->subled_info[2].intensity,
1281 			      brightness,
1282 			      drvdata->rgb_speed };
1283 
1284 	ret = rgb_cfg_call(drvdata->hdev, SET_RGB_CFG, index, rgb_profile, 6);
1285 	switch (ret) {
1286 	case 0:
1287 		led_cdev->brightness = brightness;
1288 		break;
1289 	case -ENODEV: /* during switch to IAP -ENODEV is expected */
1290 	case -ENOSYS: /* during rmmod -ENOSYS is expected */
1291 		dev_dbg(led_cdev->dev, "Failed to write RGB profile: %i\n",
1292 			ret);
1293 		break;
1294 	default:
1295 		dev_err(led_cdev->dev, "Failed to write RGB profile: %i\n",
1296 			ret);
1297 	}
1298 }
1299 
1300 #define LEGOS_DEVICE_ATTR_RW(_name, _attrname, _rtype, _group)                 \
1301 	static ssize_t _name##_store(struct device *dev,                       \
1302 				     struct device_attribute *attr,            \
1303 				     const char *buf, size_t count)            \
1304 	{                                                                      \
1305 		return _group##_property_store(dev, attr, buf, count,          \
1306 					       _name.index);                   \
1307 	}                                                                      \
1308 	static ssize_t _name##_show(struct device *dev,                        \
1309 				    struct device_attribute *attr, char *buf)  \
1310 	{                                                                      \
1311 		return _group##_property_show(dev, attr, buf, _name.index);    \
1312 	}                                                                      \
1313 	static ssize_t _name##_##_rtype##_show(                                \
1314 		struct device *dev, struct device_attribute *attr, char *buf)  \
1315 	{                                                                      \
1316 		return _group##_property_options(dev, attr, buf, _name.index); \
1317 	}                                                                      \
1318 	static DEVICE_ATTR_RW_NAMED(_name, _attrname)
1319 
1320 #define LEGOS_DEVICE_ATTR_RO(_name, _attrname, _group)                        \
1321 	static ssize_t _name##_show(struct device *dev,                       \
1322 				    struct device_attribute *attr, char *buf) \
1323 	{                                                                     \
1324 		return _group##_property_show(dev, attr, buf, _name.index);   \
1325 	}                                                                     \
1326 	static DEVICE_ATTR_RO_NAMED(_name, _attrname)
1327 
1328 /* Gamepad */
1329 static struct gos_cfg_attr auto_sleep_time = { FEATURE_AUTO_SLEEP_TIME };
1330 LEGOS_DEVICE_ATTR_RW(auto_sleep_time, "auto_sleep_time", range, gamepad);
1331 static DEVICE_ATTR_RO(auto_sleep_time_range);
1332 
1333 static struct gos_cfg_attr dpad_mode = { FEATURE_DPAD_MODE };
1334 LEGOS_DEVICE_ATTR_RW(dpad_mode, "dpad_mode", index, gamepad);
1335 static DEVICE_ATTR_RO(dpad_mode_index);
1336 
1337 static struct gos_cfg_attr gamepad_mode = { FEATURE_GAMEPAD_MODE };
1338 LEGOS_DEVICE_ATTR_RW(gamepad_mode, "mode", index, gamepad);
1339 static DEVICE_ATTR_RO_NAMED(gamepad_mode_index, "mode_index");
1340 
1341 static struct gos_cfg_attr gamepad_poll_rate = { FEATURE_POLL_RATE };
1342 LEGOS_DEVICE_ATTR_RW(gamepad_poll_rate, "poll_rate", index, gamepad);
1343 static DEVICE_ATTR_RO_NAMED(gamepad_poll_rate_index, "poll_rate_index");
1344 
1345 static struct attribute *legos_gamepad_attrs[] = {
1346 	&dev_attr_auto_sleep_time.attr,
1347 	&dev_attr_auto_sleep_time_range.attr,
1348 	&dev_attr_dpad_mode.attr,
1349 	&dev_attr_dpad_mode_index.attr,
1350 	&dev_attr_gamepad_mode.attr,
1351 	&dev_attr_gamepad_mode_index.attr,
1352 	&dev_attr_gamepad_poll_rate.attr,
1353 	&dev_attr_gamepad_poll_rate_index.attr,
1354 	NULL,
1355 };
1356 
1357 static const struct attribute_group gamepad_attr_group = {
1358 	.name = "gamepad",
1359 	.attrs = legos_gamepad_attrs,
1360 };
1361 
1362 /* IMU */
1363 static struct gos_cfg_attr imu_bypass_enabled = { FEATURE_IMU_BYPASS };
1364 LEGOS_DEVICE_ATTR_RW(imu_bypass_enabled, "bypass_enabled", index, gamepad);
1365 static DEVICE_ATTR_RO_NAMED(imu_bypass_enabled_index, "bypass_enabled_index");
1366 
1367 static struct gos_cfg_attr imu_manufacturer = { TEST_IMU_MFR };
1368 LEGOS_DEVICE_ATTR_RO(imu_manufacturer, "manufacturer", test);
1369 
1370 static struct gos_cfg_attr imu_sensor_enabled = { FEATURE_IMU_ENABLE };
1371 LEGOS_DEVICE_ATTR_RW(imu_sensor_enabled, "sensor_enabled", index, gamepad);
1372 static DEVICE_ATTR_RO_NAMED(imu_sensor_enabled_index, "sensor_enabled_index");
1373 
1374 static struct attribute *legos_imu_attrs[] = {
1375 	&dev_attr_imu_bypass_enabled.attr,
1376 	&dev_attr_imu_bypass_enabled_index.attr,
1377 	&dev_attr_imu_manufacturer.attr,
1378 	&dev_attr_imu_sensor_enabled.attr,
1379 	&dev_attr_imu_sensor_enabled_index.attr,
1380 	NULL,
1381 };
1382 
1383 static const struct attribute_group imu_attr_group = {
1384 	.name = "imu",
1385 	.attrs = legos_imu_attrs,
1386 };
1387 
1388 /* MCU */
1389 static DEVICE_ATTR_RO(mcu_id);
1390 
1391 static struct gos_cfg_attr os_mode = { FEATURE_OS_MODE };
1392 LEGOS_DEVICE_ATTR_RW(os_mode, "os_mode", index, gamepad);
1393 static DEVICE_ATTR_RO(os_mode_index);
1394 
1395 static struct attribute *legos_mcu_attrs[] = {
1396 	&dev_attr_mcu_id.attr,
1397 	&dev_attr_os_mode.attr,
1398 	&dev_attr_os_mode_index.attr,
1399 	NULL,
1400 };
1401 
1402 static const struct attribute_group mcu_attr_group = {
1403 	.attrs = legos_mcu_attrs,
1404 };
1405 
1406 /* Mouse */
1407 static struct gos_cfg_attr mouse_wheel_step = { FEATURE_MOUSE_WHEEL_STEP };
1408 LEGOS_DEVICE_ATTR_RW(mouse_wheel_step, "step", range, gamepad);
1409 static DEVICE_ATTR_RO_NAMED(mouse_wheel_step_range, "step_range");
1410 
1411 static struct attribute *legos_mouse_attrs[] = {
1412 	&dev_attr_mouse_wheel_step.attr,
1413 	&dev_attr_mouse_wheel_step_range.attr,
1414 	NULL,
1415 };
1416 
1417 static const struct attribute_group mouse_attr_group = {
1418 	.name = "mouse",
1419 	.attrs = legos_mouse_attrs,
1420 };
1421 
1422 /* Touchpad */
1423 static struct gos_cfg_attr touchpad_enabled = { FEATURE_TOUCHPAD_ENABLE };
1424 LEGOS_DEVICE_ATTR_RW(touchpad_enabled, "enabled", index, gamepad);
1425 static DEVICE_ATTR_RO_NAMED(touchpad_enabled_index, "enabled_index");
1426 
1427 static struct gos_cfg_attr touchpad_linux_mode = { CFG_LINUX_MODE };
1428 LEGOS_DEVICE_ATTR_RW(touchpad_linux_mode, "linux_mode", index, touchpad);
1429 static DEVICE_ATTR_RO_NAMED(touchpad_linux_mode_index, "linux_mode_index");
1430 
1431 static struct gos_cfg_attr touchpad_manufacturer = { TEST_TP_MFR };
1432 LEGOS_DEVICE_ATTR_RO(touchpad_manufacturer, "manufacturer", test);
1433 
1434 static struct gos_cfg_attr touchpad_version = { TEST_TP_VER };
1435 LEGOS_DEVICE_ATTR_RO(touchpad_version, "version", test);
1436 
1437 static struct gos_cfg_attr touchpad_windows_mode = { CFG_WINDOWS_MODE };
1438 LEGOS_DEVICE_ATTR_RW(touchpad_windows_mode, "windows_mode", index, touchpad);
1439 static DEVICE_ATTR_RO_NAMED(touchpad_windows_mode_index, "windows_mode_index");
1440 
1441 static struct attribute *legos_touchpad_attrs[] = {
1442 	&dev_attr_touchpad_enabled.attr,
1443 	&dev_attr_touchpad_enabled_index.attr,
1444 	&dev_attr_touchpad_linux_mode.attr,
1445 	&dev_attr_touchpad_linux_mode_index.attr,
1446 	&dev_attr_touchpad_manufacturer.attr,
1447 	&dev_attr_touchpad_version.attr,
1448 	&dev_attr_touchpad_windows_mode.attr,
1449 	&dev_attr_touchpad_windows_mode_index.attr,
1450 	NULL,
1451 };
1452 
1453 static const struct attribute_group touchpad_attr_group = {
1454 	.name = "touchpad",
1455 	.attrs = legos_touchpad_attrs,
1456 };
1457 
1458 static const struct attribute_group *top_level_attr_groups[] = {
1459 	&gamepad_attr_group,
1460 	&imu_attr_group,
1461 	&mcu_attr_group,
1462 	&mouse_attr_group,
1463 	&touchpad_attr_group,
1464 	NULL,
1465 };
1466 
1467 /* RGB */
1468 static struct gos_cfg_attr rgb_enabled = { FEATURE_RGB_ENABLE };
1469 LEGOS_DEVICE_ATTR_RW(rgb_enabled, "enabled", index, gamepad);
1470 static DEVICE_ATTR_RO_NAMED(rgb_enabled_index, "enabled_index");
1471 
1472 static DEVICE_ATTR_RW_NAMED(rgb_effect, "effect");
1473 static DEVICE_ATTR_RO_NAMED(rgb_effect_index, "effect_index");
1474 static DEVICE_ATTR_RW_NAMED(rgb_mode, "mode");
1475 static DEVICE_ATTR_RO_NAMED(rgb_mode_index, "mode_index");
1476 static DEVICE_ATTR_RW_NAMED(rgb_profile, "profile");
1477 static DEVICE_ATTR_RO_NAMED(rgb_profile_range, "profile_range");
1478 static DEVICE_ATTR_RW_NAMED(rgb_speed, "speed");
1479 static DEVICE_ATTR_RO_NAMED(rgb_speed_range, "speed_range");
1480 
1481 static struct attribute *gos_rgb_attrs[] = {
1482 	&dev_attr_rgb_enabled.attr,
1483 	&dev_attr_rgb_enabled_index.attr,
1484 	&dev_attr_rgb_effect.attr,
1485 	&dev_attr_rgb_effect_index.attr,
1486 	&dev_attr_rgb_mode.attr,
1487 	&dev_attr_rgb_mode_index.attr,
1488 	&dev_attr_rgb_profile.attr,
1489 	&dev_attr_rgb_profile_range.attr,
1490 	&dev_attr_rgb_speed.attr,
1491 	&dev_attr_rgb_speed_range.attr,
1492 	NULL,
1493 };
1494 
1495 static struct attribute_group rgb_attr_group = {
1496 	.attrs = gos_rgb_attrs,
1497 };
1498 
1499 static struct mc_subled gos_rgb_subled_info[] = {
1500 	{
1501 		.color_index = LED_COLOR_ID_RED,
1502 		.brightness = 0x50,
1503 		.intensity = 0x24,
1504 		.channel = 0x1,
1505 	},
1506 	{
1507 		.color_index = LED_COLOR_ID_GREEN,
1508 		.brightness = 0x50,
1509 		.intensity = 0x22,
1510 		.channel = 0x2,
1511 	},
1512 	{
1513 		.color_index = LED_COLOR_ID_BLUE,
1514 		.brightness = 0x50,
1515 		.intensity = 0x99,
1516 		.channel = 0x3,
1517 	},
1518 };
1519 
1520 static void cfg_setup(struct work_struct *work)
1521 {
1522 	struct delayed_work *dwork = container_of(work, struct delayed_work, work);
1523 	struct gos_cfg_drvdata *drvdata = container_of(dwork, struct gos_cfg_drvdata,
1524 						       gos_cfg_setup);
1525 	bool gp_registered, rgb_registered;
1526 	int ret;
1527 
1528 	if (!drvdata)
1529 		return;
1530 
1531 	/* MCU */
1532 	ret = mcu_property_out(drvdata->hdev, GET_MCU_ID, FEATURE_NONE, NULL, 0);
1533 	if (ret) {
1534 		dev_err(&drvdata->hdev->dev, "Failed to retrieve MCU ID: %i\n",
1535 			ret);
1536 		return;
1537 	}
1538 
1539 	ret = mcu_property_out(drvdata->hdev, GET_VERSION, FEATURE_NONE, NULL, 0);
1540 	if (ret) {
1541 		dev_err(&drvdata->hdev->dev, "Failed to retrieve MCU Version: %i\n", ret);
1542 		return;
1543 	}
1544 
1545 	ret = mcu_property_out(drvdata->hdev, GET_PL_TEST, TEST_TP_MFR, NULL, 0);
1546 	if (ret) {
1547 		dev_err(&drvdata->hdev->dev,
1548 			"Failed to retrieve Touchpad Manufacturer: %i\n", ret);
1549 		return;
1550 	}
1551 
1552 	ret = mcu_property_out(drvdata->hdev, GET_PL_TEST, TEST_TP_VER, NULL, 0);
1553 	if (ret) {
1554 		dev_err(&drvdata->hdev->dev,
1555 			"Failed to retrieve Touchpad Firmware Version: %i\n", ret);
1556 		return;
1557 	}
1558 
1559 	ret = mcu_property_out(drvdata->hdev, GET_PL_TEST, TEST_IMU_MFR, NULL, 0);
1560 	if (ret) {
1561 		dev_err(&drvdata->hdev->dev,
1562 			"Failed to retrieve IMU Manufacturer: %i\n", ret);
1563 		return;
1564 	}
1565 
1566 	ret = mcu_property_out(drvdata->hdev, GET_GAMEPAD_CFG, FEATURE_OS_MODE,
1567 			       NULL, 0);
1568 	if (ret) {
1569 		dev_err(&drvdata->hdev->dev,
1570 			"Failed to retrieve OS Mode: %i\n", ret);
1571 		return;
1572 	}
1573 
1574 /* Pairs with smp_store_release from below */
1575 	gp_registered = smp_load_acquire(&drvdata->gp_registered);
1576 	if (gp_registered)
1577 		goto try_rgb;
1578 
1579 	ret = sysfs_create_groups(&drvdata->hdev->dev.kobj, top_level_attr_groups);
1580 	if (ret) {
1581 		dev_err(&drvdata->hdev->dev,
1582 			"Failed to create gamepad configuration attributes: %i\n", ret);
1583 		goto try_rgb;
1584 	}
1585 
1586 /* Pairs with smp_load_acquire in attribute show/store functions */
1587 	smp_store_release(&drvdata->gp_registered, true);
1588 	gp_registered = true;
1589 
1590 try_rgb:
1591 /* Pairs with smp_store_release from below */
1592 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1593 	if (rgb_registered)
1594 		goto update_kobjects;
1595 
1596 	ret = devm_led_classdev_multicolor_register(&drvdata->hdev->dev, &drvdata->led_mc);
1597 	if (ret) {
1598 		dev_err(&drvdata->hdev->dev,
1599 			"Failed to create RGB device: %i\n", ret);
1600 		goto update_kobjects;
1601 	}
1602 
1603 	ret = devm_device_add_group(drvdata->led_mc.led_cdev.dev, &rgb_attr_group);
1604 	if (ret) {
1605 		dev_err(&drvdata->hdev->dev,
1606 			"Failed to create RGB configuration attributes: %i\n", ret);
1607 		goto update_kobjects;
1608 	}
1609 
1610 /* Pairs with smp_load_acquire in attribute show/store functions */
1611 	smp_store_release(&drvdata->rgb_registered, true);
1612 	rgb_registered = true;
1613 
1614 update_kobjects:
1615 	if (gp_registered)
1616 		kobject_uevent(&drvdata->hdev->dev.kobj, KOBJ_CHANGE);
1617 	if (rgb_registered)
1618 		kobject_uevent(&drvdata->led_mc.led_cdev.dev->kobj, KOBJ_CHANGE);
1619 }
1620 
1621 static int hid_gos_cfg_probe(struct hid_device *hdev,
1622 			     const struct hid_device_id *_id)
1623 {
1624 	struct gos_cfg_drvdata *drvdata;
1625 	int ret;
1626 
1627 	drvdata = devm_kzalloc(&hdev->dev, sizeof(struct gos_cfg_drvdata), GFP_KERNEL);
1628 	if (!drvdata)
1629 		return -ENOMEM;
1630 
1631 	hid_set_drvdata(hdev, drvdata);
1632 	drvdata->hdev = hdev;
1633 
1634 	mutex_init(&drvdata->cfg_mutex);
1635 	init_completion(&drvdata->send_cmd_complete);
1636 
1637 	/* Device is hardwired and name is guaranteed to be unique */
1638 	drvdata->led_mc.led_cdev.name = "go_s:rgb:joystick_rings";
1639 	drvdata->led_mc.led_cdev.brightness = 0x50;
1640 	drvdata->led_mc.led_cdev.max_brightness = 0x64;
1641 	drvdata->led_mc.led_cdev.color = LED_COLOR_ID_RGB;
1642 	drvdata->led_mc.led_cdev.brightness_set = hid_gos_brightness_set;
1643 	drvdata->led_mc.num_colors = 3;
1644 	drvdata->led_mc.subled_info = devm_kmemdup(&hdev->dev, gos_rgb_subled_info,
1645 						   sizeof(gos_rgb_subled_info), GFP_KERNEL);
1646 	if (!drvdata->led_mc.subled_info)
1647 		return -ENOMEM;
1648 
1649 	/* Executing calls prior to returning from probe will lock the MCU. Schedule
1650 	 * initial data call after probe has completed and MCU can accept calls.
1651 	 */
1652 	INIT_DELAYED_WORK(&drvdata->gos_cfg_setup, &cfg_setup);
1653 	ret = schedule_delayed_work(&drvdata->gos_cfg_setup, msecs_to_jiffies(2));
1654 	if (!ret) {
1655 		dev_err(&hdev->dev, "Failed to schedule startup delayed work\n");
1656 		return -ENODEV;
1657 	}
1658 
1659 	return 0;
1660 }
1661 
1662 static void hid_gos_cfg_remove(struct hid_device *hdev)
1663 {
1664 	struct gos_cfg_drvdata *drvdata = hid_get_drvdata(hdev);
1665 
1666 	if (!drvdata)
1667 		return;
1668 
1669 	disable_delayed_work_sync(&drvdata->gos_cfg_setup);
1670 	sysfs_remove_groups(&hdev->dev.kobj, top_level_attr_groups);
1671 	hid_hw_close(hdev);
1672 	hid_hw_stop(hdev);
1673 	hid_set_drvdata(hdev, NULL);
1674 }
1675 
1676 static int hid_gos_cfg_reset_resume(struct hid_device *hdev)
1677 {
1678 	struct gos_cfg_drvdata *drvdata = hid_get_drvdata(hdev);
1679 	bool gp_registered, rgb_registered;
1680 	u8 os_mode;
1681 	int ret;
1682 
1683 	if (!drvdata)
1684 		return -ENODEV;
1685 
1686 	os_mode = drvdata->os_mode;
1687 /* Pairs with smp_store_release from gos_cfg_setup */
1688 	gp_registered = smp_load_acquire(&drvdata->gp_registered);
1689 /* Pairs with smp_store_release from gos_cfg_setup */
1690 	rgb_registered = smp_load_acquire(&drvdata->rgb_registered);
1691 	if (!gp_registered || !rgb_registered) {
1692 		ret = schedule_delayed_work(&drvdata->gos_cfg_setup, msecs_to_jiffies(2));
1693 		if (!ret) {
1694 			dev_err(&hdev->dev, "Failed to schedule startup delayed work\n");
1695 			return -ENODEV;
1696 		}
1697 
1698 		return 0;
1699 	}
1700 
1701 	ret = mcu_property_out(drvdata->hdev, SET_GAMEPAD_CFG,
1702 			       FEATURE_OS_MODE, &os_mode, 1);
1703 	if (ret < 0)
1704 		return ret;
1705 
1706 	ret = mcu_property_out(drvdata->hdev, GET_GAMEPAD_CFG,
1707 			       FEATURE_OS_MODE, NULL, 0);
1708 	if (ret < 0)
1709 		return ret;
1710 
1711 	if (drvdata->os_mode != os_mode)
1712 		return -ENODEV;
1713 
1714 	kobject_uevent(&drvdata->hdev->dev.kobj, KOBJ_CHANGE);
1715 	return 0;
1716 }
1717 
1718 static int hid_gos_probe(struct hid_device *hdev,
1719 			 const struct hid_device_id *id)
1720 {
1721 	int ret, ep;
1722 
1723 	if (!hid_is_usb(hdev))
1724 		return -EINVAL;
1725 
1726 	ret = hid_parse(hdev);
1727 	if (ret) {
1728 		hid_err(hdev, "Parse failed\n");
1729 		return ret;
1730 	}
1731 
1732 	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
1733 	if (ret) {
1734 		hid_err(hdev, "Failed to start HID device\n");
1735 		return ret;
1736 	}
1737 
1738 	ret = hid_hw_open(hdev);
1739 	if (ret) {
1740 		hid_err(hdev, "Failed to open HID device\n");
1741 		hid_hw_stop(hdev);
1742 		return ret;
1743 	}
1744 
1745 	ep = get_endpoint_address(hdev);
1746 	if (ep != GO_S_CFG_INTF_IN) {
1747 		dev_dbg(&hdev->dev, "Started interface %x as generic HID device.\n", ep);
1748 		return 0;
1749 	}
1750 
1751 	ret = hid_gos_cfg_probe(hdev, id);
1752 	if (ret)
1753 		dev_err_probe(&hdev->dev, ret, "Failed to start configuration interface");
1754 
1755 	dev_dbg(&hdev->dev, "Started interface %x as Go S configuration interface\n", ep);
1756 	return ret;
1757 }
1758 
1759 static void hid_gos_remove(struct hid_device *hdev)
1760 {
1761 	int ep = get_endpoint_address(hdev);
1762 
1763 	switch (ep) {
1764 	case GO_S_CFG_INTF_IN:
1765 		hid_gos_cfg_remove(hdev);
1766 		break;
1767 	default:
1768 		hid_hw_close(hdev);
1769 		hid_hw_stop(hdev);
1770 
1771 		break;
1772 	}
1773 }
1774 
1775 static int hid_gos_reset_resume(struct hid_device *hdev)
1776 {
1777 	int ep = get_endpoint_address(hdev);
1778 
1779 	switch (ep) {
1780 	case GO_S_CFG_INTF_IN:
1781 		return hid_gos_cfg_reset_resume(hdev);
1782 	default:
1783 		break;
1784 	}
1785 
1786 	return 0;
1787 }
1788 
1789 static int hid_gos_cfg_suspend(struct hid_device *hdev)
1790 {
1791 	struct gos_cfg_drvdata *drvdata = hid_get_drvdata(hdev);
1792 
1793 	if (!drvdata)
1794 		return -ENODEV;
1795 
1796 	disable_delayed_work_sync(&drvdata->gos_cfg_setup);
1797 
1798 	return 0;
1799 }
1800 
1801 static int hid_gos_suspend(struct hid_device *hdev, pm_message_t msg)
1802 {
1803 	int ret;
1804 	u8 ep;
1805 
1806 	/* Safe assumption. SET_INTERFACE ioctl can't be used while driver is bound */
1807 	ret = get_endpoint_address(hdev);
1808 	if (ret <= 0)
1809 		return 0;
1810 
1811 	ep = ret;
1812 	if (ep == GO_S_CFG_INTF_IN)
1813 		return hid_gos_cfg_suspend(hdev);
1814 
1815 	return 0;
1816 }
1817 
1818 static const struct hid_device_id hid_gos_devices[] = {
1819 	{ HID_USB_DEVICE(USB_VENDOR_ID_QHE,
1820 			 USB_DEVICE_ID_LENOVO_LEGION_GO_S_XINPUT) },
1821 	{ HID_USB_DEVICE(USB_VENDOR_ID_QHE,
1822 			 USB_DEVICE_ID_LENOVO_LEGION_GO_S_DINPUT) },
1823 	{}
1824 };
1825 
1826 MODULE_DEVICE_TABLE(hid, hid_gos_devices);
1827 static struct hid_driver hid_lenovo_go_s = {
1828 	.name = "hid-lenovo-go-s",
1829 	.id_table = hid_gos_devices,
1830 	.probe = hid_gos_probe,
1831 	.remove = hid_gos_remove,
1832 	.raw_event = hid_gos_raw_event,
1833 	.reset_resume = pm_ptr(hid_gos_reset_resume),
1834 	.suspend = pm_ptr(hid_gos_suspend),
1835 };
1836 module_hid_driver(hid_lenovo_go_s);
1837 
1838 MODULE_AUTHOR("Derek J. Clark");
1839 MODULE_DESCRIPTION("HID Driver for Lenovo Legion Go S Series gamepad.");
1840 MODULE_LICENSE("GPL");
1841