usb_hid: honor a boot protocol request that arrives after startup - #11282
usb_hid: honor a boot protocol request that arrives after startup#11282mikeysklar wants to merge 2 commits into
Conversation
dd114ae to
cd80fd8
Compare
|
I worked on this a lot years ago, as you can tell. I am surprised you need a new report descriptor without the Report ID slot. Part of the point of boot keyboard and boot mouse is that the descriptor sent by the device is ignored. Instead the host assumes the standard descriptors, as described in https://www.usb.org/sites/default/files/hid1_12.pdf in the boot devices sections So is this a work-around for something that Macs are not doing properly in their "BIOS"? I think the original code solved the issue on PC's. |
|
You're right about the descriptor. The bug is timing: the swap runs only at VM start, so a later SET_PROTOCOL is missed. Not Mac specific. I'll cut it to that. |
cd80fd8 to
8861fe9
Compare
|
Found a second bug in my own fix, fixed in 2d2ccf2. With two devices enabled only the boot Testing is a real
Single boot keyboard, baseline Not Mac specific. The original code does work on PCs, but only when the request lands |
usb_hid_setup_devices() swaps in the boot keyboard or mouse, whose report ID is 0, but it only runs from usb_setup_with_vm() at VM start. A SET_PROTOCOL(boot) arriving while code.py is already running is not acted on until the next VM restart, so reports keep their report-ID prefix while the host is reading them as 8-byte boot reports. That matches bitboy85's report in adafruit#1136: get_boot_device() returns 1 yet a phantom left Ctrl is held, because the 0x01 prefix lands in the modifier byte. Check tud_hid_get_protocol() in send_report() instead, and drop the report ID while the host has the interface in boot protocol. Measured on a Metro RP2040, with the host request simulated by setting TinyUSB's protocol_mode over SWD: before, reports stay 9 bytes after the switch; after, they become 8 bytes on the next send. Default HID configuration is unchanged.
In boot protocol the host reads the fixed 8-byte boot report and ignores every other device on the interface. send_report() stripped the report ID for the boot device but still sent the other devices' reports, so a second enabled device put its report ID in the host's modifier byte. Enabling KEYBOARD and CONSUMER_CONTROL together sent 03 01 00, read as Ctrl+Shift held. usb_hid_setup_devices() already replaces the device tuple when the host asks before code.py starts. Do the same at send time for a request that arrives later. Also sample the protocol after the ready wait rather than before it. hidd_reset() zeroes the interface and HID_PROTOCOL_BOOT is 0, so a report starting during a bus reset could read BOOT, wait two seconds, then send unprefixed into an interface that had re-enumerated back into report protocol. Measured on an Adafruit Feather RP2040, host Ubuntu 26.04.1, using a real SET_PROTOCOL(boot) control transfer over usbfs. Consumer control reports seen while the host held boot protocol: 20 per trial before, 0 after, three trials each. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5806ac3 to
2d2ccf2
Compare
What
In boot protocol the boot device sends without a report ID, and the other devices do not send.
Why
#1136, eight years old. Two defects, both putting a stray byte where the host reads modifiers.
SET_PROTOCOL(boot)arriving later is missed and reports keep the report ID. The01lands in the modifier byte, a held left CtrlCONSUMER_CONTROLsent03 01 00, read as Ctrl+ShiftHardware tested
Adafruit Feather RP2040, host Ubuntu 26.04.1. Real
SET_PROTOCOL(boot)over usbfs,GET_PROTOCOLread back. Three trials per build.Single boot keyboard, armed IN transfer while the host is in boot protocol:
d897c1501prefixb697e83Keyboard plus consumer control, same conditions:
b697e8303prefix, 20 per trial2d2ccf2Every arm returns to 9 bytes when report protocol is restored, so behavior tracks protocol.
Not tested: real BIOS, GRUB, KVM, Windows, non-RP2 ports, zephyr-cp.
Scope
usbhidkeeps the interface in report protocol, so no shipping OS sends it unpromptedAI assistance
Written with an LLM agent (Claude). I ran the boards myself.