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