Symptom: in boot protocol (BIOS / UEFI) one keypress emitted ~10
characters. _kbd_write_ep1 was rebuilding and re-arming EP1 on every
USB SOF poll; report-mode HID drivers diff consecutive reports and
collapse duplicates, but boot-mode hosts treat each IN as a fresh
press.
Changes:
- Add 9-byte lastEP1_* shadow in bank-0 RAM, plus hidProtocol /
hidIdleRate / hidIdleCounter state.
- _kbd_write_ep1: compare freshly-built bytes against the shadow with
CMPRS A, M. On match, only resend when the SET_IDLE counter has
expired; otherwise NAK silently. On mismatch, copy to shadow and
send.
- _usb_htd_hid_set_idle: actually capture wValueHi (HID 1.11 §7.2.4)
instead of just ACKing — store as hidIdleRate, reload counter.
- New _usb_htd_hid_set_protocol: capture wValueLo (HID 1.11 §7.2.5)
into hidProtocol; invalidate shadow so the new wire format ships
immediately. Wire dispatch table (0x210b) to it instead of the
default STALL handler.
- _usb_sof: tick hidIdleCounter when rate is non-zero so the resend
fires at idle-rate cadence.
- _kbd_write_ep1 sets UE1R_C=8 in boot protocol, 9 in report. The
9th byte (consumer/extraState0) is kept in the EP1 buffer slack
but truncated on the wire under boot protocol.
Net effect: a held key in BIOS mode now produces one keydown plus one
keyup, matching report-mode behaviour.
FN+middle was scrolling same as plain middle because the FN-alt path
always converted TrackPoint to wheel/pan. Now FN+middle jumps to
normal mouse passthrough (REL_X/REL_Y + BTN_MIDDLE), giving proper
middle-drag behavior. FN without middle still does back/forward + scroll.
Verified on real hardware via evtest on higgs (Pi 5).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Middle-button scroll state machine (3-state: idle/undecided/scrolling)
with 150ms timeout — short press sends middle click, hold converts
TrackPoint movement to scroll wheel events. FN+middle passes through.
Also implements:
- CapsLock LED feedback via host LED output reports (P5.3/PWM0)
- FN+F7 (LGUI+P), FN+F9 (LGUI+I), FN+F11 (LCTRL+LALT+TAB)
- HID GET_REPORT with per-interface responses
- SET/CLEAR FEATURE for DEVICE_REMOTE_WAKEUP
Tested with 23/23 simulator tests passing (test_scroll.py).
Flash space: 10,238/10,239 words used (1 word free).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This indeed fixes the values read back:
80000000ff No buttons, no movement
80010000ff Left button
80050000ff Left+right buttons
80070000ff All buttons
800012fdff Force applied
80000fffff force applied
Adds support for:
- CLEAR/SET FEATURE (ignored)
- GET_CONFIGURATION (always returns 1 since there is only a single config)
- GET_INTERFACE (always returns 0 since there are not altsettings)
Matrix is getting scanned and converted into boot-style HID interface.
Most keys are basically working.
However the enabled debug UART prevents use of the following keys:
DELETE PRINTSCREEN INSERT PAGEUP PAGEDOWN
as S15 is in fixed output mode and thus can't be sensed right now.
Tested:
- UART debug output works at 115200 baud (pad S15)
- Jumps to bootloader on watchdog timeout
- Jumps to bootloader when Return is held while plugging in USB
- Jumps to bootloader when UTX/URX lines are shorted
- Measured max GPIO toggling speed is 3MHz