Skip to content

Escalate USB recovery when keyboard HID writes time out - #1516

Draft
adamshiervani wants to merge 1 commit into
devfrom
fix/hidg0-write-timeout-recovery
Draft

Escalate USB recovery when keyboard HID writes time out#1516
adamshiervani wants to merge 1 commit into
devfrom
fix/hidg0-write-timeout-recovery

Conversation

@adamshiervani

@adamshiervani adamshiervani commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #1512

After a UDC rebind, the DWC3 race can leave /dev/hidg0 openable but dead: every write times out while the UDC still reports configured. Recovery verifies health by reopening the chardev — which succeeds in that state — and writeWithTimeout swallows deadline errors (host-suspend tolerance), so the existing escalation to a full gadget reconfigure never fires. Keyboard input is silently dropped (mouse fine, state configured) until identifier profiles are cycled by hand.

Changes

  • The recovery ladder verifies with a write probe, not just a reopen: re-send the current keys-down state (a no-op for the host) with the timeout surfaced. Probe failing while configured → escalate to the full reconfigure, so recovery completes before the user types.
  • Consecutive keyboard write timeouts are counted; the streak resets on success, on recovery, and outside configured (where timeouts are expected, e.g. host suspend). 3 in a row while configured → full reconfigure, rate-limited to 30s. Covers breakage with no preceding detach.

Testing

  • Unit tests for probe, streak accounting, and escalation policy (stalled endpoint simulated with a full pipe).
  • New ra-hid-write-recovery e2e reproduces the bug deterministically: unbind usbhid from the gadget keyboard interface on the host → gadget writes time out while configured. Fails on dev (keyboard dead for the full 120s window), passes here (recovery ~2s after the first timeout, confirmed by re-enumeration in host dmesg).
  • On device: a UDC unbind whose rebind left hidg0 unusable converges via ladder → reconfigure in one extra re-enumeration — no input needed, no reconfigure loop after.

After a UDC rebind, the RV1106 DWC3 race can leave /dev/hidg0 openable
but non-functional: every write times out while the UDC still reports
"configured". The rebind recovery path verified health by reopening the
chardev — which succeeds in this state — and writeWithTimeout swallows
the deadline errors (host-suspend tolerance), so nothing ever escalated
to the full gadget reconfigure that actually fixes it. Keyboard input
was silently dropped until the user manually cycled identifier profiles
(#1512).

Two complementary mechanisms:

1. Write-probe verification in the recovery ladder: after reopening the
   keyboard HID file, re-send the current keys-down state (a no-op for
   the host) and, unlike the regular report path, surface a timeout.
   While the UDC reports "configured", a reopen that probes broken is
   not success — the ladder escalates to the full reconfigure instead
   of declaring victory, fixing the gadget before the user ever types.

2. Runtime write-timeout streak: consecutive keyboard write timeouts
   are counted (reset on success, on recovery, and while the state is
   not "configured", where timeouts are expected — e.g. host suspend).
   When the streak reaches 3 while "configured", recovery runs the full
   reconfigure directly, rate-limited to one attempt per 30s. This
   catches breakage that occurs without a preceding detach event.

Fixes #1512
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keyboard HID file not ready after UDC rebind - automatic recovery fails, manual identifier cycling required

1 participant