[PATCH v3 10/10] HID: steam: Retry send/recv reports if stale
From: Vicki Pfau <hidden>
Date: 2026-07-10 02:02:10
Subsystem:
hid core layer, the rest · Maintainers:
Jiri Kosina, Benjamin Tissoires, Linus Torvalds
Sometimes recv report will reply with a stale result from a previous send report. Instead of failing out, we should retry them, as they generally reply correctly after three tries, give or take. Signed-off-by: Vicki Pfau <redacted> --- drivers/hid/hid-steam.c | 54 +++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 13 deletions(-)
diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
index a80d54ed9784..3f5d4a88b864 100644
--- a/drivers/hid/hid-steam.c
+++ b/drivers/hid/hid-steam.c@@ -501,6 +501,43 @@ static int steam_write_settings(struct steam_device *steam, return steam_recv_report(steam, cmd, 2 + cmd[1]); } +static int steam_exchange_report(struct steam_device *steam, u8 *cmd, int csize, + u8 *reply, int rsize) +{ + unsigned int retries = 5; + int ret; + + guard(mutex)(&steam->report_mutex); + do { + ret = steam_send_report(steam, cmd, csize); + if (ret < 0) + return ret; + ret = steam_recv_report(steam, reply, rsize); + /* + * Sometimes this can fail on the first few tries on the Steam + * Controller (2015). It appears to be a firmware bug, and Steam + * itself just retries, so we should also retry a few times to + * see if we get it. + */ + if (ret == -EPROTO) + continue; + if (ret < 0) { + hid_err(steam->hdev, "%s: error reading reply (%*ph)\n", + __func__, csize, cmd); + return ret; + } + if (reply[0] == cmd[0] && reply[1] >= 1) + break; + if (retries > 0) + continue; + hid_err(steam->hdev, "%s: invalid reply (%*ph)\n", __func__, + rsize, reply); + return -EPROTO; + } while (retries--); + + return ret; +} + static int steam_get_serial(struct steam_device *steam) { /*
@@ -511,15 +548,10 @@ static int steam_get_serial(struct steam_device *steam) u8 cmd[] = {ID_GET_STRING_ATTRIBUTE, sizeof(steam->serial_no), ATTRIB_STR_UNIT_SERIAL}; u8 reply[3 + STEAM_SERIAL_LEN + 1]; - guard(mutex)(&steam->report_mutex); - ret = steam_send_report(steam, cmd, sizeof(cmd)); + ret = steam_exchange_report(steam, cmd, sizeof(cmd), reply, sizeof(reply)); if (ret < 0) return ret; - ret = steam_recv_report(steam, reply, sizeof(reply)); - if (ret < 0) - return ret; - if (reply[0] != ID_GET_STRING_ATTRIBUTE || reply[1] < 1 || - reply[1] > sizeof(steam->serial_no) || reply[2] != ATTRIB_STR_UNIT_SERIAL) { + if (reply[1] > sizeof(steam->serial_no) || reply[2] != ATTRIB_STR_UNIT_SERIAL) { hid_err(steam->hdev, "%s: invalid reply (%*ph)\n", __func__, (int)sizeof(reply), reply); return -EIO;
@@ -538,14 +570,10 @@ static int steam_get_attributes(struct steam_device *steam) int i; struct steam_controller_attribute *attr; - guard(mutex)(&steam->report_mutex); - ret = steam_send_report(steam, cmd, sizeof(cmd)); - if (ret < 0) - return ret; - ret = steam_recv_report(steam, reply, sizeof(reply)); + ret = steam_exchange_report(steam, cmd, sizeof(cmd), reply, sizeof(reply)); if (ret < 0) return ret; - if (reply[0] != ID_GET_ATTRIBUTES_VALUES || reply[1] < 2) { + if (reply[1] < 2) { hid_err(steam->hdev, "%s: invalid reply (%*ph)\n", __func__, (int)sizeof(reply), reply); return -EIO;
--
2.54.0