3939#define DWC2_DEBUG 2
4040
4141#include "device/dcd.h"
42+ #include "device/usbd_pvt.h"
4243#include "dwc2_common.h"
4344
4445//--------------------------------------------------------------------+
@@ -52,6 +53,7 @@ typedef struct {
5253 uint8_t interval ;
5354} xfer_ctl_t ;
5455
56+ // This variable is modified from ISR context, so it must be protected by critical section
5557static xfer_ctl_t xfer_status [DWC2_EP_MAX ][2 ];
5658#define XFER_CTL_BASE (_ep , _dir ) (&xfer_status[_ep][_dir])
5759
@@ -343,6 +345,9 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
343345 }
344346}
345347
348+ // Since this function returns void, it is not possible to return a boolean success message
349+ // We must make sure that this function is not called when the EP is disabled
350+ // Must be called from critical section
346351static void edpt_schedule_packets (uint8_t rhport , const uint8_t epnum , const uint8_t dir ) {
347352 dwc2_regs_t * dwc2 = DWC2_REG (rhport );
348353 xfer_ctl_t * const xfer = XFER_CTL_BASE (epnum , dir );
@@ -553,6 +558,8 @@ void dcd_edpt_close_all(uint8_t rhport) {
553558 dwc2_regs_t * dwc2 = DWC2_REG (rhport );
554559 uint8_t const ep_count = _dwc2_controller [rhport ].ep_count ;
555560
561+ usbd_spin_lock (false);
562+
556563 _dcd_data .allocated_epin_count = 0 ;
557564
558565 // Disable non-control interrupt
@@ -574,8 +581,9 @@ void dcd_edpt_close_all(uint8_t rhport) {
574581
575582 dfifo_flush_tx (dwc2 , 0x10 ); // all tx fifo
576583 dfifo_flush_rx (dwc2 );
577-
578584 dfifo_device_init (rhport ); // re-init dfifo
585+
586+ usbd_spin_unlock (false);
579587}
580588
581589bool dcd_edpt_iso_alloc (uint8_t rhport , uint8_t ep_addr , uint16_t largest_packet_size ) {
@@ -593,21 +601,31 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpo
593601bool dcd_edpt_xfer (uint8_t rhport , uint8_t ep_addr , uint8_t * buffer , uint16_t total_bytes ) {
594602 uint8_t const epnum = tu_edpt_number (ep_addr );
595603 uint8_t const dir = tu_edpt_dir (ep_addr );
596-
597604 xfer_ctl_t * xfer = XFER_CTL_BASE (epnum , dir );
598- xfer -> buffer = buffer ;
599- xfer -> ff = NULL ;
600- xfer -> total_len = total_bytes ;
605+ bool ret ;
601606
602- // EP0 can only handle one packet
603- if (epnum == 0 ) {
604- _dcd_data .ep0_pending [dir ] = total_bytes ;
607+ usbd_spin_lock (false);
608+
609+ if (xfer -> max_size == 0 ) {
610+ ret = false; // Endpoint is closed
611+ } else {
612+ xfer -> buffer = buffer ;
613+ xfer -> ff = NULL ;
614+ xfer -> total_len = total_bytes ;
615+
616+ // EP0 can only handle one packet
617+ if (epnum == 0 ) {
618+ _dcd_data .ep0_pending [dir ] = total_bytes ;
619+ }
620+
621+ // Schedule packets to be sent within interrupt
622+ edpt_schedule_packets (rhport , epnum , dir );
623+ ret = true;
605624 }
606625
607- // Schedule packets to be sent within interrupt
608- edpt_schedule_packets (rhport , epnum , dir );
626+ usbd_spin_unlock (false);
609627
610- return true ;
628+ return ret ;
611629}
612630
613631// The number of bytes has to be given explicitly to allow more flexible control of how many
@@ -620,17 +638,27 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
620638
621639 uint8_t const epnum = tu_edpt_number (ep_addr );
622640 uint8_t const dir = tu_edpt_dir (ep_addr );
623-
624641 xfer_ctl_t * xfer = XFER_CTL_BASE (epnum , dir );
625- xfer -> buffer = NULL ;
626- xfer -> ff = ff ;
627- xfer -> total_len = total_bytes ;
642+ bool ret ;
628643
629- // Schedule packets to be sent within interrupt
630- // TODO xfer fifo may only available for slave mode
631- edpt_schedule_packets (rhport , epnum , dir );
644+ usbd_spin_lock (false);
632645
633- return true;
646+ if (xfer -> max_size == 0 ) {
647+ ret = false; // Endpoint is closed
648+ } else {
649+ xfer -> buffer = NULL ;
650+ xfer -> ff = ff ;
651+ xfer -> total_len = total_bytes ;
652+
653+ // Schedule packets to be sent within interrupt
654+ // TODO xfer fifo may only available for slave mode
655+ edpt_schedule_packets (rhport , epnum , dir );
656+ ret = true;
657+ }
658+
659+ usbd_spin_unlock (false);
660+
661+ return ret ;
634662}
635663
636664void dcd_edpt_stall (uint8_t rhport , uint8_t ep_addr ) {
@@ -657,6 +685,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
657685//--------------------------------------------------------------------
658686
659687// 7.4.1 Initialization on USB Reset
688+ // Must be called from critical section
660689static void handle_bus_reset (uint8_t rhport ) {
661690 dwc2_regs_t * dwc2 = DWC2_REG (rhport );
662691 const uint8_t ep_count = dwc2_ep_count (dwc2 );
@@ -1009,7 +1038,6 @@ static void handle_ep_irq(uint8_t rhport, uint8_t dir) {
10091038 */
10101039void dcd_int_handler (uint8_t rhport ) {
10111040 dwc2_regs_t * dwc2 = DWC2_REG (rhport );
1012-
10131041 const uint32_t gintmask = dwc2 -> gintmsk ;
10141042 const uint32_t gintsts = dwc2 -> gintsts & gintmask ;
10151043
@@ -1019,7 +1047,10 @@ void dcd_int_handler(uint8_t rhport) {
10191047#if TU_CHECK_MCU (OPT_MCU_ESP32S2 , OPT_MCU_ESP32S3 )
10201048 _allocated_fifos = 1 ;
10211049#endif
1050+
1051+ usbd_spin_lock (true);
10221052 handle_bus_reset (rhport );
1053+ usbd_spin_unlock (true);
10231054 }
10241055
10251056 if (gintsts & GINTSTS_ENUMDNE ) {
0 commit comments