@@ -66,6 +66,10 @@ enum {
6666 SIE_CTRL_SPEED_FULL = 2 ,
6767};
6868
69+ enum {
70+ EPX_CTRL_DEFAULT = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER | offsetof(usb_host_dpram_t , epx_data )
71+ };
72+
6973//--------------------------------------------------------------------+
7074//
7175//--------------------------------------------------------------------+
@@ -123,7 +127,7 @@ TU_ATTR_ALWAYS_INLINE static inline void sie_stop_xfer(void) {
123127 while (usb_hw -> sie_ctrl & USB_SIE_CTRL_STOP_TRANS_BITS ) {}
124128}
125129
126- TU_ATTR_ALWAYS_INLINE static inline void sie_start_xfer (bool send_setup , bool is_rx , bool need_pre ) {
130+ static void __tusb_irq_path_func ( sie_start_xfer ) (bool send_setup , bool is_rx , bool need_pre ) {
127131 uint32_t sie_ctrl = usb_hw -> sie_ctrl & SIE_CTRL_BASE_MASK ; // preserve base bits
128132 if (send_setup ) {
129133 sie_ctrl |= USB_SIE_CTRL_SEND_SETUP_BITS ;
@@ -135,31 +139,16 @@ TU_ATTR_ALWAYS_INLINE static inline void sie_start_xfer(bool send_setup, bool is
135139 }
136140
137141 // START_TRANS bit on SIE_CTRL has the same behavior as the AVAILABLE bit
138- // described in RP2040 Datasheet, release 2.1, section "4.1.2.5.1. Concurrent access".
142+ // described in RP2040 Datasheet, release 2.1, section "4.1.2.5.1. Concurrent access".!
139143 // We write everything except the START_TRANS bit first, then wait some cycles.
140144 usb_hw -> sie_ctrl = sie_ctrl ;
141145 busy_wait_at_least_cycles (12 );
142146 usb_hw -> sie_ctrl = sie_ctrl | USB_SIE_CTRL_START_TRANS_BITS ;
143147}
144148
145- TU_ATTR_ALWAYS_INLINE static inline void epx_start_xfer (hw_endpoint_t * ep , bool is_setup ) {
146- usb_hw -> dev_addr_ctrl = (uint32_t )(ep -> dev_addr | (tu_edpt_number (ep -> ep_addr ) << USB_ADDR_ENDP_ENDPOINT_LSB ));
147- sie_start_xfer (is_setup , tu_edpt_dir (ep -> ep_addr ) == TUSB_DIR_IN , ep -> need_pre );
148- }
149-
150149// prepare epx_ctrl register for new endpoint
151- TU_ATTR_ALWAYS_INLINE static inline void epx_ctrl_prepare (hw_endpoint_t * ep ) {
152- // RP2040-E4: USB host writes status to the upper half of buffer control in single buffered mode.
153- // The buffer selector toggles even in single-buffered mode, so the previous transfer's status
154- // may have been written to BUF1 half, leaving BUF0 with a stale AVAILABLE bit. Clear it here.
155- #if defined(PICO_RP2040 ) && PICO_RP2040 == 1
156- usbh_dpram -> epx_buf_ctrl = 0 ;
157- #endif
158-
159- // ep control
160- const uint32_t ep_ctrl = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER |
161- ((uint32_t )ep -> transfer_type << EP_CTRL_BUFFER_TYPE_LSB ) | hw_data_offset (ep -> dpram_buf );
162- usbh_dpram -> epx_ctrl = ep_ctrl ;
150+ TU_ATTR_ALWAYS_INLINE static inline void epx_ctrl_prepare (uint8_t transfer_type ) {
151+ usbh_dpram -> epx_ctrl = EPX_CTRL_DEFAULT | ((uint32_t )transfer_type << EP_CTRL_BUFFER_TYPE_LSB );
163152}
164153
165154// Save buffer context for EPX preemption (called after STOP_TRANS).
@@ -196,44 +185,43 @@ static void __tusb_irq_path_func(epx_save_context)(hw_endpoint_t *ep) {
196185
197186 usbh_dpram -> epx_buf_ctrl = 0 ;
198187
199- ep -> pending = 1 ;
200- ep -> active = false;
188+ ep -> state = EPSTATE_PENDING ;
201189}
202190
203- // All non-interrupt endpoints use shared EPX.
204- // Save the current EPX context, mark pending, switch to ep
191+ // switch epx to new endpoint and start the transfer
205192static void __tusb_irq_path_func (epx_switch_ep )(hw_endpoint_t * ep ) {
206- const bool is_setup = (ep -> pending == 2 );
193+ const bool is_setup = (ep -> state == EPSTATE_PENDING_SETUP );
207194
208- epx = ep ; // switch pointer
209- ep -> pending = 0 ;
210- ep -> active = true;
195+ epx = ep ; // switch pointer
196+ ep -> state = EPSTATE_ACTIVE ;
211197
212198 if (is_setup ) {
213199 // panic("new setup \n");
214- epx_start_xfer (ep , true);
200+ usb_hw -> dev_addr_ctrl = ep -> dev_addr ;
201+ sie_start_xfer (true, false, ep -> need_pre );
215202 } else {
216- io_rw_32 * ep_reg = & usbh_dpram -> epx_ctrl ;
203+ const bool is_rx = (tu_edpt_dir (ep -> ep_addr ) == TUSB_DIR_IN );
204+ io_rw_32 * ep_reg = & usbh_dpram -> epx_ctrl ;
217205 io_rw_32 * buf_reg = & usbh_dpram -> epx_buf_ctrl ;
218206
219- epx_ctrl_prepare (ep );
220- rp2usb_buffer_start (ep , ep_reg , buf_reg , tu_edpt_dir (ep -> ep_addr ) == TUSB_DIR_IN ,
221- ep -> transfer_type == TUSB_XFER_INTERRUPT );
207+ epx_ctrl_prepare (ep -> transfer_type );
208+ rp2usb_buffer_start (ep , ep_reg , buf_reg , is_rx , false);
222209
223- epx_start_xfer (ep , false);
210+ usb_hw -> dev_addr_ctrl = (uint32_t )(ep -> dev_addr | (tu_edpt_number (ep -> ep_addr ) << USB_ADDR_ENDP_ENDPOINT_LSB ));
211+ sie_start_xfer (is_setup , is_rx , ep -> need_pre );
224212 }
225213}
226214
227215// Round-robin find next pending ep after current epx
228216static hw_endpoint_t * __tusb_irq_path_func (epx_next_pending )(hw_endpoint_t * cur_ep ) {
229217 const uint cur_idx = (uint )(cur_ep - & ep_pool [0 ]);
230218 for (uint i = cur_idx + 1 ; i < TU_ARRAY_SIZE (ep_pool ); i ++ ) {
231- if (ep_pool [i ].pending ) {
219+ if (ep_pool [i ].state >= EPSTATE_PENDING ) {
232220 return & ep_pool [i ];
233221 }
234222 }
235223 for (uint i = 0 ; i < cur_idx ; i ++ ) {
236- if (ep_pool [i ].pending ) {
224+ if (ep_pool [i ].state >= EPSTATE_PENDING ) {
237225 return & ep_pool [i ];
238226 }
239227 }
@@ -246,7 +234,7 @@ static hw_endpoint_t *__tusb_irq_path_func(epx_next_pending)(hw_endpoint_t *cur_
246234//--------------------------------------------------------------------+
247235static void __tusb_irq_path_func (xfer_complete_isr )(hw_endpoint_t * ep , xfer_result_t xfer_result , bool is_more ) {
248236 // Mark transfer as done before we tell the tinyusb stack
249- uint xferred_len = ep -> xferred_len ;
237+ uint32_t xferred_len = ep -> xferred_len ;
250238 rp2usb_reset_transfer (ep );
251239 hcd_event_xfer_complete (ep -> dev_addr , ep -> ep_addr , xferred_len , xfer_result , true);
252240
@@ -345,7 +333,7 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) {
345333
346334 // Even if STOP_TRANS bit is clear, controller maybe in middle of retrying and may re-raise timeout once extra time
347335 // Only handle if epx is active, don't carry more epx transfer since STOP_TRANS is raced and not safe.
348- if (epx -> active ) {
336+ if (epx -> state == EPSTATE_ACTIVE ) {
349337 xfer_complete_isr (epx , XFER_RESULT_FAILED , false);
350338 }
351339 }
@@ -392,7 +380,7 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) {
392380 usb_hw_clear -> inte = USB_INTE_HOST_SOF_BITS ;
393381 usb_hw -> nak_poll = USB_NAK_POLL_RESET ;
394382 epx_switch_request = false;
395- } else if (epx -> active ) {
383+ } else if (epx -> state == EPSTATE_ACTIVE ) {
396384 if (epx_switch_request ) {
397385 // Second SOF with no transfer completion: endpoint is NAK-retrying, safe to switch.
398386 epx_switch_request = false;
@@ -498,7 +486,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
498486
499487 // reset epx if it is currently active with unplugged device
500488 if (epx -> max_packet_size > 0 && epx -> dev_addr == dev_addr ) {
501- // if (epx->active ) {
489+ // if (epx->state == EPSTATE_ACTIVE ) {
502490 // // need to abort transfer
503491 // }
504492 epx -> max_packet_size = 0 ;
@@ -507,7 +495,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
507495 for (size_t i = 0 ; i < TU_ARRAY_SIZE (ep_pool ); i ++ ) {
508496 hw_endpoint_t * ep = & ep_pool [i ];
509497 if (ep -> dev_addr == dev_addr && ep -> max_packet_size > 0 ) {
510- ep -> pending = 0 ; // clear any pending transfer
498+ ep -> state = EPSTATE_IDLE ; // clear any pending transfer
511499
512500 if (ep -> interrupt_num ) {
513501 // disable interrupt endpoint
@@ -642,10 +630,10 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
642630
643631 // If EPX is busy with another transfer, mark as pending
644632 rp2usb_critical_enter ();
645- if (epx -> active ) {
633+ if (epx -> state == EPSTATE_ACTIVE ) {
646634 ep -> user_buf = buffer ;
647635 ep -> remaining_len = buflen ;
648- ep -> pending = 1 ;
636+ ep -> state = EPSTATE_PENDING ;
649637
650638 #ifdef HAS_STOP_EPX_ON_NAK
651639 usb_hw_set -> nak_poll = USB_NAK_POLL_STOP_EPX_ON_NAK_BITS ;
@@ -660,9 +648,10 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
660648
661649 epx = ep ;
662650
663- epx_ctrl_prepare (ep );
651+ epx_ctrl_prepare (ep -> transfer_type );
664652 rp2usb_xfer_start (ep , ep_reg , buf_reg , buffer , NULL , buflen ); // prepare bufctrl
665- epx_start_xfer (ep , false);
653+ usb_hw -> dev_addr_ctrl = (uint32_t )(ep -> dev_addr | (tu_edpt_number (ep -> ep_addr ) << USB_ADDR_ENDP_ENDPOINT_LSB ));
654+ sie_start_xfer (false, tu_edpt_dir (ep -> ep_addr ) == TUSB_DIR_IN , ep -> need_pre );
666655 }
667656 rp2usb_critical_exit ();
668657 }
@@ -688,18 +677,20 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, const uint8_t setup_packet
688677 ep -> xferred_len = 0 ;
689678
690679 // If EPX is busy, mark as pending setup (DPRAM already has the packet)
691- if (epx -> active ) {
692- ep -> pending = 2 ; // setup
680+ if (epx -> state == EPSTATE_ACTIVE ) {
681+ ep -> state = EPSTATE_PENDING_SETUP ;
693682 #ifdef HAS_STOP_EPX_ON_NAK
694683 usb_hw_set -> nak_poll = USB_NAK_POLL_STOP_EPX_ON_NAK_BITS ;
695684 #else
696685 usb_hw -> nak_poll = (300 << USB_NAK_POLL_DELAY_FS_LSB ) | (300 << USB_NAK_POLL_DELAY_LS_LSB );
697686 usb_hw_set -> inte = USB_INTE_HOST_SOF_BITS ;
698687 #endif
699688 } else {
700- epx = ep ;
701- ep -> active = true;
702- epx_start_xfer (ep , true);
689+ epx = ep ;
690+ ep -> state = EPSTATE_ACTIVE ;
691+
692+ usb_hw -> dev_addr_ctrl = ep -> dev_addr ;
693+ sie_start_xfer (true, tu_edpt_dir (ep -> ep_addr ) == TUSB_DIR_IN , ep -> need_pre );
703694 }
704695
705696 rp2usb_critical_exit ();
0 commit comments