diff options
| author | hathach <[email protected]> | 2026-06-19 22:55:54 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-06-19 22:55:54 +0700 |
| commit | 58b5447b606b49c76187c48e5b76690f4a111143 (patch) | |
| tree | db17a05437cec861c6f424686c1c610a971f26aa /src | |
| parent | 0c4c0be4589b2807abde5ef9ab156b6aaaad6616 (diff) | |
dcd/ch58x: advance EP0 OUT data toggle for multi-packet control transfers
The manual-toggle ISR skipped EP0 entirely (if (ep != 0)), so EP0's RX data toggle
was set to DATA1 once at SETUP and never advanced. A control-OUT whose data stage
exceeds the EP0 packet size (a vendor/WebUSB OUT, a large HID SET_REPORT, or an
HS DFU download) desynced on the second packet and stalled.
EP0 has no hardware auto-toggle on CH58x (per the datasheet RB_UEP_AUTO_TOG applies
only to EP1/2/3/5/6/7), so flip its RX toggle on every OUT and always process the
packet -- restoring what the removed dcd_ch58x_usbfs.c did. The HIL examples keep
their control-OUT data stages within a single packet, so this was latent.
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 | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index e8b3c86b2..164b6f7bf 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -336,10 +336,13 @@ void dcd_int_handler(uint8_t rhport) { switch (token) { case PID_OUT: { #ifdef CH32_USBFS_EP_MANUAL_TOG - // Manual toggle: drop OUT packets whose data toggle doesn't match (host retransmit), - // otherwise flip the expected RX toggle for the next packet. EP0 is driven by the - // SETUP/status flow below, so its toggle is left to that path. - if (ep != 0) { + // Manual toggle. EP0 has no hardware auto-toggle (RB_UEP_AUTO_TOG covers only EP1/2/3/5/6/7), + // so advance its RX toggle on every OUT and always process it; a control-OUT data stage + // longer than the EP0 packet size would otherwise stall on the second packet. For the other + // endpoints, drop toggle-mismatched OUT (host retransmit) and flip the expected RX toggle. + if (ep == 0) { + EP_CTRL(0) ^= USBFS_EPC_R_TOG; + } else { if (!(int_st & USBFS_INT_ST_TOG_OK)) { break; } EP_CTRL(ep) ^= USBFS_EPC_R_TOG; } |
