diff options
| author | hathach <[email protected]> | 2026-06-19 22:54:50 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-06-19 22:54:50 +0700 |
| commit | 0c4c0be4589b2807abde5ef9ab156b6aaaad6616 (patch) | |
| tree | 7f313ea1aa2e06893f976c3099413858733dd78f /src | |
| parent | dcb060c894713d60ce0ab009733e5d59a32d0d23 (diff) | |
dcd/ch58x: keep IRQ masked across the EP-arming RMW in dcd_edpt_xfer
dcd_edpt_xfer() re-enabled the USB interrupt before update_in() / ep_rx_set_response(),
which read-modify-write the (combined) EP control register. On CH58x the ISR RMWs that
same register to flip the manual data toggle, so a transfer interrupt landing mid-RMW
could drop the toggle flip and desync the endpoint. Move dcd_int_enable() to after the
arming so the whole sequence is atomic w.r.t. the ISR (matching the CH32X035 port #3703).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/portable/wch/dcd_ch32_usbfs.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 12b45c784..e8b3c86b2 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -500,12 +500,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to uint8_t dir = tu_edpt_dir(ep_addr); struct usb_xfer *xfer = &data.xfer[ep][dir]; + // Keep the IRQ masked across the whole arming sequence: update_in()/ep_rx_set_response() do a + // read-modify-write of the (combined) EP control register, which the ISR also RMWs to flip the + // manual data toggle; re-enabling before they run lets a transfer IRQ clobber that toggle. dcd_int_disable(rhport); xfer->valid = true; xfer->buffer = buffer; xfer->len = total_bytes; xfer->processed_len = 0; - dcd_int_enable(rhport); if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true); @@ -513,6 +515,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : USBFS_EP_R_RES_ACK; ep_rx_set_response(ep, rx_res); } + dcd_int_enable(rhport); return true; } |
