-
Notifications
You must be signed in to change notification settings - Fork 7.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make USBHIDKeyboard work at boot #6964
Conversation
@@ -661,6 +665,13 @@ esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descr | |||
log_e("Interface %s invalid or already enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]); | |||
return ESP_FAIL; | |||
} | |||
if(interface == USB_INTERFACE_HID && reserve_endpoints){ | |||
// Some simple PC BIOS requires specific endpoint addresses for keyboard at boot | |||
if(!tinyusb_reserve_out_endpoint(1) ||!tinyusb_reserve_in_endpoint(1)){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this reservation of endpoints IN 1, OUT 1, USBCDC will reserve OUT 3, IN 4, IN 5 (line 665), then when USBHID.cpp:tusb_hid_load_descriptor()
calls tinyusb_get_free_in_endpoint()
/tinyusb_get_free_out_endpoint()
, those functions will return IN 3, OUT 4 because those functions prefer returning endpoints whose opposite is already used.
Some alternatives to calling tinyusb_reserve_out_endpoint()
/tinyusb_reserve_in_endpoint()
here to reserve IN 1, OUT 1:
USBHID.cpp:tusb_hid_load_descriptor()
could calltinyusb_get_free_duplex_endpoint()
which would likely get endpoints IN 1, OUT 1 becauseUSBHID.cpp:tusb_hid_load_descriptor()
runs early enough.- Change
tinyusb_get_free_in_endpoint()
/tinyusb_get_free_out_endpoint()
not to prefer returning endpoints whose opposite is already used. Or add a flag parameter.
Because USBHIDKeyboard is simple, these changes could be greatly simplified by doing some or all of the following:
I'm looking for feedback on whether some of these simplifications should be done. |
Any feedback on what I can do to get these changes in? I'm open to suggestions. Thanks. |
This has a problem on one of my PCs at boot where the PC does not send "SET PROTOCOL BOOT" to the device and it expects the device to send reports prefixed with a report ID. I'll investigate further. |
USB Keyboards actually provide two HID devices, one for boot and another for all other cases. The non-boot device can have extra functions, buttons, etc. |
1. Like a real keyboard, the USB interface descriptor will have an interface subclass of boot and an interface protocol of keyboard. This will cause some PC BIOS to send a SET PROTOCOL BOOT request to the device. 2. When the device sends reports to the host, if the host requested boot protocol, don't send a report ID because boot protocol does not use report IDs. 3. To work with some simple PC BIOS: a. Use endpoint address of 1 for input and output. b. Use separate reports for the shift key. These extra reports can be disabled by calling USBHIDKeyboard::setShiftKeyReports(false).
490a075
to
1201a79
Compare
Ok, I've reworked this with some improvements. I investigated a real keyboard from a major PC manufacturer and found that it makes the main HID device a boot keyboard. The real keyboard that I investigated has another HID device, but it is for special keys. So, like a real keyboard, I made This major PC manufacturer of a 2021 PC (which happens to not request boot protocol) needed two other work-arounds:
Let me know any feedback, thanks. |
Any feedback on what I can do to get these changes in? I'm open to suggestions. Thanks. |
1 similar comment
Any feedback on what I can do to get these changes in? I'm open to suggestions. Thanks. |
sorry for the delay @RefactorFactory . We will look into this very soon and have it in what will become version 3.0.0 (based on IDF 5.x) |
Hello @RefactorFactory, please sign CLA. Thanks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Can you please sign the CLA as requested?
Thanks @RefactorFactory for the PR!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works as expected. Tested on my ASRock motherboard (that didn't work without this PR).
I signed the CLA. Sorry it took so long. Thanks. |
Add a boot_protocol parameter to the USBHIDKeyboard constructor. When true:
The USB interface descriptor will have an interface subclass of boot and
and interface protocol of keyboard. This will cause some PC BIOS to send a
a SET PROTOCOL BOOT request to the device.
The USB report descriptor will not have a report ID because boot protocol
does not use report IDs.
When the host sends reports to the device, USBHIDKeyboard will accept a
report ID of 0 instead of checking for HID_REPORT_ID_KEYBOARD(1).
When the device sends reports to the host, it will not send a report ID
because boot protocol does not use report IDs.
Use endpoint address of 1 for input and output because some PC BIOS require
it.
By completing this PR sufficiently, you help us to review this Pull Request quicker and also help improve the quality of Release Notes
Checklist
This entire section above can be deleted if all items are checked.
Description of Change
USBHIDKeyboard didn't work at boot on my devices, so I've prototyped changes that make it work. I'm looking for feedback.
This adds a parameter to the USBHIDKeyboard constructor and when it is true, behavior is changed. I considered removing the parameter and changing the behavior all the time, but it seemed too risky.
This also adds a new parameter to the USBHID constructor, but it defaults to the old behavior.
I considered only using the new behavior if the host sends the SET PROTOCOL BOOT request, but it turns out that some BIOS do not send that request.
It is strange that some PC BIOS require specific endpoint addresses of 1 for input and output. I tried to do the reservation of the endpoint addresses similar to how USBCDC does it.
Some of the code seems ugly, so I'm looking for feedback.
Tests scenarios
I tested this with Arduino-esp32 core v2.0.4 with an ESP32 S2 board, with one old laptop and one new desktop, both from major PC manufacturers.
Related links