[PATCH v2] usbhid: tolerate intermittent errors
From: Liam Mitchell
Date: Sat Mar 07 2026 - 13:57:41 EST
Modifies usbhid error handling to tolerate intermittent protocol
errors, avoiding URB resubmission delay and device reset.
---
Protocol errors like EPROTO can occur randomly, sometimes frequently and are often not fixed by a device reset.
The current error handling will only resubmit the URB after at least 13ms delay and may reset the USB device if another error occurs 1-1.5s later, regardless of error type or count.
These delays and device resets increase the chance that input events will be missed and that users see symptoms like missed or sticky keyboard keys.
This patch allows one protocol error per 500ms to be tolerated and have the URB re-submitted immediately.
500ms was chosen to be well above the error rate of a malfunctioning
device but low enough to be useful for users with devices noisier than
mine.
Signed-off-by: Liam Mitchell <mitchell.liam@xxxxxxxxx>
Link: https://lore.kernel.org/linux-input/CAOQ1CL6Q+4GNy=kgisLzs0UBXFT3b02PG8t-0rPuW-Wf6NhQ6g@xxxxxxxxxxxxxx/
---
Changes in v2:
- revert changes to hid_io_error
- add more specific fix in hid_irq_in
- Link to v1: https://lore.kernel.org/r/20260208-usbhid-eproto-v1-1-5872c10d90bb@xxxxxxxxx
---
drivers/hid/usbhid/hid-core.c | 5 +++++
drivers/hid/usbhid/usbhid.h | 1 +
2 files changed, 6 insertions(+)
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 758eb21430cd..939e095eddfe 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -313,6 +313,11 @@ static void hid_irq_in(struct urb *urb)
case -ETIME: /* protocol error or unplug */
case -ETIMEDOUT: /* Should never happen, but... */
usbhid_mark_busy(usbhid);
+ /* Tolerate intermittent protocol errors */
+ if (time_after(jiffies, usbhid->last_proto_error + msecs_to_jiffies(500))) {
+ usbhid->last_proto_error = jiffies;
+ break;
+ }
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
hid_io_error(hid);
return;
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 75fe85d3d27a..6aab9101fe34 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -86,6 +86,7 @@ struct usbhid_device {
struct timer_list io_retry; /* Retry timer */
unsigned long stop_retry; /* Time to give up, in jiffies */
unsigned int retry_delay; /* Delay length in ms */
+ unsigned long last_proto_error; /* Last protocol error time, in jiffies */
struct work_struct reset_work; /* Task context for resets */
wait_queue_head_t wait; /* For sleeping */
};
---
base-commit: b91e36222ccfb1b0985d1fcc4fb13b68fb99c972
change-id: 20260208-usbhid-eproto-152c7abcb185
Best regards,
--
Liam Mitchell <mitchell.liam@xxxxxxxxx>