summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-06-19 22:54:50 +0700
committerhathach <[email protected]>2026-06-19 22:54:50 +0700
commit0c4c0be4589b2807abde5ef9ab156b6aaaad6616 (patch)
tree7f313ea1aa2e06893f976c3099413858733dd78f /src
parentdcb060c894713d60ce0ab009733e5d59a32d0d23 (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.c5
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;
}