Thanks for the patch - tested it (kernel 7.2.4, patch applied cleanly
after manually reconciling two small context mismatches against my
tree - the descriptor/report reads now go through
i2c_hid_read_register_retry as intended).
I ran 6 boots with dyndbg enabled (3 warm/reboot, 3 cold/shutdown+
wait+power-on), collecting `dmesg | grep -iE "elan|i2c_hid"` after
each. Full logs attached (boot-logs-devpatch.txt, each boot labeled
warm/cold).
Summary: in all 6 boots, the pattern is the same - probe succeeds
quickly (HID descriptor fetch + registration within ~1-11s), but then
every subsequent get/set report call fails with -121 for the next
~10-30s, and none of these 6 logs showed a later recovery within the
capture window (I stopped capturing 15-30s after the last -121 in most
cases). Touchpad was not usable in any of these 6.
For context: right after building this kernel, on an earlier boot NOT
included in this batch, I saw a long stream of plausible-looking report
data (changing byte values consistent with coordinate movement)
starting around 72s after boot, following the same probe-then-errors
pattern. However, I want to be clear this was NOT a case of the
touchpad actually working - I was not able to move the cursor at that
time despite the kernel apparently receiving this data. I flagged this
same discrepancy in an earlier message in this thread (kernel-level
input events without perceived touchpad function) - I still don't have
an explanation for it, and don't want to overstate this as "recovery"
since functionally the touchpad was unusable in that case too.
So across all 7 boots I've tested with this patch so far (6 in this
batch + 1 earlier), touchpad was not usable in any of them.
Re: your Windows question - I tested this, and yes, the touchpad works
immediately after boot on Windows (tested a handful of boots, worked
every time).
Let me know if you'd like me to test with a longer wait/capture window
regardless (to see if the -121 errors eventually stop even without
real functionality), adjust the number of retries/delay in the patch,
or if the "input: events without working touchpad" discrepancy is
something you'd like me to investigate further (e.g. checking whether
libinput/evtest sees the same events, or capturing raw i2c traffic).
Thanks,
Adam
On Mon, Sep 7, 2026 at 10:50 PM Lovekesh Solanki
[off-list ref] wrote:
quoted hunk ↗ jump to hunk
On Sat, Sep 05, 2026 at 10:25:46AM +0200, Adam wrote:
quoted
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",