* [PATCH v2 0/6] HID: hid-lenovo-go: fix controller configuration
@ 2026-08-30 14:56 Aditya Dash
2026-08-30 14:56 ` [PATCH v2 1/6] HID: hid-lenovo-go: use the correct calibration commands Aditya Dash
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Aditya Dash @ 2026-08-30 14:56 UTC (permalink / raw)
To: Benjamin Tissoires, Derek J. Clark, Jiri Kosina, Mark Pearson
Cc: linux-input, linux-kernel
This series fixes several issues in the controller configuration and
calibration paths in hid-lenovo-go.
1/6 fixes the calibration attributes, where the command and sub-command
are swapped. 2/6 fixes two right-controller attributes: imu_enabled
selects the bypass feature, and reset targets the left controller.
Before 3/6, any decoded configuration reply completes the shared
completion. The driver then ignores the result of the wait, so an
unrelated reply, a firmware error, an interrupted wait, or a timeout can
still be reported as success.
3/6 tracks one pending request in the driver data and matches replies by
command ID, command, sub-command, and device. It also returns request
errors to the caller.
The firmware has no sequence number, so a late reply with the same tuple
can still match a newer request.
The remaining patches fix calibration status handling.
The calibration status table defines 0x00 as unknown, 0x01 as success,
and 0x02 as failure. A Legion Go 1 returned 0x08 after a Stop was sent
while no calibration was active. The driver stores the raw value as a
status-text index, so a later read returns -EINVAL.
4/6 preserves the defined values and maps larger status values to
failure.
5/6 rejects 'unknown' as an action. The action table contains it at index
zero, but the options attribute advertises only 'start' and 'stop'.
A previous result can also hide a new calibration attempt:
failure -> start -> failure
The status appears unchanged for the whole operation. 6/6 clears the
selected status to unknown before submitting a Start. Stop leaves the
status unchanged.
---
Changes in v2:
- Drop the FPS DPI patch; the existing request is correct.
- Drop the v1 Boolean calibration-result mapping. Preserve values 0x00
through 0x02 and map only larger failure values.
- Move the existing pending command state into the driver data and
initialize it in cfg_probe().
- Use scoped IRQ-save guards and validate the report size and ID together.
- Drop the v1 no-wait calibration path. Correct requests receive their
matching SET replies within the existing 50 ms timeout.
- Reject 'unknown' and clear only the selected status on Start.
v1: https://lore.kernel.org/all/20260821214810.87826-1-mradityadash@gmail.com/
Aditya Dash (6):
HID: hid-lenovo-go: use the correct calibration commands
HID: hid-lenovo-go: use the right controller selectors
HID: hid-lenovo-go: return configuration request errors
HID: hid-lenovo-go: normalize calibration failure status
HID: hid-lenovo-go: reject unknown calibration action
HID: hid-lenovo-go: clear calibration status on start
drivers/hid/hid-lenovo-go.c | 179 +++++++++++++++++++++++++++---------
1 file changed, 136 insertions(+), 43 deletions(-)
base-commit: 1292bca0f8d835d2ad96d309595b2e97f3106d3d
--
2.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/6] HID: hid-lenovo-go: use the correct calibration commands
2026-08-30 14:56 [PATCH v2 0/6] HID: hid-lenovo-go: fix controller configuration Aditya Dash
@ 2026-08-30 14:56 ` Aditya Dash
2026-08-30 14:56 ` [PATCH v2 2/6] HID: hid-lenovo-go: use the right controller selectors Aditya Dash
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Aditya Dash @ 2026-08-30 14:56 UTC (permalink / raw)
To: Benjamin Tissoires, Derek J. Clark, Jiri Kosina, Mark Pearson
Cc: linux-input, linux-kernel
The calibration attributes pass the calibration operation as the command
and the configuration command as the sub-command. This sends each request
with the two fields reversed.
Swap the command and sub-command values for all six calibration attributes.
For example, the malformed left joystick Start request is:
05 00 04 0c 03 01 ...
The corrected request is:
05 00 0c 04 03 01 ...
The bytes identify the output report, configuration group, command,
sub-command, left controller, and Start action, in that order.
Fixes: 995887a10da1 ("HID: hid-lenovo-go: Add Calibration Settings")
Assisted-by: Pi:gpt-5.6-sol
Signed-off-by: Aditya Dash <mradityadash@gmail.com>
Reviewed-by: Derek J. Clark <derekjohn.clark@gmail.com>
Tested-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
drivers/hid/hid-lenovo-go.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c
index 318b1152ff8b..b8248bf8965c 100644
--- a/drivers/hid/hid-lenovo-go.c
+++ b/drivers/hid/hid-lenovo-go.c
@@ -1911,18 +1911,18 @@ LEGO_DEVICE_ATTR_RW(rumble_notification_left, "rumble_notification",
static DEVICE_ATTR_RO_NAMED(rumble_notification_left_index,
"rumble_notification_index");
-static struct go_cfg_attr cal_trigg_left = { TRIGGER_CALIBRATE };
-LEGO_CAL_DEVICE_ATTR(cal_trigg_left, "calibrate_trigger", SET_TRIGGER_CFG,
+static struct go_cfg_attr cal_trigg_left = { SET_TRIGGER_CFG };
+LEGO_CAL_DEVICE_ATTR(cal_trigg_left, "calibrate_trigger", TRIGGER_CALIBRATE,
LEFT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_trigg_left_index, "calibrate_trigger_index");
-static struct go_cfg_attr cal_joy_left = { JOYSTICK_CALIBRATE };
-LEGO_CAL_DEVICE_ATTR(cal_joy_left, "calibrate_joystick", SET_JOYSTICK_CFG,
+static struct go_cfg_attr cal_joy_left = { SET_JOYSTICK_CFG };
+LEGO_CAL_DEVICE_ATTR(cal_joy_left, "calibrate_joystick", JOYSTICK_CALIBRATE,
LEFT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_joy_left_index, "calibrate_joystick_index");
-static struct go_cfg_attr cal_gyro_left = { GYRO_CALIBRATE };
-LEGO_CAL_DEVICE_ATTR(cal_gyro_left, "calibrate_gyro", SET_GYRO_CFG,
+static struct go_cfg_attr cal_gyro_left = { SET_GYRO_CFG };
+LEGO_CAL_DEVICE_ATTR(cal_gyro_left, "calibrate_gyro", GYRO_CALIBRATE,
LEFT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_gyro_left_index, "calibrate_gyro_index");
@@ -2018,18 +2018,18 @@ LEGO_DEVICE_ATTR_RW(rumble_notification_right, "rumble_notification",
static DEVICE_ATTR_RO_NAMED(rumble_notification_right_index,
"rumble_notification_index");
-static struct go_cfg_attr cal_trigg_right = { TRIGGER_CALIBRATE };
-LEGO_CAL_DEVICE_ATTR(cal_trigg_right, "calibrate_trigger", SET_TRIGGER_CFG,
+static struct go_cfg_attr cal_trigg_right = { SET_TRIGGER_CFG };
+LEGO_CAL_DEVICE_ATTR(cal_trigg_right, "calibrate_trigger", TRIGGER_CALIBRATE,
RIGHT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_trigg_right_index, "calibrate_trigger_index");
-static struct go_cfg_attr cal_joy_right = { JOYSTICK_CALIBRATE };
-LEGO_CAL_DEVICE_ATTR(cal_joy_right, "calibrate_joystick", SET_JOYSTICK_CFG,
+static struct go_cfg_attr cal_joy_right = { SET_JOYSTICK_CFG };
+LEGO_CAL_DEVICE_ATTR(cal_joy_right, "calibrate_joystick", JOYSTICK_CALIBRATE,
RIGHT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_joy_right_index, "calibrate_joystick_index");
-static struct go_cfg_attr cal_gyro_right = { GYRO_CALIBRATE };
-LEGO_CAL_DEVICE_ATTR(cal_gyro_right, "calibrate_gyro", SET_GYRO_CFG,
+static struct go_cfg_attr cal_gyro_right = { SET_GYRO_CFG };
+LEGO_CAL_DEVICE_ATTR(cal_gyro_right, "calibrate_gyro", GYRO_CALIBRATE,
RIGHT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_gyro_right_index, "calibrate_gyro_index");
--
2.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/6] HID: hid-lenovo-go: use the right controller selectors
2026-08-30 14:56 [PATCH v2 0/6] HID: hid-lenovo-go: fix controller configuration Aditya Dash
2026-08-30 14:56 ` [PATCH v2 1/6] HID: hid-lenovo-go: use the correct calibration commands Aditya Dash
@ 2026-08-30 14:56 ` Aditya Dash
2026-08-30 14:56 ` [PATCH v2 3/6] HID: hid-lenovo-go: return configuration request errors Aditya Dash
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Aditya Dash @ 2026-08-30 14:56 UTC (permalink / raw)
To: Benjamin Tissoires, Derek J. Clark, Jiri Kosina, Mark Pearson
Cc: linux-input, linux-kernel
The right imu_enabled attribute selects FEATURE_IMU_BYPASS, and the right
reset attribute targets the left controller.
Select FEATURE_IMU_ENABLE for the right imu_enabled attribute. Target the
right controller for a right reset.
Fixes: 82cd9bc866e1 ("HID: hid-lenovo-go: Add Feature Status Attributes")
Assisted-by: Pi:gpt-5.6-sol
Signed-off-by: Aditya Dash <mradityadash@gmail.com>
Reviewed-by: Derek J. Clark <derekjohn.clark@gmail.com>
Tested-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
drivers/hid/hid-lenovo-go.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c
index b8248bf8965c..b937d11dd6f6 100644
--- a/drivers/hid/hid-lenovo-go.c
+++ b/drivers/hid/hid-lenovo-go.c
@@ -1999,13 +1999,13 @@ LEGO_DEVICE_ATTR_RW(imu_bypass_right, "imu_bypass_enabled", RIGHT_CONTROLLER,
index, feature_status);
static DEVICE_ATTR_RO_NAMED(imu_bypass_right_index, "imu_bypass_enabled_index");
-static struct go_cfg_attr imu_enabled_right = { FEATURE_IMU_BYPASS };
+static struct go_cfg_attr imu_enabled_right = { FEATURE_IMU_ENABLE };
LEGO_DEVICE_ATTR_RW(imu_enabled_right, "imu_enabled", RIGHT_CONTROLLER, index,
feature_status);
static DEVICE_ATTR_RO_NAMED(imu_enabled_right_index, "imu_enabled_index");
static struct go_cfg_attr reset_right = { FEATURE_RESET_GAMEPAD };
-LEGO_DEVICE_ATTR_WO(reset_right, "reset", LEFT_CONTROLLER, feature_status);
+LEGO_DEVICE_ATTR_WO(reset_right, "reset", RIGHT_CONTROLLER, feature_status);
static struct go_cfg_attr rumble_mode_right = { RUMBLE_MODE };
LEGO_DEVICE_ATTR_RW(rumble_mode_right, "rumble_mode", RIGHT_CONTROLLER, index,
--
2.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 3/6] HID: hid-lenovo-go: return configuration request errors
2026-08-30 14:56 [PATCH v2 0/6] HID: hid-lenovo-go: fix controller configuration Aditya Dash
2026-08-30 14:56 ` [PATCH v2 1/6] HID: hid-lenovo-go: use the correct calibration commands Aditya Dash
2026-08-30 14:56 ` [PATCH v2 2/6] HID: hid-lenovo-go: use the right controller selectors Aditya Dash
@ 2026-08-30 14:56 ` Aditya Dash
2026-08-30 14:56 ` [PATCH v2 4/6] HID: hid-lenovo-go: normalize calibration failure status Aditya Dash
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Aditya Dash @ 2026-08-30 14:56 UTC (permalink / raw)
To: Benjamin Tissoires, Derek J. Clark, Jiri Kosina, Mark Pearson
Cc: linux-input, linux-kernel
Any decoded configuration reply completes the shared completion. The driver
also ignores the result of its interruptible wait. An unrelated reply, a
firmware error, an interrupted wait, or a timeout can therefore be reported
as success.
Add pending command state to the driver data. Match replies by command ID,
command, sub-command, and device, and return request errors to the caller.
Clear the pending request after an interruption or timeout so a late reply
cannot replace that result.
Keep the existing 50 ms wait for every configuration request. Corrected
calibration requests on an Original Legion Go received their matching SET
replies within 8 ms. The final calibration result remains asynchronous.
The firmware has no sequence number. A late reply with the same tuple can
still match a newer request.
Fixes: d69ccfcbc955 ("HID: hid-lenovo-go: Add Lenovo Legion Go Series HID Driver")
Assisted-by: Pi:gpt-5.6-sol
Signed-off-by: Aditya Dash <mradityadash@gmail.com>
---
drivers/hid/hid-lenovo-go.c | 107 +++++++++++++++++++++++++++++-------
1 file changed, 86 insertions(+), 21 deletions(-)
diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c
index b937d11dd6f6..dbfacbb70394 100644
--- a/drivers/hid/hid-lenovo-go.c
+++ b/drivers/hid/hid-lenovo-go.c
@@ -21,6 +21,7 @@
#include <linux/led-class-multicolor.h>
#include <linux/mutex.h>
#include <linux/printk.h>
+#include <linux/spinlock.h>
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/unaligned.h>
@@ -31,13 +32,27 @@
#include "hid-ids.h"
#define GO_GP_INTF_IN 0x83
+#define GO_INPUT_REPORT_ID 0x04
#define GO_OUTPUT_REPORT_ID 0x05
#define GO_GP_RESET_SUCCESS 0x01
#define GO_PACKET_SIZE 64
+#define GO_COMMAND_TIMEOUT_MS 50
+
+/* Lenovo replies identify a command and a sub-command, but have no sequence. */
+struct hid_go_cmd {
+ struct completion done;
+ spinlock_t lock; /* protects fields below */
+ bool pending;
+ u8 id;
+ u8 command;
+ u8 sub_command;
+ u8 device;
+ int result;
+};
static struct hid_go_cfg {
struct delayed_work go_cfg_setup;
- struct completion send_cmd_complete;
+ struct hid_go_cmd cmd;
struct led_classdev *led_cdev;
struct hid_device *hdev;
struct mutex cfg_mutex; /*ensure single synchronous output report*/
@@ -331,6 +346,62 @@ static const char *const os_mode_text[] = {
[LINUX] = "linux",
};
+static void hid_go_cmd_arm(u8 id, u8 command, u8 sub_command, u8 device)
+{
+ guard(spinlock_irqsave)(&drvdata.cmd.lock);
+
+ reinit_completion(&drvdata.cmd.done);
+ drvdata.cmd.pending = true;
+ drvdata.cmd.id = id;
+ drvdata.cmd.command = command;
+ drvdata.cmd.sub_command = sub_command;
+ drvdata.cmd.device = device;
+}
+
+static void hid_go_cmd_consume(const struct command_report *cmd_rep, int result)
+{
+ guard(spinlock_irqsave)(&drvdata.cmd.lock);
+
+ if (drvdata.cmd.pending && cmd_rep->id == drvdata.cmd.id &&
+ cmd_rep->cmd == drvdata.cmd.command &&
+ cmd_rep->sub_cmd == drvdata.cmd.sub_command &&
+ cmd_rep->device_type == drvdata.cmd.device) {
+ drvdata.cmd.pending = false;
+ drvdata.cmd.result = result;
+ complete(&drvdata.cmd.done);
+ }
+}
+
+static int hid_go_cmd_finish(long wait_result)
+{
+ guard(spinlock_irqsave)(&drvdata.cmd.lock);
+
+ if (wait_result <= 0) {
+ drvdata.cmd.pending = false;
+ return wait_result < 0 ? wait_result : -ETIMEDOUT;
+ }
+
+ return drvdata.cmd.result;
+}
+
+static int hid_go_cmd_cancel(int result)
+{
+ guard(spinlock_irqsave)(&drvdata.cmd.lock);
+
+ drvdata.cmd.pending = false;
+ return result;
+}
+
+static int hid_go_send_output_report(struct hid_device *hdev, u8 *packet)
+{
+ int ret;
+
+ ret = hid_hw_output_report(hdev, packet, GO_PACKET_SIZE);
+ if (ret < 0)
+ return ret;
+ return ret == GO_PACKET_SIZE ? 0 : -EINVAL;
+}
+
static int hid_go_version_event(struct command_report *cmd_rep)
{
switch (cmd_rep->sub_cmd) {
@@ -654,7 +725,7 @@ static int hid_go_raw_event(struct hid_device *hdev, struct hid_report *report,
struct command_report *cmd_rep;
int ep, ret;
- if (size != GO_PACKET_SIZE)
+ if (size != GO_PACKET_SIZE || data[0] != GO_INPUT_REPORT_ID)
goto passthrough;
ep = get_endpoint_address(hdev);
@@ -707,7 +778,7 @@ static int hid_go_raw_event(struct hid_device *hdev, struct hid_report *report,
dev_dbg(&hdev->dev, "Rx data as raw input report: [%*ph]\n",
GO_PACKET_SIZE, data);
- complete(&drvdata.send_cmd_complete);
+ hid_go_cmd_consume(cmd_rep, ret);
return ret;
passthrough:
@@ -722,7 +793,8 @@ static int mcu_property_out(struct hid_device *hdev, u8 id, u8 command,
unsigned char *dmabuf __free(kfree) = NULL;
u8 header[] = { GO_OUTPUT_REPORT_ID, id, command, index, device };
size_t header_size = ARRAY_SIZE(header);
- int timeout = 50;
+ unsigned long timeout = msecs_to_jiffies(GO_COMMAND_TIMEOUT_MS);
+ long wait_result;
int ret;
if (header_size + len > GO_PACKET_SIZE)
@@ -740,22 +812,14 @@ static int mcu_property_out(struct hid_device *hdev, u8 id, u8 command,
dev_dbg(&hdev->dev, "Send data as raw output report: [%*ph]\n",
GO_PACKET_SIZE, dmabuf);
- ret = hid_hw_output_report(hdev, dmabuf, GO_PACKET_SIZE);
- if (ret < 0)
- return ret;
-
- ret = ret == GO_PACKET_SIZE ? 0 : -EINVAL;
+ hid_go_cmd_arm(id, command, index, device);
+ ret = hid_go_send_output_report(hdev, dmabuf);
if (ret)
- return ret;
-
- ret = wait_for_completion_interruptible_timeout(&drvdata.send_cmd_complete,
- msecs_to_jiffies(timeout));
-
- if (ret == 0) /* timeout occurred */
- ret = -EBUSY;
+ return hid_go_cmd_cancel(ret);
- reinit_completion(&drvdata.send_cmd_complete);
- return 0;
+ wait_result = wait_for_completion_interruptible_timeout(&drvdata.cmd.done,
+ timeout);
+ return hid_go_cmd_finish(wait_result);
}
static ssize_t version_show(struct device *dev, struct device_attribute *attr,
@@ -2362,9 +2426,12 @@ static int hid_go_cfg_probe(struct hid_device *hdev,
if (!buf)
return -ENOMEM;
+ mutex_init(&drvdata.cfg_mutex);
+ init_completion(&drvdata.cmd.done);
+ spin_lock_init(&drvdata.cmd.lock);
+ drvdata.cmd.pending = false;
hid_set_drvdata(hdev, &drvdata);
drvdata.hdev = hdev;
- mutex_init(&drvdata.cfg_mutex);
ret = sysfs_create_groups(&hdev->dev.kobj, top_level_attr_groups);
if (ret) {
@@ -2388,8 +2455,6 @@ static int hid_go_cfg_probe(struct hid_device *hdev,
drvdata.led_cdev = &go_cdev_rgb.led_cdev;
- init_completion(&drvdata.send_cmd_complete);
-
/* Executing calls prior to returning from probe will lock the MCU. Schedule
* initial data call after probe has completed and MCU can accept calls.
*/
--
2.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 4/6] HID: hid-lenovo-go: normalize calibration failure status
2026-08-30 14:56 [PATCH v2 0/6] HID: hid-lenovo-go: fix controller configuration Aditya Dash
` (2 preceding siblings ...)
2026-08-30 14:56 ` [PATCH v2 3/6] HID: hid-lenovo-go: return configuration request errors Aditya Dash
@ 2026-08-30 14:56 ` Aditya Dash
2026-08-30 14:56 ` [PATCH v2 5/6] HID: hid-lenovo-go: reject unknown calibration action Aditya Dash
2026-08-30 14:56 ` [PATCH v2 6/6] HID: hid-lenovo-go: clear calibration status on start Aditya Dash
5 siblings, 0 replies; 7+ messages in thread
From: Aditya Dash @ 2026-08-30 14:56 UTC (permalink / raw)
To: Benjamin Tissoires, Derek J. Clark, Jiri Kosina, Mark Pearson
Cc: linux-input, linux-kernel
The driver stores the firmware result byte as an index into the
calibration status text. A Legion Go 1 returned 0x08 after an idle Stop.
The status table has only three entries, so a later read returns -EINVAL.
Keep the defined values 0x00 through 0x02. Treat larger result values as
failure before storing them.
Fixes: 995887a10da1 ("HID: hid-lenovo-go: Add Calibration Settings")
Assisted-by: Pi:gpt-5.6-sol
Signed-off-by: Aditya Dash <mradityadash@gmail.com>
---
drivers/hid/hid-lenovo-go.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c
index dbfacbb70394..c7a2e621a4ad 100644
--- a/drivers/hid/hid-lenovo-go.c
+++ b/drivers/hid/hid-lenovo-go.c
@@ -648,17 +648,22 @@ static int hid_go_light_event(struct command_report *cmd_rep)
static int hid_go_device_status_event(struct command_report *cmd_rep)
{
+ u8 status = cmd_rep->data[1];
+
+ if (status > CAL_STAT_FAILURE)
+ status = CAL_STAT_FAILURE;
+
switch (cmd_rep->device_type) {
case LEFT_CONTROLLER:
switch (cmd_rep->data[0]) {
case CALDEV_GYROSCOPE:
- drvdata.gp_left_gyro_cal_status = cmd_rep->data[1];
+ drvdata.gp_left_gyro_cal_status = status;
return 0;
case CALDEV_JOYSTICK:
- drvdata.gp_left_joy_cal_status = cmd_rep->data[1];
+ drvdata.gp_left_joy_cal_status = status;
return 0;
case CALDEV_TRIGGER:
- drvdata.gp_left_trigg_cal_status = cmd_rep->data[1];
+ drvdata.gp_left_trigg_cal_status = status;
return 0;
default:
return -EINVAL;
@@ -667,13 +672,13 @@ static int hid_go_device_status_event(struct command_report *cmd_rep)
case RIGHT_CONTROLLER:
switch (cmd_rep->data[0]) {
case CALDEV_GYROSCOPE:
- drvdata.gp_right_gyro_cal_status = cmd_rep->data[1];
+ drvdata.gp_right_gyro_cal_status = status;
return 0;
case CALDEV_JOYSTICK:
- drvdata.gp_right_joy_cal_status = cmd_rep->data[1];
+ drvdata.gp_right_joy_cal_status = status;
return 0;
case CALDEV_TRIGGER:
- drvdata.gp_right_trigg_cal_status = cmd_rep->data[1];
+ drvdata.gp_right_trigg_cal_status = status;
return 0;
default:
return -EINVAL;
--
2.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 5/6] HID: hid-lenovo-go: reject unknown calibration action
2026-08-30 14:56 [PATCH v2 0/6] HID: hid-lenovo-go: fix controller configuration Aditya Dash
` (3 preceding siblings ...)
2026-08-30 14:56 ` [PATCH v2 4/6] HID: hid-lenovo-go: normalize calibration failure status Aditya Dash
@ 2026-08-30 14:56 ` Aditya Dash
2026-08-30 14:56 ` [PATCH v2 6/6] HID: hid-lenovo-go: clear calibration status on start Aditya Dash
5 siblings, 0 replies; 7+ messages in thread
From: Aditya Dash @ 2026-08-30 14:56 UTC (permalink / raw)
To: Benjamin Tissoires, Derek J. Clark, Jiri Kosina, Mark Pearson
Cc: linux-input, linux-kernel
The calibration action table includes 'unknown' at index zero. The options
attribute skips that entry and lists only 'start' and 'stop', but the
store searches the full table. Writing 'unknown' therefore sends a request
without an action byte.
Reject CAL_UNKNOWN before building the request. Leave Start and Stop
unchanged.
Fixes: 995887a10da1 ("HID: hid-lenovo-go: Add Calibration Settings")
Assisted-by: Pi:gpt-5.6-sol
Signed-off-by: Aditya Dash <mradityadash@gmail.com>
---
drivers/hid/hid-lenovo-go.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c
index c7a2e621a4ad..a4231d188b7a 100644
--- a/drivers/hid/hid-lenovo-go.c
+++ b/drivers/hid/hid-lenovo-go.c
@@ -1419,6 +1419,8 @@ static ssize_t calibrate_config_store(struct device *dev,
ret = sysfs_match_string(cal_enabled_text, buf);
if (ret < 0)
return ret;
+ if (ret == CAL_UNKNOWN)
+ return -EINVAL;
val = ret;
if (!val)
--
2.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 6/6] HID: hid-lenovo-go: clear calibration status on start
2026-08-30 14:56 [PATCH v2 0/6] HID: hid-lenovo-go: fix controller configuration Aditya Dash
` (4 preceding siblings ...)
2026-08-30 14:56 ` [PATCH v2 5/6] HID: hid-lenovo-go: reject unknown calibration action Aditya Dash
@ 2026-08-30 14:56 ` Aditya Dash
5 siblings, 0 replies; 7+ messages in thread
From: Aditya Dash @ 2026-08-30 14:56 UTC (permalink / raw)
To: Benjamin Tissoires, Derek J. Clark, Jiri Kosina, Mark Pearson
Cc: linux-input, linux-kernel
A completed calibration leaves success or failure in its status file. If
the next calibration has the same result, userspace sees no change and
cannot tell when the new attempt starts or finishes.
Link each calibration action attribute to its status field. Set only that
field to unknown before submitting Start. Stop leaves the status unchanged,
and the next firmware result replaces unknown with success or failure.
Fixes: 995887a10da1 ("HID: hid-lenovo-go: Add Calibration Settings")
Assisted-by: Pi:gpt-5.6-sol
Signed-off-by: Aditya Dash <mradityadash@gmail.com>
---
drivers/hid/hid-lenovo-go.c | 37 +++++++++++++++++++++++++++++--------
1 file changed, 29 insertions(+), 8 deletions(-)
diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c
index a4231d188b7a..2ed367abd4cc 100644
--- a/drivers/hid/hid-lenovo-go.c
+++ b/drivers/hid/hid-lenovo-go.c
@@ -111,6 +111,11 @@ struct go_cfg_attr {
u8 index;
};
+struct go_cal_cfg_attr {
+ u8 index;
+ u8 *status;
+};
+
struct command_report {
u8 report_id;
u8 id;
@@ -1410,7 +1415,8 @@ static ssize_t device_status_show(struct device *dev,
static ssize_t calibrate_config_store(struct device *dev,
struct device_attribute *attr,
const char *buf, u8 cmd, u8 sub_cmd,
- size_t count, enum dev_type device_type)
+ size_t count, enum dev_type device_type,
+ u8 *cal_status)
{
size_t size = 1;
u8 val = 0;
@@ -1425,6 +1431,8 @@ static ssize_t calibrate_config_store(struct device *dev,
val = ret;
if (!val)
size = 0;
+ if (val == CAL_START)
+ *cal_status = CAL_STAT_UNKNOWN;
ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, cmd, sub_cmd,
device_type, &val, size);
@@ -1822,7 +1830,8 @@ static void hid_go_brightness_set(struct led_classdev *led_cdev,
const char *buf, size_t count) \
{ \
return calibrate_config_store(dev, attr, buf, _name.index, \
- _scmd, count, _dtype); \
+ _scmd, count, _dtype, \
+ _name.status); \
} \
static ssize_t _name##_##_rtype##_show( \
struct device *dev, struct device_attribute *attr, char *buf) \
@@ -1982,17 +1991,23 @@ LEGO_DEVICE_ATTR_RW(rumble_notification_left, "rumble_notification",
static DEVICE_ATTR_RO_NAMED(rumble_notification_left_index,
"rumble_notification_index");
-static struct go_cfg_attr cal_trigg_left = { SET_TRIGGER_CFG };
+static struct go_cal_cfg_attr cal_trigg_left = {
+ SET_TRIGGER_CFG, &drvdata.gp_left_trigg_cal_status
+};
LEGO_CAL_DEVICE_ATTR(cal_trigg_left, "calibrate_trigger", TRIGGER_CALIBRATE,
LEFT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_trigg_left_index, "calibrate_trigger_index");
-static struct go_cfg_attr cal_joy_left = { SET_JOYSTICK_CFG };
+static struct go_cal_cfg_attr cal_joy_left = {
+ SET_JOYSTICK_CFG, &drvdata.gp_left_joy_cal_status
+};
LEGO_CAL_DEVICE_ATTR(cal_joy_left, "calibrate_joystick", JOYSTICK_CALIBRATE,
LEFT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_joy_left_index, "calibrate_joystick_index");
-static struct go_cfg_attr cal_gyro_left = { SET_GYRO_CFG };
+static struct go_cal_cfg_attr cal_gyro_left = {
+ SET_GYRO_CFG, &drvdata.gp_left_gyro_cal_status
+};
LEGO_CAL_DEVICE_ATTR(cal_gyro_left, "calibrate_gyro", GYRO_CALIBRATE,
LEFT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_gyro_left_index, "calibrate_gyro_index");
@@ -2089,17 +2104,23 @@ LEGO_DEVICE_ATTR_RW(rumble_notification_right, "rumble_notification",
static DEVICE_ATTR_RO_NAMED(rumble_notification_right_index,
"rumble_notification_index");
-static struct go_cfg_attr cal_trigg_right = { SET_TRIGGER_CFG };
+static struct go_cal_cfg_attr cal_trigg_right = {
+ SET_TRIGGER_CFG, &drvdata.gp_right_trigg_cal_status
+};
LEGO_CAL_DEVICE_ATTR(cal_trigg_right, "calibrate_trigger", TRIGGER_CALIBRATE,
RIGHT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_trigg_right_index, "calibrate_trigger_index");
-static struct go_cfg_attr cal_joy_right = { SET_JOYSTICK_CFG };
+static struct go_cal_cfg_attr cal_joy_right = {
+ SET_JOYSTICK_CFG, &drvdata.gp_right_joy_cal_status
+};
LEGO_CAL_DEVICE_ATTR(cal_joy_right, "calibrate_joystick", JOYSTICK_CALIBRATE,
RIGHT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_joy_right_index, "calibrate_joystick_index");
-static struct go_cfg_attr cal_gyro_right = { SET_GYRO_CFG };
+static struct go_cal_cfg_attr cal_gyro_right = {
+ SET_GYRO_CFG, &drvdata.gp_right_gyro_cal_status
+};
LEGO_CAL_DEVICE_ATTR(cal_gyro_right, "calibrate_gyro", GYRO_CALIBRATE,
RIGHT_CONTROLLER, index);
static DEVICE_ATTR_RO_NAMED(cal_gyro_right_index, "calibrate_gyro_index");
--
2.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-30 14:57 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-30 14:56 [PATCH v2 0/6] HID: hid-lenovo-go: fix controller configuration Aditya Dash
2026-08-30 14:56 ` [PATCH v2 1/6] HID: hid-lenovo-go: use the correct calibration commands Aditya Dash
2026-08-30 14:56 ` [PATCH v2 2/6] HID: hid-lenovo-go: use the right controller selectors Aditya Dash
2026-08-30 14:56 ` [PATCH v2 3/6] HID: hid-lenovo-go: return configuration request errors Aditya Dash
2026-08-30 14:56 ` [PATCH v2 4/6] HID: hid-lenovo-go: normalize calibration failure status Aditya Dash
2026-08-30 14:56 ` [PATCH v2 5/6] HID: hid-lenovo-go: reject unknown calibration action Aditya Dash
2026-08-30 14:56 ` [PATCH v2 6/6] HID: hid-lenovo-go: clear calibration status on start Aditya Dash
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®