@@ -58,15 +58,18 @@ typedef union {
5858 volatile uint32_t u32 ;
5959} hw_fifo_t ;
6060
61- typedef struct TU_ATTR_PACKED
62- {
63- void * buf ; /* the start address of a transfer data buffer */
61+ typedef struct {
62+ union {
63+ uint8_t * buf ; /* the start address of a transfer data buffer */
64+ tu_fifo_t * fifo ;
65+ };
6466 uint16_t length ; /* the number of bytes in the buffer */
6567 uint16_t remaining ; /* the number of bytes remaining in the buffer */
68+ bool armed ; /* true while a transfer is posted */
69+ bool use_fifo ; /* true: buf is tu_fifo_t*; false: buf is plain byte pointer. */
6670} pipe_state_t ;
6771
68- typedef struct
69- {
72+ typedef struct {
7073 union {
7174 tusb_control_request_t setup_packet ;
7275 uint32_t setup_buffer [2 ];
@@ -75,7 +78,6 @@ typedef struct
7578 int8_t status_out ;
7679 pipe_state_t pipe0 ;
7780 pipe_state_t pipe [2 ][TUP_DCD_ENDPOINT_MAX - 1 ]; /* pipe[direction][endpoint number - 1] */
78- uint16_t pipe_buf_is_fifo [2 ]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */
7981} dcd_data_t ;
8082
8183static dcd_data_t _dcd ;
@@ -197,22 +199,21 @@ static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr) {
197199
198200 if (rem == 0 && pipe -> length > 0 ) {
199201 pipe -> buf = NULL ;
202+ pipe -> armed = false;
200203 return true;
201204 }
202205
203206 musb_regs_t * musb_regs = MUSB_REGS (rhport );
204207 musb_ep_csr_t * ep_csr = get_ep_csr (musb_regs , epnum );
205208 const unsigned mps = ep_csr -> tx_maxp ;
206209 const unsigned len = TU_MIN (mps , rem );
207- void * buf = pipe -> buf ;
208210 volatile void * fifo_ptr = & musb_regs -> fifo [epnum ];
209- // TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem);
210211 if (len ) {
211- if (_dcd . pipe_buf_is_fifo [ TUSB_DIR_IN ] & TU_BIT ( epnum_minus1 ) ) {
212- tu_hwfifo_write_from_fifo (fifo_ptr , ( tu_fifo_t * ) buf , len , NULL );
212+ if (pipe -> use_fifo ) {
213+ tu_hwfifo_write_from_fifo (fifo_ptr , pipe -> fifo , len , NULL );
213214 } else {
214- tu_hwfifo_write (fifo_ptr , buf , len , NULL );
215- pipe -> buf = ( uint8_t * ) buf + len ;
215+ tu_hwfifo_write (fifo_ptr , pipe -> buf , len , NULL );
216+ pipe -> buf += len ;
216217 }
217218 pipe -> remaining = rem - len ;
218219 }
@@ -231,11 +232,17 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr)
231232 // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, ep_csr->rx_csrl);
232233
233234 //Fail gracefully. Spurious interrupt.
234- if (!(ep_csr -> rx_csrl & MUSB_RXCSRL1_RXRDY )) return false;
235+ if (!(ep_csr -> rx_csrl & MUSB_RXCSRL1_RXRDY )) {
236+ return false;
237+ }
235238
236- void * buf = pipe -> buf ;
237- if (buf == NULL ) {
238- ep_csr -> rx_csrl = MUSB_RXCSRL1_FLUSH ;
239+ if (!pipe -> armed ) {
240+ // Packet is already ACK'd by hardware and sitting in the Rx FIFO, but no transfer is
241+ // posted. Do NOT flush (per MUSB spec §3.3.11 FlushFIFO) - that would silently drop
242+ // acknowledged data. Mask this endpoint's Rx interrupt so the ISR stops re-firing;
243+ // the FIFO stays occupied so hardware NAKs further OUT tokens (natural backpressure).
244+ // The next dcd_edpt_xfer() on this endpoint will drain the staged packet.
245+ musb_regs -> intr_rxen &= (uint16_t ) ~TU_BIT (epnum );
239246 return false;
240247 }
241248
@@ -245,40 +252,58 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr)
245252 const unsigned len = TU_MIN (TU_MIN (rem , mps ), vld );
246253 volatile void * fifo_ptr = & musb_regs -> fifo [epnum ];
247254 if (len ) {
248- if (_dcd . pipe_buf_is_fifo [ TUSB_DIR_OUT ] & TU_BIT ( epnum_minus1 ) ) {
249- tu_hwfifo_read_to_fifo (fifo_ptr , ( tu_fifo_t * ) buf , len , NULL );
255+ if (pipe -> use_fifo ) {
256+ tu_hwfifo_read_to_fifo (fifo_ptr , pipe -> fifo , len , NULL );
250257 } else {
251- tu_hwfifo_read (fifo_ptr , buf , len , NULL );
252- pipe -> buf = ( uint8_t * ) buf + len ;
258+ tu_hwfifo_read (fifo_ptr , pipe -> buf , len , NULL );
259+ pipe -> buf += len ;
253260 }
254261 pipe -> remaining = rem - len ;
255262 }
256263
257264 ep_csr -> rx_csrl = 0 ; /* Always Clear RXRDY bit */
258265 if ((len < mps ) || (rem == len )) {
259266 pipe -> buf = NULL ;
260- return NULL != buf ;
267+ pipe -> armed = false;
268+ return true;
261269 }
262270 return false;
263271}
264272
265- static bool edpt_n_xfer (uint8_t rhport , uint8_t ep_addr , uint8_t * buffer , uint16_t total_bytes )
273+ static bool edpt_n_xfer (uint8_t rhport , uint8_t ep_addr , void * buffer , uint16_t total_bytes , bool use_fifo )
266274{
267275 unsigned epnum = tu_edpt_number (ep_addr );
268276 unsigned epnum_minus1 = epnum - 1 ;
269277 unsigned dir_in = tu_edpt_dir (ep_addr );
270278
271279 pipe_state_t * pipe = & _dcd .pipe [dir_in ][epnum_minus1 ];
272- pipe -> buf = buffer ;
280+ if (use_fifo ) {
281+ pipe -> fifo = (tu_fifo_t * ) buffer ;
282+ } else {
283+ pipe -> buf = (uint8_t * ) buffer ;
284+ }
273285 pipe -> length = total_bytes ;
274286 pipe -> remaining = total_bytes ;
287+ pipe -> use_fifo = use_fifo ;
288+ pipe -> armed = true;
275289
276290 if (dir_in ) {
277291 handle_xfer_in (rhport , ep_addr );
278292 } else {
279293 musb_regs_t * musb_regs = MUSB_REGS (rhport );
280294 musb_ep_csr_t * ep_csr = get_ep_csr (musb_regs , epnum );
281- if (ep_csr -> rx_csrl & MUSB_RXCSRL1_RXRDY ) ep_csr -> rx_csrl = 0 ;
295+
296+ // Re-enable Rx interrupt (may have been masked by the no-buffer path in handle_xfer_out)
297+ musb_regs -> intr_rxen |= (uint16_t ) TU_BIT (epnum );
298+
299+ // Drain any packet staged in the Rx FIFO from a prior no-buffer interrupt
300+ if (ep_csr -> rx_csrl & MUSB_RXCSRL1_RXRDY ) {
301+ if (handle_xfer_out (rhport , ep_addr )) {
302+ dcd_event_xfer_complete (rhport , ep_addr ,
303+ pipe -> length - pipe -> remaining ,
304+ XFER_RESULT_SUCCESS , false);
305+ }
306+ }
282307 }
283308 return true;
284309}
@@ -411,7 +436,7 @@ static void process_ep0(uint8_t rhport)
411436 return ;
412437 }
413438
414- /* When CSRL0 is zero, it means that completion of sending a any length packet
439+ /* When CSRL0 is zero, it means that completion of sending any length packet
415440 * or receiving a zero length packet. */
416441 if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir (req )) {
417442 /* STATUS IN */
@@ -611,6 +636,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
611636 pipe -> buf = NULL ;
612637 pipe -> length = 0 ;
613638 pipe -> remaining = 0 ;
639+ pipe -> armed = false;
614640
615641 musb_regs_t * musb = MUSB_REGS (rhport );
616642 musb_ep_csr_t * ep_csr = get_ep_csr (musb , epn );
@@ -656,6 +682,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc )
656682 pipe -> buf = NULL ;
657683 pipe -> length = 0 ;
658684 pipe -> remaining = 0 ;
685+ pipe -> armed = false;
659686
660687 musb_regs_t * musb = MUSB_REGS (rhport );
661688 musb_ep_csr_t * ep_csr = get_ep_csr (musb , epn );
@@ -722,13 +749,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
722749 musb_dcd_int_disable (rhport );
723750
724751 if (epnum ) {
725- _dcd .pipe_buf_is_fifo [tu_edpt_dir (ep_addr )] &= ~TU_BIT (epnum - 1 );
726- ret = edpt_n_xfer (rhport , ep_addr , buffer , total_bytes );
752+ ret = edpt_n_xfer (rhport , ep_addr , buffer , total_bytes , false);
727753 } else {
728754 ret = edpt0_xfer (rhport , ep_addr , buffer , total_bytes );
729755 }
730756
731- if (ie ) musb_dcd_int_enable (rhport );
757+ if (ie ) {
758+ musb_dcd_int_enable (rhport );
759+ }
732760 return ret ;
733761}
734762
@@ -744,8 +772,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
744772 TU_ASSERT (epnum );
745773 unsigned const ie = musb_dcd_get_int_enable (rhport );
746774 musb_dcd_int_disable (rhport );
747- _dcd .pipe_buf_is_fifo [tu_edpt_dir (ep_addr )] |= TU_BIT (epnum - 1 );
748- ret = edpt_n_xfer (rhport , ep_addr , (uint8_t * )ff , total_bytes );
775+ ret = edpt_n_xfer (rhport , ep_addr , ff , total_bytes , true);
749776 if (ie ) musb_dcd_int_enable (rhport );
750777 return ret ;
751778}
@@ -768,6 +795,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
768795 } else {
769796 const uint8_t is_rx = 1 - tu_edpt_dir (ep_addr );
770797 ep_csr -> maxp_csr [is_rx ].csrl = MUSB_CSRL_SEND_STALL (is_rx );
798+ _dcd .pipe [tu_edpt_dir (ep_addr )][epn - 1 ].armed = false;
771799 }
772800
773801 if (ie ) musb_dcd_int_enable (rhport );
0 commit comments