@@ -82,7 +82,8 @@ typedef struct {
8282
8383enum {
8484 PIPE0_STATE_IDLE = 0 , // no active control transfer
85- PIPE0_STATE_DATA , // DATA stage (IN or OUT — direction implied by CSR/dir)
85+ PIPE0_STATE_DATA_IN , // DATA IN stage
86+ PIPE0_STATE_DATA_OUT , // DATA OUT stage
8687 PIPE0_STATE_STATUS_IN , // STATUS IN — device sends IN-ZLP; awaits send-ACK IRQ
8788 PIPE0_STATE_STATUS_OUT , // post-DATAEND, neither edpt0_xfer(STATUS OUT) nor confirmation IRQ has happened yet
8889 PIPE0_STATE_STATUS_OUT_PENDING , // one of {edpt0_xfer(STATUS OUT), confirmation IRQ} has happened; the other fires xfer_complete
@@ -95,12 +96,41 @@ typedef struct {
9596 uint16_t remain_wlength ; // bytes remaining in the control transfer's DATA stage
9697 uint8_t state ;
9798 uint8_t pending_addr ; // new USB address latched by dcd_set_address; applied when STATUS IN completes
99+ tusb_control_request_t deferred_setup ;
100+ bool deferred_setup_valid ;
98101 } pipe0 ;
99102 pipe_state_t pipe [MUSB_PIPE_COUNT ];
100103} dcd_data_t ;
101104
102105static dcd_data_t _dcd ;
103106
107+ static void pipe0_start_setup (uint8_t rhport , musb_ep_csr_t * ep_csr ,
108+ tusb_control_request_t const * req , bool is_isr ) {
109+ _dcd .pipe0 .remain_wlength = req -> wLength ;
110+
111+ if (req -> wLength == 0 ) {
112+ _dcd .pipe0 .state = PIPE0_STATE_STATUS_IN ;
113+ } else {
114+ if (req -> bmRequestType & TUSB_DIR_IN_MASK ) {
115+ _dcd .pipe0 .state = PIPE0_STATE_DATA_IN ;
116+ ep_csr -> csr0l = MUSB_CSRL0_RXRDYC ;
117+ } else {
118+ _dcd .pipe0 .state = PIPE0_STATE_DATA_OUT ;
119+ }
120+ }
121+
122+ dcd_event_setup_received (rhport , (const uint8_t * ) req , is_isr );
123+ }
124+
125+ static void pipe0_process_deferred_setup (uint8_t rhport , musb_ep_csr_t * ep_csr , bool is_isr ) {
126+ if (!_dcd .pipe0 .deferred_setup_valid ) {
127+ return ;
128+ }
129+
130+ _dcd .pipe0 .deferred_setup_valid = false;
131+ pipe0_start_setup (rhport , ep_csr , & _dcd .pipe0 .deferred_setup , is_isr );
132+ }
133+
104134// EP0 must not call this — it has its own scalars in dcd_data_t.
105135TU_ATTR_ALWAYS_INLINE static inline pipe_state_t * pipe_get (uint8_t epnum , tusb_dir_t epdir ) {
106136 size_t idx = epnum - 1u ;
@@ -323,7 +353,7 @@ static void process_epout(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum,
323353
324354static bool edpt_n_xfer (uint8_t rhport , uint8_t ep_addr , void * buffer , uint16_t total_bytes , bool use_fifo , bool is_isr ) {
325355 const uint8_t epnum = tu_edpt_number (ep_addr );
326- const unsigned dir_in = tu_edpt_dir (ep_addr );
356+ const tusb_dir_t dir_in = tu_edpt_dir (ep_addr );
327357
328358 pipe_state_t * pipe = pipe_get (epnum , dir_in );
329359 if (use_fifo ) {
@@ -361,7 +391,8 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
361391 const unsigned dir_in = tu_edpt_dir (ep_addr );
362392
363393 switch (_dcd .pipe0 .state ) {
364- case PIPE0_STATE_DATA : {
394+ case PIPE0_STATE_DATA_IN :
395+ case PIPE0_STATE_DATA_OUT : {
365396 _dcd .pipe0 .xact_len = total_bytes ;
366397 if (dir_in ) {
367398 // DATA IN: load FIFO, set TXRDY. Add DATAEND on the last chunk
@@ -396,6 +427,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
396427 // Second event — IRQ already arrived, fire complete now.
397428 _dcd .pipe0 .state = PIPE0_STATE_IDLE ;
398429 dcd_event_xfer_complete (rhport , ep_addr , 0 , XFER_RESULT_SUCCESS , is_isr );
430+ pipe0_process_deferred_setup (rhport , ep_csr , is_isr );
399431 break ;
400432
401433 default : break ;
@@ -410,9 +442,14 @@ static void process_ep0(uint8_t rhport) {
410442 musb_ep_csr_t * ep_csr = get_ep_csr (musb_regs , 0 );
411443 uint_fast8_t csrl = ep_csr -> csr0l ;
412444
445+ if (csrl & MUSB_CSRL0_DATAEND ) {
446+ return ;
447+ }
448+
413449 if (csrl & MUSB_CSRL0_STALLED ) {
414450 ep_csr -> csr0l = 0 ;
415451 _dcd .pipe0 .state = PIPE0_STATE_IDLE ;
452+ _dcd .pipe0 .deferred_setup_valid = false;
416453 return ;
417454 }
418455
@@ -421,6 +458,7 @@ static void process_ep0(uint8_t rhport) {
421458 // do nothing, it is probably another setup packet, usbd will reset its state.
422459 ep_csr -> csr0l = MUSB_CSRL0_SETENDC ;
423460 _dcd .pipe0 .state = PIPE0_STATE_IDLE ;
461+ _dcd .pipe0 .deferred_setup_valid = false;
424462 if (!(csrl & MUSB_CSRL0_RXRDY )) {
425463 return ; /* no SETUP waiting behind it */
426464 }
@@ -438,22 +476,10 @@ static void process_ep0(uint8_t rhport) {
438476 } setup_packet ;
439477 setup_packet .u32 [0 ] = musb_regs -> fifo [0 ];
440478 setup_packet .u32 [1 ] = musb_regs -> fifo [0 ];
441-
442- _dcd .pipe0 .remain_wlength = setup_packet .req .wLength ;
443-
444- if (setup_packet .req .wLength == 0 ) {
445- _dcd .pipe0 .state = PIPE0_STATE_STATUS_IN ;
446- } else {
447- _dcd .pipe0 .state = PIPE0_STATE_DATA ;
448- // If OUT (rx) direction, let edpt0_xfer() clear RXRDY when it's ready to receive data.
449- if (setup_packet .req .bmRequestType & TUSB_DIR_IN_MASK ) {
450- ep_csr -> csr0l = MUSB_CSRL0_RXRDYC ;
451- }
452- }
453- dcd_event_setup_received (rhport , (const uint8_t * )& setup_packet .req , true);
479+ pipe0_start_setup (rhport , ep_csr , & setup_packet .req , true);
454480 break ;
455481
456- case PIPE0_STATE_DATA : {
482+ case PIPE0_STATE_DATA_OUT : {
457483 // EP0 OUT is single-packet (TU_ASSERT total_bytes <= EP0_SIZE in edpt0_xfer)
458484 // so the whole packet drains in one shot.
459485 if (count0 ) {
@@ -470,24 +496,53 @@ static void process_ep0(uint8_t rhport) {
470496 break ;
471497 }
472498
473- default : break ;
499+ // New SETUP packet arrived while old control transfer is not finished yet. This could happen in following scenarios:
500+ // - Status IN/OUT finished, IRQ and new setup packet IRQ arrive at the same time.
501+ // - Data IN finished and status OUT is received, both IRQs and new setup packet IRQ arrive at the same time.
502+ // could happen when CPU load is high, save the new setup packet for later processing after current status stage complete.
503+ case PIPE0_STATE_STATUS_OUT :
504+ case PIPE0_STATE_STATUS_OUT_PENDING :
505+ case PIPE0_STATE_STATUS_IN :
506+ case PIPE0_STATE_DATA_IN : {
507+ TU_ASSERT (sizeof (tusb_control_request_t ) == count0 , );
508+ union {
509+ tusb_control_request_t req ;
510+ uint32_t u32 [2 ];
511+ } setup_packet ;
512+ setup_packet .u32 [0 ] = musb_regs -> fifo [0 ];
513+ setup_packet .u32 [1 ] = musb_regs -> fifo [0 ];
514+
515+ _dcd .pipe0 .deferred_setup = setup_packet .req ;
516+ _dcd .pipe0 .deferred_setup_valid = true;
517+ ep_csr -> csr0l = MUSB_CSRL0_RXRDYC ;
518+ goto process_status ;
519+ }
474520 }
475521
476522 return ;
477523 }
478524
525+ process_status :
479526 /* When CSRL0 is zero, it means that either
480527 * - completion of sending any length packet TxPktRdy clear
481528 * - or status stage is complete (ZLP) after DataEnd is set */
482529 switch (_dcd .pipe0 .state ) {
483- case PIPE0_STATE_DATA :
530+ case PIPE0_STATE_DATA_IN :
484531 // csrl == 0 in DATA state = TXRDY just cleared, i.e. a DATA IN packet was successfully sent. If the just-sent
485532 // packet was the last (DATAEND was set when ep0_remain_datalen hit zero), transition
486533 // to STATUS_OUT to await the host's STATUS-OUT ZLP confirmation IRQ.
487534 if (_dcd .pipe0 .remain_wlength == 0 ) {
488535 _dcd .pipe0 .state = PIPE0_STATE_STATUS_OUT ;
489536 }
490537 dcd_event_xfer_complete (rhport , TU_EP0_IN , _dcd .pipe0 .xact_len , XFER_RESULT_SUCCESS , true);
538+
539+ // If a new SETUP was deferred while still in DATA_IN, treat STATUS OUT as
540+ // already confirmed in this same interrupt window and complete control OUT.
541+ if (_dcd .pipe0 .state == PIPE0_STATE_STATUS_OUT && _dcd .pipe0 .deferred_setup_valid ) {
542+ _dcd .pipe0 .state = PIPE0_STATE_IDLE ;
543+ dcd_event_xfer_complete (rhport , TU_EP0_OUT , 0 , XFER_RESULT_SUCCESS , true);
544+ pipe0_process_deferred_setup (rhport , ep_csr , true);
545+ }
491546 break ;
492547
493548 case PIPE0_STATE_STATUS_OUT :
@@ -499,6 +554,7 @@ static void process_ep0(uint8_t rhport) {
499554 // Second event — edpt0_xfer(STATUS OUT) already called, fire complete now.
500555 _dcd .pipe0 .state = PIPE0_STATE_IDLE ;
501556 dcd_event_xfer_complete (rhport , TU_EP0_OUT , 0 , XFER_RESULT_SUCCESS , true);
557+ pipe0_process_deferred_setup (rhport , ep_csr , true);
502558 break ;
503559
504560 case PIPE0_STATE_STATUS_IN :
@@ -508,6 +564,7 @@ static void process_ep0(uint8_t rhport) {
508564 }
509565 _dcd .pipe0 .state = PIPE0_STATE_IDLE ;
510566 dcd_event_xfer_complete (rhport , TU_EP0_IN , 0 , XFER_RESULT_SUCCESS , true);
567+ pipe0_process_deferred_setup (rhport , ep_csr , true);
511568 break ;
512569
513570 default : break ;
@@ -527,6 +584,7 @@ static void process_bus_reset(uint8_t rhport) {
527584 _dcd .pipe0 .buf = NULL ;
528585 _dcd .pipe0 .xact_len = 0 ;
529586 _dcd .pipe0 .remain_wlength = 0 ;
587+ _dcd .pipe0 .deferred_setup_valid = false;
530588
531589 musb -> intr_txen = 1 ; /* Enable only EP0 */
532590 musb -> intr_rxen = 0 ;
@@ -646,7 +704,7 @@ void dcd_sof_enable(uint8_t rhport, bool en)
646704bool dcd_edpt_open (uint8_t rhport , tusb_desc_endpoint_t const * ep_desc ) {
647705 const unsigned ep_addr = ep_desc -> bEndpointAddress ;
648706 const unsigned epn = tu_edpt_number (ep_addr );
649- const unsigned epdir = tu_edpt_dir (ep_addr );
707+ const tusb_dir_t epdir = tu_edpt_dir (ep_addr );
650708 const unsigned mps = tu_edpt_packet_size (ep_desc );
651709
652710 pipe_state_t * pipe = pipe_get (epn , epdir );
@@ -689,7 +747,7 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet
689747bool dcd_edpt_iso_activate (uint8_t rhport , tusb_desc_endpoint_t const * ep_desc ) {
690748 const unsigned ep_addr = ep_desc -> bEndpointAddress ;
691749 const unsigned epn = tu_edpt_number (ep_addr );
692- const unsigned dir_in = tu_edpt_dir (ep_addr );
750+ const tusb_dir_t dir_in = tu_edpt_dir (ep_addr );
693751 const unsigned mps = tu_edpt_packet_size (ep_desc );
694752
695753 unsigned const ie = musb_dcd_get_int_enable (rhport );
@@ -804,6 +862,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
804862 if (ep_addr == TU_EP0_OUT ) { /* Ignore EP0 OUT */
805863 _dcd .pipe0 .state = PIPE0_STATE_IDLE ;
806864 _dcd .pipe0 .buf = NULL ;
865+ _dcd .pipe0 .deferred_setup_valid = false;
807866 ep_csr -> csr0l = MUSB_CSRL0_STALL ;
808867 }
809868 } else {
0 commit comments