Thread (2 messages) flat view 2 messages, 2 authors, 5d ago

Re: [BUG] HID: i2c-hid: ELAN 04F3:30FD touchpad reset race causes -EREMOTEIO on HP Pavilion Gaming 15-ec1xxx

From: Lovekesh Solanki <hidden>
Date: 2026-09-07 20:50:38
Subsystem: hid core layer, the rest · Maintainers: Jiri Kosina, Benjamin Tissoires, Linus Torvalds

Possibly related (same subject, not in this thread)

On Sat, Sep 05, 2026 at 10:25:46AM +0200, Adam wrote:
One more finding, potentially significant: I found that holding/tapping
F9 at boot (HP's boot menu) repeatedly, or alternatively entering the
UEFI Firmware Settings from GRUB and immediately continuing boot, gives
the touchpad a reliable, working boot on my Ubuntu installation
(tested this handful of times, consistently works).
Hmm.. I guess the f9 trick just moves probe's luck, nothing more.

I wonder what would happen if we added a good amount of bounded
retries on -EREMOTEIO and -EIO errors on the two reads
[i2c_hid_fetch_hid_descriptor(), i2c_hid_parse()] retries are
missing. I suppose firmware still responds to reads but NACKs any
write during the 'unresponsive' window which lasts far longer than
current retries can cover.

Could you test a patch below with dyndbg enabled, on a mix of warm/cold
boots, see if it improves this situation, if some boots still fail,
include their probe timestamps.

Also, on windows, does it start working immediatly after boot on all boots?

diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 0ff07fdab442..b0e8e2cc24ff 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -241,6 +241,30 @@ static int i2c_hid_read_register(struct i2c_hid *ihid, __le16 reg,
 	return i2c_hid_xfer(ihid, ihid->cmdbuf, sizeof(__le16), buf, len);
 }
 
+#define I2C_HID_DESC_FETCH_TRIES 10
+
+static int i2c_hid_read_register_retry(struct i2c_hid *ihid, __le16 reg, void *buf, size_t len) {
+	int error;
+	int i;
+
+	for(i = 0; i < I2C_HID_DESC_FETCH_TRIES; i++){
+		if(i){
+			msleep(1000);
+
+			if(i2c_hid_probe_address(ihid) < 0)
+				continue;
+		}
+
+		error = i2c_hid_read_register(ihid, reg, buf, len);
+		if(!error || (error != -EREMOTEIO && error != -EIO))
+			break;
+
+		i2c_hid_dbg(ihid, "register read failed (%d), retrying\n", error);
+	}
+
+	return error;
+}
+
 static size_t i2c_hid_encode_command(u8 *buf, u8 opcode,
 				     int report_type, int report_id)
 {
@@ -790,9 +814,7 @@ static int i2c_hid_parse(struct hid_device *hid)
 
 		i2c_hid_dbg(ihid, "asking HID report descriptor\n");
 
-		ret = i2c_hid_read_register(ihid,
-					    ihid->hdesc.wReportDescRegister,
-					    rdesc, rsize);
+		ret = i2c_hid_read_register_retry(ihid, ihid->hdesc.wReportDescRegister, rdesc, rsize);
 		if (ret) {
 			dev_err(&client->dev, "reading report descriptor failed\n");
 			goto out;
@@ -909,10 +931,9 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
 			*i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
 	} else {
 		i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
-		error = i2c_hid_read_register(ihid,
-					      ihid->wHIDDescRegister,
-					      &ihid->hdesc,
-					      sizeof(ihid->hdesc));
+
+		error = i2c_hid_read_register_retry(ihid, ihid->wHIDDescRegister, &ihid->hdesc, sizeof(ihid->hdesc));
+
 		if (error) {
 			dev_err(&ihid->client->dev,
 				"failed to fetch HID descriptor: %d\n",
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help