Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH v6 13/19] HID: hid-lenovo-go-s: Add Touchpad Mode Attributes
From: Derek J. Clark @ 2026-03-10  7:29 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Richard Hughes, Mario Limonciello, Zhixin Zhang, Mia Shao,
	Mark Pearson, Pierre-Loup A . Griffais, Derek J . Clark,
	linux-input, linux-doc, linux-kernel
In-Reply-To: <20260310072937.3295875-1-derekjohn.clark@gmail.com>

Adds attributes for managing the touchpad operating modes.

Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v6:
  - Make local attributes static.
  - Use NULL instead of 0 in mcu_propery_out when there is no data.
---
 drivers/hid/hid-lenovo-go-s.c | 142 ++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c
index 97c572cfe66c..5899cabe950f 100644
--- a/drivers/hid/hid-lenovo-go-s.c
+++ b/drivers/hid/hid-lenovo-go-s.c
@@ -47,6 +47,8 @@ static struct hid_gos_cfg {
 	u8 os_mode;
 	u8 rgb_en;
 	u8 tp_en;
+	u8 tp_linux_mode;
+	u8 tp_windows_mode;
 } drvdata;
 
 struct gos_cfg_attr {
@@ -145,6 +147,22 @@ static const char *const dpad_mode_text[] = {
 	[DIR4] = "4-way",
 };
 
+enum touchpad_mode_index {
+	TP_REL,
+	TP_ABS,
+};
+
+static const char *const touchpad_mode_text[] = {
+	[TP_REL] = "relative",
+	[TP_ABS] = "absolute",
+};
+
+enum touchpad_config_index {
+	CFG_WINDOWS_MODE = 0x03,
+	CFG_LINUX_MODE,
+
+};
+
 static int hid_gos_version_event(u8 *data)
 {
 	struct version_report *ver_rep = (struct version_report *)data;
@@ -204,6 +222,25 @@ static int hid_gos_gamepad_cfg_event(struct command_report *cmd_rep)
 	return ret;
 }
 
+static int hid_gos_touchpad_event(struct command_report *cmd_rep)
+{
+	int ret = 0;
+
+	switch (cmd_rep->sub_cmd) {
+	case CFG_LINUX_MODE:
+		drvdata.tp_linux_mode = cmd_rep->data[0];
+		break;
+	case CFG_WINDOWS_MODE:
+		drvdata.tp_windows_mode = cmd_rep->data[0];
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static int hid_gos_set_event_return(struct command_report *cmd_rep)
 {
 	if (cmd_rep->data[0] != 0)
@@ -251,7 +288,11 @@ static int hid_gos_raw_event(struct hid_device *hdev, struct hid_report *report,
 	case GET_GAMEPAD_CFG:
 		ret = hid_gos_gamepad_cfg_event(cmd_rep);
 		break;
+	case GET_TP_PARAM:
+		ret = hid_gos_touchpad_event(cmd_rep);
+		break;
 	case SET_GAMEPAD_CFG:
+	case SET_TP_PARAM:
 		ret = hid_gos_set_event_return(cmd_rep);
 		break;
 	default:
@@ -530,6 +571,95 @@ static ssize_t gamepad_property_options(struct device *dev,
 	return count;
 }
 
+static ssize_t touchpad_property_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count,
+				       enum touchpad_config_index index)
+{
+	size_t size = 1;
+	u8 val = 0;
+	int ret;
+
+	switch (index) {
+	case CFG_WINDOWS_MODE:
+		ret = sysfs_match_string(touchpad_mode_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	case CFG_LINUX_MODE:
+		ret = sysfs_match_string(touchpad_mode_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (!val)
+		size = 0;
+
+	ret = mcu_property_out(drvdata.hdev, SET_TP_PARAM, index, &val, size);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t touchpad_property_show(struct device *dev,
+				      struct device_attribute *attr, char *buf,
+				      enum touchpad_config_index index)
+{
+	int ret = 0;
+	u8 i;
+
+	ret = mcu_property_out(drvdata.hdev, GET_TP_PARAM, index, NULL, 0);
+	if (ret < 0)
+		return ret;
+
+	switch (index) {
+	case CFG_WINDOWS_MODE:
+		i = drvdata.tp_windows_mode;
+		break;
+	case CFG_LINUX_MODE:
+		i = drvdata.tp_linux_mode;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (i >= ARRAY_SIZE(touchpad_mode_text))
+		return -EINVAL;
+
+	return sysfs_emit(buf, "%s\n", touchpad_mode_text[i]);
+}
+
+static ssize_t touchpad_property_options(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf,
+					 enum touchpad_config_index index)
+{
+	size_t count = 0;
+	unsigned int i;
+
+	switch (index) {
+	case CFG_WINDOWS_MODE:
+	case CFG_LINUX_MODE:
+		for (i = 0; i < ARRAY_SIZE(touchpad_mode_text); i++) {
+			count += sysfs_emit_at(buf, count, "%s ",
+					       touchpad_mode_text[i]);
+		}
+		break;
+	default:
+		return count;
+	}
+
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+
 static ssize_t mcu_id_show(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
@@ -659,9 +789,21 @@ static struct gos_cfg_attr touchpad_enabled = { FEATURE_TOUCHPAD_ENABLE };
 LEGOS_DEVICE_ATTR_RW(touchpad_enabled, "enabled", index, gamepad);
 static DEVICE_ATTR_RO_NAMED(touchpad_enabled_index, "enabled_index");
 
+static struct gos_cfg_attr touchpad_linux_mode = { CFG_LINUX_MODE };
+LEGOS_DEVICE_ATTR_RW(touchpad_linux_mode, "linux_mode", index, touchpad);
+static DEVICE_ATTR_RO_NAMED(touchpad_linux_mode_index, "linux_mode_index");
+
+static struct gos_cfg_attr touchpad_windows_mode = { CFG_WINDOWS_MODE };
+LEGOS_DEVICE_ATTR_RW(touchpad_windows_mode, "windows_mode", index, touchpad);
+static DEVICE_ATTR_RO_NAMED(touchpad_windows_mode_index, "windows_mode_index");
+
 static struct attribute *legos_touchpad_attrs[] = {
 	&dev_attr_touchpad_enabled.attr,
 	&dev_attr_touchpad_enabled_index.attr,
+	&dev_attr_touchpad_linux_mode.attr,
+	&dev_attr_touchpad_linux_mode_index.attr,
+	&dev_attr_touchpad_windows_mode.attr,
+	&dev_attr_touchpad_windows_mode_index.attr,
 	NULL,
 };
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 12/19] HID: hid-lenovo-go-s: Add Feature Status Attributes
From: Derek J. Clark @ 2026-03-10  7:29 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Richard Hughes, Mario Limonciello, Zhixin Zhang, Mia Shao,
	Mark Pearson, Pierre-Loup A . Griffais, Derek J . Clark,
	linux-input, linux-doc, linux-kernel, Ethan Tidmore
In-Reply-To: <20260310072937.3295875-1-derekjohn.clark@gmail.com>

Adds features status attributes for the gamepad, MCU, touchpad/mouse,
and IMU devices.

Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Co-developed-by: Ethan Tidmore <ethantidmore06@gmail.com>
Signed-off-by: Ethan Tidmore <ethantidmore06@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v6:
  - Include positive promotion bug fix from Ethan Tidmore.
  - Include impossible condition bug fix from Ethan Tidmore.
  - Make local attributes static.
  - Use NULL instead of 0 in mcu_propery_out when there is no data.
v4:
  - Cleaner formatting on debug message.
---
 drivers/hid/hid-lenovo-go-s.c | 484 +++++++++++++++++++++++++++++++++-
 1 file changed, 483 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c
index 8ee75f724b5b..97c572cfe66c 100644
--- a/drivers/hid/hid-lenovo-go-s.c
+++ b/drivers/hid/hid-lenovo-go-s.c
@@ -15,6 +15,7 @@
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/jiffies.h>
+#include <linux/kstrtox.h>
 #include <linux/mutex.h>
 #include <linux/printk.h>
 #include <linux/string.h>
@@ -35,7 +36,17 @@ static struct hid_gos_cfg {
 	struct completion send_cmd_complete;
 	struct hid_device *hdev;
 	struct mutex cfg_mutex; /*ensure single synchronous output report*/
+	u8 gp_auto_sleep_time;
+	u8 gp_dpad_mode;
+	u8 gp_mode;
+	u8 gp_poll_rate;
+	u8 imu_bypass_en;
+	u8 imu_sensor_en;
 	u8 mcu_id[12];
+	u8 mouse_step;
+	u8 os_mode;
+	u8 rgb_en;
+	u8 tp_en;
 } drvdata;
 
 struct gos_cfg_attr {
@@ -66,7 +77,73 @@ enum mcu_command_index {
 	GET_PL_TEST = 0xdf,
 };
 
-#define FEATURE_NONE 0x00
+enum feature_enabled_index {
+	FEATURE_DISABLED,
+	FEATURE_ENABLED,
+};
+
+static const char *const feature_enabled_text[] = {
+	[FEATURE_DISABLED] = "false",
+	[FEATURE_ENABLED] = "true",
+};
+
+enum feature_status_index {
+	FEATURE_NONE = 0x00,
+	FEATURE_GAMEPAD_MODE = 0x01,
+	FEATURE_AUTO_SLEEP_TIME = 0x04,
+	FEATURE_IMU_BYPASS,
+	FEATURE_RGB_ENABLE,
+	FEATURE_IMU_ENABLE,
+	FEATURE_TOUCHPAD_ENABLE,
+	FEATURE_OS_MODE = 0x0A,
+	FEATURE_POLL_RATE = 0x10,
+	FEATURE_DPAD_MODE,
+	FEATURE_MOUSE_WHEEL_STEP,
+};
+
+enum gamepad_mode_index {
+	XINPUT,
+	DINPUT,
+};
+
+static const char *const gamepad_mode_text[] = {
+	[XINPUT] = "xinput",
+	[DINPUT] = "dinput",
+};
+
+enum os_type_index {
+	WINDOWS,
+	LINUX,
+};
+
+static const char *const os_type_text[] = {
+	[WINDOWS] = "windows",
+	[LINUX] = "linux",
+};
+
+enum poll_rate_index {
+	HZ125,
+	HZ250,
+	HZ500,
+	HZ1000,
+};
+
+static const char *const poll_rate_text[] = {
+	[HZ125] = "125",
+	[HZ250] = "250",
+	[HZ500] = "500",
+	[HZ1000] = "1000",
+};
+
+enum dpad_mode_index {
+	DIR8,
+	DIR4,
+};
+
+static const char *const dpad_mode_text[] = {
+	[DIR8] = "8-way",
+	[DIR4] = "4-way",
+};
 
 static int hid_gos_version_event(u8 *data)
 {
@@ -84,6 +161,57 @@ static int hid_gos_mcu_id_event(struct command_report *cmd_rep)
 	return 0;
 }
 
+static int hid_gos_gamepad_cfg_event(struct command_report *cmd_rep)
+{
+	int ret = 0;
+
+	switch (cmd_rep->sub_cmd) {
+	case FEATURE_GAMEPAD_MODE:
+		drvdata.gp_mode = cmd_rep->data[0];
+		break;
+	case FEATURE_AUTO_SLEEP_TIME:
+		drvdata.gp_auto_sleep_time = cmd_rep->data[0];
+		break;
+	case FEATURE_IMU_BYPASS:
+		drvdata.imu_bypass_en = cmd_rep->data[0];
+		break;
+	case FEATURE_RGB_ENABLE:
+		drvdata.rgb_en = cmd_rep->data[0];
+		break;
+	case FEATURE_IMU_ENABLE:
+		drvdata.imu_sensor_en = cmd_rep->data[0];
+		break;
+	case FEATURE_TOUCHPAD_ENABLE:
+		drvdata.tp_en = cmd_rep->data[0];
+		break;
+	case FEATURE_OS_MODE:
+		drvdata.os_mode = cmd_rep->data[0];
+		break;
+	case FEATURE_POLL_RATE:
+		drvdata.gp_poll_rate = cmd_rep->data[0];
+		break;
+	case FEATURE_DPAD_MODE:
+		drvdata.gp_dpad_mode = cmd_rep->data[0];
+		break;
+	case FEATURE_MOUSE_WHEEL_STEP:
+		drvdata.mouse_step = cmd_rep->data[0];
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int hid_gos_set_event_return(struct command_report *cmd_rep)
+{
+	if (cmd_rep->data[0] != 0)
+		return -EIO;
+
+	return 0;
+}
+
 static int get_endpoint_address(struct hid_device *hdev)
 {
 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
@@ -120,6 +248,12 @@ static int hid_gos_raw_event(struct hid_device *hdev, struct hid_report *report,
 	case GET_MCU_ID:
 		ret = hid_gos_mcu_id_event(cmd_rep);
 		break;
+	case GET_GAMEPAD_CFG:
+		ret = hid_gos_gamepad_cfg_event(cmd_rep);
+		break;
+	case SET_GAMEPAD_CFG:
+		ret = hid_gos_set_event_return(cmd_rep);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
@@ -174,17 +308,329 @@ static int mcu_property_out(struct hid_device *hdev, u8 command, u8 index,
 	return 0;
 }
 
+static ssize_t gamepad_property_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count,
+				      enum feature_status_index index)
+{
+	size_t size = 1;
+	u8 val = 0;
+	int ret;
+
+	switch (index) {
+	case FEATURE_GAMEPAD_MODE:
+		ret = sysfs_match_string(gamepad_mode_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	case FEATURE_AUTO_SLEEP_TIME:
+		ret = kstrtou8(buf, 10, &val);
+		if (ret)
+			return ret;
+		break;
+	case FEATURE_IMU_ENABLE:
+		ret = sysfs_match_string(feature_enabled_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	case FEATURE_IMU_BYPASS:
+		ret = sysfs_match_string(feature_enabled_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	case FEATURE_RGB_ENABLE:
+		ret = sysfs_match_string(feature_enabled_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	case FEATURE_TOUCHPAD_ENABLE:
+		ret = sysfs_match_string(feature_enabled_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	case FEATURE_OS_MODE:
+		ret = sysfs_match_string(os_type_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	case FEATURE_POLL_RATE:
+		ret = sysfs_match_string(poll_rate_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	case FEATURE_DPAD_MODE:
+		ret = sysfs_match_string(dpad_mode_text, buf);
+		if (ret < 0)
+			return ret;
+		val = ret;
+		break;
+	case FEATURE_MOUSE_WHEEL_STEP:
+		ret = kstrtou8(buf, 10, &val);
+		if (ret)
+			return ret;
+		if (val < 1 || val > 127)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!val)
+		size = 0;
+
+	ret = mcu_property_out(drvdata.hdev, SET_GAMEPAD_CFG, index, &val,
+			       size);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t gamepad_property_show(struct device *dev,
+				     struct device_attribute *attr, char *buf,
+				     enum feature_status_index index)
+{
+	ssize_t count = 0;
+	u8 i;
+
+	count = mcu_property_out(drvdata.hdev, GET_GAMEPAD_CFG, index, NULL, 0);
+	if (count < 0)
+		return count;
+
+	switch (index) {
+	case FEATURE_GAMEPAD_MODE:
+		i = drvdata.gp_mode;
+		if (i >= ARRAY_SIZE(gamepad_mode_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", gamepad_mode_text[i]);
+		break;
+	case FEATURE_AUTO_SLEEP_TIME:
+		count = sysfs_emit(buf, "%u\n", drvdata.gp_auto_sleep_time);
+		break;
+	case FEATURE_IMU_ENABLE:
+		i = drvdata.imu_sensor_en;
+		if (i >= ARRAY_SIZE(feature_enabled_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]);
+		break;
+	case FEATURE_IMU_BYPASS:
+		i = drvdata.imu_bypass_en;
+		if (i >= ARRAY_SIZE(feature_enabled_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]);
+		break;
+	case FEATURE_RGB_ENABLE:
+		i = drvdata.rgb_en;
+		if (i >= ARRAY_SIZE(feature_enabled_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]);
+		break;
+	case FEATURE_TOUCHPAD_ENABLE:
+		i = drvdata.tp_en;
+		if (i >= ARRAY_SIZE(feature_enabled_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", feature_enabled_text[i]);
+		break;
+	case FEATURE_OS_MODE:
+		i = drvdata.os_mode;
+		if (i >= ARRAY_SIZE(os_type_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", os_type_text[i]);
+		break;
+	case FEATURE_POLL_RATE:
+		i = drvdata.gp_poll_rate;
+		if (i >= ARRAY_SIZE(poll_rate_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", poll_rate_text[i]);
+		break;
+	case FEATURE_DPAD_MODE:
+		i = drvdata.gp_dpad_mode;
+		if (i >= ARRAY_SIZE(dpad_mode_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", dpad_mode_text[i]);
+		break;
+	case FEATURE_MOUSE_WHEEL_STEP:
+		i = drvdata.mouse_step;
+		if (i < 1 || i > 127)
+			return -EINVAL;
+		count = sysfs_emit(buf, "%u\n", i);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static ssize_t gamepad_property_options(struct device *dev,
+					struct device_attribute *attr,
+					char *buf,
+					enum feature_status_index index)
+{
+	size_t count = 0;
+	unsigned int i;
+
+	switch (index) {
+	case FEATURE_GAMEPAD_MODE:
+		for (i = 0; i < ARRAY_SIZE(gamepad_mode_text); i++) {
+			count += sysfs_emit_at(buf, count, "%s ",
+					       gamepad_mode_text[i]);
+		}
+		break;
+	case FEATURE_AUTO_SLEEP_TIME:
+		return sysfs_emit(buf, "0-255\n");
+	case FEATURE_IMU_ENABLE:
+		for (i = 0; i < ARRAY_SIZE(feature_enabled_text); i++) {
+			count += sysfs_emit_at(buf, count, "%s ",
+					       feature_enabled_text[i]);
+		}
+		break;
+	case FEATURE_IMU_BYPASS:
+	case FEATURE_RGB_ENABLE:
+	case FEATURE_TOUCHPAD_ENABLE:
+		for (i = 0; i < ARRAY_SIZE(feature_enabled_text); i++) {
+			count += sysfs_emit_at(buf, count, "%s ",
+					       feature_enabled_text[i]);
+		}
+		break;
+	case FEATURE_OS_MODE:
+		for (i = 0; i < ARRAY_SIZE(os_type_text); i++) {
+			count += sysfs_emit_at(buf, count, "%s ",
+					       os_type_text[i]);
+		}
+		break;
+	case FEATURE_POLL_RATE:
+		for (i = 0; i < ARRAY_SIZE(poll_rate_text); i++) {
+			count += sysfs_emit_at(buf, count, "%s ",
+					       poll_rate_text[i]);
+		}
+		break;
+	case FEATURE_DPAD_MODE:
+		for (i = 0; i < ARRAY_SIZE(dpad_mode_text); i++) {
+			count += sysfs_emit_at(buf, count, "%s ",
+					       dpad_mode_text[i]);
+		}
+		break;
+	case FEATURE_MOUSE_WHEEL_STEP:
+		return sysfs_emit(buf, "1-127\n");
+	default:
+		return count;
+	}
+
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+
 static ssize_t mcu_id_show(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
 	return sysfs_emit(buf, "%*phN\n", 12, &drvdata.mcu_id);
 }
 
+#define LEGOS_DEVICE_ATTR_RW(_name, _attrname, _rtype, _group)                 \
+	static ssize_t _name##_store(struct device *dev,                       \
+				     struct device_attribute *attr,            \
+				     const char *buf, size_t count)            \
+	{                                                                      \
+		return _group##_property_store(dev, attr, buf, count,          \
+					       _name.index);                   \
+	}                                                                      \
+	static ssize_t _name##_show(struct device *dev,                        \
+				    struct device_attribute *attr, char *buf)  \
+	{                                                                      \
+		return _group##_property_show(dev, attr, buf, _name.index);    \
+	}                                                                      \
+	static ssize_t _name##_##_rtype##_show(                                \
+		struct device *dev, struct device_attribute *attr, char *buf)  \
+	{                                                                      \
+		return _group##_property_options(dev, attr, buf, _name.index); \
+	}                                                                      \
+	static DEVICE_ATTR_RW_NAMED(_name, _attrname)
+
+#define LEGOS_DEVICE_ATTR_RO(_name, _attrname, _group)                        \
+	static ssize_t _name##_show(struct device *dev,                       \
+				    struct device_attribute *attr, char *buf) \
+	{                                                                     \
+		return _group##_property_show(dev, attr, buf, _name.index);   \
+	}                                                                     \
+	static DEVICE_ATTR_RO_NAMED(_name, _attrname)
+
+/* Gamepad */
+static struct gos_cfg_attr auto_sleep_time = { FEATURE_AUTO_SLEEP_TIME };
+LEGOS_DEVICE_ATTR_RW(auto_sleep_time, "auto_sleep_time", range, gamepad);
+static DEVICE_ATTR_RO(auto_sleep_time_range);
+
+static struct gos_cfg_attr dpad_mode = { FEATURE_DPAD_MODE };
+LEGOS_DEVICE_ATTR_RW(dpad_mode, "dpad_mode", index, gamepad);
+static DEVICE_ATTR_RO(dpad_mode_index);
+
+static struct gos_cfg_attr gamepad_mode = { FEATURE_GAMEPAD_MODE };
+LEGOS_DEVICE_ATTR_RW(gamepad_mode, "mode", index, gamepad);
+static DEVICE_ATTR_RO_NAMED(gamepad_mode_index, "mode_index");
+
+static struct gos_cfg_attr gamepad_poll_rate = { FEATURE_POLL_RATE };
+LEGOS_DEVICE_ATTR_RW(gamepad_poll_rate, "poll_rate", index, gamepad);
+static DEVICE_ATTR_RO_NAMED(gamepad_poll_rate_index, "poll_rate_index");
+
+static struct attribute *legos_gamepad_attrs[] = {
+	&dev_attr_auto_sleep_time.attr,
+	&dev_attr_auto_sleep_time_range.attr,
+	&dev_attr_dpad_mode.attr,
+	&dev_attr_dpad_mode_index.attr,
+	&dev_attr_gamepad_mode.attr,
+	&dev_attr_gamepad_mode_index.attr,
+	&dev_attr_gamepad_poll_rate.attr,
+	&dev_attr_gamepad_poll_rate_index.attr,
+	NULL,
+};
+
+static const struct attribute_group gamepad_attr_group = {
+	.name = "gamepad",
+	.attrs = legos_gamepad_attrs,
+};
+
+/* IMU */
+static struct gos_cfg_attr imu_bypass_enabled = { FEATURE_IMU_BYPASS };
+LEGOS_DEVICE_ATTR_RW(imu_bypass_enabled, "bypass_enabled", index, gamepad);
+static DEVICE_ATTR_RO_NAMED(imu_bypass_enabled_index, "bypass_enabled_index");
+
+static struct gos_cfg_attr imu_sensor_enabled = { FEATURE_IMU_ENABLE };
+LEGOS_DEVICE_ATTR_RW(imu_sensor_enabled, "sensor_enabled", index, gamepad);
+static DEVICE_ATTR_RO_NAMED(imu_sensor_enabled_index, "sensor_enabled_index");
+
+static struct attribute *legos_imu_attrs[] = {
+	&dev_attr_imu_bypass_enabled.attr,
+	&dev_attr_imu_bypass_enabled_index.attr,
+	&dev_attr_imu_sensor_enabled.attr,
+	&dev_attr_imu_sensor_enabled_index.attr,
+	NULL,
+};
+
+static const struct attribute_group imu_attr_group = {
+	.name = "imu",
+	.attrs = legos_imu_attrs,
+};
+
 /* MCU */
 static DEVICE_ATTR_RO(mcu_id);
 
+static struct gos_cfg_attr os_mode = { FEATURE_OS_MODE };
+LEGOS_DEVICE_ATTR_RW(os_mode, "os_mode", index, gamepad);
+static DEVICE_ATTR_RO(os_mode_index);
+
 static struct attribute *legos_mcu_attrs[] = {
 	&dev_attr_mcu_id.attr,
+	&dev_attr_os_mode.attr,
+	&dev_attr_os_mode_index.attr,
 	NULL,
 };
 
@@ -192,8 +638,44 @@ static const struct attribute_group mcu_attr_group = {
 	.attrs = legos_mcu_attrs,
 };
 
+/* Mouse */
+static struct gos_cfg_attr mouse_wheel_step = { FEATURE_MOUSE_WHEEL_STEP };
+LEGOS_DEVICE_ATTR_RW(mouse_wheel_step, "step", range, gamepad);
+static DEVICE_ATTR_RO_NAMED(mouse_wheel_step_range, "step_range");
+
+static struct attribute *legos_mouse_attrs[] = {
+	&dev_attr_mouse_wheel_step.attr,
+	&dev_attr_mouse_wheel_step_range.attr,
+	NULL,
+};
+
+static const struct attribute_group mouse_attr_group = {
+	.name = "mouse",
+	.attrs = legos_mouse_attrs,
+};
+
+/* Touchpad */
+static struct gos_cfg_attr touchpad_enabled = { FEATURE_TOUCHPAD_ENABLE };
+LEGOS_DEVICE_ATTR_RW(touchpad_enabled, "enabled", index, gamepad);
+static DEVICE_ATTR_RO_NAMED(touchpad_enabled_index, "enabled_index");
+
+static struct attribute *legos_touchpad_attrs[] = {
+	&dev_attr_touchpad_enabled.attr,
+	&dev_attr_touchpad_enabled_index.attr,
+	NULL,
+};
+
+static const struct attribute_group touchpad_attr_group = {
+	.name = "touchpad",
+	.attrs = legos_touchpad_attrs,
+};
+
 static const struct attribute_group *top_level_attr_groups[] = {
+	&gamepad_attr_group,
+	&imu_attr_group,
 	&mcu_attr_group,
+	&mouse_attr_group,
+	&touchpad_attr_group,
 	NULL,
 };
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 14/19] HID: hid-lenovo-go-s: Add RGB LED control interface
From: Derek J. Clark @ 2026-03-10  7:29 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Richard Hughes, Mario Limonciello, Zhixin Zhang, Mia Shao,
	Mark Pearson, Pierre-Loup A . Griffais, Derek J . Clark,
	linux-input, linux-doc, linux-kernel
In-Reply-To: <20260310072937.3295875-1-derekjohn.clark@gmail.com>

Adds an LED multicolor class device and attribute group for controlling
the RGB of the Left and right joystick rings. In addition to the standard
led_cdev attributes, additional attributes that allow for the control of
the effect (monocolor, breathe, rainbow, and chroma), speed of the
effect change, an enable toggle, and profile.

Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v6:
  - Make local attributes static.
  - Use NULL instead of 0 in mcu_propery_out when there is no data.
v4:
  - Cleaner formatting on multiple debug messages.
---
 drivers/hid/hid-lenovo-go-s.c | 422 ++++++++++++++++++++++++++++++++++
 1 file changed, 422 insertions(+)

diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c
index 5899cabe950f..0123c4b03cf4 100644
--- a/drivers/hid/hid-lenovo-go-s.c
+++ b/drivers/hid/hid-lenovo-go-s.c
@@ -16,6 +16,7 @@
 #include <linux/hid.h>
 #include <linux/jiffies.h>
 #include <linux/kstrtox.h>
+#include <linux/led-class-multicolor.h>
 #include <linux/mutex.h>
 #include <linux/printk.h>
 #include <linux/string.h>
@@ -34,6 +35,7 @@
 static struct hid_gos_cfg {
 	struct delayed_work gos_cfg_setup;
 	struct completion send_cmd_complete;
+	struct led_classdev *led_cdev;
 	struct hid_device *hdev;
 	struct mutex cfg_mutex; /*ensure single synchronous output report*/
 	u8 gp_auto_sleep_time;
@@ -45,7 +47,11 @@ static struct hid_gos_cfg {
 	u8 mcu_id[12];
 	u8 mouse_step;
 	u8 os_mode;
+	u8 rgb_effect;
 	u8 rgb_en;
+	u8 rgb_mode;
+	u8 rgb_profile;
+	u8 rgb_speed;
 	u8 tp_en;
 	u8 tp_linux_mode;
 	u8 tp_windows_mode;
@@ -163,6 +169,38 @@ enum touchpad_config_index {
 
 };
 
+enum rgb_mode_index {
+	RGB_MODE_DYNAMIC,
+	RGB_MODE_CUSTOM,
+};
+
+static const char *const rgb_mode_text[] = {
+	[RGB_MODE_DYNAMIC] = "dynamic",
+	[RGB_MODE_CUSTOM] = "custom",
+};
+
+enum rgb_effect_index {
+	RGB_EFFECT_MONO,
+	RGB_EFFECT_BREATHE,
+	RGB_EFFECT_CHROMA,
+	RGB_EFFECT_RAINBOW,
+};
+
+static const char *const rgb_effect_text[] = {
+	[RGB_EFFECT_MONO] = "monocolor",
+	[RGB_EFFECT_BREATHE] = "breathe",
+	[RGB_EFFECT_CHROMA] = "chroma",
+	[RGB_EFFECT_RAINBOW] = "rainbow",
+};
+
+enum rgb_config_index {
+	LIGHT_MODE_SEL = 0x01,
+	LIGHT_PROFILE_SEL,
+	USR_LIGHT_PROFILE_1,
+	USR_LIGHT_PROFILE_2,
+	USR_LIGHT_PROFILE_3,
+};
+
 static int hid_gos_version_event(u8 *data)
 {
 	struct version_report *ver_rep = (struct version_report *)data;
@@ -241,6 +279,39 @@ static int hid_gos_touchpad_event(struct command_report *cmd_rep)
 	return ret;
 }
 
+static int hid_gos_light_event(struct command_report *cmd_rep)
+{
+	struct led_classdev_mc *mc_cdev;
+	int ret = 0;
+
+	switch (cmd_rep->sub_cmd) {
+	case LIGHT_MODE_SEL:
+		drvdata.rgb_mode = cmd_rep->data[0];
+		ret = 0;
+		break;
+	case LIGHT_PROFILE_SEL:
+		drvdata.rgb_profile = cmd_rep->data[0];
+		ret = 0;
+		break;
+	case USR_LIGHT_PROFILE_1:
+	case USR_LIGHT_PROFILE_2:
+	case USR_LIGHT_PROFILE_3:
+		mc_cdev = lcdev_to_mccdev(drvdata.led_cdev);
+		drvdata.rgb_effect = cmd_rep->data[0];
+		mc_cdev->subled_info[0].intensity = cmd_rep->data[1];
+		mc_cdev->subled_info[1].intensity = cmd_rep->data[2];
+		mc_cdev->subled_info[2].intensity = cmd_rep->data[3];
+		drvdata.led_cdev->brightness = cmd_rep->data[4];
+		drvdata.rgb_speed = cmd_rep->data[5];
+		ret = 0;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int hid_gos_set_event_return(struct command_report *cmd_rep)
 {
 	if (cmd_rep->data[0] != 0)
@@ -291,7 +362,11 @@ static int hid_gos_raw_event(struct hid_device *hdev, struct hid_report *report,
 	case GET_TP_PARAM:
 		ret = hid_gos_touchpad_event(cmd_rep);
 		break;
+	case GET_RGB_CFG:
+		ret = hid_gos_light_event(cmd_rep);
+		break;
 	case SET_GAMEPAD_CFG:
+	case SET_RGB_CFG:
 	case SET_TP_PARAM:
 		ret = hid_gos_set_event_return(cmd_rep);
 		break;
@@ -666,6 +741,274 @@ static ssize_t mcu_id_show(struct device *dev, struct device_attribute *attr,
 	return sysfs_emit(buf, "%*phN\n", 12, &drvdata.mcu_id);
 }
 
+static int rgb_cfg_call(struct hid_device *hdev, enum mcu_command_index cmd,
+			enum rgb_config_index index, u8 *val, size_t size)
+{
+	if (cmd != SET_RGB_CFG && cmd != GET_RGB_CFG)
+		return -EINVAL;
+
+	if (index < LIGHT_MODE_SEL || index > USR_LIGHT_PROFILE_3)
+		return -EINVAL;
+
+	return mcu_property_out(hdev, cmd, index, val, size);
+}
+
+static int rgb_attr_show(void)
+{
+	enum rgb_config_index index;
+
+	index = drvdata.rgb_profile + 2;
+
+	return rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, index, NULL, 0);
+};
+
+static ssize_t rgb_effect_store(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(drvdata.led_cdev);
+	enum rgb_config_index index;
+	u8 effect;
+	int ret;
+
+	ret = sysfs_match_string(rgb_effect_text, buf);
+	if (ret < 0)
+		return ret;
+
+	effect = ret;
+	index = drvdata.rgb_profile + 2;
+	u8 rgb_profile[6] = { effect,
+			      mc_cdev->subled_info[0].intensity,
+			      mc_cdev->subled_info[1].intensity,
+			      mc_cdev->subled_info[2].intensity,
+			      drvdata.led_cdev->brightness,
+			      drvdata.rgb_speed };
+
+	ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6);
+	if (ret)
+		return ret;
+
+	drvdata.rgb_effect = effect;
+	return count;
+};
+
+static ssize_t rgb_effect_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int ret;
+
+	ret = rgb_attr_show();
+	if (ret)
+		return ret;
+
+	if (drvdata.rgb_effect >= ARRAY_SIZE(rgb_effect_text))
+		return -EINVAL;
+
+	return sysfs_emit(buf, "%s\n", rgb_effect_text[drvdata.rgb_effect]);
+}
+
+static ssize_t rgb_effect_index_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	ssize_t count = 0;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(rgb_effect_text); i++)
+		count += sysfs_emit_at(buf, count, "%s ", rgb_effect_text[i]);
+
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+
+static ssize_t rgb_speed_store(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t count)
+{
+	struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(drvdata.led_cdev);
+	enum rgb_config_index index;
+	int val = 0;
+	int ret;
+
+	ret = kstrtoint(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	if (val < 0 || val > 100)
+		return -EINVAL;
+
+	index = drvdata.rgb_profile + 2;
+	u8 rgb_profile[6] = { drvdata.rgb_effect,
+			      mc_cdev->subled_info[0].intensity,
+			      mc_cdev->subled_info[1].intensity,
+			      mc_cdev->subled_info[2].intensity,
+			      drvdata.led_cdev->brightness,
+			      val };
+
+	ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6);
+	if (ret)
+		return ret;
+
+	drvdata.rgb_speed = val;
+
+	return count;
+};
+
+static ssize_t rgb_speed_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	int ret;
+
+	ret = rgb_attr_show();
+	if (ret)
+		return ret;
+
+	if (drvdata.rgb_speed > 100)
+		return -EINVAL;
+
+	return sysfs_emit(buf, "%hhu\n", drvdata.rgb_speed);
+}
+
+static ssize_t rgb_speed_range_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "0-100\n");
+}
+
+static ssize_t rgb_mode_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	int ret;
+	u8 val;
+
+	ret = sysfs_match_string(rgb_mode_text, buf);
+	if (ret <= 0)
+		return ret;
+
+	val = ret;
+
+	ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, LIGHT_MODE_SEL, &val,
+			   1);
+	if (ret)
+		return ret;
+
+	drvdata.rgb_mode = val;
+
+	return count;
+};
+
+static ssize_t rgb_mode_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int ret;
+
+	ret = rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, LIGHT_MODE_SEL, NULL, 0);
+	if (ret)
+		return ret;
+
+	if (drvdata.rgb_mode >= ARRAY_SIZE(rgb_mode_text))
+		return -EINVAL;
+
+	return sysfs_emit(buf, "%s\n", rgb_mode_text[drvdata.rgb_mode]);
+};
+
+static ssize_t rgb_mode_index_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	ssize_t count = 0;
+	unsigned int i;
+
+	for (i = 1; i < ARRAY_SIZE(rgb_mode_text); i++)
+		count += sysfs_emit_at(buf, count, "%s ", rgb_mode_text[i]);
+
+	if (count)
+		buf[count - 1] = '\n';
+
+	return count;
+}
+
+static ssize_t rgb_profile_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
+{
+	size_t size = 1;
+	int ret;
+	u8 val;
+
+	ret = kstrtou8(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	if (val < 1 || val > 3)
+		return -EINVAL;
+
+	ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, LIGHT_PROFILE_SEL, &val, size);
+	if (ret)
+		return ret;
+
+	drvdata.rgb_profile = val;
+
+	return count;
+};
+
+static ssize_t rgb_profile_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int ret;
+
+	ret = rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, LIGHT_PROFILE_SEL, NULL, 0);
+	if (ret)
+		return ret;
+
+	if (drvdata.rgb_profile < 1 || drvdata.rgb_profile > 3)
+		return -EINVAL;
+
+	return sysfs_emit(buf, "%hhu\n", drvdata.rgb_profile);
+};
+
+static ssize_t rgb_profile_range_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "1-3\n");
+}
+
+static void hid_gos_brightness_set(struct led_classdev *led_cdev,
+				   enum led_brightness brightness)
+{
+	struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(drvdata.led_cdev);
+	enum rgb_config_index index;
+	int ret;
+
+	if (brightness > led_cdev->max_brightness) {
+		dev_err(led_cdev->dev, "Invalid argument\n");
+		return;
+	}
+
+	index = drvdata.rgb_profile + 2;
+	u8 rgb_profile[6] = { drvdata.rgb_effect,
+			      mc_cdev->subled_info[0].intensity,
+			      mc_cdev->subled_info[1].intensity,
+			      mc_cdev->subled_info[2].intensity,
+			      brightness,
+			      drvdata.rgb_speed };
+
+	ret = rgb_cfg_call(drvdata.hdev, SET_RGB_CFG, index, rgb_profile, 6);
+	switch (ret) {
+	case 0:
+		led_cdev->brightness = brightness;
+		break;
+	case -ENODEV: /* during switch to IAP -ENODEV is expected */
+	case -ENOSYS: /* during rmmod -ENOSYS is expected */
+		dev_dbg(led_cdev->dev, "Failed to write RGB profile: %i\n",
+			ret);
+		break;
+	default:
+		dev_err(led_cdev->dev, "Failed to write RGB profile: %i\n",
+			ret);
+	};
+}
+
 #define LEGOS_DEVICE_ATTR_RW(_name, _attrname, _rtype, _group)                 \
 	static ssize_t _name##_store(struct device *dev,                       \
 				     struct device_attribute *attr,            \
@@ -821,6 +1164,70 @@ static const struct attribute_group *top_level_attr_groups[] = {
 	NULL,
 };
 
+/* RGB */
+static struct gos_cfg_attr rgb_enabled = { FEATURE_RGB_ENABLE };
+LEGOS_DEVICE_ATTR_RW(rgb_enabled, "enabled", index, gamepad);
+static DEVICE_ATTR_RO_NAMED(rgb_enabled_index, "enabled_index");
+
+static DEVICE_ATTR_RW_NAMED(rgb_effect, "effect");
+static DEVICE_ATTR_RO_NAMED(rgb_effect_index, "effect_index");
+static DEVICE_ATTR_RW_NAMED(rgb_mode, "mode");
+static DEVICE_ATTR_RO_NAMED(rgb_mode_index, "mode_index");
+static DEVICE_ATTR_RW_NAMED(rgb_profile, "profile");
+static DEVICE_ATTR_RO_NAMED(rgb_profile_range, "profile_range");
+static DEVICE_ATTR_RW_NAMED(rgb_speed, "speed");
+static DEVICE_ATTR_RO_NAMED(rgb_speed_range, "speed_range");
+
+static struct attribute *gos_rgb_attrs[] = {
+	&dev_attr_rgb_enabled.attr,
+	&dev_attr_rgb_enabled_index.attr,
+	&dev_attr_rgb_effect.attr,
+	&dev_attr_rgb_effect_index.attr,
+	&dev_attr_rgb_mode.attr,
+	&dev_attr_rgb_mode_index.attr,
+	&dev_attr_rgb_profile.attr,
+	&dev_attr_rgb_profile_range.attr,
+	&dev_attr_rgb_speed.attr,
+	&dev_attr_rgb_speed_range.attr,
+	NULL,
+};
+
+static struct attribute_group rgb_attr_group = {
+	.attrs = gos_rgb_attrs,
+};
+
+static struct mc_subled gos_rgb_subled_info[] = {
+	{
+		.color_index = LED_COLOR_ID_RED,
+		.brightness = 0x50,
+		.intensity = 0x24,
+		.channel = 0x1,
+	},
+	{
+		.color_index = LED_COLOR_ID_GREEN,
+		.brightness = 0x50,
+		.intensity = 0x22,
+		.channel = 0x2,
+	},
+	{
+		.color_index = LED_COLOR_ID_BLUE,
+		.brightness = 0x50,
+		.intensity = 0x99,
+		.channel = 0x3,
+	},
+};
+
+static struct led_classdev_mc gos_cdev_rgb = {
+	.led_cdev = {
+		.name = "go_s:rgb:joystick_rings",
+		.brightness = 0x50,
+		.max_brightness = 0x64,
+		.brightness_set = hid_gos_brightness_set,
+	},
+	.num_colors = ARRAY_SIZE(gos_rgb_subled_info),
+	.subled_info = gos_rgb_subled_info,
+};
+
 static void cfg_setup(struct work_struct *work)
 {
 	int ret;
@@ -856,6 +1263,21 @@ static int hid_gos_cfg_probe(struct hid_device *hdev,
 		return ret;
 	}
 
+	ret = devm_led_classdev_multicolor_register(&hdev->dev, &gos_cdev_rgb);
+	if (ret) {
+		dev_err_probe(&hdev->dev, ret, "Failed to create RGB device\n");
+		return ret;
+	}
+
+	ret = devm_device_add_group(gos_cdev_rgb.led_cdev.dev, &rgb_attr_group);
+	if (ret) {
+		dev_err_probe(&hdev->dev, ret,
+			      "Failed to create RGB configuratiion attributes\n");
+		return ret;
+	}
+
+	drvdata.led_cdev = &gos_cdev_rgb.led_cdev;
+
 	init_completion(&drvdata.send_cmd_complete);
 
 	/* Executing calls prior to returning from probe will lock the MCU. Schedule
-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 15/19] HID: hid-lenovo-go-s: Add IMU and Touchpad RO Attributes
From: Derek J. Clark @ 2026-03-10  7:29 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Richard Hughes, Mario Limonciello, Zhixin Zhang, Mia Shao,
	Mark Pearson, Pierre-Loup A . Griffais, Derek J . Clark,
	linux-input, linux-doc, linux-kernel
In-Reply-To: <20260310072937.3295875-1-derekjohn.clark@gmail.com>

Adds attributes for reporting the touchpad manufacturer, version, and
IMU manufacturer.

Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v6:
  - Make local attributes static.
  - Use NULL instead of 0 in mcu_propery_out when there is no data.
v4:
 - Cache RO values at probe instead of calling them at request. Values
   don't change and reading the touchpad data is slow.
v3:
 - Fix bug where the touchpad attributes were assigned to the touchpad
   _show function instead of the test _show function.
---
 drivers/hid/hid-lenovo-go-s.c | 124 ++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c
index 0123c4b03cf4..431fffde4695 100644
--- a/drivers/hid/hid-lenovo-go-s.c
+++ b/drivers/hid/hid-lenovo-go-s.c
@@ -43,6 +43,7 @@ static struct hid_gos_cfg {
 	u8 gp_mode;
 	u8 gp_poll_rate;
 	u8 imu_bypass_en;
+	u8 imu_manufacturer;
 	u8 imu_sensor_en;
 	u8 mcu_id[12];
 	u8 mouse_step;
@@ -55,6 +56,8 @@ static struct hid_gos_cfg {
 	u8 tp_en;
 	u8 tp_linux_mode;
 	u8 tp_windows_mode;
+	u8 tp_version;
+	u8 tp_manufacturer;
 } drvdata;
 
 struct gos_cfg_attr {
@@ -201,6 +204,36 @@ enum rgb_config_index {
 	USR_LIGHT_PROFILE_3,
 };
 
+enum test_command_index {
+	TEST_TP_MFR = 0x02,
+	TEST_IMU_MFR,
+	TEST_TP_VER,
+};
+
+enum tp_mfr_index {
+	TP_NONE,
+	TP_BETTERLIFE,
+	TP_SIPO,
+};
+
+static const char *const touchpad_manufacturer_text[] = {
+	[TP_NONE] = "none",
+	[TP_BETTERLIFE] = "BetterLife",
+	[TP_SIPO] = "SIPO",
+};
+
+enum imu_mfr_index {
+	IMU_NONE,
+	IMU_BOSCH,
+	IMU_ST,
+};
+
+static const char *const imu_manufacturer_text[] = {
+	[IMU_NONE] = "none",
+	[IMU_BOSCH] = "Bosch",
+	[IMU_ST] = "ST",
+};
+
 static int hid_gos_version_event(u8 *data)
 {
 	struct version_report *ver_rep = (struct version_report *)data;
@@ -279,6 +312,30 @@ static int hid_gos_touchpad_event(struct command_report *cmd_rep)
 	return ret;
 }
 
+static int hid_gos_pl_test_event(struct command_report *cmd_rep)
+{
+	int ret = 0;
+
+	switch (cmd_rep->sub_cmd) {
+	case TEST_TP_MFR:
+		drvdata.tp_manufacturer = cmd_rep->data[0];
+		ret = 0;
+		break;
+	case TEST_IMU_MFR:
+		drvdata.imu_manufacturer = cmd_rep->data[0];
+		ret = 0;
+		break;
+	case TEST_TP_VER:
+		drvdata.tp_version = cmd_rep->data[0];
+		ret = 0;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int hid_gos_light_event(struct command_report *cmd_rep)
 {
 	struct led_classdev_mc *mc_cdev;
@@ -362,6 +419,9 @@ static int hid_gos_raw_event(struct hid_device *hdev, struct hid_report *report,
 	case GET_TP_PARAM:
 		ret = hid_gos_touchpad_event(cmd_rep);
 		break;
+	case GET_PL_TEST:
+		ret = hid_gos_pl_test_event(cmd_rep);
+		break;
 	case GET_RGB_CFG:
 		ret = hid_gos_light_event(cmd_rep);
 		break;
@@ -735,6 +795,37 @@ static ssize_t touchpad_property_options(struct device *dev,
 	return count;
 }
 
+static ssize_t test_property_show(struct device *dev,
+				  struct device_attribute *attr, char *buf,
+				  enum test_command_index index)
+{
+	size_t count = 0;
+	u8 i;
+
+	switch (index) {
+	case TEST_TP_MFR:
+		i = drvdata.tp_manufacturer;
+		if (i >= ARRAY_SIZE(touchpad_manufacturer_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", touchpad_manufacturer_text[i]);
+		break;
+	case TEST_IMU_MFR:
+		i = drvdata.imu_manufacturer;
+		if (i >= ARRAY_SIZE(imu_manufacturer_text))
+			return -EINVAL;
+		count = sysfs_emit(buf, "%s\n", imu_manufacturer_text[i]);
+		break;
+	case TEST_TP_VER:
+		count = sysfs_emit(buf, "%u\n", drvdata.tp_version);
+		break;
+	default:
+		count = -EINVAL;
+		break;
+	}
+
+	return count;
+}
+
 static ssize_t mcu_id_show(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
@@ -1076,6 +1167,9 @@ static struct gos_cfg_attr imu_bypass_enabled = { FEATURE_IMU_BYPASS };
 LEGOS_DEVICE_ATTR_RW(imu_bypass_enabled, "bypass_enabled", index, gamepad);
 static DEVICE_ATTR_RO_NAMED(imu_bypass_enabled_index, "bypass_enabled_index");
 
+static struct gos_cfg_attr imu_manufacturer = { TEST_IMU_MFR };
+LEGOS_DEVICE_ATTR_RO(imu_manufacturer, "manufacturer", test);
+
 static struct gos_cfg_attr imu_sensor_enabled = { FEATURE_IMU_ENABLE };
 LEGOS_DEVICE_ATTR_RW(imu_sensor_enabled, "sensor_enabled", index, gamepad);
 static DEVICE_ATTR_RO_NAMED(imu_sensor_enabled_index, "sensor_enabled_index");
@@ -1083,6 +1177,7 @@ static DEVICE_ATTR_RO_NAMED(imu_sensor_enabled_index, "sensor_enabled_index");
 static struct attribute *legos_imu_attrs[] = {
 	&dev_attr_imu_bypass_enabled.attr,
 	&dev_attr_imu_bypass_enabled_index.attr,
+	&dev_attr_imu_manufacturer.attr,
 	&dev_attr_imu_sensor_enabled.attr,
 	&dev_attr_imu_sensor_enabled_index.attr,
 	NULL,
@@ -1136,6 +1231,12 @@ static struct gos_cfg_attr touchpad_linux_mode = { CFG_LINUX_MODE };
 LEGOS_DEVICE_ATTR_RW(touchpad_linux_mode, "linux_mode", index, touchpad);
 static DEVICE_ATTR_RO_NAMED(touchpad_linux_mode_index, "linux_mode_index");
 
+static struct gos_cfg_attr touchpad_manufacturer = { TEST_TP_MFR };
+LEGOS_DEVICE_ATTR_RO(touchpad_manufacturer, "manufacturer", test);
+
+static struct gos_cfg_attr touchpad_version = { TEST_TP_VER };
+LEGOS_DEVICE_ATTR_RO(touchpad_version, "version", test);
+
 static struct gos_cfg_attr touchpad_windows_mode = { CFG_WINDOWS_MODE };
 LEGOS_DEVICE_ATTR_RW(touchpad_windows_mode, "windows_mode", index, touchpad);
 static DEVICE_ATTR_RO_NAMED(touchpad_windows_mode_index, "windows_mode_index");
@@ -1145,6 +1246,8 @@ static struct attribute *legos_touchpad_attrs[] = {
 	&dev_attr_touchpad_enabled_index.attr,
 	&dev_attr_touchpad_linux_mode.attr,
 	&dev_attr_touchpad_linux_mode_index.attr,
+	&dev_attr_touchpad_manufacturer.attr,
+	&dev_attr_touchpad_version.attr,
 	&dev_attr_touchpad_windows_mode.attr,
 	&dev_attr_touchpad_windows_mode_index.attr,
 	NULL,
@@ -1245,6 +1348,27 @@ static void cfg_setup(struct work_struct *work)
 		dev_err(&drvdata.hdev->dev, "Failed to retrieve MCU Version: %i\n", ret);
 		return;
 	}
+
+	ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, TEST_TP_MFR, NULL, 0);
+	if (ret) {
+		dev_err(&drvdata.hdev->dev,
+			"Failed to retrieve Touchpad Manufacturer: %i\n", ret);
+		return;
+	}
+
+	ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, TEST_TP_VER, NULL, 0);
+	if (ret) {
+		dev_err(&drvdata.hdev->dev,
+			"Failed to retrieve Touchpad Firmware Version: %i\n", ret);
+		return;
+	}
+
+	ret = mcu_property_out(drvdata.hdev, GET_PL_TEST, TEST_IMU_MFR, NULL, 0);
+	if (ret) {
+		dev_err(&drvdata.hdev->dev,
+			"Failed to retrieve IMU Manufacturer: %i\n", ret);
+		return;
+	}
 }
 
 static int hid_gos_cfg_probe(struct hid_device *hdev,
-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 17/19] HID: hid-lenovo-go-s: Remove unneeded semicolon
From: Derek J. Clark @ 2026-03-10  7:29 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Richard Hughes, Mario Limonciello, Zhixin Zhang, Mia Shao,
	Mark Pearson, Pierre-Loup A . Griffais, Derek J . Clark,
	linux-input, linux-doc, linux-kernel, Chen Ni
In-Reply-To: <20260310072937.3295875-1-derekjohn.clark@gmail.com>

From: Chen Ni <nichen@iscas.ac.cn>

Remove unnecessary semicolons reported by Coccinelle/coccicheck and the
semantic patch at scripts/coccinelle/misc/semicolon.cocci.

Signed-off-by: Chen Ni <nichen@iscas.ac.cn>
Reviewed-by: Derek J. Clark <derekjohn.clark@gmail.com>
Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
 drivers/hid/hid-lenovo-go-s.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c
index 431fffde4695..8ffa25b20f9c 100644
--- a/drivers/hid/hid-lenovo-go-s.c
+++ b/drivers/hid/hid-lenovo-go-s.c
@@ -1097,7 +1097,7 @@ static void hid_gos_brightness_set(struct led_classdev *led_cdev,
 	default:
 		dev_err(led_cdev->dev, "Failed to write RGB profile: %i\n",
 			ret);
-	};
+	}
 }
 
 #define LEGOS_DEVICE_ATTR_RW(_name, _attrname, _rtype, _group)                 \
-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 16/19] HID: Add documentation for Lenovo Legion Go drivers
From: Derek J. Clark @ 2026-03-10  7:29 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Richard Hughes, Mario Limonciello, Zhixin Zhang, Mia Shao,
	Mark Pearson, Pierre-Loup A . Griffais, Derek J . Clark,
	linux-input, linux-doc, linux-kernel
In-Reply-To: <20260310072937.3295875-1-derekjohn.clark@gmail.com>

Adds ABI documentation for the hid-lenovo-go-s and hid-lenovo-go
drivers.

Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
v3:
  - Remove excess + from every line of patch.
---
 .../ABI/testing/sysfs-driver-hid-lenovo-go    | 724 ++++++++++++++++++
 .../ABI/testing/sysfs-driver-hid-lenovo-go-s  | 304 ++++++++
 MAINTAINERS                                   |   2 +
 3 files changed, 1030 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lenovo-go
 create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-lenovo-go b/Documentation/ABI/testing/sysfs-driver-hid-lenovo-go
new file mode 100644
index 000000000000..c8221373ef76
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-lenovo-go
@@ -0,0 +1,724 @@
+What:		/sys/class/leds/go:rgb:joystick_rings/effect
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the display effect of the RGB interface.
+
+		Values are monocolor, breathe, chroma, or rainbow.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/class/leds/go:rgb:joystick_rings/effect_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the effect attribute.
+
+		Values are monocolor, breathe, chroma, or rainbow.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/class/leds/go:rgb:joystick_rings/enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the RGB interface.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/class/leds/go:rgb:joystick_rings/enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the enabled attribute.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/class/leds/go:rgb:joystick_rings/mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the operating mode of the RGB interface.
+
+		Values are dynamic or custom. Custom allows setting the RGB effect and color.
+    Dynamic is a Windows mode for syncing Lenovo RGB interfaces not currently
+    supported under Linux.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/class/leds/go:rgb:joystick_rings/mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the mode attribute.
+
+		Values are dynamic or custom.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/class/leds/go:rgb:joystick_rings/profile
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls selecting the configured RGB profile.
+
+		Values are 1-3.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/class/leds/go:rgb:joystick_rings/profile_range
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the profile attribute.
+
+		Values are 1-3.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/class/leds/go:rgb:joystick_rings/speed
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the change rate for the breathe, chroma, and rainbow effects.
+
+		Values are 0-100.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/class/leds/go:rgb:joystick_rings/speed_range
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the speed attribute.
+
+		Values are 0-100.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/firmware_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the firmware version of the internal MCU.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/fps_mode_dpi
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the DPI of the right handle when the FPS mode switch is on.
+
+		Values are 500, 800, 1200, and 1800.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/fps_mode_dpi_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the fps_mode_dpi attribute.
+
+		Values are 500, 800, 1200, and 1800.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/hardware_generation
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the hardware generation of the internal MCU.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/hardware_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the hardware version of the internal MCU.
+
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/auto_sleep_time
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the sleep timer due to inactivity for the left removable controller.
+
+		Values are 0-255.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/auto_sleep_time_range
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the left_handle/auto_sleep_time attribute.
+
+		Values are 0-255.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_gyro
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This initiates or halts calibration of the left removable controller's IMU.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_gyro_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the left_handle/calibrate_gyro attribute.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_gyro_status
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the result of the last attempted calibration of the left removable controller's IMU.
+
+		Values are unknown, success, failure.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_joystick
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This initiates or halts calibration of the left removable controller's joystick.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_joystick_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the left_handle/calibrate_jotstick attribute.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_joystick_status
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the result of the last attempted calibration of the left removable controller's joystick.
+
+		Values are unknown, success, failure.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_tirgger
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This initiates or halts calibration of the left removable controller's trigger.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_gyro_trigger
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the left_handle/calibrate_trigger attribute.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/calibrate_trigger_status
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the result of the last attempted calibration of the left removable controller's trigger.
+
+		Values are unknown, success, failure.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/firmware_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the left removable controller's firmware version.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/hardware_generation
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the hardware generation of the left removable controller.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/hardware_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the hardware version of the left removable controller.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/imu_bypass_enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the IMU bypass function of the left removable controller.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/imu_bypass_enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the left_handle/imu_bypass_enabled attribute.
+
+		Values are true or false.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/imu_enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the IMU of the left removable controller.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/imu_enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the left_handle/imu_enabled attribute.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/product_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the product version of the left removable controller.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/protocol_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the protocol version of the left removable controller.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/reset
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	Resets the left removable controller to factory defaults.
+
+		Writing 1 to this path initiates.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/rumble_mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls setting the response behavior for rumble events for the left removable controller.
+
+		Values are fps, racing, standarg, spg, rpg.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/rumble_mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the left_handle/rumble_mode attribute.
+
+		Values are fps, racing, standarg, spg, rpg.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/rumble_notification
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling haptic rumble events for the left removable controller.
+
+		Values are true, false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/rumble_notification_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the left_handle/rumble_notification attribute.
+
+		Values are true, false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the operating mode of the built-in controller.
+
+		Values are xinput or dinput.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/left_handle/mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the mode attribute.
+
+		Values are xinput or dinput.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the behavior of built in chord combinations.
+
+		Values are windows or linux.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the os_mode attribute.
+
+		Values are windows or linux.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/product_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the product version of the internal MCU.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/protocol_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the protocol version of the internal MCU.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/reset_mcu
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	Resets the internal MCU to factory defaults.
+
+		Writing 1 to this path initiates.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/auto_sleep_time
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the sleep timer due to inactivity for the right removable controller.
+
+		Values are 0-255.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/auto_sleep_time_range
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the right_handle/auto_sleep_time attribute.
+
+		Values are 0-255.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_gyro
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This initiates or halts calibration of the right removable controller's IMU.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_gyro_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the right_handle/calibrate_gyro attribute.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_gyro_status
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the result of the last attempted calibration of the right removable controller's IMU.
+
+		Values are unknown, success, failure.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_joystick
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This initiates or halts calibration of the right removable controller's joystick.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_joystick_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the right_handle/calibrate_jotstick attribute.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_joystick_status
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the result of the last attempted calibration of the right removable controller's joystick.
+
+		Values are unknown, success, failure.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_tirgger
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This initiates or halts calibration of the right removable controller's trigger.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_gyro_trigger
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the right_handle/calibrate_trigger attribute.
+
+		Values are start, stop.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/calibrate_trigger_status
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the result of the last attempted calibration of the right removable controller's trigger.
+
+		Values are unknown, success, failure.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/firmware_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the right removable controller's firmware version.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/hardware_generation
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the hardware generation of the right removable controller.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/hardware_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the hardware version of the right removable controller.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/imu_bypass_enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the IMU bypass function of the right removable controller.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/imu_bypass_enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the right_handle/imu_bypass_enabled attribute.
+
+		Values are true or false.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/imu_enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the IMU of the right removable controller.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/imu_enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the right_handle/imu_enabled attribute.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/product_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the product version of the right removable controller.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/protocol_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the protocol version of the right removable controller.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/reset
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	Resets the right removable controller to factory defaults.
+
+		Writing 1 to this path initiates.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/rumble_mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls setting the response behavior for rumble events for the right removable controller.
+
+		Values are fps, racing, standarg, spg, rpg.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/rumble_mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the right_handle/rumble_mode attribute.
+
+		Values are fps, racing, standarg, spg, rpg.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/rumble_notification
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling haptic rumble events for the right removable controller.
+
+		Values are true, false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/right_handle/rumble_notification_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the right_handle/rumble_notification attribute.
+
+		Values are true, false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/rumble_intensity
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls setting the rumble intensity for both removable controllers.
+
+		Values are off, low, medium, high.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/rumble_intensity_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the rumble_intensity attribute.
+
+		Values are off, low, medium, high.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the touchpad.
+
+		Values are true, false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the touchpad/enabled attribute.
+
+		Values are true, false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/vibration_enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling haptic rumble events for the touchpad.
+
+		Values are true, false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/vibration_enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the touchpad/vibration_enabled attribute.
+
+		Values are true, false.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/vibration_intensity
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls setting the intensity of the touchpad haptics.
+
+		Values are off, low, medium, high.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/vibration_intensity_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the touchpad/vibration_intensity attribute.
+
+		Values are off, low, medium, high.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/firmware_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the firmware version of the internal wireless transmission dongle.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/hardware_generation
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the hardware generation of the internal wireless transmission dongle.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/hardware_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the hardware version of the internal wireless transmission dongle.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/product_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the product version of the internal wireless transmission dongle.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/tx_dongle/protocol_version
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the protocol version of the internal wireless transmission dongle.
+
+		Applies to Lenovo Legion Go and Go 2 line of handheld devices.
+
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s b/Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s
new file mode 100644
index 000000000000..4d317074bb7e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s
@@ -0,0 +1,304 @@
+What:		/sys/class/leds/go_s:rgb:joystick_rings/effect
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the display effect of the RGB interface.
+
+		Values are monocolor, breathe, chroma, or rainbow.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/class/leds/go_s:rgb:joystick_rings/effect_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the effect attribute.
+
+		Values are monocolor, breathe, chroma, or rainbow.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/class/leds/go_s:rgb:joystick_rings/enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the RGB interface.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/class/leds/go_s:rgb:joystick_rings/enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the enabled attribute.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/class/leds/go_s:rgb:joystick_rings/mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the operating mode of the RGB interface.
+
+		Values are dynamic or custom. Custom allows setting the RGB effect and color.
+    Dynamic is a Windows mode for syncing Lenovo RGB interfaces not currently
+    supported under Linux.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/class/leds/go_s:rgb:joystick_rings/mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the mode attribute.
+
+		Values are dynamic or custom.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/class/leds/go_s:rgb:joystick_rings/profile
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls selecting the configured RGB profile.
+
+		Values are 1-3.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/class/leds/go_s:rgb:joystick_rings/profile_range
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the profile attribute.
+
+		Values are 1-3.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/class/leds/go_s:rgb:joystick_rings/speed
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the change rate for the breathe, chroma, and rainbow effects.
+
+		Values are 0-100.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/class/leds/go_s:rgb:joystick_rings/speed_range
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the speed attribute.
+
+		Values are 0-100.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/auto_sleep_time
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the sleep timer due to inactivity for the built-in controller.
+
+		Values are 0-255.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/auto_sleep_time_range
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the gamepad/auto_sleep_time attribute.
+
+		Values are 0-255.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/dpad_mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the operating mode of the built-in controllers D-pad.
+
+		Values are 4-way or 8-way.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/dpad_mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the gamepad/dpad_mode attribute.
+
+		Values are 4-way or 8-way.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the operating mode of the built-in controller.
+
+		Values are xinput or dinput.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the gamepad/mode attribute.
+
+		Values are xinput or dinput.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/poll_rate
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls the poll rate in Hz of the built-in controller.
+
+		Values are 125, 250, 500, or 1000.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/gamepad/poll_rate_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the gamepad/poll_rate attribute.
+
+		Values are 125, 250, 500, or 1000.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/bypass_enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the IMU bypass function. When enabled the IMU data is directly reported to the OS through
+an HIDRAW interface.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/bypass_enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the imu/bypass_enabled attribute.
+
+		Values are true or false.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/manufacturer
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the manufacturer of the intertial measurment unit.
+
+		Values are Bosch or ST.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/sensor_enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the IMU.
+
+		Values are true, false, or wake-2s.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/imu/sensor_enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the imu/sensor_enabled attribute.
+
+		Values are true, false, or wake-2s.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/mcu_id
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the MCU Identification Number
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/mouse/step
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls which value is used for the mouse sensitivity.
+
+		Values are 1-127.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/mouse/step_range
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the mouse/step attribute.
+
+		Values are 1-127.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls which value is used for the touchpads operating mode.
+
+		Values are windows or linux.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the os_mode attribute.
+
+		Values are windows or linux.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls enabling or disabling the built-in touchpad.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the touchpad/enabled attribute.
+
+		Values are true or false.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/linux_mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls behavior of the touchpad events when os_mode is set to linux.
+
+		Values are absolute or relative.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/linux_mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the touchpad/linux_mode attribute.
+
+		Values are absolute or relative.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/windows_mode
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This controls behavior of the touchpad events when os_mode is set to windows.
+
+		Values are absolute or relative.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/windows_mode_index
+Date:		April 2026
+Contact:	linux-input@vger.kernel.org
+Description:	This displays the available options for the touchpad/windows_mode attribute.
+
+		Values are absolute or relative.
+
+		Applies to Lenovo Legion Go S line of handheld devices.
diff --git a/MAINTAINERS b/MAINTAINERS
index c81f10292ff7..146159a8b2e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14420,6 +14420,8 @@ M:	Derek J. Clark <derekjohn.clark@gmail.com>
 M:	Mark Pearson <mpearson-lenovo@squebb.ca>
 L:	linux-input@vger.kernel.org
 S:	Maintained
+F:	Documentation/ABI/testing/sysfs-driver-hid-lenovo-go
+F:	Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s
 F:	drivers/hid/hid-lenovo-go-s.c
 F:	drivers/hid/hid-lenovo-go.c
 F:	drivers/hid/hid-lenovo.c
-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 18/19] HID: hid-lenovo-go: Remove unneeded semicolon
From: Derek J. Clark @ 2026-03-10  7:29 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Richard Hughes, Mario Limonciello, Zhixin Zhang, Mia Shao,
	Mark Pearson, Pierre-Loup A . Griffais, Derek J . Clark,
	linux-input, linux-doc, linux-kernel, Chen Ni
In-Reply-To: <20260310072937.3295875-1-derekjohn.clark@gmail.com>

From: Chen Ni <nichen@iscas.ac.cn>

Remove unnecessary semicolons after switch statements and function
bodies. Most issues were reported by Coccinelle/coccicheck using the
semantic patch at scripts/coccinelle/misc/semicolon.cocci. Additional
instances found during manual code review were also fixed.

Signed-off-by: Chen Ni <nichen@iscas.ac.cn>
Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
 drivers/hid/hid-lenovo-go.c | 52 ++++++++++++++++++-------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c
index 54861f2e04fc..d4d26c783356 100644
--- a/drivers/hid/hid-lenovo-go.c
+++ b/drivers/hid/hid-lenovo-go.c
@@ -455,7 +455,7 @@ static int hid_go_feature_status_event(struct command_report *cmd_rep)
 			return 0;
 		default:
 			return -EINVAL;
-		};
+		}
 	case FEATURE_IMU_BYPASS:
 		switch (cmd_rep->device_type) {
 		case LEFT_CONTROLLER:
@@ -466,7 +466,7 @@ static int hid_go_feature_status_event(struct command_report *cmd_rep)
 			return 0;
 		default:
 			return -EINVAL;
-		};
+		}
 		break;
 	case FEATURE_LIGHT_ENABLE:
 		drvdata.rgb_en = cmd_rep->data[0];
@@ -481,7 +481,7 @@ static int hid_go_feature_status_event(struct command_report *cmd_rep)
 			return 0;
 		default:
 			return -EINVAL;
-		};
+		}
 		break;
 	case FEATURE_TOUCHPAD_ENABLE:
 		drvdata.tp_en = cmd_rep->data[0];
@@ -515,7 +515,7 @@ static int hid_go_motor_event(struct command_report *cmd_rep)
 			return 0;
 		default:
 			return -EINVAL;
-		};
+		}
 		break;
 	case RUMBLE_MODE:
 		switch (cmd_rep->device_type) {
@@ -527,7 +527,7 @@ static int hid_go_motor_event(struct command_report *cmd_rep)
 			return 0;
 		default:
 			return -EINVAL;
-		};
+		}
 	case TP_VIBRATION_ENABLE:
 		drvdata.tp_vibration_en = cmd_rep->data[0];
 		return 0;
@@ -625,7 +625,7 @@ static int hid_go_os_mode_cfg_event(struct command_report *cmd_rep)
 		return 0;
 	default:
 		return -EINVAL;
-	};
+	}
 }
 
 static int hid_go_set_event_return(struct command_report *cmd_rep)
@@ -699,14 +699,14 @@ static int hid_go_raw_event(struct hid_device *hdev, struct hid_report *report,
 		default:
 			ret = -EINVAL;
 			break;
-		};
+		}
 		break;
 	case OS_MODE_DATA:
 		ret = hid_go_os_mode_cfg_event(cmd_rep);
 		break;
 	default:
 		goto passthrough;
-	};
+	}
 	dev_dbg(&hdev->dev, "Rx data as raw input report: [%*ph]\n",
 		GO_PACKET_SIZE, data);
 
@@ -925,7 +925,7 @@ static ssize_t feature_status_store(struct device *dev,
 		break;
 	default:
 		return -EINVAL;
-	};
+	}
 
 	if (ret < 0)
 		return ret;
@@ -1013,7 +1013,7 @@ static ssize_t feature_status_show(struct device *dev,
 			break;
 		default:
 			return -EINVAL;
-		};
+		}
 		count = sysfs_emit(buf, "%u\n", i);
 		break;
 	case FEATURE_FPS_SWITCH_STATUS:
@@ -1032,7 +1032,7 @@ static ssize_t feature_status_show(struct device *dev,
 		break;
 	default:
 		return -EINVAL;
-	};
+	}
 
 	return count;
 }
@@ -1070,7 +1070,7 @@ static ssize_t feature_status_options(struct device *dev,
 		break;
 	default:
 		return -EINVAL;
-	};
+	}
 
 	if (count)
 		buf[count - 1] = '\n';
@@ -1111,7 +1111,7 @@ static ssize_t motor_config_store(struct device *dev,
 		ret = sysfs_match_string(intensity_text, buf);
 		val = ret;
 		break;
-	};
+	}
 
 	if (ret < 0)
 		return ret;
@@ -1161,7 +1161,7 @@ static ssize_t motor_config_show(struct device *dev,
 			break;
 		default:
 			return -EINVAL;
-		};
+		}
 		if (i >= ARRAY_SIZE(enabled_status_text))
 			return -EINVAL;
 
@@ -1177,7 +1177,7 @@ static ssize_t motor_config_show(struct device *dev,
 			break;
 		default:
 			return -EINVAL;
-		};
+		}
 		if (i >= ARRAY_SIZE(rumble_mode_text))
 			return -EINVAL;
 
@@ -1197,7 +1197,7 @@ static ssize_t motor_config_show(struct device *dev,
 
 		count = sysfs_emit(buf, "%s\n", intensity_text[i]);
 		break;
-	};
+	}
 
 	return count;
 }
@@ -1232,7 +1232,7 @@ static ssize_t motor_config_options(struct device *dev,
 					       enabled_status_text[i]);
 		}
 		break;
-	};
+	}
 
 	if (count)
 		buf[count - 1] = '\n';
@@ -1333,7 +1333,7 @@ static ssize_t device_status_show(struct device *dev,
 		break;
 	default:
 		return -EINVAL;
-	};
+	}
 
 	if (i >= ARRAY_SIZE(cal_status_text))
 		return -EINVAL;
@@ -1459,7 +1459,7 @@ static int rgb_attr_show(void)
 	index = drvdata.rgb_profile + 3;
 
 	return rgb_cfg_call(drvdata.hdev, GET_RGB_CFG, index, NULL, 0);
-};
+}
 
 static ssize_t rgb_effect_store(struct device *dev,
 				struct device_attribute *attr, const char *buf,
@@ -1489,7 +1489,7 @@ static ssize_t rgb_effect_store(struct device *dev,
 
 	drvdata.rgb_effect = effect;
 	return count;
-};
+}
 
 static ssize_t rgb_effect_show(struct device *dev,
 			       struct device_attribute *attr, char *buf)
@@ -1555,7 +1555,7 @@ static ssize_t rgb_speed_store(struct device *dev,
 	drvdata.rgb_speed = val;
 
 	return count;
-};
+}
 
 static ssize_t rgb_speed_show(struct device *dev, struct device_attribute *attr,
 			      char *buf)
@@ -1599,7 +1599,7 @@ static ssize_t rgb_mode_store(struct device *dev, struct device_attribute *attr,
 	drvdata.rgb_mode = val;
 
 	return count;
-};
+}
 
 static ssize_t rgb_mode_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
@@ -1614,7 +1614,7 @@ static ssize_t rgb_mode_show(struct device *dev, struct device_attribute *attr,
 		return -EINVAL;
 
 	return sysfs_emit(buf, "%s\n", rgb_mode_text[drvdata.rgb_mode]);
-};
+}
 
 static ssize_t rgb_mode_index_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
@@ -1653,7 +1653,7 @@ static ssize_t rgb_profile_store(struct device *dev,
 	drvdata.rgb_profile = val;
 
 	return count;
-};
+}
 
 static ssize_t rgb_profile_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -1668,7 +1668,7 @@ static ssize_t rgb_profile_show(struct device *dev,
 		return -EINVAL;
 
 	return sysfs_emit(buf, "%hhu\n", drvdata.rgb_profile);
-};
+}
 
 static ssize_t rgb_profile_range_show(struct device *dev,
 				      struct device_attribute *attr, char *buf)
@@ -1707,7 +1707,7 @@ static void hid_go_brightness_set(struct led_classdev *led_cdev,
 		break;
 	default:
 		dev_err(led_cdev->dev, "Failed to write RGB profile: %i\n", ret);
-	};
+	}
 }
 
 #define LEGO_DEVICE_ATTR_RW(_name, _attrname, _dtype, _rtype, _group)         \
-- 
2.53.0


^ permalink raw reply related

* [PATCH v6 19/19] HID: hid-lenovo-go-s: Fix spelling mistake "configuratiion" -> "configuration"
From: Derek J. Clark @ 2026-03-10  7:29 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires
  Cc: Richard Hughes, Mario Limonciello, Zhixin Zhang, Mia Shao,
	Mark Pearson, Pierre-Loup A . Griffais, Derek J . Clark,
	linux-input, linux-doc, linux-kernel, Colin Ian King
In-Reply-To: <20260310072937.3295875-1-derekjohn.clark@gmail.com>

From: Colin Ian King <colin.i.king@gmail.com>

There is a spelling mistake in a dev_err_probe message. Fix it.

Signed-off-by: Colin Ian King <colin.i.king@gmail.com>
Reviewed-by: Derek J. Clark <derekjohn.clark@gmail.com>
Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
 drivers/hid/hid-lenovo-go-s.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/hid-lenovo-go-s.c b/drivers/hid/hid-lenovo-go-s.c
index 8ffa25b20f9c..01c7bdd4fbe0 100644
--- a/drivers/hid/hid-lenovo-go-s.c
+++ b/drivers/hid/hid-lenovo-go-s.c
@@ -1396,7 +1396,7 @@ static int hid_gos_cfg_probe(struct hid_device *hdev,
 	ret = devm_device_add_group(gos_cdev_rgb.led_cdev.dev, &rgb_attr_group);
 	if (ret) {
 		dev_err_probe(&hdev->dev, ret,
-			      "Failed to create RGB configuratiion attributes\n");
+			      "Failed to create RGB configuration attributes\n");
 		return ret;
 	}
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.19-6.6] HID: asus: add xg mobile 2023 external hardware support
From: Sasha Levin @ 2026-03-10  9:01 UTC (permalink / raw)
  To: patches, stable
  Cc: Denis Benato, Jiri Kosina, Sasha Levin, jikos, bentiss,
	linux-input, linux-kernel
In-Reply-To: <20260310090145.2709021-1-sashal@kernel.org>

From: Denis Benato <denis.benato@linux.dev>

[ Upstream commit 377f8e788945d45b012ed9cfc35ca56c02e86cd8 ]

XG mobile stations have the 0x5a endpoint and has to be initialized:
add them to hid-asus.

Signed-off-by: Denis Benato <denis.benato@linux.dev>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis

### What the commit does
This commit adds a new USB device ID (`USB_DEVICE_ID_ASUSTEK_XGM_2023 =
0x1a9a`) for the ASUS XG Mobile 2023 docking station to the hid-asus
driver. The change consists of:
1. Defining the device ID constant in `hid-ids.h` (1 line)
2. Adding the device to the `asus_devices[]` table in `hid-asus.c` (3
   lines, no quirk flags)

### Classification: New Device ID Addition
This is a textbook **new device ID addition to an existing driver**. The
hid-asus driver already exists in all stable kernel trees. Only the USB
device ID entry is new.

The commit message states: "XG mobile stations have the 0x5a endpoint
and has to be initialized: add them to hid-asus." This means the
device's HID interface (with report ID 0x5a = `FEATURE_KBD_REPORT_ID`)
needs the hid-asus driver to bind to it, rather than the generic HID
driver, for the device to function properly.

### Device entry details
The entry has **no quirk flags** set. This means minimal special
handling — the device simply needs to be claimed by hid-asus (rather
than generic HID) for proper initialization and event handling. The hid-
asus driver provides baseline handling that differs from the generic HID
driver, including filtering of `FEATURE_KBD_LED_REPORT_ID` events in the
raw_event handler.

### Risk assessment
- **Scope**: 4 lines changed across 2 files
- **Risk**: Extremely low — this only affects devices with USB VID/PID
  `0x0b05:0x1a9a`. No existing device behavior is modified.
- **Self-contained**: Yes — no dependencies on other commits. The change
  only requires the existing hid-asus driver infrastructure.

### Stable kernel criteria
- **Obviously correct**: Yes — adding a device ID to an existing table
  with established patterns
- **Fixes real issue**: Enables hardware support for users with XG
  Mobile 2023 docking stations
- **Small and contained**: 4 lines total
- **No new features/APIs**: Just a device ID, no new quirk mechanisms or
  user-visible interfaces
- **Exception category**: New Device IDs — explicitly listed as
  appropriate for stable

### Verification
- Read `asus_probe()` at hid-asus.c:1127-1248 to confirm behavior with
  zero quirk flags — device goes through standard HID parse/start path
  and gets named "Asus Keyboard"
- Confirmed `USB_DEVICE_ID_ASUSTEK_XGM_2023` is only defined and used in
  these two files (self-contained)
- Confirmed the device table entry follows the exact same pattern as
  other entries in `asus_devices[]` (e.g., `USB_DEVICE_ID_ASUS_AK1D` and
  `USB_DEVICE_ID_ASUS_MD_5110` also have no quirk flags)
- Confirmed `FEATURE_KBD_REPORT_ID` is defined as `0x5a` at line 51,
  matching the commit message about the 0x5a endpoint
- No quirk flag dependencies — the entry is independent of any other
  code changes

**YES**

 drivers/hid/hid-asus.c | 3 +++
 drivers/hid/hid-ids.h  | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 8487332bf43b0..b1ad4e9f20c85 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1404,6 +1404,9 @@ static const struct hid_device_id asus_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
 	    USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X),
 	  QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
+	    USB_DEVICE_ID_ASUSTEK_XGM_2023),
+	},
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
 	    USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
 	  QUIRK_ROG_CLAYMORE_II_KEYBOARD },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 85ab1ac511096..7fd67745ee010 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -229,6 +229,7 @@
 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X		0x1b4c
 #define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD	0x196b
 #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD	0x1869
+#define USB_DEVICE_ID_ASUSTEK_XGM_2023	0x1a9a
 
 #define USB_VENDOR_ID_ATEN		0x0557
 #define USB_DEVICE_ID_ATEN_UC100KM	0x2004
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.19-5.10] HID: mcp2221: cancel last I2C command on read error
From: Sasha Levin @ 2026-03-10  9:01 UTC (permalink / raw)
  To: patches, stable
  Cc: Romain Sioen, Jiri Kosina, Sasha Levin, gupt21, jikos, bentiss,
	linux-i2c, linux-input, linux-kernel
In-Reply-To: <20260310090145.2709021-1-sashal@kernel.org>

From: Romain Sioen <romain.sioen@microchip.com>

[ Upstream commit e31b556c0ba21f20c298aa61181b96541140b7b9 ]

When an I2C SMBus read operation fails, the MCP2221 internal state machine
may not reset correctly, causing subsequent transactions to fail.

By adding a short delay and explicitly cancelling the last command,
we ensure the device is ready for the next operation.

Fix an issue where i2cdetect was not able to detect all devices correctly
on the bus.

Signed-off-by: Romain Sioen <romain.sioen@microchip.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have a complete picture. Let me summarize the analysis.

## Analysis

### What the commit fixes

The MCP2221 is a USB-to-I2C/UART bridge chip. When an I2C SMBus read
operation exhausts its 5 retries (meaning the device didn't become
ready), the function `mcp_i2c_smbus_read` previously returned the error
immediately without cleaning up the device's internal state machine.
This left the I2C bus in a stuck state, causing subsequent I2C
transactions to fail.

The fix adds two lines before the error return:
1. `usleep_range(980, 1000)` - a small delay needed by the device
2. `mcp_cancel_last_cmd(mcp)` - sends a cancel command to reset the
   device state and free the I2C bus

### Is this a real bug fix?

Yes. The commit message explicitly states this fixes a real-world issue:
`i2cdetect` was unable to detect all devices on the bus. This is a
functional bug where failed reads leave the MCP2221 in a bad state,
breaking subsequent operations.

### Pattern consistency

The fix follows the **exact same pattern** already used in two other
places in the same driver:
1. `mcp_chk_last_cmd_status_free_bus()` (line 225-226):
   `usleep_range(980, 1000)` + `mcp_cancel_last_cmd(mcp)` on error
2. `mcp_set_i2c_speed()` (line 244-245): same pattern on error

This is simply adding the same established error recovery to a path that
was missing it.

### Scope and risk

- **2 lines added** - extremely small and surgical
- **No behavioral change** on the success path
- Only affects the error path after all 5 retries are exhausted
- Uses well-established functions already present in the driver
- Low risk of regression - the alternative (not cancelling) is already
  broken

### Stable criteria assessment

- **Obviously correct**: Follows the same pattern used elsewhere in the
  driver for the same purpose
- **Fixes a real bug**: I2C bus gets stuck, preventing device detection
- **Small and contained**: 2 lines added, single file, single error path
- **No new features**: Just error recovery

### Verification

- git log confirmed this is commit b4664742e46dc, merged recently
- Read the full `mcp_cancel_last_cmd()` function at line 204-211: sends
  `MCP2221_I2C_CANCEL` to reset device state
- Read `mcp_chk_last_cmd_status_free_bus()` at line 216-230: confirms
  the same `usleep + cancel` pattern is established
- Read `mcp_set_i2c_speed()` at line 232-249: confirms the same pattern
  in a third location
- The fix is self-contained with no dependencies on other commits
- The `mcp_cancel_last_cmd` function has existed since at least v6.1
  (introduced with the read refactoring), so it's available in stable
  trees
- Author is from Microchip (the chip vendor), adding credibility to the
  fix

**YES**

 drivers/hid/hid-mcp2221.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index 33603b019f975..ef3b5c77c38e3 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -353,6 +353,8 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
 				usleep_range(90, 100);
 				retries++;
 			} else {
+				usleep_range(980, 1000);
+				mcp_cancel_last_cmd(mcp);
 				return ret;
 			}
 		} else {
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.19-5.10] HID: asus: avoid memory leak in asus_report_fixup()
From: Sasha Levin @ 2026-03-10  9:01 UTC (permalink / raw)
  To: patches, stable
  Cc: Günther Noack, Benjamin Tissoires, Sasha Levin, jikos,
	linux-input, linux-kernel
In-Reply-To: <20260310090145.2709021-1-sashal@kernel.org>

From: Günther Noack <gnoack@google.com>

[ Upstream commit 2bad24c17742fc88973d6aea526ce1353f5334a3 ]

The asus_report_fixup() function was returning a newly allocated
kmemdup()-allocated buffer, but never freeing it.  Switch to
devm_kzalloc() to ensure the memory is managed and freed automatically
when the device is removed.

The caller of report_fixup() does not take ownership of the returned
pointer, but it is permitted to return a pointer whose lifetime is at
least that of the input buffer.

Also fix a harmless out-of-bounds read by copying only the original
descriptor size.

Assisted-by: Gemini-CLI:Google Gemini 3
Signed-off-by: Günther Noack <gnoack@google.com>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis

### Problem Description

The `asus_report_fixup()` function in `drivers/hid/hid-asus.c` had a
memory leak in the `QUIRK_T100CHI | QUIRK_T90CHI` path. The buggy code
used `kmemdup()` to allocate a new report descriptor buffer, but this
buffer was never freed by anyone:

**The leak mechanism (verified by reading hid-core.c:1285-1307):**
1. Caller allocates `buf` via `kmemdup()` (line 1291)
2. Caller passes `buf` to `report_fixup()` (line 1296)
3. The old `report_fixup()` returned a *new* `kmemdup()`'d pointer,
   discarding `buf`
4. Caller does `start = kmemdup(start, size, ...)` — making *yet another
   copy* (line 1303)
5. Caller does `kfree(buf)` — frees the original, but NOT the
   intermediate kmemdup from report_fixup()
6. The intermediate buffer is **leaked**

### Fix Analysis

The fix is small (11 insertions, 4 deletions) and does three things:

1. **Switches from `kmemdup()` to `devm_kzalloc()`**: Ties the
   allocation to the HID device lifetime, so it's automatically freed on
   device removal. This eliminates the leak.

2. **Fixes error handling**: Old code returned `NULL` on allocation
   failure, which the caller doesn't handle well. New code returns the
   original `rdesc`, matching the pattern already used by
   `QUIRK_G752_KEYBOARD` in the same function.

3. **Fixes out-of-bounds read**: Old code did `kmemdup(rdesc, *rsize,
   ...)` where `*rsize` was already set to `rsize_orig + 1` (one byte
   larger than the actual descriptor). New code does `memcpy(new_rdesc,
   rdesc, rsize_orig)`, copying only the valid data.

### Stable Criteria Assessment

- **Fixes a real bug**: Yes — memory leak on every T100CHI/T90CHI
  keyboard report descriptor parse
- **Obviously correct**: Yes — follows the identical pattern used by
  QUIRK_G752_KEYBOARD in the same function (verified in the diff
  context)
- **Small and contained**: Yes — 15 lines changed in a single file
- **No new features**: Correct — pure bug fix
- **Bug has existed since 2017**: Commit 73c75d3958579 introduced
  T100CHI support with the buggy `kmemdup()` pattern, present in all
  stable trees

### Risk Assessment

**Very low risk.** The fix:
- Follows an existing pattern already proven in the same function
  (QUIRK_G752_KEYBOARD)
- Only affects ASUS T100CHI and T90CHI hardware
- The devm_kzalloc lifetime (device lifetime) is correct since the
  caller copies the returned data immediately
- No dependencies on other commits

### Verification

- **Verified caller behavior**: Read `hid-core.c:1285-1307` — confirmed
  the caller does `kmemdup()` of the returned pointer then `kfree(buf)`,
  meaning any new allocation from `report_fixup()` is leaked
- **Verified the existing devm_kzalloc pattern**: The
  QUIRK_G752_KEYBOARD block in the same function already uses
  `devm_kzalloc` with the same allocation + `return rdesc` on failure
  pattern
- **Verified bug age**: `git log --oneline` showed commit
  `73c75d3958579` (2017-08-04) introduced the T100CHI support with
  `kmemdup()`, confirmed present in stable trees via `git tag
  --contains`
- **Verified commit SHA**: `git show 5dc6c17c16935` confirmed the commit
  matches the diff under review, with upstream commit `2bad24c17742f`
- **Verified the OOB read**: Old code set `*rsize = rsize_orig + 1`
  BEFORE `kmemdup(rdesc, *rsize, ...)`, reading one byte past the
  original descriptor — confirmed by the diff context showing the order
  of operations

This is a clear, small, low-risk fix for a real memory leak (and minor
OOB read) in a HID driver, following an established pattern already in
the same function. It meets all stable kernel criteria.

**YES**

 drivers/hid/hid-asus.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 472bca54642b9..8487332bf43b0 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1306,14 +1306,21 @@ static const __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		 */
 		if (*rsize == rsize_orig &&
 			rdesc[offs] == 0x09 && rdesc[offs + 1] == 0x76) {
-			*rsize = rsize_orig + 1;
-			rdesc = kmemdup(rdesc, *rsize, GFP_KERNEL);
-			if (!rdesc)
-				return NULL;
+			__u8 *new_rdesc;
+
+			new_rdesc = devm_kzalloc(&hdev->dev, rsize_orig + 1,
+						 GFP_KERNEL);
+			if (!new_rdesc)
+				return rdesc;
 
 			hid_info(hdev, "Fixing up %s keyb report descriptor\n",
 				drvdata->quirks & QUIRK_T100CHI ?
 				"T100CHI" : "T90CHI");
+
+			memcpy(new_rdesc, rdesc, rsize_orig);
+			*rsize = rsize_orig + 1;
+			rdesc = new_rdesc;
+
 			memmove(rdesc + offs + 4, rdesc + offs + 2, 12);
 			rdesc[offs] = 0x19;
 			rdesc[offs + 1] = 0x00;
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.19-5.10] platform/x86: touchscreen_dmi: Add quirk for y-inverted Goodix touchscreen on SUPI S10
From: Sasha Levin @ 2026-03-10  9:01 UTC (permalink / raw)
  To: patches, stable
  Cc: Hans de Goede, Yajat Kumar, Ilpo Järvinen, Sasha Levin,
	hansg, linux-input, platform-driver-x86, linux-kernel
In-Reply-To: <20260310090145.2709021-1-sashal@kernel.org>

From: Hans de Goede <johannes.goede@oss.qualcomm.com>

[ Upstream commit 7d87ed70fc95482c12edf9493c249b6413be485e ]

The touchscreen on the SUPI S10 tablet reports inverted Y coordinates,
causing touch input to be mirrored vertically relative to the display.

Add a quirk to set the "touchscreen-inverted-y" boolean device-property
on the touchscreen device, so that the goodix_ts driver will fixup
the coordinates.

Reported-by: Yajat Kumar <yajatapps3@gmail.com>
Closes: https://lore.kernel.org/linux-input/20251230221639.582406-1-yajatapps3@gmail.com/
Tested-by: Yajat Kumar <yajatapps3@gmail.com>
Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Link: https://patch.msgid.link/20260217132346.34535-1-johannes.goede@oss.qualcomm.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis

### What the commit does
This adds a DMI-based touchscreen quirk for the SUPI S10 tablet. The
tablet's Goodix touchscreen (GDIX1001) reports inverted Y coordinates,
causing touch input to be vertically mirrored. The fix adds:

1. A new property entry array `gdix1001_y_inverted_props[]` with
   `touchscreen-inverted-y`
2. A corresponding `ts_dmi_data` struct pointing to ACPI name "GDIX1001"
3. A DMI table entry matching vendor "SUPI", product "S10"

### Stable kernel criteria assessment

**Fixes a real bug:** Yes. Without this quirk, touch input is vertically
mirrored on this tablet, making it essentially unusable for touch
interaction.

**Hardware quirk exception:** This is a textbook DMI-based hardware
quirk — exactly the type explicitly listed as appropriate for stable
backporting. The `touchscreen_dmi.c` file exists solely for these
entries; it has hundreds of similar quirks already.

**Small and contained:** Yes. ~18 lines added to a single file,
following the exact same pattern as every other entry in the file.

**Risk of regression:** Extremely low. The DMI matching
(`DMI_SYS_VENDOR: "SUPI"`, `DMI_PRODUCT_NAME: "S10"`) ensures this code
only activates on the specific affected tablet. No other hardware is
impacted.

**Tested and reviewed:** Yes. Has both `Tested-by: Yajat Kumar` (the
reporter/user) and `Reviewed-by: Ilpo Järvinen` (Intel maintainer). The
commit author Hans de Goede is the well-known x86 platform maintainer
who handles most touchscreen quirks.

**No new features:** Correct. This uses existing infrastructure
(`ts_dmi_data`, `property_entry`, `dmi_system_id` matching) to fix a
specific device.

**Dependencies:** None. The `touchscreen_dmi.c` framework and the Goodix
driver's handling of `touchscreen-inverted-y` have been present for many
kernel versions.

### Verification
- The commit follows the identical pattern used by all other entries in
  `touchscreen_dmi.c` — no novel code patterns
- The `gdix1001_y_inverted_props` is a subset of the existing
  `gdix1001_upside_down_props` (which sets both inverted-x and
  inverted-y), confirming this is a well-established mechanism
- Reporter and tester are the same person (Yajat Kumar), confirming the
  fix resolves the reported issue
- The author (Hans de Goede) is the primary maintainer for x86
  touchscreen quirks
- The `Closes:` link to lore.kernel.org confirms a real user report from
  December 2025

### Risk vs benefit
- **Benefit:** Makes touchscreen usable on SUPI S10 tablets — critical
  for those users
- **Risk:** Near zero — DMI-scoped to one specific device model, uses
  existing well-tested infrastructure

**YES**

 drivers/platform/x86/touchscreen_dmi.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index bdc19cd8d3edf..d83c387821ea1 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -410,6 +410,16 @@ static const struct ts_dmi_data gdix1002_upside_down_data = {
 	.properties	= gdix1001_upside_down_props,
 };
 
+static const struct property_entry gdix1001_y_inverted_props[] = {
+	PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+	{ }
+};
+
+static const struct ts_dmi_data gdix1001_y_inverted_data = {
+	.acpi_name	= "GDIX1001",
+	.properties	= gdix1001_y_inverted_props,
+};
+
 static const struct property_entry gp_electronic_t701_props[] = {
 	PROPERTY_ENTRY_U32("touchscreen-size-x", 960),
 	PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
@@ -1658,6 +1668,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
 			DMI_MATCH(DMI_PRODUCT_SKU, "PN20170413488"),
 		},
 	},
+	{
+		/* SUPI S10 */
+		.driver_data = (void *)&gdix1001_y_inverted_data,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SUPI"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "S10"),
+		},
+	},
 	{
 		/* Techbite Arc 11.6 */
 		.driver_data = (void *)&techbite_arc_11_6_data,
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.19-6.1] HID: apple: avoid memory leak in apple_report_fixup()
From: Sasha Levin @ 2026-03-10  9:01 UTC (permalink / raw)
  To: patches, stable
  Cc: Günther Noack, Benjamin Tissoires, Sasha Levin, jikos,
	linux-input, linux-kernel
In-Reply-To: <20260310090145.2709021-1-sashal@kernel.org>

From: Günther Noack <gnoack@google.com>

[ Upstream commit 239c15116d80f67d32f00acc34575f1a6b699613 ]

The apple_report_fixup() function was returning a
newly kmemdup()-allocated buffer, but never freeing it.

The caller of report_fixup() does not take ownership of the returned
pointer, but it *is* permitted to return a sub-portion of the input
rdesc, whose lifetime is managed by the caller.

Assisted-by: Gemini-CLI:Google Gemini 3
Signed-off-by: Günther Noack <gnoack@google.com>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

This is very revealing. The caller's flow is:

1. `buf = kmemdup(start, size, ...)` — makes a copy of rdesc
2. `start = device->driver->report_fixup(device, buf, &size)` — calls
   the fixup, passing `buf`
3. `start = kmemdup(start, size, ...)` — copies whatever `report_fixup`
   returned
4. `kfree(buf)` — frees the original buf

**The old buggy code**: `apple_report_fixup` did `rdesc = kmemdup(rdesc
+ 1, ...)` which allocated a NEW buffer and returned it. The caller then
does `kmemdup(start, size)` (copies it again) and `kfree(buf)` (frees
the ORIGINAL `buf`). But the intermediate buffer allocated by
`apple_report_fixup` is never freed — leaked.

**The fix**: Instead of `kmemdup(rdesc + 1, ...)`, just do `rdesc =
rdesc + 1`. This returns a pointer into the caller's `buf`, which the
caller will properly copy and then free.

This is safe because:
- The caller already makes a copy of whatever is returned
  (`kmemdup(start, size)`)
- The caller then frees `buf`
- Since `rdesc + 1` points into `buf`, it's valid until `kfree(buf)`
  which happens AFTER the copy

## Analysis

**What problem the commit solves**: Every time `apple_report_fixup()` is
called for a Magic Keyboard with the `APPLE_RDESC_BATTERY` quirk, a
`kmemdup()` allocation leaks memory. This happens at device probe time,
so each time a Magic Keyboard is connected (or the driver is reloaded),
memory is leaked.

**Meets stable kernel rules**:
1. **Obviously correct and tested** — Yes, the fix simply changes
   `kmemdup(rdesc + 1, ...)` to `rdesc + 1`. The caller already copies
   the returned buffer, so the intermediate allocation was unnecessary.
2. **Fixes a real bug** — Yes, a real memory leak.
3. **Important issue** — Memory leak that occurs on every device probe
   for affected Apple Magic Keyboards. While not a crash, it's a
   persistent resource leak.
4. **Small and contained** — Yes, a 3-line change (removes kmemdup +
   error check, replaces with pointer arithmetic).
5. **No new features** — Correct, pure bug fix.

**Risk vs benefit**: Very low risk. The change simplifies the code by
removing an allocation. The caller's code in `hid-core.c` explicitly
handles this case (comment says "report_fixup() returns a sub-portion of
the input rdesc"). Benefit is fixing a real memory leak affecting Apple
keyboard users.

**Affected versions**: The buggy code was introduced in commit
`6e143293e17a7` which first appeared in v5.17-rc1. All stable trees from
5.17+ are affected (6.1.y, 6.6.y, 6.12.y, etc.).

**Dependencies**: None. The fix is self-contained and applies cleanly.

## Verification

- `git show 6e143293e17a7` confirmed this is the commit that introduced
  the buggy `kmemdup` call in `apple_report_fixup()`, first appearing in
  v5.17-rc1
- Read `hid-core.c:1285-1304` confirmed the caller does NOT take
  ownership of the returned pointer — it copies it with `kmemdup(start,
  size)` and then frees `buf`, meaning any separate allocation by
  `report_fixup` is leaked
- The caller's comment at line 1298-1301 explicitly states
  "report_fixup() returns a static read-only memory... we have no idea
  if that memory needs to be cleaned up" — confirming the caller cannot
  and does not free the report_fixup return value
- Read the fixed code at `hid-apple.c:691-692` confirming `rdesc = rdesc
  + 1` correctly returns a sub-portion of the input buffer, which the
  caller handles properly
- The fix removes 3 lines and adds 1 line — minimal change with clear
  semantics

**YES**

 drivers/hid/hid-apple.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 2f9a2e07c4263..9dcb252c5d6c7 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -689,9 +689,7 @@ static const __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		hid_info(hdev,
 			 "fixing up Magic Keyboard battery report descriptor\n");
 		*rsize = *rsize - 1;
-		rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL);
-		if (!rdesc)
-			return NULL;
+		rdesc = rdesc + 1;
 
 		rdesc[0] = 0x05;
 		rdesc[1] = 0x01;
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.19-6.12] HID: apple: Add EPOMAKER TH87 to the non-apple keyboards list
From: Sasha Levin @ 2026-03-10  9:01 UTC (permalink / raw)
  To: patches, stable
  Cc: Takashi Iwai, Jiri Kosina, Sasha Levin, jikos, bentiss,
	linux-input, linux-kernel
In-Reply-To: <20260310090145.2709021-1-sashal@kernel.org>

From: Takashi Iwai <tiwai@suse.de>

[ Upstream commit 7c698de0dc5daa1e1a5fd1f0c6aa1b6bb2f5d867 ]

EPOMAKER TH87 has the very same ID as Apple Aluminum keyboard
(05ac:024f) although it doesn't work as expected in compatible way.

Put three entries to the non-apple keyboards list to exclude this
device: one for BT ("TH87"), one for USB ("HFD Epomaker TH87") and one
for dongle ("2.4G Wireless Receiver").

Link: https://bugzilla.suse.com/show_bug.cgi?id=1258455
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

The patch just adds three string entries to the array. The only concern
is whether the exact context (previous entries) exists in stable trees,
but since this is just appending to an array, even if some intermediate
entries are missing, the patch can be trivially adjusted.

### Problem Being Fixed

The EPOMAKER TH87 keyboard uses the same USB vendor/product ID as Apple
Aluminum keyboards (05ac:024f). Without this fix, the hid-apple driver
applies Apple-specific key translation logic to this non-Apple keyboard,
causing it to not work as expected. The bug is tracked in SUSE's
bugzilla (bsc#1258455), confirming it affects real users.

### Stable Kernel Rules Assessment

1. **Obviously correct and tested**: Yes - trivial addition of string
   entries to a quirk list. Same pattern used for 10+ other keyboards.
   Comes from SUSE maintainer (Takashi Iwai).
2. **Fixes a real bug**: Yes - keyboard doesn't work correctly without
   this fix.
3. **Important issue**: Yes - keyboard malfunction for affected users
   (wrong key mappings).
4. **Small and contained**: Yes - adds 3 lines to a static array, zero
   logic changes.
5. **No new features/APIs**: Correct - uses existing infrastructure.
6. **Applies cleanly**: Should apply with trivial context adjustment if
   intermediate entries are missing.

### Risk Assessment

**Risk: Extremely low.** The change only adds entries to a name-matching
list. The matching uses `strncmp` prefix matching. The entries are
specific enough ("TH87", "HFD Epomaker TH87", "2.4G Wireless Receiver")
to only match intended devices. One concern: "2.4G Wireless Receiver" is
a somewhat generic name and could match other devices' dongles, but the
effect of matching (setting `APPLE_IS_NON_APPLE` flag which changes
fnmode default) is benign for actual non-Apple keyboards.

### Verification

- **Verified** `non_apple_keyboards` infrastructure was introduced in
  commit `a0a05054583fe` (v6.0-rc1), present in all current stable trees
  (6.1.y+).
- **Verified** the commit adds only 3 string entries to the static
  `non_apple_keyboards[]` array at line 368-370.
- **Verified** `apple_is_non_apple_keyboard()` uses `strncmp` prefix
  matching at line 380.
- **Verified** the effect of matching is setting `APPLE_IS_NON_APPLE`
  quirk bit at line 770, which changes function key behavior default.
- **Verified** the bug is tracked at
  `https://bugzilla.suse.com/show_bug.cgi?id=1258455` (referenced in
  Link: tag).
- **Verified** this follows the exact same pattern as 7+ previous non-
  apple keyboard additions (GANSS, Hailuck, Jamesdonkey, A3R, hfd.cn,
  WKB603, SONiX AK870 PRO, SONiX KN85).
- **Verified** author is Takashi Iwai (tiwai@suse.de), a senior SUSE
  kernel maintainer.

### Conclusion

This is a textbook hardware quirk addition. It adds device
identification entries to an existing mechanism, fixing a real-world
keyboard malfunction reported by users (with bugzilla link). The change
is trivial (3 lines of string data), zero risk to existing
functionality, and follows an established pattern used by many other
entries. It clearly meets all stable kernel criteria.

**YES**

 drivers/hid/hid-apple.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 233e367cce1d1..2f9a2e07c4263 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -365,6 +365,9 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
 	{ "A3R" },
 	{ "hfd.cn" },
 	{ "WKB603" },
+	{ "TH87" },			/* EPOMAKER TH87 BT mode */
+	{ "HFD Epomaker TH87" },	/* EPOMAKER TH87 USB mode */
+	{ "2.4G Wireless Receiver" },	/* EPOMAKER TH87 dongle */
 };
 
 static bool apple_is_non_apple_keyboard(struct hid_device *hdev)
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.19-5.15] HID: magicmouse: fix battery reporting for Apple Magic Trackpad 2
From: Sasha Levin @ 2026-03-10  9:01 UTC (permalink / raw)
  To: patches, stable
  Cc: Julius Lehmann, Jiri Kosina, Sasha Levin, jikos, bentiss,
	linux-input, linux-kernel
In-Reply-To: <20260310090145.2709021-1-sashal@kernel.org>

From: Julius Lehmann <lehmanju@devpi.de>

[ Upstream commit 5f3518d77419255f8b12bb23c8ec22acbeb6bc5b ]

Battery reporting does not work for the Apple Magic Trackpad 2 if it is
connected via USB. The current hid descriptor fixup code checks for a
hid descriptor length of exactly 83 bytes. If the hid descriptor is
larger, which is the case for newer apple mice, the fixup is not
applied.

This fix checks for hid descriptor sizes greater/equal 83 bytes which
applies the fixup for newer devices as well.

Signed-off-by: Julius Lehmann <lehmanju@devpi.de>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis

### Problem
Battery reporting doesn't work for Apple Magic Trackpad 2 when connected
via USB if the HID descriptor is larger than exactly 83 bytes. Newer
Apple devices have expanded HID descriptors, so the original strict
equality check (`*rsize == 83`) causes the battery report fixup to be
silently skipped.

### The Fix
A single-character change: `*rsize == 83` becomes `*rsize >= 83`. This
allows the descriptor fixup to apply for newer devices with larger
descriptors.

### Safety Analysis
The fix is safe because:
1. The `>= 83` check still guarantees the descriptor is at least 83
   bytes, so accessing `rdesc[46]` and `rdesc[58]` is within bounds.
2. The additional content checks (`rdesc[46] == 0x84 && rdesc[58] ==
   0x85`) still validate the descriptor format before applying any
   modification.
3. The device type is still checked (`is_usb_magicmouse2` or
   `is_usb_magictrackpad2`), so unrelated devices are unaffected.

### Stable Criteria Assessment
- **Fixes a real bug**: Yes — battery reporting completely broken for
  newer Apple trackpad/mouse devices over USB.
- **Obviously correct**: Yes — the original check was overly
  restrictive; the `>=` check is the natural fix while maintaining
  safety through the other validation checks.
- **Small and contained**: Yes — single character change in one file,
  one driver.
- **No new features**: Correct — just enables existing battery reporting
  functionality for devices it should already work with.
- **Low regression risk**: Very low — only affects Apple Magic Mouse 2 /
  Magic Trackpad 2 USB devices, and the content validation guards
  against incorrect application.

### User Impact
Apple Magic Mouse 2 and Magic Trackpad 2 are widely used peripherals.
Users connecting via USB (e.g., for charging) lose battery level
reporting without this fix. This affects real hardware that many people
use daily.

### Verification
- `git blame` confirmed the original `*rsize == 83` check was introduced
  in commit `0b91b4e4dae63` ("HID: magicmouse: Report battery level over
  USB", Nov 2021), so the bug has existed since then.
- Read the surrounding code (lines 973-1006) to confirm the `rdesc[46]`
  and `rdesc[58]` access is safe with `>= 83` guard.
- `git log --grep` confirmed multiple battery-related fixes to this
  driver, indicating ongoing maintenance and real user interest.
- The device checks (`is_usb_magicmouse2`, `is_usb_magictrackpad2`)
  limit scope to specific Apple products only.
- The fix is self-contained with no dependencies on other commits.

**YES**

 drivers/hid/hid-magicmouse.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 91f621ceb924b..f4cf29c2e8330 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -990,7 +990,7 @@ static const __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 	 */
 	if ((is_usb_magicmouse2(hdev->vendor, hdev->product) ||
 	     is_usb_magictrackpad2(hdev->vendor, hdev->product)) &&
-	    *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
+	    *rsize >= 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
 		hid_info(hdev,
 			 "fixing up magicmouse battery report descriptor\n");
 		*rsize = *rsize - 1;
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.19-6.18] HID: intel-ish-hid: ipc: Add Nova Lake-H/S PCI device IDs
From: Sasha Levin @ 2026-03-10  9:01 UTC (permalink / raw)
  To: patches, stable
  Cc: Zhang Lixu, Andy Shevchenko, Srinivas Pandruvada, Jiri Kosina,
	Sasha Levin, jikos, bentiss, linux-input, linux-kernel
In-Reply-To: <20260310090145.2709021-1-sashal@kernel.org>

From: Zhang Lixu <lixu.zhang@intel.com>

[ Upstream commit 22f8bcec5aeb05104b3eaa950cb5a345e95f0aa8 ]

Add device IDs of Nova Lake-H and Nova Lake-S into ishtp support list.

Signed-off-by: Zhang Lixu <lixu.zhang@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis: HID: intel-ish-hid: ipc: Add Nova Lake-H/S PCI device IDs

### What the commit does

This commit adds PCI device IDs for two new Intel platforms (Nova Lake-H
and Nova Lake-S) to the existing `intel-ish-hid` driver. The changes
are:

1. Two new `#define` entries for PCI device IDs (`0xD354` for NVL_H,
   `0x6E78` for NVL_S) in `hw-ish.h`
2. Two new enum values, firmware generation string macros, driver data
   entries, and PCI ID table entries in `pci-ish.c`

### Classification: New Device IDs to Existing Driver

This falls squarely into the **"NEW DEVICE IDs"** exception category,
which is explicitly listed as appropriate for stable backports:

> Adding PCI IDs, USB IDs, ACPI IDs, etc. to existing drivers. These are
trivial additions that enable hardware support. The driver must already
exist in stable; only the ID is new.

The `intel-ish-hid` driver has been in the kernel for many years, with a
long list of existing Intel platform IDs (CHV, BXT, APL, SPT, CNL, GLK,
ICL, CML, CMP, EHL, TGL, ADL, RPL, MTL, ARL, LNL, PTL, WCL).

### Stable Criteria Assessment

- **Obviously correct**: Yes - follows the exact same pattern as all
  prior device ID additions (PTL, WCL, LNL, etc.)
- **Fixes a real bug**: Enables hardware that would otherwise be non-
  functional on Nova Lake platforms
- **Small and contained**: Yes - only touches two files, adds ~12 lines
  following an established pattern
- **No new features/APIs**: Correct - just enables existing driver on
  new hardware
- **Risk**: Extremely low - the new IDs only match new hardware;
  existing hardware is completely unaffected

### Review Quality

- **Reviewed-by**: Andy Shevchenko (Intel, prolific kernel reviewer)
- **Acked-by**: Srinivas Pandruvada (Intel ISH subsystem maintainer)
- **Signed-off-by**: Jiri Kosina (HID maintainer)

This has full maintainer sign-off chain.

### Risk Assessment

The risk is essentially zero. The new PCI device IDs (`0xD354`,
`0x6E78`) will only match on Nova Lake hardware. No existing systems are
affected. The code pattern is identical to the most recent additions
(WCL, PTL) which themselves followed the same pattern.

### Verification

- Verified the diff adds only PCI device ID definitions, enum values,
  firmware generation strings, driver data entries, and PCI table
  entries - no behavioral changes to existing code
- Verified the pattern matches prior additions (e.g., WCL added in the
  same manner with `ISHTP_DRIVER_DATA_WCL`, `ISH_FW_GEN_WCL`, etc.)
- Verified the driver (`intel-ish-hid`) has existed in the kernel for
  many years with 20+ existing platform IDs
- Verified no code logic changes - purely data additions
- The commit has proper review chain (Reviewed-by, Acked-by from
  subsystem maintainer, Signed-off-by from HID maintainer)

### Conclusion

This is a textbook device ID addition to an existing, well-established
driver. It enables Intel ISH (sensor hub) functionality on Nova Lake-H
and Nova Lake-S platforms. Without this, users with Nova Lake hardware
would have non-functional sensor hubs. The change is trivially safe,
well-reviewed, and follows an established pattern.

**YES**

 drivers/hid/intel-ish-hid/ipc/hw-ish.h  |  2 ++
 drivers/hid/intel-ish-hid/ipc/pci-ish.c | 12 ++++++++++++
 2 files changed, 14 insertions(+)

diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
index fa5d68c363134..27389971b96cc 100644
--- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h
+++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
@@ -39,6 +39,8 @@
 #define PCI_DEVICE_ID_INTEL_ISH_PTL_H		0xE345
 #define PCI_DEVICE_ID_INTEL_ISH_PTL_P		0xE445
 #define PCI_DEVICE_ID_INTEL_ISH_WCL		0x4D45
+#define PCI_DEVICE_ID_INTEL_ISH_NVL_H		0xD354
+#define PCI_DEVICE_ID_INTEL_ISH_NVL_S		0x6E78
 
 #define	REVISION_ID_CHT_A0	0x6
 #define	REVISION_ID_CHT_Ax_SI	0x0
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index 1612e8cb23f0c..ed3405c05e73c 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -28,11 +28,15 @@ enum ishtp_driver_data_index {
 	ISHTP_DRIVER_DATA_LNL_M,
 	ISHTP_DRIVER_DATA_PTL,
 	ISHTP_DRIVER_DATA_WCL,
+	ISHTP_DRIVER_DATA_NVL_H,
+	ISHTP_DRIVER_DATA_NVL_S,
 };
 
 #define ISH_FW_GEN_LNL_M "lnlm"
 #define ISH_FW_GEN_PTL "ptl"
 #define ISH_FW_GEN_WCL "wcl"
+#define ISH_FW_GEN_NVL_H "nvlh"
+#define ISH_FW_GEN_NVL_S "nvls"
 
 #define ISH_FIRMWARE_PATH(gen) "intel/ish/ish_" gen ".bin"
 #define ISH_FIRMWARE_PATH_ALL "intel/ish/ish_*.bin"
@@ -47,6 +51,12 @@ static struct ishtp_driver_data ishtp_driver_data[] = {
 	[ISHTP_DRIVER_DATA_WCL] = {
 		.fw_generation = ISH_FW_GEN_WCL,
 	},
+	[ISHTP_DRIVER_DATA_NVL_H] = {
+		.fw_generation = ISH_FW_GEN_NVL_H,
+	},
+	[ISHTP_DRIVER_DATA_NVL_S] = {
+		.fw_generation = ISH_FW_GEN_NVL_S,
+	},
 };
 
 static const struct pci_device_id ish_pci_tbl[] = {
@@ -76,6 +86,8 @@ static const struct pci_device_id ish_pci_tbl[] = {
 	{PCI_DEVICE_DATA(INTEL, ISH_PTL_H, ISHTP_DRIVER_DATA_PTL)},
 	{PCI_DEVICE_DATA(INTEL, ISH_PTL_P, ISHTP_DRIVER_DATA_PTL)},
 	{PCI_DEVICE_DATA(INTEL, ISH_WCL, ISHTP_DRIVER_DATA_WCL)},
+	{PCI_DEVICE_DATA(INTEL, ISH_NVL_H, ISHTP_DRIVER_DATA_NVL_H)},
+	{PCI_DEVICE_DATA(INTEL, ISH_NVL_S, ISHTP_DRIVER_DATA_NVL_S)},
 	{}
 };
 MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.19-5.15] HID: magicmouse: avoid memory leak in magicmouse_report_fixup()
From: Sasha Levin @ 2026-03-10  9:01 UTC (permalink / raw)
  To: patches, stable
  Cc: Günther Noack, Benjamin Tissoires, Sasha Levin, jikos,
	linux-input, linux-kernel
In-Reply-To: <20260310090145.2709021-1-sashal@kernel.org>

From: Günther Noack <gnoack@google.com>

[ Upstream commit 91e8c6e601bdc1ccdf886479b6513c01c7e51c2c ]

The magicmouse_report_fixup() function was returning a
newly kmemdup()-allocated buffer, but never freeing it.

The caller of report_fixup() does not take ownership of the returned
pointer, but it *is* permitted to return a sub-portion of the input
rdesc, whose lifetime is managed by the caller.

Assisted-by: Gemini-CLI:Google Gemini 3
Signed-off-by: Günther Noack <gnoack@google.com>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have all the information needed for a thorough analysis.

## Analysis

### What the commit fixes

The `magicmouse_report_fixup()` function was introduced in commit
`0b91b4e4dae63` (v5.16 era, 2021) and uses `kmemdup(rdesc + 1, *rsize,
GFP_KERNEL)` to create a new buffer. The caller in `hid_open_report()`
(hid-core.c) does **not** free the returned pointer — it immediately
`kmemdup()`s the result again and frees its own copy. So the buffer
allocated by magicmouse was leaked every time the device was
initialized.

The fix replaces `kmemdup(rdesc + 1, ...)` with simply `rdesc + 1`,
returning a sub-portion of the input buffer. This is explicitly
permitted by the `report_fixup()` contract as documented in
`include/linux/hid.h` (lines 839-843), and is safe because
`hid_open_report()` immediately copies the returned data.

### Stable kernel criteria assessment

1. **Fixes a real bug**: Yes — memory leak on every device probe for
   Apple Magic Mouse 2 and Magic Trackpad 2 connected via USB.
2. **Obviously correct**: Yes — the HID core immediately `kmemdup()`s
   the return value, so returning a pointer into the caller's buffer is
   safe. The documentation explicitly says "a sub-portion of it" is
   valid.
3. **Small and contained**: Yes — removes 3 lines (kmemdup + NULL
   check), changes one line. Single file, single function.
4. **No new features**: Correct — pure bug fix.
5. **Low risk**: Very low — the change is simpler than the original
   code. Removes an allocation that was never needed.

### User impact

This affects all users of Apple Magic Mouse 2 and Magic Trackpad 2 over
USB. Each time the device is probed (e.g., plugged in, resumed), ~82
bytes are leaked. While not catastrophic per-event, it's a real resource
leak that accumulates.

### Risk assessment

Minimal risk. The fix makes the code simpler and removes a dynamic
allocation. The HID core's defensive `kmemdup()` of the returned pointer
ensures the approach is safe.

### Dependency check

The buggy `kmemdup()` was introduced in commit `0b91b4e4dae63` ("HID:
magicmouse: Report battery level over USB"), which was in v5.16. This
code exists in all current stable trees (6.1.y, 6.6.y, 6.12.y). The fix
is self-contained with no dependencies on other commits.

### Verification

- **git show 0b91b4e4dae63** confirmed the kmemdup was introduced in the
  original "Report battery level over USB" commit (2021, v5.16 era)
- **hid-core.c hid_open_report()** verified: the caller kmemdup's the
  return value immediately and frees its own buffer — it does NOT take
  ownership of the returned pointer (lines 1285-1307)
- **include/linux/hid.h documentation** (lines 839-843) confirmed:
  returning "a sub-portion of it" is explicitly documented as valid
- **git log --oneline -- drivers/hid/hid-magicmouse.c** confirmed the
  commit under review (`c0993f362e2ef`) is the fix, with no other
  dependencies
- **Commit 225c43c0e9164** (the next commit after) only changes the size
  check from `== 83` to `>= 83` and does not affect the fix's
  applicability

This is a clear, small, self-contained memory leak fix in a widely-used
driver. It meets all stable kernel criteria with minimal risk.

**YES**

 drivers/hid/hid-magicmouse.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index f4cf29c2e8330..9eadf3252d0dc 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -994,9 +994,7 @@ static const __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		hid_info(hdev,
 			 "fixing up magicmouse battery report descriptor\n");
 		*rsize = *rsize - 1;
-		rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL);
-		if (!rdesc)
-			return NULL;
+		rdesc = rdesc + 1;
 
 		rdesc[0] = 0x05;
 		rdesc[1] = 0x01;
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH v7 1/3] input: trackpoint - Enable doubletap by default on capable devices
From: Ilpo Järvinen @ 2026-03-10  9:15 UTC (permalink / raw)
  To: Vishnu Sankar
  Cc: Mark Pearson, dmitry.torokhov, hmh, Hans de Goede, corbet,
	derekjohn.clark, linux-input, LKML, ibm-acpi-devel, linux-doc,
	platform-driver-x86, vsankar
In-Reply-To: <CABxCQKtf=RYrpgnbM0ODo3GA0oW3jgR=_erc9RCD6gEasasA+A@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3180 bytes --]

On Tue, 10 Mar 2026, Vishnu Sankar wrote:

> Hi Ilpo,
> 
> Thank you so much for the review.
> 
> On Mon, Mar 9, 2026 at 5:01 PM Ilpo Järvinen
> <ilpo.jarvinen@linux.intel.com> wrote:
> >
> > On Mon, 9 Feb 2026, Vishnu Sankar wrote:
> >
> > > Enable doubletap functionality by default on TrackPoint devices that
> > > support it. The feature is detected using firmware ID pattern matching
> > > (PNP: LEN03xxx) with a deny list of incompatible devices.
> > >
> > > This provides immediate doubletap functionality without requiring
> > > userspace configuration. The hardware is enabled during device
> > > detection, while event filtering continues to be handled by the
> > > thinkpad_acpi driver as before.
> > >
> > > Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
> > > Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> > > Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > > ---
> > > Changes in v7:
> > > - Removed unwanted comments
> > > - Removed psmouse_info ()
> > >
> > > Changes in v6:
> > > - No Changes
> > >
> > > Changes in v5:
> > > - Renamed function to trackpoint_is_dt_capable()
> > > - Simplified string comparison without sscanf()
> > > - Removed wrapper function as suggested
> > > - Fixed missing period in comment
> > >
> > > Changes in v4:
> > > - Simplified approach: removed all sysfs attributes and user interface
> > > - Enable doubletap by default during device detection
> > > - Removed global variables and complex attribute infrastructure
> > > - Uses minimal firmware ID detection with deny list
> > > - Follows KISS principle as suggested by reviewers
> > >
> > > Changes in v3:
> > > - No changes
> > >
> > > Changes in v2:
> > > - Improve commit messages
> > > - Sysfs attributes moved to trackpoint.c
> > > - Removed unnecessary comments
> > > - Removed unnecessary debug messages
> > > - Using strstarts() instead of strcmp()
> > > - is_trackpoint_dt_capable() modified
> > > - Removed _BIT suffix and used BIT() define
> > > - Reverse the trackpoint_doubletap_status() logic to return error first
> > > - Removed export functions as a result of the design change
> > > - Changed trackpoint_dev->psmouse to parent_psmouse
> > > - The path of trackpoint.h is not changed
> > > ---
> > >  drivers/input/mouse/trackpoint.c | 45 ++++++++++++++++++++++++++++++++
> > >  drivers/input/mouse/trackpoint.h |  5 ++++
> > >  2 files changed, 50 insertions(+)
> > >

> > > diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
> > > index 5f6643b69a2c..e12d76350252 100644
> > > --- a/drivers/input/mouse/trackpoint.c
> > > +++ b/drivers/input/mouse/trackpoint.c

> > > +     /* Must start with "PNP: LEN03" */
> > > +     if (!strstarts(pnp_id, "PNP: LEN03"))
> >
> > Missing include.
>
> Sorry, I am a bit confused here:
> strstarts() is already available through the existing
> #include <linux/string.h> in thinkpad_acpi.c.
> 
> Do you think I should do anything else here?

Yes.

The file you're modifying in this patch is trackpoint.c which doesn't 
have that include so please add it also there. :-)

-- 
 i.

^ permalink raw reply

* Re: [PATCH v7 1/3] input: trackpoint - Enable doubletap by default on capable devices
From: Vishnu Sankar @ 2026-03-10  9:21 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: Mark Pearson, dmitry.torokhov, hmh, Hans de Goede, corbet,
	derekjohn.clark, linux-input, LKML, ibm-acpi-devel, linux-doc,
	platform-driver-x86, vsankar
In-Reply-To: <0df2daf8-31ee-4fe3-fc38-de138b302549@linux.intel.com>

Hi Ilpo,

Thank you.

On Tue, Mar 10, 2026 at 6:15 PM Ilpo Järvinen
<ilpo.jarvinen@linux.intel.com> wrote:
>
> On Tue, 10 Mar 2026, Vishnu Sankar wrote:
>
> > Hi Ilpo,
> >
> > Thank you so much for the review.
> >
> > On Mon, Mar 9, 2026 at 5:01 PM Ilpo Järvinen
> > <ilpo.jarvinen@linux.intel.com> wrote:
> > >
> > > On Mon, 9 Feb 2026, Vishnu Sankar wrote:
> > >
> > > > Enable doubletap functionality by default on TrackPoint devices that
> > > > support it. The feature is detected using firmware ID pattern matching
> > > > (PNP: LEN03xxx) with a deny list of incompatible devices.
> > > >
> > > > This provides immediate doubletap functionality without requiring
> > > > userspace configuration. The hardware is enabled during device
> > > > detection, while event filtering continues to be handled by the
> > > > thinkpad_acpi driver as before.
> > > >
> > > > Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
> > > > Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> > > > Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > > > ---
> > > > Changes in v7:
> > > > - Removed unwanted comments
> > > > - Removed psmouse_info ()
> > > >
> > > > Changes in v6:
> > > > - No Changes
> > > >
> > > > Changes in v5:
> > > > - Renamed function to trackpoint_is_dt_capable()
> > > > - Simplified string comparison without sscanf()
> > > > - Removed wrapper function as suggested
> > > > - Fixed missing period in comment
> > > >
> > > > Changes in v4:
> > > > - Simplified approach: removed all sysfs attributes and user interface
> > > > - Enable doubletap by default during device detection
> > > > - Removed global variables and complex attribute infrastructure
> > > > - Uses minimal firmware ID detection with deny list
> > > > - Follows KISS principle as suggested by reviewers
> > > >
> > > > Changes in v3:
> > > > - No changes
> > > >
> > > > Changes in v2:
> > > > - Improve commit messages
> > > > - Sysfs attributes moved to trackpoint.c
> > > > - Removed unnecessary comments
> > > > - Removed unnecessary debug messages
> > > > - Using strstarts() instead of strcmp()
> > > > - is_trackpoint_dt_capable() modified
> > > > - Removed _BIT suffix and used BIT() define
> > > > - Reverse the trackpoint_doubletap_status() logic to return error first
> > > > - Removed export functions as a result of the design change
> > > > - Changed trackpoint_dev->psmouse to parent_psmouse
> > > > - The path of trackpoint.h is not changed
> > > > ---
> > > >  drivers/input/mouse/trackpoint.c | 45 ++++++++++++++++++++++++++++++++
> > > >  drivers/input/mouse/trackpoint.h |  5 ++++
> > > >  2 files changed, 50 insertions(+)
> > > >
>
> > > > diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
> > > > index 5f6643b69a2c..e12d76350252 100644
> > > > --- a/drivers/input/mouse/trackpoint.c
> > > > +++ b/drivers/input/mouse/trackpoint.c
>
> > > > +     /* Must start with "PNP: LEN03" */
> > > > +     if (!strstarts(pnp_id, "PNP: LEN03"))
> > >
> > > Missing include.
> >
> > Sorry, I am a bit confused here:
> > strstarts() is already available through the existing
> > #include <linux/string.h> in thinkpad_acpi.c.
> >
> > Do you think I should do anything else here?
>
> Yes.
>
> The file you're modifying in this patch is trackpoint.c which doesn't
> have that include so please add it also there. :-)
Aaah, Sorry!!. Got it.
I’ll add the missing #include <linux/string.h>
Thank you for pointing it out.
>
> --
>  i.



-- 

Regards,

      Vishnu Sankar

^ permalink raw reply

* Re: [PATCH v7 1/3] input: trackpoint - Enable doubletap by default on capable devices
From: Ilpo Järvinen @ 2026-03-10  9:30 UTC (permalink / raw)
  To: Vishnu Sankar
  Cc: Mark Pearson, dmitry.torokhov, hmh, Hans de Goede, corbet,
	derekjohn.clark, linux-input, LKML, ibm-acpi-devel, linux-doc,
	platform-driver-x86, vsankar
In-Reply-To: <CABxCQKt_1Hv2hPDpzQQ3TxFJWbRNHs-vRDi9hNhBq4oaoGkt3w@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3944 bytes --]

On Tue, 10 Mar 2026, Vishnu Sankar wrote:

> Hi Ilpo,
> 
> Thank you.
> 
> On Tue, Mar 10, 2026 at 6:15 PM Ilpo Järvinen
> <ilpo.jarvinen@linux.intel.com> wrote:
> >
> > On Tue, 10 Mar 2026, Vishnu Sankar wrote:
> >
> > > Hi Ilpo,
> > >
> > > Thank you so much for the review.
> > >
> > > On Mon, Mar 9, 2026 at 5:01 PM Ilpo Järvinen
> > > <ilpo.jarvinen@linux.intel.com> wrote:
> > > >
> > > > On Mon, 9 Feb 2026, Vishnu Sankar wrote:
> > > >
> > > > > Enable doubletap functionality by default on TrackPoint devices that
> > > > > support it. The feature is detected using firmware ID pattern matching
> > > > > (PNP: LEN03xxx) with a deny list of incompatible devices.
> > > > >
> > > > > This provides immediate doubletap functionality without requiring
> > > > > userspace configuration. The hardware is enabled during device
> > > > > detection, while event filtering continues to be handled by the
> > > > > thinkpad_acpi driver as before.
> > > > >
> > > > > Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
> > > > > Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> > > > > Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > > > > ---
> > > > > Changes in v7:
> > > > > - Removed unwanted comments
> > > > > - Removed psmouse_info ()
> > > > >
> > > > > Changes in v6:
> > > > > - No Changes
> > > > >
> > > > > Changes in v5:
> > > > > - Renamed function to trackpoint_is_dt_capable()
> > > > > - Simplified string comparison without sscanf()
> > > > > - Removed wrapper function as suggested
> > > > > - Fixed missing period in comment
> > > > >
> > > > > Changes in v4:
> > > > > - Simplified approach: removed all sysfs attributes and user interface
> > > > > - Enable doubletap by default during device detection
> > > > > - Removed global variables and complex attribute infrastructure
> > > > > - Uses minimal firmware ID detection with deny list
> > > > > - Follows KISS principle as suggested by reviewers
> > > > >
> > > > > Changes in v3:
> > > > > - No changes
> > > > >
> > > > > Changes in v2:
> > > > > - Improve commit messages
> > > > > - Sysfs attributes moved to trackpoint.c
> > > > > - Removed unnecessary comments
> > > > > - Removed unnecessary debug messages
> > > > > - Using strstarts() instead of strcmp()
> > > > > - is_trackpoint_dt_capable() modified
> > > > > - Removed _BIT suffix and used BIT() define
> > > > > - Reverse the trackpoint_doubletap_status() logic to return error first
> > > > > - Removed export functions as a result of the design change
> > > > > - Changed trackpoint_dev->psmouse to parent_psmouse
> > > > > - The path of trackpoint.h is not changed
> > > > > ---
> > > > >  drivers/input/mouse/trackpoint.c | 45 ++++++++++++++++++++++++++++++++
> > > > >  drivers/input/mouse/trackpoint.h |  5 ++++
> > > > >  2 files changed, 50 insertions(+)
> > > > >
> >
> > > > > diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
> > > > > index 5f6643b69a2c..e12d76350252 100644
> > > > > --- a/drivers/input/mouse/trackpoint.c
> > > > > +++ b/drivers/input/mouse/trackpoint.c
> >
> > > > > +     /* Must start with "PNP: LEN03" */
> > > > > +     if (!strstarts(pnp_id, "PNP: LEN03"))
> > > >
> > > > Missing include.
> > >
> > > Sorry, I am a bit confused here:
> > > strstarts() is already available through the existing
> > > #include <linux/string.h> in thinkpad_acpi.c.
> > >
> > > Do you think I should do anything else here?
> >
> > Yes.
> >
> > The file you're modifying in this patch is trackpoint.c which doesn't
> > have that include so please add it also there. :-)
> Aaah, Sorry!!. Got it.
> I’ll add the missing #include <linux/string.h>
> Thank you for pointing it out.

Thanks. Please also double check you added inux/array_size.h into the 
correct file in case you were confused what file this patch modifies.

-- 
 i.

^ permalink raw reply

* [PATCH 6.19 113/311] HID: Add HID_CLAIMED_INPUT guards in raw_event callbacks missing them
From: Sasha Levin @ 2026-03-10 11:02 UTC (permalink / raw)
  To: patches, stable
  Cc: Greg Kroah-Hartman, Jiri Kosina, Benjamin Tissoires,
	Bastien Nocera, linux-input, stable
In-Reply-To: <cover.1773140654.git.sashal@kernel.org>

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

commit ecfa6f34492c493a9a1dc2900f3edeb01c79946b upstream.

In commit 2ff5baa9b527 ("HID: appleir: Fix potential NULL dereference at
raw event handle"), we handle the fact that raw event callbacks
can happen even for a HID device that has not been "claimed" causing a
crash if a broken device were attempted to be connected to the system.

Fix up the remaining in-tree HID drivers that forgot to add this same
check to resolve the same issue.

Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: Bastien Nocera <hadess@hadess.net>
Cc: linux-input@vger.kernel.org
Cc: stable <stable@kernel.org>
Assisted-by: gkh_clanker_2000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/hid/hid-cmedia.c          | 2 +-
 drivers/hid/hid-creative-sb0540.c | 2 +-
 drivers/hid/hid-zydacron.c        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/hid-cmedia.c b/drivers/hid/hid-cmedia.c
index 528d7f3612157..8bf5649b0c793 100644
--- a/drivers/hid/hid-cmedia.c
+++ b/drivers/hid/hid-cmedia.c
@@ -99,7 +99,7 @@ static int cmhid_raw_event(struct hid_device *hid, struct hid_report *report,
 {
 	struct cmhid *cm = hid_get_drvdata(hid);
 
-	if (len != CM6533_JD_RAWEV_LEN)
+	if (len != CM6533_JD_RAWEV_LEN || !(hid->claimed & HID_CLAIMED_INPUT))
 		goto out;
 	if (memcmp(data+CM6533_JD_SFX_OFFSET, ji_sfx, sizeof(ji_sfx)))
 		goto out;
diff --git a/drivers/hid/hid-creative-sb0540.c b/drivers/hid/hid-creative-sb0540.c
index b4c8e7a5d3e02..dfd6add353d19 100644
--- a/drivers/hid/hid-creative-sb0540.c
+++ b/drivers/hid/hid-creative-sb0540.c
@@ -153,7 +153,7 @@ static int creative_sb0540_raw_event(struct hid_device *hid,
 	u64 code, main_code;
 	int key;
 
-	if (len != 6)
+	if (len != 6 || !(hid->claimed & HID_CLAIMED_INPUT))
 		return 0;
 
 	/* From daemons/hw_hiddev.c sb0540_rec() in lirc */
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index 3bdb26f455925..1aae80f848f50 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -114,7 +114,7 @@ static int zc_raw_event(struct hid_device *hdev, struct hid_report *report,
 	unsigned key;
 	unsigned short index;
 
-	if (report->id == data[0]) {
+	if (report->id == data[0] && (hdev->claimed & HID_CLAIMED_INPUT)) {
 
 		/* break keys */
 		for (index = 0; index < 4; index++) {
-- 
2.51.0


^ permalink raw reply related

* [PATCH 6.18 143/314] HID: Add HID_CLAIMED_INPUT guards in raw_event callbacks missing them
From: Sasha Levin @ 2026-03-10 11:16 UTC (permalink / raw)
  To: patches, stable
  Cc: Greg Kroah-Hartman, Jiri Kosina, Benjamin Tissoires,
	Bastien Nocera, linux-input, stable
In-Reply-To: <cover.1773141554.git.sashal@kernel.org>

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

commit ecfa6f34492c493a9a1dc2900f3edeb01c79946b upstream.

In commit 2ff5baa9b527 ("HID: appleir: Fix potential NULL dereference at
raw event handle"), we handle the fact that raw event callbacks
can happen even for a HID device that has not been "claimed" causing a
crash if a broken device were attempted to be connected to the system.

Fix up the remaining in-tree HID drivers that forgot to add this same
check to resolve the same issue.

Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: Bastien Nocera <hadess@hadess.net>
Cc: linux-input@vger.kernel.org
Cc: stable <stable@kernel.org>
Assisted-by: gkh_clanker_2000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/hid/hid-cmedia.c          | 2 +-
 drivers/hid/hid-creative-sb0540.c | 2 +-
 drivers/hid/hid-zydacron.c        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/hid-cmedia.c b/drivers/hid/hid-cmedia.c
index 528d7f3612157..8bf5649b0c793 100644
--- a/drivers/hid/hid-cmedia.c
+++ b/drivers/hid/hid-cmedia.c
@@ -99,7 +99,7 @@ static int cmhid_raw_event(struct hid_device *hid, struct hid_report *report,
 {
 	struct cmhid *cm = hid_get_drvdata(hid);
 
-	if (len != CM6533_JD_RAWEV_LEN)
+	if (len != CM6533_JD_RAWEV_LEN || !(hid->claimed & HID_CLAIMED_INPUT))
 		goto out;
 	if (memcmp(data+CM6533_JD_SFX_OFFSET, ji_sfx, sizeof(ji_sfx)))
 		goto out;
diff --git a/drivers/hid/hid-creative-sb0540.c b/drivers/hid/hid-creative-sb0540.c
index b4c8e7a5d3e02..dfd6add353d19 100644
--- a/drivers/hid/hid-creative-sb0540.c
+++ b/drivers/hid/hid-creative-sb0540.c
@@ -153,7 +153,7 @@ static int creative_sb0540_raw_event(struct hid_device *hid,
 	u64 code, main_code;
 	int key;
 
-	if (len != 6)
+	if (len != 6 || !(hid->claimed & HID_CLAIMED_INPUT))
 		return 0;
 
 	/* From daemons/hw_hiddev.c sb0540_rec() in lirc */
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index 3bdb26f455925..1aae80f848f50 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -114,7 +114,7 @@ static int zc_raw_event(struct hid_device *hdev, struct hid_report *report,
 	unsigned key;
 	unsigned short index;
 
-	if (report->id == data[0]) {
+	if (report->id == data[0] && (hdev->claimed & HID_CLAIMED_INPUT)) {
 
 		/* break keys */
 		for (index = 0; index < 4; index++) {
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH v7 1/3] input: trackpoint - Enable doubletap by default on capable devices
From: Vishnu Sankar @ 2026-03-10 11:54 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: Mark Pearson, dmitry.torokhov, hmh, Hans de Goede, corbet,
	derekjohn.clark, linux-input, LKML, ibm-acpi-devel, linux-doc,
	platform-driver-x86, vsankar
In-Reply-To: <8216aaaf-bdaa-2a48-a7de-b0b81d49eda5@linux.intel.com>

Hi Ilpo,

Thanks again.

On Tue, Mar 10, 2026 at 6:30 PM Ilpo Järvinen
<ilpo.jarvinen@linux.intel.com> wrote:
>
> On Tue, 10 Mar 2026, Vishnu Sankar wrote:
>
> > Hi Ilpo,
> >
> > Thank you.
> >
> > On Tue, Mar 10, 2026 at 6:15 PM Ilpo Järvinen
> > <ilpo.jarvinen@linux.intel.com> wrote:
> > >
> > > On Tue, 10 Mar 2026, Vishnu Sankar wrote:
> > >
> > > > Hi Ilpo,
> > > >
> > > > Thank you so much for the review.
> > > >
> > > > On Mon, Mar 9, 2026 at 5:01 PM Ilpo Järvinen
> > > > <ilpo.jarvinen@linux.intel.com> wrote:
> > > > >
> > > > > On Mon, 9 Feb 2026, Vishnu Sankar wrote:
> > > > >
> > > > > > Enable doubletap functionality by default on TrackPoint devices that
> > > > > > support it. The feature is detected using firmware ID pattern matching
> > > > > > (PNP: LEN03xxx) with a deny list of incompatible devices.
> > > > > >
> > > > > > This provides immediate doubletap functionality without requiring
> > > > > > userspace configuration. The hardware is enabled during device
> > > > > > detection, while event filtering continues to be handled by the
> > > > > > thinkpad_acpi driver as before.
> > > > > >
> > > > > > Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
> > > > > > Suggested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> > > > > > Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > > > > > ---
> > > > > > Changes in v7:
> > > > > > - Removed unwanted comments
> > > > > > - Removed psmouse_info ()
> > > > > >
> > > > > > Changes in v6:
> > > > > > - No Changes
> > > > > >
> > > > > > Changes in v5:
> > > > > > - Renamed function to trackpoint_is_dt_capable()
> > > > > > - Simplified string comparison without sscanf()
> > > > > > - Removed wrapper function as suggested
> > > > > > - Fixed missing period in comment
> > > > > >
> > > > > > Changes in v4:
> > > > > > - Simplified approach: removed all sysfs attributes and user interface
> > > > > > - Enable doubletap by default during device detection
> > > > > > - Removed global variables and complex attribute infrastructure
> > > > > > - Uses minimal firmware ID detection with deny list
> > > > > > - Follows KISS principle as suggested by reviewers
> > > > > >
> > > > > > Changes in v3:
> > > > > > - No changes
> > > > > >
> > > > > > Changes in v2:
> > > > > > - Improve commit messages
> > > > > > - Sysfs attributes moved to trackpoint.c
> > > > > > - Removed unnecessary comments
> > > > > > - Removed unnecessary debug messages
> > > > > > - Using strstarts() instead of strcmp()
> > > > > > - is_trackpoint_dt_capable() modified
> > > > > > - Removed _BIT suffix and used BIT() define
> > > > > > - Reverse the trackpoint_doubletap_status() logic to return error first
> > > > > > - Removed export functions as a result of the design change
> > > > > > - Changed trackpoint_dev->psmouse to parent_psmouse
> > > > > > - The path of trackpoint.h is not changed
> > > > > > ---
> > > > > >  drivers/input/mouse/trackpoint.c | 45 ++++++++++++++++++++++++++++++++
> > > > > >  drivers/input/mouse/trackpoint.h |  5 ++++
> > > > > >  2 files changed, 50 insertions(+)
> > > > > >
> > >
> > > > > > diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
> > > > > > index 5f6643b69a2c..e12d76350252 100644
> > > > > > --- a/drivers/input/mouse/trackpoint.c
> > > > > > +++ b/drivers/input/mouse/trackpoint.c
> > >
> > > > > > +     /* Must start with "PNP: LEN03" */
> > > > > > +     if (!strstarts(pnp_id, "PNP: LEN03"))
> > > > >
> > > > > Missing include.
> > > >
> > > > Sorry, I am a bit confused here:
> > > > strstarts() is already available through the existing
> > > > #include <linux/string.h> in thinkpad_acpi.c.
> > > >
> > > > Do you think I should do anything else here?
> > >
> > > Yes.
> > >
> > > The file you're modifying in this patch is trackpoint.c which doesn't
> > > have that include so please add it also there. :-)
> > Aaah, Sorry!!. Got it.
> > I’ll add the missing #include <linux/string.h>
> > Thank you for pointing it out.
>
> Thanks. Please also double check you added inux/array_size.h into the
> correct file in case you were confused what file this patch modifies.
Thanks, and yes — I got mixed up earlier and checked the includes in
the wrong file, which led to my confusion.
Sorry about that.
>
> --
>  i.



-- 

Regards,

      Vishnu Sankar

^ permalink raw reply

* [PATCH 03/61] ceph: Prefer IS_ERR_OR_NULL over manual NULL check
From: Philipp Hahn @ 2026-03-10 11:48 UTC (permalink / raw)
  To: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
	gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
	linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
	linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
	linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
	linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
	linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
	linux-sctp, linux-security-module, linux-sh, linux-sound,
	linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
	netdev, ntfs3, samba-technical, sched-ext, target-devel,
	tipc-discussion, v9fs, Philipp Hahn
  Cc: Ilya Dryomov, Alex Markuze, Viacheslav Dubeyko
In-Reply-To: <20260310-b4-is_err_or_null-v1-0-bd63b656022d@avm.de>

Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
check.

Change generated with coccinelle.

To: Ilya Dryomov <idryomov@gmail.com>
To: Alex Markuze <amarkuze@redhat.com>
To: Viacheslav Dubeyko <slava@dubeyko.com>
Cc: ceph-devel@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
---
 fs/ceph/dir.c  | 2 +-
 fs/ceph/snap.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 86d7aa594ea99335af3e91a95c0a418fdc1b8a8a..934250748ae4fd4c148fd27bdf91175047c2877d 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -889,7 +889,7 @@ int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry)
 {
 	struct dentry *result = ceph_lookup(dir, dentry, 0);
 
-	if (result && !IS_ERR(result)) {
+	if (!IS_ERR_OR_NULL(result)) {
 		/*
 		 * We created the item, then did a lookup, and found
 		 * it was already linked to another inode we already
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index 52b4c2684f922bfed39550311e793bfe3622cd26..528ad581be160713f91416115659e2dc6f259576 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -902,7 +902,7 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc,
 bad:
 	err = -EIO;
 fail:
-	if (realm && !IS_ERR(realm))
+	if (!IS_ERR_OR_NULL(realm))
 		ceph_put_snap_realm(mdsc, realm);
 	if (first_realm)
 		ceph_put_snap_realm(mdsc, first_realm);

-- 
2.43.0


^ permalink raw reply related

* [PATCH 13/61] squashfs: Prefer IS_ERR_OR_NULL over manual NULL check
From: Philipp Hahn @ 2026-03-10 11:48 UTC (permalink / raw)
  To: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
	gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
	linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
	linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
	linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
	linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
	linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
	linux-sctp, linux-security-module, linux-sh, linux-sound,
	linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
	netdev, ntfs3, samba-technical, sched-ext, target-devel,
	tipc-discussion, v9fs, Philipp Hahn
  Cc: Phillip Lougher
In-Reply-To: <20260310-b4-is_err_or_null-v1-0-bd63b656022d@avm.de>

Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
check.

Change generated with coccinelle.

To: Phillip Lougher <phillip@squashfs.org.uk>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
---
 fs/squashfs/cache.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
index 67abd4dff222235e75d8c2b10d5e9b811d6e38d8..8888cc02966e2e33210c872c733205d4c581ecc9 100644
--- a/fs/squashfs/cache.c
+++ b/fs/squashfs/cache.c
@@ -198,7 +198,7 @@ void squashfs_cache_delete(struct squashfs_cache *cache)
 {
 	int i, j;
 
-	if (IS_ERR(cache) || cache == NULL)
+	if (IS_ERR_OR_NULL(cache))
 		return;
 
 	for (i = 0; i < cache->entries; i++) {

-- 
2.43.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox