3939#define DWC2_DEBUG 2
4040
4141#include "device/dcd.h"
42+ #include "device/usbd_pvt.h"
4243#include "dwc2_common.h"
4344
44- #if TU_CHECK_MCU (OPT_MCU_GD32VF103 )
45- #define DWC2_EP_COUNT (_dwc2 ) DWC2_EP_MAX
46- #else
47- #define DWC2_EP_COUNT (_dwc2 ) ((_dwc2)->ghwcfg2_bm.num_dev_ep + 1)
48- #endif
49-
5045//--------------------------------------------------------------------+
5146// MACRO TYPEDEF CONSTANT ENUM
5247//--------------------------------------------------------------------+
@@ -58,6 +53,7 @@ typedef struct {
5853 uint8_t interval ;
5954} xfer_ctl_t ;
6055
56+ // This variable is modified from ISR context, so it must be protected by critical section
6157static xfer_ctl_t xfer_status [DWC2_EP_MAX ][2 ];
6258#define XFER_CTL_BASE (_ep , _dir ) (&xfer_status[_ep][_dir])
6359
@@ -79,6 +75,16 @@ CFG_TUD_MEM_SECTION static struct {
7975 TUD_EPBUF_DEF (setup_packet , 8 );
8076} _dcd_usbbuf ;
8177
78+ TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_ep_count (const dwc2_regs_t * dwc2 ) {
79+ #if TU_CHECK_MCU (OPT_MCU_GD32VF103 )
80+ return DWC2_EP_MAX ;
81+ #else
82+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2 -> ghwcfg2 };
83+ return ghwcfg2 .num_dev_ep + 1 ;
84+ #endif
85+ }
86+
87+
8288//--------------------------------------------------------------------
8389// DMA
8490//--------------------------------------------------------------------
@@ -102,7 +108,8 @@ bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
102108TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled (const dwc2_regs_t * dwc2 ) {
103109 (void ) dwc2 ;
104110 // Internal DMA only
105- return CFG_TUD_DWC2_DMA_ENABLE && dwc2 -> ghwcfg2_bm .arch == GHWCFG2_ARCH_INTERNAL_DMA ;
111+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2 -> ghwcfg2 };
112+ return CFG_TUD_DWC2_DMA_ENABLE && ghwcfg2 .arch == GHWCFG2_ARCH_INTERNAL_DMA ;
106113}
107114
108115static void dma_setup_prepare (uint8_t rhport ) {
@@ -261,20 +268,15 @@ static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint
261268 xfer -> interval = p_endpoint_desc -> bInterval ;
262269
263270 // Endpoint control
264- union {
265- uint32_t value ;
266- dwc2_depctl_t bm ;
267- } depctl ;
268- depctl .value = 0 ;
269-
270- depctl .bm .mps = xfer -> max_size ;
271- depctl .bm .active = 1 ;
272- depctl .bm .type = p_endpoint_desc -> bmAttributes .xfer ;
271+ dwc2_depctl_t depctl = {.value = 0 };
272+ depctl .mps = xfer -> max_size ;
273+ depctl .active = 1 ;
274+ depctl .type = p_endpoint_desc -> bmAttributes .xfer ;
273275 if (p_endpoint_desc -> bmAttributes .xfer != TUSB_XFER_ISOCHRONOUS ) {
274- depctl .bm . set_data0_iso_even = 1 ;
276+ depctl .set_data0_iso_even = 1 ;
275277 }
276278 if (dir == TUSB_DIR_IN ) {
277- //depctl.bm. tx_fifo_num = epnum;
279+ //depctl.tx_fifo_num = epnum;
278280 uint8_t fifo_num = epnum ;
279281#if TU_CHECK_MCU (OPT_MCU_ESP32S2 , OPT_MCU_ESP32S3 )
280282 // Special Case for EP5, which is used by CDC but not actually called by the driver
@@ -285,7 +287,7 @@ static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint
285287 fifo_num = get_free_fifo ();
286288 }
287289#endif
288- depctl .bm . tx_fifo_num = fifo_num ;
290+ depctl .tx_fifo_num = fifo_num ;
289291 }
290292
291293 dwc2_dep_t * dep = & dwc2 -> ep [dir == TUSB_DIR_IN ? 0 : 1 ][epnum ];
@@ -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 );
@@ -365,31 +370,22 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
365370 }
366371
367372 // transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC.
368- union {
369- uint32_t value ;
370- dwc2_ep_tsize_t bm ;
371- } deptsiz ;
372- deptsiz .value = 0 ;
373- deptsiz .bm .xfer_size = total_bytes ;
374- deptsiz .bm .packet_count = num_packets ;
375-
373+ dwc2_ep_tsize_t deptsiz = {.value = 0 };
374+ deptsiz .xfer_size = total_bytes ;
375+ deptsiz .packet_count = num_packets ;
376376 dep -> tsiz = deptsiz .value ;
377377
378378 // control
379- union {
380- dwc2_depctl_t bm ;
381- uint32_t value ;
382- } depctl ;
383- depctl .value = dep -> ctl ;
384-
385- depctl .bm .clear_nak = 1 ;
386- depctl .bm .enable = 1 ;
387- if (depctl .bm .type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer -> interval == 1 ) {
388- const uint32_t odd_now = (dwc2 -> dsts_bm .frame_number & 1u );
379+ dwc2_depctl_t depctl = {.value = dep -> ctl };
380+ depctl .clear_nak = 1 ;
381+ depctl .enable = 1 ;
382+ if (depctl .type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer -> interval == 1 ) {
383+ const dwc2_dsts_t dsts = {.value = dwc2 -> dsts };
384+ const uint32_t odd_now = dsts .frame_number & 1u ;
389385 if (odd_now ) {
390- depctl .bm . set_data0_iso_even = 1 ;
386+ depctl .set_data0_iso_even = 1 ;
391387 } else {
392- depctl .bm . set_data1_iso_odd = 1 ;
388+ depctl .set_data1_iso_odd = 1 ;
393389 }
394390 }
395391
@@ -432,7 +428,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
432428
433429 // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required
434430 // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347)
435- if (dwc2 -> ghwcfg2_bm .hs_phy_type == GHWCFG2_HSPHY_ULPI ) {
431+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2 -> ghwcfg2 };
432+ if (ghwcfg2 .hs_phy_type == GHWCFG2_HSPHY_ULPI ) {
436433 dcfg |= DCFG_XCVRDLY ;
437434 }
438435 } else {
@@ -561,6 +558,8 @@ void dcd_edpt_close_all(uint8_t rhport) {
561558 dwc2_regs_t * dwc2 = DWC2_REG (rhport );
562559 uint8_t const ep_count = _dwc2_controller [rhport ].ep_count ;
563560
561+ usbd_spin_lock (false);
562+
564563 _dcd_data .allocated_epin_count = 0 ;
565564
566565 // Disable non-control interrupt
@@ -582,8 +581,9 @@ void dcd_edpt_close_all(uint8_t rhport) {
582581
583582 dfifo_flush_tx (dwc2 , 0x10 ); // all tx fifo
584583 dfifo_flush_rx (dwc2 );
585-
586584 dfifo_device_init (rhport ); // re-init dfifo
585+
586+ usbd_spin_unlock (false);
587587}
588588
589589bool dcd_edpt_iso_alloc (uint8_t rhport , uint8_t ep_addr , uint16_t largest_packet_size ) {
@@ -601,21 +601,31 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpo
601601bool dcd_edpt_xfer (uint8_t rhport , uint8_t ep_addr , uint8_t * buffer , uint16_t total_bytes ) {
602602 uint8_t const epnum = tu_edpt_number (ep_addr );
603603 uint8_t const dir = tu_edpt_dir (ep_addr );
604-
605604 xfer_ctl_t * xfer = XFER_CTL_BASE (epnum , dir );
606- xfer -> buffer = buffer ;
607- xfer -> ff = NULL ;
608- xfer -> total_len = total_bytes ;
605+ bool ret ;
609606
610- // EP0 can only handle one packet
611- if (epnum == 0 ) {
612- _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;
613624 }
614625
615- // Schedule packets to be sent within interrupt
616- edpt_schedule_packets (rhport , epnum , dir );
626+ usbd_spin_unlock (false);
617627
618- return true ;
628+ return ret ;
619629}
620630
621631// The number of bytes has to be given explicitly to allow more flexible control of how many
@@ -628,17 +638,27 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
628638
629639 uint8_t const epnum = tu_edpt_number (ep_addr );
630640 uint8_t const dir = tu_edpt_dir (ep_addr );
631-
632641 xfer_ctl_t * xfer = XFER_CTL_BASE (epnum , dir );
633- xfer -> buffer = NULL ;
634- xfer -> ff = ff ;
635- xfer -> total_len = total_bytes ;
642+ bool ret ;
636643
637- // Schedule packets to be sent within interrupt
638- // TODO xfer fifo may only available for slave mode
639- edpt_schedule_packets (rhport , epnum , dir );
644+ usbd_spin_lock (false);
640645
641- 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 ;
642662}
643663
644664void dcd_edpt_stall (uint8_t rhport , uint8_t ep_addr ) {
@@ -665,9 +685,10 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
665685//--------------------------------------------------------------------
666686
667687// 7.4.1 Initialization on USB Reset
688+ // Must be called from critical section
668689static void handle_bus_reset (uint8_t rhport ) {
669690 dwc2_regs_t * dwc2 = DWC2_REG (rhport );
670- const uint8_t ep_count = DWC2_EP_COUNT (dwc2 );
691+ const uint8_t ep_count = dwc2_ep_count (dwc2 );
671692
672693 tu_memclr (xfer_status , sizeof (xfer_status ));
673694
@@ -697,7 +718,9 @@ static void handle_bus_reset(uint8_t rhport) {
697718 dfifo_device_init (rhport );
698719
699720 // 5. Reset device address
700- dwc2 -> dcfg_bm .address = 0 ;
721+ dwc2_dcfg_t dcfg = {.value = dwc2 -> dcfg };
722+ dcfg .address = 0 ;
723+ dwc2 -> dcfg = dcfg .value ;
701724
702725 // Fixed both control EP0 size to 64 bytes
703726 dwc2 -> epin [0 ].ctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos );
@@ -717,8 +740,9 @@ static void handle_bus_reset(uint8_t rhport) {
717740
718741static void handle_enum_done (uint8_t rhport ) {
719742 dwc2_regs_t * dwc2 = DWC2_REG (rhport );
743+ const dwc2_dsts_t dsts = {.value = dwc2 -> dsts };
720744 tusb_speed_t speed ;
721- switch (dwc2 -> dsts_bm .enum_speed ) {
745+ switch (dsts .enum_speed ) {
722746 case DCFG_SPEED_HIGH :
723747 speed = TUSB_SPEED_HIGH ;
724748 break ;
@@ -763,12 +787,12 @@ static void handle_rxflvl_irq(uint8_t rhport) {
763787 const volatile uint32_t * rx_fifo = dwc2 -> fifo [0 ];
764788
765789 // Pop control word off FIFO
766- const dwc2_grxstsp_t grxstsp_bm = dwc2 -> grxstsp_bm ;
767- const uint8_t epnum = grxstsp_bm .ep_ch_num ;
790+ const dwc2_grxstsp_t grxstsp = {. value = dwc2 -> grxstsp } ;
791+ const uint8_t epnum = grxstsp .ep_ch_num ;
768792
769793 dwc2_dep_t * epout = & dwc2 -> epout [epnum ];
770794
771- switch (grxstsp_bm .packet_status ) {
795+ switch (grxstsp .packet_status ) {
772796 case GRXSTS_PKTSTS_GLOBAL_OUT_NAK :
773797 // Global OUT NAK: do nothing
774798 break ;
@@ -790,7 +814,7 @@ static void handle_rxflvl_irq(uint8_t rhport) {
790814
791815 case GRXSTS_PKTSTS_RX_DATA : {
792816 // Out packet received
793- const uint16_t byte_count = grxstsp_bm .byte_count ;
817+ const uint16_t byte_count = grxstsp .byte_count ;
794818 xfer_ctl_t * xfer = XFER_CTL_BASE (epnum , TUSB_DIR_OUT );
795819
796820 if (byte_count ) {
@@ -804,7 +828,8 @@ static void handle_rxflvl_irq(uint8_t rhport) {
804828
805829 // short packet, minus remaining bytes (xfer_size)
806830 if (byte_count < xfer -> max_size ) {
807- xfer -> total_len -= epout -> tsiz_bm .xfer_size ;
831+ const dwc2_ep_tsize_t tsiz = {.value = epout -> tsiz };
832+ xfer -> total_len -= tsiz .xfer_size ;
808833 if (epnum == 0 ) {
809834 xfer -> total_len -= _dcd_data .ep0_pending [TUSB_DIR_OUT ];
810835 _dcd_data .ep0_pending [TUSB_DIR_OUT ] = 0 ;
@@ -866,11 +891,13 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
866891 // - 64 bytes or
867892 // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL)
868893 if (diepint_bm .txfifo_empty && (dwc2 -> diepempmsk & (1 << epnum ))) {
869- const uint16_t remain_packets = epin -> tsiz_bm .packet_count ;
894+ dwc2_ep_tsize_t tsiz = {.value = epin -> tsiz };
895+ const uint16_t remain_packets = tsiz .packet_count ;
870896
871897 // Process every single packet (only whole packets can be written to fifo)
872898 for (uint16_t i = 0 ; i < remain_packets ; i ++ ) {
873- const uint16_t remain_bytes = (uint16_t ) epin -> tsiz_bm .xfer_size ;
899+ tsiz .value = epin -> tsiz ;
900+ const uint16_t remain_bytes = (uint16_t ) tsiz .xfer_size ;
874901 const uint16_t xact_bytes = tu_min16 (remain_bytes , xfer -> max_size );
875902
876903 // Check if dtxfsts has enough space available
@@ -889,7 +916,8 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
889916 }
890917
891918 // Turn off TXFE if all bytes are written.
892- if (epin -> tsiz_bm .xfer_size == 0 ) {
919+ tsiz .value = epin -> tsiz ;
920+ if (tsiz .xfer_size == 0 ) {
893921 dwc2 -> diepempmsk &= ~(1 << epnum );
894922 }
895923 }
@@ -920,7 +948,8 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
920948 xfer_ctl_t * xfer = XFER_CTL_BASE (epnum , TUSB_DIR_OUT );
921949
922950 // determine actual received bytes
923- const uint16_t remain = epout -> tsiz_bm .xfer_size ;
951+ const dwc2_ep_tsize_t tsiz = {.value = epout -> tsiz };
952+ const uint16_t remain = tsiz .xfer_size ;
924953 xfer -> total_len -= remain ;
925954
926955 // this is ZLP, so prepare EP0 for next setup
@@ -956,7 +985,7 @@ static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepin
956985static void handle_ep_irq (uint8_t rhport , uint8_t dir ) {
957986 dwc2_regs_t * dwc2 = DWC2_REG (rhport );
958987 const bool is_dma = dma_device_enabled (dwc2 );
959- const uint8_t ep_count = DWC2_EP_COUNT (dwc2 );
988+ const uint8_t ep_count = dwc2_ep_count (dwc2 );
960989 const uint8_t daint_offset = (dir == TUSB_DIR_IN ) ? DAINT_IEPINT_Pos : DAINT_OEPINT_Pos ;
961990 dwc2_dep_t * ep_base = & dwc2 -> ep [dir == TUSB_DIR_IN ? 0 : 1 ][0 ];
962991
@@ -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