summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-06-19 22:55:54 +0700
committerhathach <[email protected]>2026-06-19 22:55:54 +0700
commit58b5447b606b49c76187c48e5b76690f4a111143 (patch)
treedb17a05437cec861c6f424686c1c610a971f26aa /src
parent0c4c0be4589b2807abde5ef9ab156b6aaaad6616 (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.c11
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;
}