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