diff options
| author | hathach <[email protected]> | 2026-06-17 16:26:38 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-06-18 15:56:23 +0700 |
| commit | de341b14abe3bc3e25962cbb26aa61bc0126adcf (patch) | |
| tree | 4999729614bdf87ff36a3bcd3af6103698913588 | |
| parent | 47f534680215a68391a46cd45decde9b6f0a6573 (diff) | |
dcd/stm32_fsdev: restore CH32 EP0 CONTROL type atomically with arming
edpt_xfer() restored EP0 to CONTROL at the top of the function, before
the OUT stage was armed (rx bufsize + STAT_RX=VALID written further
down, with interrupts enabled in between). That re-enabled the CH32
blind OUT ACK while STAT_RX was still NAK and the buffer size stale, so
a host-retried DATA OUT / status ZLP could be ACKed into the wrong
buffer in the gap.
Fold the CONTROL restore into the single exclusive write that programs
STAT_RX=VALID for the OUT direction, after the buffer size is set, so
type and arming go live together. The IN direction keeps the (now
atomic) early restore, where no pending OUT exists to be blind-ACKed.
Co-Authored-By: Claude Fable 5 <[email protected]>
| -rw-r--r-- | src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 8dd790404..6279f8102 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -754,14 +754,13 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) { xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); const uint8_t ep_idx = xfer->ep_idx; + if (dir == TUSB_DIR_IN) { #if defined(TUP_USBIP_FSDEV_CH32) - // Re-enable normal control transfer semantics when EP0 transfer is explicitly armed. - if (ep_num == 0u) { - ep0_set_type(U_EP_CONTROL, true); - } + // Safe to restore CONTROL before arming IN: no pending OUT for the errata to blind-ACK. + if (ep_num == 0u) { + ep0_set_type(U_EP_CONTROL, true); + } #endif - - if (dir == TUSB_DIR_IN) { dcd_transmit_packet(xfer, ep_idx); } else { uint32_t ep_reg = ep_read(ep_idx) | U_EP_CTR_TX | U_EP_CTR_RX; // reserve CTR @@ -781,6 +780,13 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) { btable_set_rx_bufsize(ep_idx, BTABLE_BUF_RX, cnt); } +#if defined(TUP_USBIP_FSDEV_CH32) + // Restore CONTROL in the same write as STAT_RX=VALID (after bufsize): a separate earlier + // write would re-enable the blind OUT ACK while still NAK'd with a stale buffer. + if (ep_num == 0u) { + ep_reg = (ep_reg & ~U_EP_T_FIELD) | U_EP_CONTROL; + } +#endif ep_change_status(&ep_reg, dir, EP_STAT_VALID); ep_write(ep_idx, ep_reg, true); } |
