Pico-PIO-USB host: a device that drops off the root port during attach debounce is never reported again
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 45/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- c
- Domain
- backend, embedded-iot
Research direction
Read src/host/usbh.c around the 150 ms attach debounce and src/portable/raspberrypi/pio_usb/hcd_pio_usb.c around hcd_port_connect_status() and root-port connection handling. Reproduce with a Pico-PIO-USB host and a device that disconnects during debounce, then trace how the root port handles disconnect and reconnect before its first reset. Done when the device is detected and enumerates after reconnecting without reinitializing the host.
Written by the indexing model from the issue text.
Description
Operating System
Others
Commit SHA
472a9c333: 0.21.0 (dae3f9a36) plus GP2040-CE’s two patches (control transfer timeout, ad7acc849 backport). The code involved (usbh.c root-port debounce, hcd_pio_usb.c) is unchanged in master 702e55db3.
Board
Haute42 COSMOX C-AT (RP2040) running GP2040-CE, device plugged into its Pico-PIO-USB host port (Pico-PIO-USB ba9733c = 5a37a66 + 2 commits)
Firmware
GP2040-CE in PS5 mode, with a PS4/PS5 auth dongle on the PIO-USB host port. The host side uses TinyUSB with TUH_CFGID_RPI_PIO_USB_CONFIGURATION.
What happened ?
If a device plugged straight into the Pico-PIO-USB root port drops off the bus during the 150 ms attach debounce, it’s never enumerated. After that, the port never reports any device again, even after physically unplugging and replugging, until the host is re-initialized.
What happens:
- On a new connection, pio_usb_host_frame() sets root->connected = true and root->suspended = true (“need a bus reset before operating”) and raises CONNECT.
- usbh ignores attach/remove events on that root port for ENUM_DEBOUNCING_DELAY_MS (150 ms), then checks hcd_port_connect_status().
- While the port is suspended, pio_usb doesn’t run connection_check(), so it doesn’t notice the disconnect either, and root->connected stays true.
- hcd_port_connect_status() reads the raw line state. If the device is off the bus at that moment, usbh logs “Device unplugged while debouncing”, ends the enumeration and waits for the next attach event.
- pio_usb only detects a new connection while !root->connected, so that event never comes. The root-port retry in master (f9a0687e8) doesn’t kick in either, because hcd_port_connect_status() is false at that point.
0.17 didn’t have this: enum_new_device() reset the root port right away, so pio_usb was already operating and reported the disconnect and reconnect.
We hit it with a PS4/PS5 auth dongle (Booter5, 0079:1893). It connects and drops off the bus several times while powering up, so it was never enumerated, whether plugged in together with the board or into an already running one. Plugged straight into a Mac, it works fine.
This change in hcd_pio_usb.c fixed it for us:
bool hcd_port_connect_status(uint8_t rhport) {
uint8_t const pio_rhport = RHPORT_PIO(rhport);
root_port_t *root = PIO_USB_ROOT_PORT(pio_rhport);
port_pin_status_t line_state = pio_usb_bus_get_line_state(root);
bool const connected = (line_state != PORT_PIN_SE0);
// Until the port is reset, pio_usb neither watches for a disconnect nor reports a new connection
// while it still marks the port connected. If the device dropped off the bus in the meantime
// (e.g. while usbh debounces the attach), usbh gives up on it here, so mark the port disconnected
// to let pio_usb report the device again once it reconnects.
if (!connected && root->connected && root->suspended) {
root->connected = false;
}
return connected;
}
With it, every cold plug and hot plug enumerated and the dongle worked: 6 cold plugs, plus hot plugs, on a PS5 and on a Mac. It could also be fixed on the Pico-PIO-USB side, by noticing disconnects while the port waits for its first reset.
How to reproduce ?
- A TinyUSB host on Pico-PIO-USB (CFG_TUH_RPI_PIO_USB=1).
- Connect a device that drops off the bus within the first ~150 ms after connecting, then reconnects. Our dongle does this on every power-up.
- The device is never enumerated, and nothing plugged into that port is detected afterwards until reboot.
We haven’t tried it, but a second board running a TinyUSB device example that calls tud_disconnect() ~50 ms after connecting and tud_connect() again a few hundred ms later should hit the same window deterministically.
Debug Log as txt file (LOG/CFG_TUSB_DEBUG=2)
No CFG_TUSB_DEBUG log, because the board has no UART available. We added counters instead, shown on the board’s display:
- without the fix: 1 attach event, the enumeration ends with “unplugged while debouncing”, and there are no further attach events, ever;
- with the fix: 4 attach events and 3 failed enumerations (the first at the debounce check, one on a failed transfer), then the device mounts.
Screenshots
No response
I have checked existing issues, discussion and documentation
- I confirm I have checked existing issues, discussion and documentation.
- Dominant language
- C
- Stars
- 7.2k
- Forks
- 1.6k
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 96
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from hathach/tinyusb
-
followup Prio 📌
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
followup Prio 📌
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
Maintainers usually reply within 1 day
-
test_audio_host: out-of-bounds read in test_audio_host_uses_exponential_full_speed_iso_intervalOpenfollowup Prio 📌
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day
-
followup Prio 📌
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
followup Prio 📌
Difficulty 1/5 Under an hour Newbie friendliness 84/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 95/100
containers/crun#2415 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
zephyrproject-rtos/zephyr#123423 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
dspromote: /etc/exports uses -alldirs on non-mount-point directories, so mountd exports nothingOpenbug
Difficulty 2/5 1-3 hours Newbie friendliness 83/100
nextbsd/nextbsd-userland#434 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
Maintainers usually reply within 1 day