diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c index d74a37c1980f1..cacc5bd5ed2b6 100644 --- a/drivers/hid/hid-lenovo-go-s.c +++ b/drivers/hid/hid-lenovo-go-s.c @@ -2,7 +2,8 @@ /* * HID driver for Lenovo Legion Go S devices. * - * Copyright (c) 2025 Derek J. Clark + * Copyright (c) 2026 Derek J. Clark + * Copyright (c) 2026 Valve Corporation */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -32,7 +33,6 @@ #define GO_S_PACKET_SIZE 64 struct hid_gos_cfg { - unsigned char *buf; struct delayed_work gos_cfg_setup; struct completion send_cmd_complete; struct led_classdev *led_cdev; @@ -397,12 +397,12 @@ static int hid_gos_raw_event(struct hid_device *hdev, struct hid_report *report, struct command_report *cmd_rep; int ep, ret; - if (size != GO_S_PACKET_SIZE) - goto passthrough; - ep = get_endpoint_address(hdev); if (ep != GO_S_CFG_INTF_IN) - goto passthrough; + return 0; + + if (size != GO_S_PACKET_SIZE) + return -EINVAL; cmd_rep = (struct command_report *)data; @@ -439,35 +439,32 @@ static int hid_gos_raw_event(struct hid_device *hdev, struct hid_report *report, complete(&drvdata.send_cmd_complete); return ret; - -passthrough: - /* Forward other HID reports so they generate events */ - hid_input_report(hdev, HID_INPUT_REPORT, data, size, 1); - return 0; } static int mcu_property_out(struct hid_device *hdev, u8 command, u8 index, u8 *data, size_t len) { + unsigned char *dmabuf __free(kfree) = NULL; u8 header[] = { command, index }; size_t header_size = ARRAY_SIZE(header); - size_t total_size = header_size + len; - int timeout = 5; - int ret; + int timeout, ret; - /* PL_TEST commands can take longer because they go out to another device */ - if (command == GET_PL_TEST) - timeout = 200; + if (header_size + len > GO_S_PACKET_SIZE) + return -EINVAL; guard(mutex)(&drvdata.cfg_mutex); - memcpy(drvdata.buf, header, header_size); - memcpy(drvdata.buf + header_size, data, len); - memset(drvdata.buf + total_size, 0, GO_S_PACKET_SIZE - total_size); + /* We can't use a devm_alloc reusable buffer without side effects during suspend */ + dmabuf = kzalloc(GO_S_PACKET_SIZE, GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + memcpy(dmabuf, header, header_size); + memcpy(dmabuf + header_size, data, len); dev_dbg(&hdev->dev, "Send data as raw output report: [%*ph]\n", - GO_S_PACKET_SIZE, drvdata.buf); + GO_S_PACKET_SIZE, dmabuf); - ret = hid_hw_output_report(hdev, drvdata.buf, GO_S_PACKET_SIZE); + ret = hid_hw_output_report(hdev, dmabuf, GO_S_PACKET_SIZE); if (ret < 0) return ret; @@ -475,16 +472,16 @@ static int mcu_property_out(struct hid_device *hdev, u8 command, u8 index, if (ret) return ret; + /* PL_TEST commands can take longer because they go out to another device */ + timeout = (command == GET_PL_TEST) ? 200 : 5; ret = wait_for_completion_interruptible_timeout(&drvdata.send_cmd_complete, msecs_to_jiffies(timeout)); if (ret == 0) /* timeout occurred */ ret = -EBUSY; - if (ret > 0) /* timeout/interrupt didn't occur */ - ret = 0; reinit_completion(&drvdata.send_cmd_complete); - return ret; + return 0; } static ssize_t gamepad_property_store(struct device *dev, @@ -540,7 +537,6 @@ static ssize_t gamepad_property_store(struct device *dev, if (ret < 0) return ret; val = ret; - drvdata.os_mode = val; break; case FEATURE_POLL_RATE: ret = sysfs_match_string(poll_rate_text, buf); @@ -807,13 +803,8 @@ static ssize_t test_property_show(struct device *dev, enum test_command_index index) { size_t count = 0; - int ret; u8 i; - ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, index, 0, 0); - if (ret) - return ret; - switch (index) { case TEST_TP_MFR: i = drvdata.tp_manufacturer; @@ -1359,40 +1350,28 @@ static void cfg_setup(struct work_struct *work) ret = mcu_property_out(drvdata.hdev, GET_VERSION, FEATURE_NONE, 0, 0); if (ret) { - dev_err(&drvdata.hdev->dev, - "Failed to retrieve MCU Version: %i\n", ret); - return; - } - - /* RGB */ - ret = mcu_property_out(drvdata.hdev, GET_GAMEPAD_CFG, FEATURE_RGB_ENABLE, - 0, 0); - if (ret < 0) { - dev_err(drvdata.led_cdev->dev, - "Failed to retrieve RGB enabled: %i\n", ret); + dev_err(&drvdata.hdev->dev, "Failed to retrieve MCU Version: %i\n", ret); return; } - ret = mcu_property_out(drvdata.hdev, GET_RGB_CFG, LIGHT_MODE_SEL, 0, - 0); - if (ret < 0) { - dev_err(drvdata.led_cdev->dev, - "Failed to retrieve RGB Mode: %i\n", ret); + ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, TEST_TP_MFR, 0, 0); + if (ret) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve Touchpad Manufacturer: %i\n", ret); return; } - ret = mcu_property_out(drvdata.hdev, GET_RGB_CFG, LIGHT_PROFILE_SEL, - 0, 0); - if (ret < 0) { - dev_err(drvdata.led_cdev->dev, - "Failed to retrieve RGB Profile: %i\n", ret); + ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, TEST_TP_VER, 0, 0); + if (ret) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve Touchpad Firmware Version: %i\n", ret); return; } - ret = rgb_attr_show(); - if (ret < 0) { - dev_err(drvdata.led_cdev->dev, - "Failed to retrieve RGB Profile Data: %i\n", ret); + ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, TEST_IMU_MFR, 0, 0); + if (ret) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve IMU Manufacturer: %i\n", ret); return; } } @@ -1400,15 +1379,9 @@ static void cfg_setup(struct work_struct *work) static int hid_gos_cfg_probe(struct hid_device *hdev, const struct hid_device_id *_id) { - unsigned char *buf; int ret; - buf = devm_kzalloc(&hdev->dev, GO_S_PACKET_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - hid_set_drvdata(hdev, &drvdata); - drvdata.buf = buf; drvdata.hdev = hdev; mutex_init(&drvdata.cfg_mutex); @@ -1440,13 +1413,12 @@ static int hid_gos_cfg_probe(struct hid_device *hdev, * initial data call after probe has completed and MCU can accept calls. */ INIT_DELAYED_WORK(&drvdata.gos_cfg_setup, &cfg_setup); - ret = schedule_delayed_work(&drvdata.gos_cfg_setup, - msecs_to_jiffies(2)); + ret = schedule_delayed_work(&drvdata.gos_cfg_setup, msecs_to_jiffies(2)); if (!ret) { - dev_err(&hdev->dev, - "Failed to schedule startup delayed work\n"); + dev_err(&hdev->dev, "Failed to schedule startup delayed work\n"); return -ENODEV; } + return 0; } @@ -1460,41 +1432,18 @@ static void hid_gos_cfg_remove(struct hid_device *hdev) hid_set_drvdata(hdev, NULL); } -static int hid_gos_cfg_reset_resume(struct hid_device *hdev) -{ - u8 os_mode = drvdata.os_mode; - int ret; - - ret = mcu_property_out(drvdata.hdev, SET_GAMEPAD_CFG, FEATURE_OS_MODE, - &os_mode, 1); - if (ret < 0) - return ret; - - ret = mcu_property_out(drvdata.hdev, GET_GAMEPAD_CFG, FEATURE_OS_MODE, 0, - 0); - if (ret < 0) - return ret; - - if (drvdata.os_mode != os_mode) - return -ENODEV; - - return 0; -} - static int hid_gos_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, ep; - hdev->quirks |= HID_QUIRK_INPUT_PER_APP | HID_QUIRK_MULTI_INPUT; - ret = hid_parse(hdev); if (ret) { hid_err(hdev, "Parse failed\n"); return ret; } - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); if (ret) { hid_err(hdev, "Failed to start HID device\n"); return ret; @@ -1509,17 +1458,15 @@ static int hid_gos_probe(struct hid_device *hdev, ep = get_endpoint_address(hdev); if (ep != GO_S_CFG_INTF_IN) { - dev_dbg(&hdev->dev, - "Started interface %x as generic HID device.\n", ep); + dev_dbg(&hdev->dev, "Started interface %x as generic HID device.\n", ep); return 0; } ret = hid_gos_cfg_probe(hdev, id); if (ret) - dev_err_probe(&hdev->dev, ret, - "Failed to start configuration interface"); + dev_err_probe(&hdev->dev, ret, "Failed to start configuration interface"); - dev_dbg(&hdev->dev, "Started Legion Go S HID Device: %x\n", ep); + dev_dbg(&hdev->dev, "Started interface %x as Go S configuration interface\n", ep); return ret; } @@ -1539,20 +1486,6 @@ static void hid_gos_remove(struct hid_device *hdev) } } -static int hid_gos_reset_resume(struct hid_device *hdev) -{ - int ep = get_endpoint_address(hdev); - - switch (ep) { - case GO_S_CFG_INTF_IN: - return hid_gos_cfg_reset_resume(hdev); - default: - break; - } - - return 0; -} - static const struct hid_device_id hid_gos_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_QHE, USB_DEVICE_ID_LENOVO_LEGION_GO_S_XINPUT) }, @@ -1567,7 +1500,6 @@ static struct hid_driver hid_lenovo_go_s = { .id_table = hid_gos_devices, .probe = hid_gos_probe, .remove = hid_gos_remove, - .reset_resume = hid_gos_reset_resume, .raw_event = hid_gos_raw_event, }; module_hid_driver(hid_lenovo_go_s); diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c index a09950874addf..6972d13802e20 100644 --- a/drivers/hid/hid-lenovo-go.c +++ b/drivers/hid/hid-lenovo-go.c @@ -2,7 +2,8 @@ /* * HID driver for Lenovo Legion Go series gamepads. * - * Copyright (c) 2025 Valve Corporation + * Copyright (c) 2026 Derek J. Clark + * Copyright (c) 2026 Valve Corporation */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -35,7 +36,6 @@ #define GO_PACKET_SIZE 64 struct hid_go_cfg { - unsigned char *buf; struct delayed_work go_cfg_setup; struct completion send_cmd_complete; struct led_classdev *led_cdev; @@ -338,19 +338,19 @@ static int hid_go_version_event(struct command_report *cmd_rep) switch (cmd_rep->device_type) { case USB_MCU: drvdata.mcu_version_product = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case TX_DONGLE: drvdata.tx_dongle_version_product = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case LEFT_CONTROLLER: drvdata.gp_left_version_product = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case RIGHT_CONTROLLER: drvdata.gp_right_version_product = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; default: return -EINVAL; @@ -359,19 +359,19 @@ static int hid_go_version_event(struct command_report *cmd_rep) switch (cmd_rep->device_type) { case USB_MCU: drvdata.mcu_version_protocol = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case TX_DONGLE: drvdata.tx_dongle_version_protocol = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case LEFT_CONTROLLER: drvdata.gp_left_version_protocol = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case RIGHT_CONTROLLER: drvdata.gp_right_version_protocol = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; default: return -EINVAL; @@ -380,19 +380,19 @@ static int hid_go_version_event(struct command_report *cmd_rep) switch (cmd_rep->device_type) { case USB_MCU: drvdata.mcu_version_firmware = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case TX_DONGLE: drvdata.tx_dongle_version_firmware = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case LEFT_CONTROLLER: drvdata.gp_left_version_firmware = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case RIGHT_CONTROLLER: drvdata.gp_right_version_firmware = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; default: return -EINVAL; @@ -401,19 +401,19 @@ static int hid_go_version_event(struct command_report *cmd_rep) switch (cmd_rep->device_type) { case USB_MCU: drvdata.mcu_version_hardware = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case TX_DONGLE: drvdata.tx_dongle_version_hardware = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case LEFT_CONTROLLER: drvdata.gp_left_version_hardware = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; case RIGHT_CONTROLLER: drvdata.gp_right_version_hardware = - get_unaligned_le32(cmd_rep->data); + get_unaligned_be32(cmd_rep->data); return 0; default: return -EINVAL; @@ -722,21 +722,28 @@ static int hid_go_raw_event(struct hid_device *hdev, struct hid_report *report, static int mcu_property_out(struct hid_device *hdev, u8 id, u8 command, u8 index, enum dev_type device, u8 *data, size_t len) { + unsigned char *dmabuf __free(kfree) = NULL; u8 header[] = { GO_OUTPUT_REPORT_ID, id, command, index, device }; size_t header_size = ARRAY_SIZE(header); - size_t total_size = header_size + len; int timeout = 50; int ret; + if (header_size + len > GO_PACKET_SIZE) + return -EINVAL; + guard(mutex)(&drvdata.cfg_mutex); - memcpy(drvdata.buf, header, header_size); - memcpy(drvdata.buf + header_size, data, len); - memset(drvdata.buf + total_size, 0, GO_PACKET_SIZE - total_size); + /* We can't use a devm_alloc reusable buffer without side effects during suspend */ + dmabuf = kzalloc(GO_PACKET_SIZE, GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + memcpy(dmabuf, header, header_size); + memcpy(dmabuf + header_size, data, len); dev_dbg(&hdev->dev, "Send data as raw output report: [%*ph]\n", - GO_PACKET_SIZE, drvdata.buf); + GO_PACKET_SIZE, dmabuf); - ret = hid_hw_output_report(hdev, drvdata.buf, GO_PACKET_SIZE); + ret = hid_hw_output_report(hdev, dmabuf, GO_PACKET_SIZE); if (ret < 0) return ret; @@ -749,11 +756,9 @@ static int mcu_property_out(struct hid_device *hdev, u8 id, u8 command, if (ret == 0) /* timeout occurred */ ret = -EBUSY; - if (ret > 0) /* timeout/interrupt didn't occur */ - ret = 0; reinit_completion(&drvdata.send_cmd_complete); - return ret; + return 0; } static ssize_t version_show(struct device *dev, struct device_attribute *attr, @@ -772,19 +777,19 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, case PRODUCT_VERSION: switch (device_type) { case USB_MCU: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.mcu_version_product); break; case TX_DONGLE: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.tx_dongle_version_product); break; case LEFT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_left_version_product); break; case RIGHT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_right_version_product); break; default: @@ -794,19 +799,19 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, case PROTOCOL_VERSION: switch (device_type) { case USB_MCU: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.mcu_version_protocol); break; case TX_DONGLE: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.tx_dongle_version_protocol); break; case LEFT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_left_version_protocol); break; case RIGHT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_right_version_protocol); break; default: @@ -816,19 +821,19 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, case FIRMWARE_VERSION: switch (device_type) { case USB_MCU: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.mcu_version_firmware); break; case TX_DONGLE: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.tx_dongle_version_firmware); break; case LEFT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_left_version_firmware); break; case RIGHT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_right_version_firmware); break; default: @@ -838,19 +843,19 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, case HARDWARE_VERSION: switch (device_type) { case USB_MCU: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.mcu_version_hardware); break; case TX_DONGLE: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.tx_dongle_version_hardware); break; case LEFT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_left_version_hardware); break; case RIGHT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_right_version_hardware); break; default: @@ -860,19 +865,19 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, case HARDWARE_GENERATION: switch (device_type) { case USB_MCU: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.mcu_version_gen); break; case TX_DONGLE: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.tx_dongle_version_gen); break; case LEFT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_left_version_gen); break; case RIGHT_CONTROLLER: - count = sysfs_emit(buf, "%u\n", + count = sysfs_emit(buf, "%x\n", drvdata.gp_right_version_gen); break; default: @@ -2182,36 +2187,167 @@ static void cfg_setup(struct work_struct *work) { int ret; - /* RGB */ - ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, - GET_FEATURE_STATUS, FEATURE_LIGHT_ENABLE, - UNSPECIFIED, 0, 0); + /* MCU Version Attrs */ + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + PRODUCT_VERSION, USB_MCU, 0, 0); if (ret < 0) { - dev_err(drvdata.led_cdev->dev, - "Failed to retrieve RGB enabled: %i\n", ret); + dev_err(&drvdata.hdev->dev, + "Failed to retrieve USB_MCU Product Version: %i\n", ret); return; } - ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_RGB_CFG, - LIGHT_MODE_SEL, UNSPECIFIED, 0, 0); + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + PROTOCOL_VERSION, USB_MCU, 0, 0); if (ret < 0) { - dev_err(drvdata.led_cdev->dev, - "Failed to retrieve RGB Mode: %i\n", ret); + dev_err(&drvdata.hdev->dev, + "Failed to retrieve USB_MCU Protocol Version: %i\n", ret); return; } - ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_RGB_CFG, - LIGHT_PROFILE_SEL, UNSPECIFIED, 0, 0); + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + FIRMWARE_VERSION, USB_MCU, 0, 0); if (ret < 0) { - dev_err(drvdata.led_cdev->dev, - "Failed to retrieve RGB Profile: %i\n", ret); + dev_err(&drvdata.hdev->dev, + "Failed to retrieve USB_MCU Firmware Version: %i\n", ret); return; } - ret = rgb_attr_show(); + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + HARDWARE_VERSION, USB_MCU, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve USB_MCU Hardware Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + HARDWARE_GENERATION, USB_MCU, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve USB_MCU Hardware Generation: %i\n", ret); + return; + } + + /* TX Dongle Version Attrs */ + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + PRODUCT_VERSION, TX_DONGLE, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve TX_DONGLE Product Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + PROTOCOL_VERSION, TX_DONGLE, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve TX_DONGLE Protocol Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + FIRMWARE_VERSION, TX_DONGLE, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve TX_DONGLE Firmware Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + HARDWARE_VERSION, TX_DONGLE, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve TX_DONGLE Hardware Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + HARDWARE_GENERATION, TX_DONGLE, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve TX_DONGLE Hardware Generation: %i\n", ret); + return; + } + + /* Left Handle Version Attrs */ + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + PRODUCT_VERSION, LEFT_CONTROLLER, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve LEFT_CONTROLLER Product Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + PROTOCOL_VERSION, LEFT_CONTROLLER, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve LEFT_CONTROLLER Protocol Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + FIRMWARE_VERSION, LEFT_CONTROLLER, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve LEFT_CONTROLLER Firmware Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + HARDWARE_VERSION, LEFT_CONTROLLER, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve LEFT_CONTROLLER Hardware Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + HARDWARE_GENERATION, LEFT_CONTROLLER, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve LEFT_CONTROLLER Hardware Generation: %i\n", ret); + return; + } + + /* Right Handle Version Attrs */ + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + PRODUCT_VERSION, RIGHT_CONTROLLER, 0, 0); if (ret < 0) { - dev_err(drvdata.led_cdev->dev, - "Failed to retrieve RGB Profile Data: %i\n", ret); + dev_err(&drvdata.hdev->dev, + "Failed to retrieve RIGHT_CONTROLLER Product Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + PROTOCOL_VERSION, RIGHT_CONTROLLER, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve RIGHT_CONTROLLER Protocol Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + FIRMWARE_VERSION, RIGHT_CONTROLLER, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve RIGHT_CONTROLLER Firmware Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + HARDWARE_VERSION, RIGHT_CONTROLLER, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve RIGHT_CONTROLLER Hardware Version: %i\n", ret); + return; + } + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_VERSION_DATA, + HARDWARE_GENERATION, RIGHT_CONTROLLER, 0, 0); + if (ret < 0) { + dev_err(&drvdata.hdev->dev, + "Failed to retrieve RIGHT_CONTROLLER Hardware Generation: %i\n", ret); return; } } @@ -2227,7 +2363,6 @@ static int hid_go_cfg_probe(struct hid_device *hdev, return -ENOMEM; hid_set_drvdata(hdev, &drvdata); - drvdata.buf = buf; drvdata.hdev = hdev; mutex_init(&drvdata.cfg_mutex); @@ -2271,34 +2406,12 @@ static int hid_go_cfg_probe(struct hid_device *hdev, static void hid_go_cfg_remove(struct hid_device *hdev) { guard(mutex)(&drvdata.cfg_mutex); - cancel_delayed_work_sync(&drvdata.go_cfg_setup); sysfs_remove_groups(&hdev->dev.kobj, top_level_attr_groups); hid_hw_close(hdev); hid_hw_stop(hdev); hid_set_drvdata(hdev, NULL); } -static int hid_go_cfg_reset_resume(struct hid_device *hdev) -{ - u8 os_mode = drvdata.os_mode; - int ret; - - ret = mcu_property_out(drvdata.hdev, OS_MODE_DATA, FEATURE_OS_MODE, - SET_OS_MODE, USB_MCU, &os_mode, 1); - if (ret < 0) - return ret; - - ret = mcu_property_out(drvdata.hdev, OS_MODE_DATA, FEATURE_OS_MODE, - GET_OS_MODE, USB_MCU, 0, 0); - if (ret < 0) - return ret; - - if (drvdata.os_mode != os_mode) - return -ENODEV; - - return 0; -} - static int hid_go_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, ep; @@ -2357,20 +2470,6 @@ static void hid_go_remove(struct hid_device *hdev) } } -static int hid_go_reset_resume(struct hid_device *hdev) -{ - int ep = get_endpoint_address(hdev); - - switch (ep) { - case GO_GP_INTF_IN: - return hid_go_cfg_reset_resume(hdev); - default: - break; - } - - return 0; -} - static const struct hid_device_id hid_go_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO2_XINPUT) }, @@ -2390,7 +2489,6 @@ static struct hid_driver hid_lenovo_go = { .probe = hid_go_probe, .remove = hid_go_remove, .raw_event = hid_go_raw_event, - .reset_resume = hid_go_reset_resume, }; module_hid_driver(hid_lenovo_go);