shared/tinyusb: Stall the CDC IN endpoint while disconnecting.

Only when dynamic USB devices are enabled.

The issue here is that when the USB reset triggers, the dynamic USB device
reset callback is called from inside the TinyUSB task.

If that callback tries to print something then it'll call through to
tud_cdc_write_flush(), but TinyUSB hasn't finished updating state yet to
know it's no longer configured. Subsequently it may try to queue a transfer
and then the low-level DCD layer panics.

By explicitly stalling the endpoint first, usbd_edpt_claim() will fail and
tud_cdc_write_flush() returns immediately.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
This commit is contained in:
Angus Gratton 2024-05-07 17:02:11 +10:00 committed by Damien George
parent 8762fe8b4c
commit 9a43989a86

View File

@ -472,6 +472,8 @@ static void mp_usbd_disconnect(mp_obj_usb_device_t *usbd) {
#if MICROPY_HW_USB_CDC
// Ensure no pending static CDC writes, as these can cause TinyUSB to crash
tud_cdc_write_clear();
// Prevent cdc write flush from initiating any new transfers while disconnecting
usbd_edpt_stall(USBD_RHPORT, USBD_CDC_EP_IN);
#endif
bool was_connected = tud_connected();