From 7d8433abab25734981f1b5eab3c5724a945df711 Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Mon, 7 Apr 2025 11:36:02 +0200 Subject: [PATCH 01/68] dwc2/host: enable disconnect interrupt + handle it Signed-off-by: Maxime Vincent --- src/portable/synopsys/dwc2/hcd_dwc2.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 7cbef05b7..4c3d23b65 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -381,7 +381,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { dwc2->hprt = HPRT_POWER; // turn on VBUS // Enable required interrupts - dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT; + dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT | GINTSTS_DISCINT; // NPTX can hold at least 2 packet, change interrupt level to half-empty uint32_t gahbcfg = dwc2->gahbcfg & ~GAHBCFG_TX_FIFO_EPMTY_LVL; @@ -1330,6 +1330,14 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { handle_channel_irq(rhport, in_isr); } + if (gintsts & GINTSTS_DISCINT) { + // Device disconnected + dwc2->gintsts = GINTSTS_DISCINT; + if (!(dwc2->hprt & HPRT_CONN_STATUS)) { + hcd_event_device_remove(rhport, in_isr); + } + } + #if CFG_TUH_DWC2_SLAVE_ENABLE // RxFIFO non-empty interrupt handling if (gintsts & GINTSTS_RXFLVL) { From 1be4171d2a00c2feed34e4e85582b4de3659e895 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Mon, 7 Apr 2025 23:30:10 +0200 Subject: [PATCH 02/68] Fix espressif build with presets. Signed-off-by: HiFiPhile --- hw/bsp/BoardPresets.json | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/hw/bsp/BoardPresets.json b/hw/bsp/BoardPresets.json index fee8f2c97..24da362da 100644 --- a/hw/bsp/BoardPresets.json +++ b/hw/bsp/BoardPresets.json @@ -12,21 +12,31 @@ "BOARD": "${presetName}" } }, + { + "name": "default single", + "hidden": true, + "description": "Configure preset for the ${presetName} board", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "BOARD": "${presetName}" + } + }, { "name": "adafruit_clue", "inherits": "default" }, { "name": "adafruit_feather_esp32_v2", - "inherits": "default" + "inherits": "default single" }, { "name": "adafruit_feather_esp32s2", - "inherits": "default" + "inherits": "default single" }, { "name": "adafruit_feather_esp32s3", - "inherits": "default" + "inherits": "default single" }, { "name": "adafruit_magtag_29gray", @@ -34,7 +44,7 @@ }, { "name": "adafruit_metro_esp32s2", - "inherits": "default" + "inherits": "default single" }, { "name": "apard32690", @@ -130,39 +140,39 @@ }, { "name": "espressif_addax_1", - "inherits": "default" + "inherits": "default single" }, { "name": "espressif_c3_devkitc", - "inherits": "default" + "inherits": "default single" }, { "name": "espressif_c6_devkitc", - "inherits": "default" + "inherits": "default single" }, { "name": "espressif_kaluga_1", - "inherits": "default" + "inherits": "default single" }, { "name": "espressif_p4_function_ev", - "inherits": "default" + "inherits": "default single" }, { "name": "espressif_s2_devkitc", - "inherits": "default" + "inherits": "default single" }, { "name": "espressif_s3_devkitc", - "inherits": "default" + "inherits": "default single" }, { "name": "espressif_s3_devkitm", - "inherits": "default" + "inherits": "default single" }, { "name": "espressif_saola_1", - "inherits": "default" + "inherits": "default single" }, { "name": "f1c100s", From 6607b76c761a3a64a7c43ceba27ae42cdb368e52 Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Tue, 8 Apr 2025 14:34:11 +0200 Subject: [PATCH 03/68] dwc2/host: remove hcd_event_device_remove() call from handle_hptr_irq to prevent double removal Signed-off-by: Maxime Vincent --- src/portable/synopsys/dwc2/hcd_dwc2.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 4c3d23b65..4aa42759f 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -1266,8 +1266,6 @@ static void handle_hprt_irq(uint8_t rhport, bool in_isr) { if (hprt_bm.conn_status) { hcd_event_device_attach(rhport, in_isr); - } else { - hcd_event_device_remove(rhport, in_isr); } } From 084c0802c310c836e0c3e972b724a5a0d17057ba Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Wed, 9 Apr 2025 01:31:16 +0200 Subject: [PATCH 04/68] dwc2: refactor bitfields. Signed-off-by: HiFiPhile --- src/portable/synopsys/dwc2/dcd_dwc2.c | 86 +-- src/portable/synopsys/dwc2/dwc2_common.c | 16 +- src/portable/synopsys/dwc2/dwc2_type.h | 945 +++++++++++------------ src/portable/synopsys/dwc2/hcd_dwc2.c | 202 +++-- 4 files changed, 643 insertions(+), 606 deletions(-) diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index c461d9a79..83ebc18cb 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -44,7 +44,7 @@ #if TU_CHECK_MCU(OPT_MCU_GD32VF103) #define DWC2_EP_COUNT(_dwc2) DWC2_EP_MAX #else - #define DWC2_EP_COUNT(_dwc2) ((_dwc2)->ghwcfg2_bm.num_dev_ep + 1) + #define DWC2_EP_COUNT(_dwc2) ({const dwc2_ghwcfg2_t ghwcfg2 = {.value = (_dwc2)->ghwcfg2}; ghwcfg2.num_dev_ep + 1;}) #endif //--------------------------------------------------------------------+ @@ -102,7 +102,8 @@ bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) { TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled(const dwc2_regs_t* dwc2) { (void) dwc2; // Internal DMA only - return CFG_TUD_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA; + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + return CFG_TUD_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA; } static void dma_setup_prepare(uint8_t rhport) { @@ -250,20 +251,15 @@ static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint xfer->interval = p_endpoint_desc->bInterval; // Endpoint control - union { - uint32_t value; - dwc2_depctl_t bm; - } depctl; - depctl.value = 0; - - depctl.bm.mps = xfer->max_size; - depctl.bm.active = 1; - depctl.bm.type = p_endpoint_desc->bmAttributes.xfer; + dwc2_depctl_t depctl = {.value = 0}; + depctl.mps = xfer->max_size; + depctl.active = 1; + depctl.type = p_endpoint_desc->bmAttributes.xfer; if (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) { - depctl.bm.set_data0_iso_even = 1; + depctl.set_data0_iso_even = 1; } if (dir == TUSB_DIR_IN) { - depctl.bm.tx_fifo_num = epnum; + depctl.tx_fifo_num = epnum; } dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum]; @@ -343,31 +339,22 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin } // transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC. - union { - uint32_t value; - dwc2_ep_tsize_t bm; - } deptsiz; - deptsiz.value = 0; - deptsiz.bm.xfer_size = total_bytes; - deptsiz.bm.packet_count = num_packets; - + dwc2_ep_tsize_t deptsiz = {.value = 0}; + deptsiz.xfer_size = total_bytes; + deptsiz.packet_count = num_packets; dep->tsiz = deptsiz.value; // control - union { - dwc2_depctl_t bm; - uint32_t value; - } depctl; - depctl.value = dep->ctl; - - depctl.bm.clear_nak = 1; - depctl.bm.enable = 1; - if (depctl.bm.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) { - const uint32_t odd_now = (dwc2->dsts_bm.frame_number & 1u); + dwc2_depctl_t depctl = {.value = dep->ctl}; + depctl.clear_nak = 1; + depctl.enable = 1; + if (depctl.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) { + const dwc2_dsts_t dsts = {.value = dwc2->dsts}; + const uint32_t odd_now = dsts.frame_number & 1u; if (odd_now) { - depctl.bm.set_data0_iso_even = 1; + depctl.set_data0_iso_even = 1; } else { - depctl.bm.set_data1_iso_odd = 1; + depctl.set_data1_iso_odd = 1; } } @@ -410,7 +397,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347) - if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) { + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + if (ghwcfg2.hs_phy_type == GHWCFG2_HSPHY_ULPI) { dcfg |= DCFG_XCVRDLY; } } else { @@ -671,7 +659,9 @@ static void handle_bus_reset(uint8_t rhport) { dfifo_device_init(rhport); // 5. Reset device address - dwc2->dcfg_bm.address = 0; + dwc2_dcfg_t dcfg = {.value = dwc2->dcfg}; + dcfg.address = 0; + dwc2->dcfg = dcfg.value; // Fixed both control EP0 size to 64 bytes dwc2->epin[0].ctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); @@ -691,8 +681,9 @@ static void handle_bus_reset(uint8_t rhport) { static void handle_enum_done(uint8_t rhport) { dwc2_regs_t *dwc2 = DWC2_REG(rhport); + const dwc2_dsts_t dsts = {.value = dwc2->dsts}; tusb_speed_t speed; - switch (dwc2->dsts_bm.enum_speed) { + switch (dsts.enum_speed) { case DCFG_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break; @@ -737,12 +728,12 @@ static void handle_rxflvl_irq(uint8_t rhport) { const volatile uint32_t* rx_fifo = dwc2->fifo[0]; // Pop control word off FIFO - const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm; - const uint8_t epnum = grxstsp_bm.ep_ch_num; + const dwc2_grxstsp_t grxstsp = {.value = dwc2->grxstsp}; + const uint8_t epnum = grxstsp.ep_ch_num; dwc2_dep_t* epout = &dwc2->epout[epnum]; - switch (grxstsp_bm.packet_status) { + switch (grxstsp.packet_status) { case GRXSTS_PKTSTS_GLOBAL_OUT_NAK: // Global OUT NAK: do nothing break; @@ -764,7 +755,7 @@ static void handle_rxflvl_irq(uint8_t rhport) { case GRXSTS_PKTSTS_RX_DATA: { // Out packet received - const uint16_t byte_count = grxstsp_bm.byte_count; + const uint16_t byte_count = grxstsp.byte_count; xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); if (byte_count) { @@ -778,7 +769,8 @@ static void handle_rxflvl_irq(uint8_t rhport) { // short packet, minus remaining bytes (xfer_size) if (byte_count < xfer->max_size) { - xfer->total_len -= epout->tsiz_bm.xfer_size; + const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz}; + xfer->total_len -= tsiz.xfer_size; if (epnum == 0) { xfer->total_len -= _dcd_data.ep0_pending[TUSB_DIR_OUT]; _dcd_data.ep0_pending[TUSB_DIR_OUT] = 0; @@ -840,11 +832,13 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep // - 64 bytes or // - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL) if (diepint_bm.txfifo_empty && (dwc2->diepempmsk & (1 << epnum))) { - const uint16_t remain_packets = epin->tsiz_bm.packet_count; + dwc2_ep_tsize_t tsiz = {.value = epin->tsiz}; + const uint16_t remain_packets = tsiz.packet_count; // Process every single packet (only whole packets can be written to fifo) for (uint16_t i = 0; i < remain_packets; i++) { - const uint16_t remain_bytes = (uint16_t) epin->tsiz_bm.xfer_size; + tsiz.value = epin->tsiz; + const uint16_t remain_bytes = (uint16_t) tsiz.xfer_size; const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size); // Check if dtxfsts has enough space available @@ -863,7 +857,8 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep } // Turn off TXFE if all bytes are written. - if (epin->tsiz_bm.xfer_size == 0) { + tsiz.value = epin->tsiz; + if (tsiz.xfer_size == 0) { dwc2->diepempmsk &= ~(1 << epnum); } } @@ -894,7 +889,8 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); // determine actual received bytes - const uint16_t remain = epout->tsiz_bm.xfer_size; + const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz}; + const uint16_t remain = tsiz.xfer_size; xfer->total_len -= remain; // this is ZLP, so prepare EP0 for next setup diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c index f80ae9acb..989a833ff 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.c +++ b/src/portable/synopsys/dwc2/dwc2_common.c @@ -88,11 +88,13 @@ static void phy_fs_init(dwc2_regs_t* dwc2) { static void phy_hs_init(dwc2_regs_t* dwc2) { uint32_t gusbcfg = dwc2->gusbcfg; + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + const dwc2_ghwcfg4_t ghwcfg4 = {.value = dwc2->ghwcfg4}; // De-select FS PHY gusbcfg &= ~GUSBCFG_PHYSEL; - if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) { + if (ghwcfg2.hs_phy_type == GHWCFG2_HSPHY_ULPI) { TU_LOG(DWC2_COMMON_DEBUG, "Highspeed ULPI PHY init\r\n"); // Select ULPI PHY (external) @@ -116,7 +118,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL; // Set 16-bit interface if supported - if (dwc2->ghwcfg4_bm.phy_data_width) { + if (ghwcfg4.phy_data_width) { gusbcfg |= GUSBCFG_PHYIF16; // 16 bit } else { gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit @@ -127,7 +129,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { dwc2->gusbcfg = gusbcfg; // mcu specific phy init - dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + dwc2_phy_init(dwc2, ghwcfg2.hs_phy_type); // Reset core after selecting PHY reset_core(dwc2); @@ -136,11 +138,11 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { // - 9 if using 8-bit PHY interface // - 5 if using 16-bit PHY interface gusbcfg &= ~GUSBCFG_TRDT_Msk; - gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos; + gusbcfg |= (ghwcfg4.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos; dwc2->gusbcfg = gusbcfg; // MCU specific PHY update post reset - dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + dwc2_phy_update(dwc2, ghwcfg2.hs_phy_type); } static bool check_dwc2(dwc2_regs_t* dwc2) { @@ -171,7 +173,7 @@ static bool check_dwc2(dwc2_regs_t* dwc2) { //-------------------------------------------------------------------- bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) { (void)dwc2; - + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; #if CFG_TUD_ENABLED if (role == TUSB_ROLE_DEVICE && !TUD_OPT_HIGH_SPEED) { return false; @@ -183,7 +185,7 @@ bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) { } #endif - return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED; + return ghwcfg2.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED; } /* dwc2 has several PHYs option diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 812096759..5ecf9d487 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -184,415 +184,470 @@ enum { //-------------------------------------------------------------------- // Common Register Bitfield //-------------------------------------------------------------------- -typedef struct TU_ATTR_PACKED { - uint32_t ses_req_scs : 1; // 0 Session request success - uint32_t ses_req : 1; // 1 Session request - uint32_t vbval_ov_en : 1; // 2 VBUS valid override enable - uint32_t vbval_ov_val : 1; // 3 VBUS valid override value - uint32_t aval_ov_en : 1; // 4 A-peripheral session valid override enable - uint32_t aval_ov_al : 1; // 5 A-peripheral session valid override value - uint32_t bval_ov_en : 1; // 6 B-peripheral session valid override enable - uint32_t bval_ov_val : 1; // 7 B-peripheral session valid override value - uint32_t hng_scs : 1; // 8 Host negotiation success - uint32_t hnp_rq : 1; // 9 HNP (host negotiation protocol) request - uint32_t host_set_hnp_en : 1; // 10 Host set HNP enable - uint32_t dev_hnp_en : 1; // 11 Device HNP enabled - uint32_t embedded_host_en : 1; // 12 Embedded host enable - uint32_t rsv13_14 : 2; // 13.14 Reserved - uint32_t dbnc_filter_bypass : 1; // 15 Debounce filter bypass - uint32_t cid_status : 1; // 16 Connector ID status - uint32_t dbnc_done : 1; // 17 Debounce done - uint32_t ases_valid : 1; // 18 A-session valid - uint32_t bses_valid : 1; // 19 B-session valid - uint32_t otg_ver : 1; // 20 OTG version 0: v1.3, 1: v2.0 - uint32_t current_mode : 1; // 21 Current mode of operation. Only from v3.00a - uint32_t mult_val_id_bc : 5; // 22..26 Multi-valued input pin ID battery charger - uint32_t chirp_en : 1; // 27 Chirp detection enable - uint32_t rsv28_30 : 3; // 28.30: Reserved - uint32_t test_mode_corr_eusb2 : 1; // 31 Test mode control for eUSB2 PHY +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t ses_req_scs : 1; // 0 Session request success + uint32_t ses_req : 1; // 1 Session request + uint32_t vbval_ov_en : 1; // 2 VBUS valid override enable + uint32_t vbval_ov_val : 1; // 3 VBUS valid override value + uint32_t aval_ov_en : 1; // 4 A-peripheral session valid override enable + uint32_t aval_ov_al : 1; // 5 A-peripheral session valid override value + uint32_t bval_ov_en : 1; // 6 B-peripheral session valid override enable + uint32_t bval_ov_val : 1; // 7 B-peripheral session valid override value + uint32_t hng_scs : 1; // 8 Host negotiation success + uint32_t hnp_rq : 1; // 9 HNP (host negotiation protocol) request + uint32_t host_set_hnp_en : 1; // 10 Host set HNP enable + uint32_t dev_hnp_en : 1; // 11 Device HNP enabled + uint32_t embedded_host_en : 1; // 12 Embedded host enable + uint32_t rsv13_14 : 2; // 13.14 Reserved + uint32_t dbnc_filter_bypass : 1; // 15 Debounce filter bypass + uint32_t cid_status : 1; // 16 Connector ID status + uint32_t dbnc_done : 1; // 17 Debounce done + uint32_t ases_valid : 1; // 18 A-session valid + uint32_t bses_valid : 1; // 19 B-session valid + uint32_t otg_ver : 1; // 20 OTG version 0: v1.3, 1: v2.0 + uint32_t current_mode : 1; // 21 Current mode of operation. Only from v3.00a + uint32_t mult_val_id_bc : 5; // 22..26 Multi-valued input pin ID battery charger + uint32_t chirp_en : 1; // 27 Chirp detection enable + uint32_t rsv28_30 : 3; // 28.30: Reserved + uint32_t test_mode_corr_eusb2 : 1; // 31 Test mode control for eUSB2 PHY + }; } dwc2_gotgctl_t; TU_VERIFY_STATIC(sizeof(dwc2_gotgctl_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t rsv0_1 : 2; // 0..1 Reserved - uint32_t ses_end_det : 1; // 2 Session end detected - uint32_t rsv3_7 : 5; // 3..7 Reserved - uint32_t srs_status_change : 1; // 8 Session request success status change - uint32_t hns_status_change : 1; // 9 Host negotiation success status change - uint32_t rsv10_16 : 7; // 10..16 Reserved - uint32_t hng_det : 1; // 17 Host negotiation detected - uint32_t adev_timeout_change : 1; // 18 A-device timeout change - uint32_t dbnc_done : 1; // 19 Debounce done - uint32_t mult_val_lp_change : 1; // 20 Multi-valued input pin change - uint32_t rsv21_31 :11; // 21..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t rsv0_1 : 2; // 0..1 Reserved + uint32_t ses_end_det : 1; // 2 Session end detected + uint32_t rsv3_7 : 5; // 3..7 Reserved + uint32_t srs_status_change : 1; // 8 Session request success status change + uint32_t hns_status_change : 1; // 9 Host negotiation success status change + uint32_t rsv10_16 : 7; // 10..16 Reserved + uint32_t hng_det : 1; // 17 Host negotiation detected + uint32_t adev_timeout_change : 1; // 18 A-device timeout change + uint32_t dbnc_done : 1; // 19 Debounce done + uint32_t mult_val_lp_change : 1; // 20 Multi-valued input pin change + uint32_t rsv21_31 :11; // 21..31 Reserved + }; } dwc2_gotgint_t; TU_VERIFY_STATIC(sizeof(dwc2_gotgint_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t gintmask : 1; // 0 Global interrupt mask - uint32_t hbst_len : 4; // 1..4 Burst length/type - uint32_t dma_en : 1; // 5 DMA enable - uint32_t rsv6 : 1; // 6 Reserved - uint32_t nptxf_empty_lvl : 1; // 7 Non-periodic Tx FIFO empty level - uint32_t ptxf_empty_lvl : 1; // 8 Periodic Tx FIFO empty level - uint32_t rsv9_20 : 12; // 9.20: Reserved - uint32_t remote_mem_support : 1; // 21 Remote memory support - uint32_t notify_all_dma_write : 1; // 22 Notify all DMA writes - uint32_t ahb_single : 1; // 23 AHB single - uint32_t inv_desc_endian : 1; // 24 Inverse descriptor endian - uint32_t rsv25_31 : 7; // 25..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t gintmask : 1; // 0 Global interrupt mask + uint32_t hbst_len : 4; // 1..4 Burst length/type + uint32_t dma_en : 1; // 5 DMA enable + uint32_t rsv6 : 1; // 6 Reserved + uint32_t nptxf_empty_lvl : 1; // 7 Non-periodic Tx FIFO empty level + uint32_t ptxf_empty_lvl : 1; // 8 Periodic Tx FIFO empty level + uint32_t rsv9_20 : 12; // 9.20: Reserved + uint32_t remote_mem_support : 1; // 21 Remote memory support + uint32_t notify_all_dma_write : 1; // 22 Notify all DMA writes + uint32_t ahb_single : 1; // 23 AHB single + uint32_t inv_desc_endian : 1; // 24 Inverse descriptor endian + uint32_t rsv25_31 : 7; // 25..31 Reserved + }; } dwc2_gahbcfg_t; TU_VERIFY_STATIC(sizeof(dwc2_gahbcfg_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t timeout_cal : 3; /* 0..2 Timeout calibration. - The USB standard timeout value for high-speed operation is 736 to 816 (inclusive) bit times. The USB standard - timeout value for full- speed operation is 16 to 18 (inclusive) bit times. The application must program this field - based on the speed of enumeration. The number of bit times added per PHY clock are as follows: - - High-speed: PHY clock One 30-MHz = 16 bit times, One 60-MHz = 8 bit times - - Full-speed: PHY clock One 30-MHz = 0.4 bit times, One 60-MHz = 0.2 bit times, One 48-MHz = 0.25 bit times */ - uint32_t phy_if16 : 1; // 3 PHY interface. 0: 8 bits, 1: 16 bits - uint32_t ulpi_utmi_sel : 1; // 4 ULPI/UTMI select. 0: UTMI+, 1: ULPI - uint32_t fs_intf_sel : 1; // 5 Fullspeed serial interface select. 0: 6-pin, 1: 3-pin - uint32_t phy_sel : 1; // 6 HS/FS PHY selection. 0: HS UTMI+ or ULPI, 1: FS serial transceiver - uint32_t ddr_sel : 1; // 7 ULPI DDR select. 0: Single data rate 8-bit, 1: Double data rate 4-bit - uint32_t srp_capable : 1; // 8 SRP-capable - uint32_t hnp_capable : 1; // 9 HNP-capable - uint32_t turnaround_time : 4; // 10..13 Turnaround time. 9: 8-bit UTMI+, 5: 16-bit UTMI+ - uint32_t rsv14 : 1; // 14 Reserved - uint32_t phy_low_power_clk_sel : 1; /* 15 PHY low-power clock select either 480-MHz or 48-MHz (low-power) PHY mode. - In FS/LS modes, the PHY can usually operate on a 48-MHz clock to save power. This bit is valid only for UTMI+ PHYs. - - 0: 480 Mhz internal PLL: the UTMI interface operates at either 60 MHz (8 bit) or 30 MHz (16-bit) - - 1 48 Mhz external clock: the UTMI interface operates at 48 MHz in FS mode and at either 48 or 6 MHz in LS mode */ - uint32_t otg_i2c_sel : 1; // 16 OTG I2C interface select. 0: UTMI-FS, 1: I2C for OTG signals - uint32_t ulpi_fsls : 1; /* 17 ULPI FS/LS select. 0: ULPI, 1: ULPI FS/LS. - valid only when the FS serial transceiver is selected on the ULPI PHY. */ - uint32_t ulpi_auto_resume : 1; // 18 ULPI Auto-resume - uint32_t ulpi_clk_sus_m : 1; // 19 ULPI Clock SuspendM - uint32_t ulpi_ext_vbus_drv : 1; // 20 ULPI External VBUS Drive - uint32_t ulpi_int_vbus_indicator : 1; // 21 ULPI Internal VBUS Indicator - uint32_t term_sel_dl_pulse : 1; // 22 TermSel DLine pulsing - uint32_t indicator_complement : 1; // 23 Indicator complement - uint32_t indicator_pass_through : 1; // 24 Indicator pass through - uint32_t ulpi_if_protect_disable : 1; // 25 ULPI interface protect disable - uint32_t ic_usb_capable : 1; // 26 IC_USB Capable - uint32_t ic_usb_traf_ctl : 1; // 27 IC_USB Traffic Control - uint32_t tx_end_delay : 1; // 28 TX end delay - uint32_t force_host_mode : 1; // 29 Force host mode - uint32_t force_dev_mode : 1; // 30 Force device mode - uint32_t corrupt_tx_pkt : 1; // 31 Corrupt Tx packet. 0: normal, 1: debug +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t timeout_cal : 3; /* 0..2 Timeout calibration. + The USB standard timeout value for high-speed operation is 736 to 816 (inclusive) bit times. The USB standard + timeout value for full- speed operation is 16 to 18 (inclusive) bit times. The application must program this field + based on the speed of enumeration. The number of bit times added per PHY clock are as follows: + - High-speed: PHY clock One 30-MHz = 16 bit times, One 60-MHz = 8 bit times + - Full-speed: PHY clock One 30-MHz = 0.4 bit times, One 60-MHz = 0.2 bit times, One 48-MHz = 0.25 bit times */ + uint32_t phy_if16 : 1; // 3 PHY interface. 0: 8 bits, 1: 16 bits + uint32_t ulpi_utmi_sel : 1; // 4 ULPI/UTMI select. 0: UTMI+, 1: ULPI + uint32_t fs_intf_sel : 1; // 5 Fullspeed serial interface select. 0: 6-pin, 1: 3-pin + uint32_t phy_sel : 1; // 6 HS/FS PHY selection. 0: HS UTMI+ or ULPI, 1: FS serial transceiver + uint32_t ddr_sel : 1; // 7 ULPI DDR select. 0: Single data rate 8-bit, 1: Double data rate 4-bit + uint32_t srp_capable : 1; // 8 SRP-capable + uint32_t hnp_capable : 1; // 9 HNP-capable + uint32_t turnaround_time : 4; // 10..13 Turnaround time. 9: 8-bit UTMI+, 5: 16-bit UTMI+ + uint32_t rsv14 : 1; // 14 Reserved + uint32_t phy_low_power_clk_sel : 1; /* 15 PHY low-power clock select either 480-MHz or 48-MHz (low-power) PHY mode. + In FS/LS modes, the PHY can usually operate on a 48-MHz clock to save power. This bit is valid only for UTMI+ PHYs. + - 0: 480 Mhz internal PLL: the UTMI interface operates at either 60 MHz (8 bit) or 30 MHz (16-bit) + - 1 48 Mhz external clock: the UTMI interface operates at 48 MHz in FS mode and at either 48 or 6 MHz in LS mode */ + uint32_t otg_i2c_sel : 1; // 16 OTG I2C interface select. 0: UTMI-FS, 1: I2C for OTG signals + uint32_t ulpi_fsls : 1; /* 17 ULPI FS/LS select. 0: ULPI, 1: ULPI FS/LS. + valid only when the FS serial transceiver is selected on the ULPI PHY. */ + uint32_t ulpi_auto_resume : 1; // 18 ULPI Auto-resume + uint32_t ulpi_clk_sus_m : 1; // 19 ULPI Clock SuspendM + uint32_t ulpi_ext_vbus_drv : 1; // 20 ULPI External VBUS Drive + uint32_t ulpi_int_vbus_indicator : 1; // 21 ULPI Internal VBUS Indicator + uint32_t term_sel_dl_pulse : 1; // 22 TermSel DLine pulsing + uint32_t indicator_complement : 1; // 23 Indicator complement + uint32_t indicator_pass_through : 1; // 24 Indicator pass through + uint32_t ulpi_if_protect_disable : 1; // 25 ULPI interface protect disable + uint32_t ic_usb_capable : 1; // 26 IC_USB Capable + uint32_t ic_usb_traf_ctl : 1; // 27 IC_USB Traffic Control + uint32_t tx_end_delay : 1; // 28 TX end delay + uint32_t force_host_mode : 1; // 29 Force host mode + uint32_t force_dev_mode : 1; // 30 Force device mode + uint32_t corrupt_tx_pkt : 1; // 31 Corrupt Tx packet. 0: normal, 1: debug + }; } dwc2_gusbcfg_t; TU_VERIFY_STATIC(sizeof(dwc2_gusbcfg_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t core_soft_rst : 1; // 0 Core Soft Reset - uint32_t piufs_soft_rst : 1; // 1 PIU FS Dedicated Controller Soft Reset - uint32_t frame_counter_rst : 1; // 2 Frame Counter Reset (host) - uint32_t intoken_q_flush : 1; // 3 IN Token Queue Flush - uint32_t rx_fifo_flush : 1; // 4 RX FIFO Flush - uint32_t tx_fifo_flush : 1; // 5 TX FIFO Flush - uint32_t tx_fifo_num : 5; // 6..10 TX FIFO Number - uint32_t rsv11_28 :18; // 11..28 Reserved - uint32_t core_soft_rst_done : 1; // 29 Core Soft Reset Done, from v4.20a - uint32_t dma_req : 1; // 30 DMA Request - uint32_t ahb_idle : 1; // 31 AHB Idle +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t core_soft_rst : 1; // 0 Core Soft Reset + uint32_t piufs_soft_rst : 1; // 1 PIU FS Dedicated Controller Soft Reset + uint32_t frame_counter_rst : 1; // 2 Frame Counter Reset (host) + uint32_t intoken_q_flush : 1; // 3 IN Token Queue Flush + uint32_t rx_fifo_flush : 1; // 4 RX FIFO Flush + uint32_t tx_fifo_flush : 1; // 5 TX FIFO Flush + uint32_t tx_fifo_num : 5; // 6..10 TX FIFO Number + uint32_t rsv11_28 :18; // 11..28 Reserved + uint32_t core_soft_rst_done : 1; // 29 Core Soft Reset Done, from v4.20a + uint32_t dma_req : 1; // 30 DMA Request + uint32_t ahb_idle : 1; // 31 AHB Idle + }; } dwc2_grstctl_t; TU_VERIFY_STATIC(sizeof(dwc2_grstctl_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number - uint32_t byte_count :11; // 4..14 Byte Count - uint32_t dpid : 2; // 15..16 Data PID - uint32_t packet_status : 4; // 17..20 Packet Status - uint32_t frame_number : 4; // 21..24 Frame Number - uint32_t rsv25_31 : 7; // 25..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number + uint32_t byte_count :11; // 4..14 Byte Count + uint32_t dpid : 2; // 15..16 Data PID + uint32_t packet_status : 4; // 17..20 Packet Status + uint32_t frame_number : 4; // 21..24 Frame Number + uint32_t rsv25_31 : 7; // 25..31 Reserved + }; } dwc2_grxstsp_t; TU_VERIFY_STATIC(sizeof(dwc2_grxstsp_t) == 4, "incorrect size"); -// Hardware Configuration -typedef struct TU_ATTR_PACKED { - uint32_t op_mode : 3; // 0..2 HNP/SRP Host/Device/OTG mode - uint32_t arch : 2; // 3..4 Slave/External/Internal DMA - uint32_t single_point : 1; // 5 0: support hub and split | 1: no hub, no split - uint32_t hs_phy_type : 2; // 6..7 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI - uint32_t fs_phy_type : 2; // 8..9 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI - uint32_t num_dev_ep : 4; // 10..13 Number of device endpoints (excluding EP0) - uint32_t num_host_ch : 4; // 14..17 Number of host channel (excluding control) - uint32_t period_channel_support : 1; // 18 Support Periodic OUT Host Channel - uint32_t enable_dynamic_fifo : 1; // 19 Dynamic FIFO Sizing Enabled - uint32_t mul_proc_intrpt : 1; // 20 Multi-Processor Interrupt enabled (OTG_MULTI_PROC_INTRPT) - uint32_t reserved21 : 1; // 21 reserved - uint32_t nptx_q_depth : 2; // 22..23 Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 - uint32_t ptx_q_depth : 2; // 24..25 Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 - uint32_t token_q_depth : 5; // 26..30 Device IN token sequence learning queue depth: 0-30 - uint32_t otg_enable_ic_usb : 1; // 31 IC_USB mode specified for mode of operation +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t op_mode : 3; // 0..2 HNP/SRP Host/Device/OTG mode + uint32_t arch : 2; // 3..4 Slave/External/Internal DMA + uint32_t single_point : 1; // 5 0: support hub and split | 1: no hub, no split + uint32_t hs_phy_type : 2; // 6..7 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI + uint32_t fs_phy_type : 2; // 8..9 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI + uint32_t num_dev_ep : 4; // 10..13 Number of device endpoints (excluding EP0) + uint32_t num_host_ch : 4; // 14..17 Number of host channel (excluding control) + uint32_t period_channel_support : 1; // 18 Support Periodic OUT Host Channel + uint32_t enable_dynamic_fifo : 1; // 19 Dynamic FIFO Sizing Enabled + uint32_t mul_proc_intrpt : 1; // 20 Multi-Processor Interrupt enabled (OTG_MULTI_PROC_INTRPT) + uint32_t reserved21 : 1; // 21 reserved + uint32_t nptx_q_depth : 2; // 22..23 Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 + uint32_t ptx_q_depth : 2; // 24..25 Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8 + uint32_t token_q_depth : 5; // 26..30 Device IN token sequence learning queue depth: 0-30 + uint32_t otg_enable_ic_usb : 1; // 31 IC_USB mode specified for mode of operation + }; } dwc2_ghwcfg2_t; TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg2_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_size_width : 4; // 0..3 Transfer size counter in bits = 11 + n (max 19 bits) - uint32_t packet_size_width : 3; // 4..6 Packet size counter in bits = 4 + n (max 10 bits) - uint32_t otg_enable : 1; // 7 OTG capable - uint32_t i2c_enable : 1; // 8 I2C interface is available - uint32_t vendor_ctrl_itf : 1; // 9 Vendor control interface is available - uint32_t optional_feature_removed : 1; // 10 remove User ID, GPIO, SOF toggle & counter to save gate count - uint32_t synch_reset : 1; // 11 0: async reset | 1: synch reset - uint32_t otg_adp_support : 1; // 12 ADP logic is present along with HSOTG controller - uint32_t otg_enable_hsic : 1; // 13 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC - uint32_t battery_charger_support : 1; // s14 upport battery charger - uint32_t lpm_mode : 1; // 15 LPM mode - uint32_t dfifo_depth : 16; // DFIFO depth - EP_LOC_CNT in terms of 32-bit words -}dwc2_ghwcfg3_t; +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_size_width : 4; // 0..3 Transfer size counter in bits = 11 + n (max 19 bits) + uint32_t packet_size_width : 3; // 4..6 Packet size counter in bits = 4 + n (max 10 bits) + uint32_t otg_enable : 1; // 7 OTG capable + uint32_t i2c_enable : 1; // 8 I2C interface is available + uint32_t vendor_ctrl_itf : 1; // 9 Vendor control interface is available + uint32_t optional_feature_removed : 1; // 10 remove User ID, GPIO, SOF toggle & counter to save gate count + uint32_t synch_reset : 1; // 11 0: async reset | 1: synch reset + uint32_t otg_adp_support : 1; // 12 ADP logic is present along with HSOTG controller + uint32_t otg_enable_hsic : 1; // 13 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC + uint32_t battery_charger_support : 1; // s14 upport battery charger + uint32_t lpm_mode : 1; // 15 LPM mode + uint32_t dfifo_depth : 16; // DFIFO depth - EP_LOC_CNT in terms of 32-bit words + }; +} dwc2_ghwcfg3_t; TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg3_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t num_dev_period_in_ep : 4; // 0..3 Number of Device Periodic IN Endpoints - uint32_t partial_powerdown : 1; // 4 Partial Power Down Enabled - uint32_t ahb_freq_min : 1; // 5 1: minimum of AHB frequency is less than 60 MHz - uint32_t hibernation : 1; // 6 Hibernation feature is enabled - uint32_t extended_hibernation : 1; // 7 Extended Hibernation feature is enabled - uint32_t reserved8 : 1; // 8 Reserved - uint32_t enhanced_lpm_support1 : 1; // 9 Enhanced LPM Support1 - uint32_t service_interval_flow : 1; // 10 Service Interval flow is supported - uint32_t ipg_isoc_support : 1; // 11 Interpacket GAP ISO OUT worst-case is supported - uint32_t acg_support : 1; // 12 Active clock gating is supported - uint32_t enhanced_lpm_support : 1; // 13 Enhanced LPM Support - uint32_t phy_data_width : 2; // 14..15 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable - uint32_t ctrl_ep_num : 4; // 16..19 Number of Device control endpoints in addition to EP0 - uint32_t iddg_filter : 1; // 20 IDDG Filter Enabled - uint32_t vbus_valid_filter : 1; // 21 VBUS Valid Filter Enabled - uint32_t a_valid_filter : 1; // 22 A Valid Filter Enabled - uint32_t b_valid_filter : 1; // 23 B Valid Filter Enabled - uint32_t session_end_filter : 1; // 24 Session End Filter Enabled - uint32_t dedicated_fifos : 1; // 25 Dedicated tx fifo for device IN Endpoint - uint32_t num_dev_in_eps : 4; // 26..29 Number of Device IN Endpoints including EP0 - uint32_t dma_desc_enabled : 1; // scatter/gather DMA configuration enabled - uint32_t dma_desc_dynamic : 1; // Dynamic scatter/gather DMA -}dwc2_ghwcfg4_t; +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t num_dev_period_in_ep : 4; // 0..3 Number of Device Periodic IN Endpoints + uint32_t partial_powerdown : 1; // 4 Partial Power Down Enabled + uint32_t ahb_freq_min : 1; // 5 1: minimum of AHB frequency is less than 60 MHz + uint32_t hibernation : 1; // 6 Hibernation feature is enabled + uint32_t extended_hibernation : 1; // 7 Extended Hibernation feature is enabled + uint32_t reserved8 : 1; // 8 Reserved + uint32_t enhanced_lpm_support1 : 1; // 9 Enhanced LPM Support1 + uint32_t service_interval_flow : 1; // 10 Service Interval flow is supported + uint32_t ipg_isoc_support : 1; // 11 Interpacket GAP ISO OUT worst-case is supported + uint32_t acg_support : 1; // 12 Active clock gating is supported + uint32_t enhanced_lpm_support : 1; // 13 Enhanced LPM Support + uint32_t phy_data_width : 2; // 14..15 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable + uint32_t ctrl_ep_num : 4; // 16..19 Number of Device control endpoints in addition to EP0 + uint32_t iddg_filter : 1; // 20 IDDG Filter Enabled + uint32_t vbus_valid_filter : 1; // 21 VBUS Valid Filter Enabled + uint32_t a_valid_filter : 1; // 22 A Valid Filter Enabled + uint32_t b_valid_filter : 1; // 23 B Valid Filter Enabled + uint32_t session_end_filter : 1; // 24 Session End Filter Enabled + uint32_t dedicated_fifos : 1; // 25 Dedicated tx fifo for device IN Endpoint + uint32_t num_dev_in_eps : 4; // 26..29 Number of Device IN Endpoints including EP0 + uint32_t dma_desc_enabled : 1; // scatter/gather DMA configuration enabled + uint32_t dma_desc_dynamic : 1; // Dynamic scatter/gather DMA + }; +} dwc2_ghwcfg4_t; TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size"); -//-------------------------------------------------------------------- -// Host Register Bitfield -//-------------------------------------------------------------------- - -typedef struct TU_ATTR_PACKED { - uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO - uint32_t req_queue_available : 8; // 16..23 Number of spaces available in the NPT transmit request queue for both IN and OU - // 24..31 is top entry in the request queue that is currently being processed by the MAC - uint32_t qtop_terminate : 1; // 24 Last entry for selected channel - uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command - uint32_t qtop_ch_num : 4; // 27..30 Channel number +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO + uint32_t req_queue_available : 8; // 16..23 Number of spaces available in the NPT transmit request queue for both IN and OU + // 24..31 is top entry in the request queue that is currently being processed by the MAC + uint32_t qtop_terminate : 1; // 24 Last entry for selected channel + uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command + uint32_t qtop_ch_num : 4; // 27..30 Channel number + }; } dwc2_hnptxsts_t; TU_VERIFY_STATIC(sizeof(dwc2_hnptxsts_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO - uint32_t req_queue_available : 7; // 16..22 Number of spaces available in the PTX transmit request queue - uint32_t qtop_terminate : 1; // 23 Last entry for selected channel - uint32_t qtop_last_period : 1; // 24 Last entry for selected channel is a periodic entry - uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command - uint32_t qtop_ch_num : 4; // 27..30 Channel number - uint32_t qtop_odd_frame : 1; // 31 Send in odd frame +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO + uint32_t req_queue_available : 7; // 16..22 Number of spaces available in the PTX transmit request queue + uint32_t qtop_terminate : 1; // 23 Last entry for selected channel + uint32_t qtop_last_period : 1; // 24 Last entry for selected channel is a periodic entry + uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command + uint32_t qtop_ch_num : 4; // 27..30 Channel number + uint32_t qtop_odd_frame : 1; // 31 Send in odd frame + }; } dwc2_hptxsts_t; TU_VERIFY_STATIC(sizeof(dwc2_hptxsts_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t conn_status : 1; // 0 Port connect status - uint32_t conn_detected : 1; // 1 Port connect detected - uint32_t enable : 1; // 2 Port enable status - uint32_t enable_change : 1; // 3 Port enable change - uint32_t over_current_active : 1; // 4 Port Over-current active - uint32_t over_current_change : 1; // 5 Port Over-current change - uint32_t resume : 1; // 6 Port resume - uint32_t suspend : 1; // 7 Port suspend - uint32_t reset : 1; // 8 Port reset - uint32_t rsv9 : 1; // 9 Reserved - uint32_t line_status : 2; // 10..11 Line status - uint32_t power : 1; // 12 Port power - uint32_t test_control : 4; // 13..16 Port Test control - uint32_t speed : 2; // 17..18 Port speed - uint32_t rsv19_31 :13; // 19..31 Reserved -}dwc2_hprt_t; +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t conn_status : 1; // 0 Port connect status + uint32_t conn_detected : 1; // 1 Port connect detected + uint32_t enable : 1; // 2 Port enable status + uint32_t enable_change : 1; // 3 Port enable change + uint32_t over_current_active : 1; // 4 Port Over-current active + uint32_t over_current_change : 1; // 5 Port Over-current change + uint32_t resume : 1; // 6 Port resume + uint32_t suspend : 1; // 7 Port suspend + uint32_t reset : 1; // 8 Port reset + uint32_t rsv9 : 1; // 9 Reserved + uint32_t line_status : 2; // 10..11 Line status + uint32_t power : 1; // 12 Port power + uint32_t test_control : 4; // 13..16 Port Test control + uint32_t speed : 2; // 17..18 Port speed + uint32_t rsv19_31 :13; // 19..31 Reserved + }; +} dwc2_hprt_t; TU_VERIFY_STATIC(sizeof(dwc2_hprt_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t ep_size : 11; // 0..10 Maximum packet size - uint32_t ep_num : 4; // 11..14 Endpoint number - uint32_t ep_dir : 1; // 15 Endpoint direction - uint32_t rsv16 : 1; // 16 Reserved - uint32_t low_speed_dev : 1; // 17 Low-speed device - uint32_t ep_type : 2; // 18..19 Endpoint type - uint32_t err_multi_count : 2; // 20..21 Error (splitEn = 1) / Multi (SplitEn = 0) count - uint32_t dev_addr : 7; // 22..28 Device address - uint32_t odd_frame : 1; // 29 Odd frame - uint32_t disable : 1; // 30 Channel disable - uint32_t enable : 1; // 31 Channel enable +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t ep_size : 11; // 0..10 Maximum packet size + uint32_t ep_num : 4; // 11..14 Endpoint number + uint32_t ep_dir : 1; // 15 Endpoint direction + uint32_t rsv16 : 1; // 16 Reserved + uint32_t low_speed_dev : 1; // 17 Low-speed device + uint32_t ep_type : 2; // 18..19 Endpoint type + uint32_t err_multi_count : 2; // 20..21 Error (splitEn = 1) / Multi (SplitEn = 0) count + uint32_t dev_addr : 7; // 22..28 Device address + uint32_t odd_frame : 1; // 29 Odd frame + uint32_t disable : 1; // 30 Channel disable + uint32_t enable : 1; // 31 Channel enable + }; } dwc2_channel_char_t; TU_VERIFY_STATIC(sizeof(dwc2_channel_char_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t hub_port : 7; // 0..6 Hub port number - uint32_t hub_addr : 7; // 7..13 Hub address - uint32_t xact_pos : 2; // 14..15 Transaction position - uint32_t split_compl : 1; // 16 Split completion - uint32_t rsv17_30 : 14; // 17..30 Reserved - uint32_t split_en : 1; // 31 Split enable +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t hub_port : 7; // 0..6 Hub port number + uint32_t hub_addr : 7; // 7..13 Hub address + uint32_t xact_pos : 2; // 14..15 Transaction position + uint32_t split_compl : 1; // 16 Split completion + uint32_t rsv17_30 : 14; // 17..30 Reserved + uint32_t split_en : 1; // 31 Split enable + }; } dwc2_channel_split_t; TU_VERIFY_STATIC(sizeof(dwc2_channel_split_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_size : 19; // 0..18 Transfer size in bytes - uint32_t packet_count : 10; // 19..28 Number of packets - uint32_t pid : 2; // 29..30 Packet ID - uint32_t do_ping : 1; // 31 Do PING +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_size : 19; // 0..18 Transfer size in bytes + uint32_t packet_count : 10; // 19..28 Number of packets + uint32_t pid : 2; // 29..30 Packet ID + uint32_t do_ping : 1; // 31 Do PING + }; } dwc2_channel_tsize_t; TU_VERIFY_STATIC(sizeof(dwc2_channel_tsize_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t num : 16; // 0..15 Frame number - uint32_t remainning : 16; // 16..31 Frame remaining +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t num : 16; // 0..15 Frame number + uint32_t remainning : 16; // 16..31 Frame remaining + }; } dwc2_hfnum_t; TU_VERIFY_STATIC(sizeof(dwc2_hfnum_t) == 4, "incorrect size"); // Host Channel typedef struct { - union { - volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics - volatile dwc2_channel_char_t hcchar_bm; - }; - union { - volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control - volatile dwc2_channel_split_t hcsplt_bm; - }; - volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt - volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask - union { - volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size - volatile dwc2_channel_tsize_t hctsiz_bm; - }; - volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address - uint32_t reserved518; // 518 + 20*ch - volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address + volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics + volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control + volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt + volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask + volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size + volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address + uint32_t reserved518; // 518 + 20*ch + volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address } dwc2_channel_t; //-------------------------------------------------------------------- // Device Register Bitfield //-------------------------------------------------------------------- -typedef struct TU_ATTR_PACKED { - uint32_t speed : 2; // 0..1 Speed - uint32_t nzsts_out_handshake : 1; // 2 Non-zero-length status OUT handshake - uint32_t en_32khz_suspsend : 1; // 3 Enable 32-kHz SUSPEND mode - uint32_t address : 7; // 4..10 Device address - uint32_t period_frame_interval : 2; // 11..12 Periodic frame interval - uint32_t en_out_nak : 1; // 13 Enable Device OUT NAK - uint32_t xcvr_delay : 1; // 14 Transceiver delay - uint32_t erratic_int_mask : 1; // 15 Erratic interrupt mask - uint32_t rsv16 : 1; // 16 Reserved - uint32_t ipg_iso_support : 1; // 17 Interpacket gap ISO support - uint32_t epin_mismatch_count : 5; // 18..22 EP IN mismatch count - uint32_t dma_desc : 1; // 23 Enable scatter/gatter DMA descriptor - uint32_t period_schedule_interval : 2; // 24..25 Periodic schedule interval for scatter/gatter DMA - uint32_t resume_valid : 6; // 26..31 Resume valid period +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t speed : 2; // 0..1 Speed + uint32_t nzsts_out_handshake : 1; // 2 Non-zero-length status OUT handshake + uint32_t en_32khz_suspsend : 1; // 3 Enable 32-kHz SUSPEND mode + uint32_t address : 7; // 4..10 Device address + uint32_t period_frame_interval : 2; // 11..12 Periodic frame interval + uint32_t en_out_nak : 1; // 13 Enable Device OUT NAK + uint32_t xcvr_delay : 1; // 14 Transceiver delay + uint32_t erratic_int_mask : 1; // 15 Erratic interrupt mask + uint32_t rsv16 : 1; // 16 Reserved + uint32_t ipg_iso_support : 1; // 17 Interpacket gap ISO support + uint32_t epin_mismatch_count : 5; // 18..22 EP IN mismatch count + uint32_t dma_desc : 1; // 23 Enable scatter/gather DMA descriptor + uint32_t period_schedule_interval : 2; // 24..25 Periodic schedule interval for scatter/gather DMA + uint32_t resume_valid : 6; // 26..31 Resume valid period + }; } dwc2_dcfg_t; TU_VERIFY_STATIC(sizeof(dwc2_dcfg_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t remote_wakeup_signal : 1; // 0 Remote wakeup signal - uint32_t soft_disconnet : 1; // 1 Soft disconnect - uint32_t gnp_in_nak_status : 1; // 2 Global non-periodic NAK IN status - uint32_t gout_nak_status : 1; // 3 Global OUT NAK status - uint32_t test_control : 3; // 4..6 Test control - uint32_t set_gnp_in_nak : 1; // 7 Set global non-periodic IN NAK - uint32_t clear_gnp_in_nak : 1; // 8 Clear global non-periodic IN NAK - uint32_t set_gout_nak : 1; // 9 Set global OUT NAK - uint32_t clear_gout_nak : 1; // 10 Clear global OUT NAK - uint32_t poweron_prog_done : 1; // 11 Power-on programming done - uint32_t rsv12 : 1; // 12 Reserved - uint32_t global_multi_count : 2; // 13..14 Global multi-count - uint32_t ignore_frame_number : 1; // 15 Ignore frame number - uint32_t nak_on_babble : 1; // 16 NAK on babble - uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA - uint32_t deep_sleep_besl_reject : 1; // 18 Deep sleep BESL reject - uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint - uint32_t rsv20_31 :12; // 20..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t remote_wakeup_signal : 1; // 0 Remote wakeup signal + uint32_t soft_disconnet : 1; // 1 Soft disconnect + uint32_t gnp_in_nak_status : 1; // 2 Global non-periodic NAK IN status + uint32_t gout_nak_status : 1; // 3 Global OUT NAK status + uint32_t test_control : 3; // 4..6 Test control + uint32_t set_gnp_in_nak : 1; // 7 Set global non-periodic IN NAK + uint32_t clear_gnp_in_nak : 1; // 8 Clear global non-periodic IN NAK + uint32_t set_gout_nak : 1; // 9 Set global OUT NAK + uint32_t clear_gout_nak : 1; // 10 Clear global OUT NAK + uint32_t poweron_prog_done : 1; // 11 Power-on programming done + uint32_t rsv12 : 1; // 12 Reserved + uint32_t global_multi_count : 2; // 13..14 Global multi-count + uint32_t ignore_frame_number : 1; // 15 Ignore frame number + uint32_t nak_on_babble : 1; // 16 NAK on babble + uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA + uint32_t deep_sleep_besl_reject : 1; // 18 Deep sleep BESL reject + uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint + uint32_t rsv20_31 :12; // 20..31 Reserved + }; } dwc2_dctl_t; TU_VERIFY_STATIC(sizeof(dwc2_dctl_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t suspend_status : 1; // 0 Suspend status - uint32_t enum_speed : 2; // 1..2 Enumerated speed - uint32_t erratic_err : 1; // 3 Erratic error - uint32_t rsv4_7 : 4; // 4..7 Reserved - uint32_t frame_number : 14; // 8..21 Frame/MicroFrame number - uint32_t line_status : 2; // 22..23 Line status - uint32_t rsv24_31 : 8; // 24..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t suspend_status : 1; // 0 Suspend status + uint32_t enum_speed : 2; // 1..2 Enumerated speed + uint32_t erratic_err : 1; // 3 Erratic error + uint32_t rsv4_7 : 4; // 4..7 Reserved + uint32_t frame_number : 14; // 8..21 Frame/MicroFrame number + uint32_t line_status : 2; // 22..23 Line status + uint32_t rsv24_31 : 8; // 24..31 Reserved + }; } dwc2_dsts_t; TU_VERIFY_STATIC(sizeof(dwc2_dsts_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_complete : 1; // 0 Transfer complete - uint32_t disabled : 1; // 1 Endpoint disabled - uint32_t ahb_err : 1; // 2 AHB error - uint32_t timeout : 1; // 3 Timeout - uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty - uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch - uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective - uint32_t txfifo_empty : 1; // 7 TX FIFO empty - uint32_t txfifo_underrun : 1; // 8 Tx FIFO under run - uint32_t bna : 1; // 9 Buffer not available - uint32_t rsv10 : 1; // 10 Reserved - uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status - uint32_t babble_err : 1; // 12 Babble error - uint32_t nak : 1; // 13 NAK - uint32_t nyet : 1; // 14 NYET - uint32_t rsv14_31 :17; // 15..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_complete : 1; // 0 Transfer complete + uint32_t disabled : 1; // 1 Endpoint disabled + uint32_t ahb_err : 1; // 2 AHB error + uint32_t timeout : 1; // 3 Timeout + uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty + uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch + uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective + uint32_t txfifo_empty : 1; // 7 TX FIFO empty + uint32_t txfifo_underrun : 1; // 8 Tx FIFO under run + uint32_t bna : 1; // 9 Buffer not available + uint32_t rsv10 : 1; // 10 Reserved + uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status + uint32_t babble_err : 1; // 12 Babble error + uint32_t nak : 1; // 13 NAK + uint32_t nyet : 1; // 14 NYET + uint32_t rsv14_31 :17; // 15..31 Reserved + }; } dwc2_diepint_t; TU_VERIFY_STATIC(sizeof(dwc2_diepint_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t mps : 11; // 0..10 Maximum packet size, EP0 only use 2 bit - uint32_t next_ep : 4; // 11..14 Next endpoint number - uint32_t active : 1; // 15 Active - const uint32_t dpid_iso_odd : 1; // 16 DATA0/DATA1 for bulk/interrupt, odd frame for isochronous - const uint32_t nak_status : 1; // 17 NAK status - uint32_t type : 2; // 18..19 Endpoint type - uint32_t rsv20 : 1; // 20 Reserved - uint32_t stall : 1; // 21 Stall - uint32_t tx_fifo_num : 4; // 22..25 Tx FIFO number (IN) - uint32_t clear_nak : 1; // 26 Clear NAK - uint32_t set_nak : 1; // 27 Set NAK - uint32_t set_data0_iso_even : 1; // 28 Set DATA0 if bulk/interrupt, even frame for isochronous - uint32_t set_data1_iso_odd : 1; // 29 Set DATA1 if bulk/interrupt, odd frame for isochronous - uint32_t disable : 1; // 30 Disable - uint32_t enable : 1; // 31 Enable +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t mps : 11; // 0..10 Maximum packet size, EP0 only use 2 bits + uint32_t next_ep : 4; // 11..14 Next endpoint number + uint32_t active : 1; // 15 Active + uint32_t dpid_iso_odd : 1; // 16 DATA0/DATA1 for bulk/interrupt, odd frame for isochronous + uint32_t nak_status : 1; // 17 NAK status + uint32_t type : 2; // 18..19 Endpoint type + uint32_t rsv20 : 1; // 20 Reserved + uint32_t stall : 1; // 21 Stall + uint32_t tx_fifo_num : 4; // 22..25 Tx FIFO number (IN) + uint32_t clear_nak : 1; // 26 Clear NAK + uint32_t set_nak : 1; // 27 Set NAK + uint32_t set_data0_iso_even : 1; // 28 Set DATA0 if bulk/interrupt, even frame for isochronous + uint32_t set_data1_iso_odd : 1; // 29 Set DATA1 if bulk/interrupt, odd frame for isochronous + uint32_t disable : 1; // 30 Disable + uint32_t enable : 1; // 31 Enable + }; } dwc2_depctl_t; TU_VERIFY_STATIC(sizeof(dwc2_depctl_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_complete : 1; // 0 Transfer complete - uint32_t disabled : 1; // 1 Endpoint disabled - uint32_t ahb_err : 1; // 2 AHB error - uint32_t setup_phase_done : 1; // 3 Setup phase done - uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled - uint32_t status_phase_rx : 1; // 5 Status phase received - uint32_t setup_b2b : 1; // 6 Setup packet back-to-back - uint32_t rsv7 : 1; // 7 Reserved - uint32_t out_packet_err : 1; // 8 OUT packet error - uint32_t bna : 1; // 9 Buffer not available - uint32_t rsv10 : 1; // 10 Reserved - uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status - uint32_t babble_err : 1; // 12 Babble error - uint32_t nak : 1; // 13 NAK - uint32_t nyet : 1; // 14 NYET - uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only) - uint32_t rsv16_31 :16; // 16..31 Reserved +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_complete : 1; // 0 Transfer complete + uint32_t disabled : 1; // 1 Endpoint disabled + uint32_t ahb_err : 1; // 2 AHB error + uint32_t setup_phase_done : 1; // 3 Setup phase done + uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled + uint32_t status_phase_rx : 1; // 5 Status phase received + uint32_t setup_b2b : 1; // 6 Setup packet back-to-back + uint32_t rsv7 : 1; // 7 Reserved + uint32_t out_packet_err : 1; // 8 OUT packet error + uint32_t bna : 1; // 9 Buffer not available + uint32_t rsv10 : 1; // 10 Reserved + uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status + uint32_t babble_err : 1; // 12 Babble error + uint32_t nak : 1; // 13 NAK + uint32_t nyet : 1; // 14 NYET + uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only) + uint32_t rsv16_31 :16; // 16..31 Reserved + }; } dwc2_doepint_t; TU_VERIFY_STATIC(sizeof(dwc2_doepint_t) == 4, "incorrect size"); -typedef struct TU_ATTR_PACKED { - uint32_t xfer_size : 19; // 0..18 Transfer size in bytes - uint32_t packet_count : 10; // 19..28 Number of packets - uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID +typedef union { + uint32_t value; + struct TU_ATTR_PACKED { + uint32_t xfer_size : 19; // 0..18 Transfer size in bytes + uint32_t packet_count : 10; // 19..28 Number of packets + uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID + }; } dwc2_ep_tsize_t; TU_VERIFY_STATIC(sizeof(dwc2_ep_tsize_t) == 4, "incorrect size"); @@ -601,26 +656,19 @@ typedef struct { union { volatile uint32_t diepctl; volatile uint32_t doepctl; - volatile uint32_t ctl; - volatile dwc2_depctl_t ctl_bm; }; uint32_t rsv04; union { volatile uint32_t intr; - volatile uint32_t diepint; - volatile dwc2_diepint_t diepint_bm; - volatile uint32_t doepint; - volatile dwc2_doepint_t doepint_bm; }; uint32_t rsv0c; union { volatile uint32_t dieptsiz; volatile uint32_t doeptsiz; volatile uint32_t tsiz; - volatile dwc2_ep_tsize_t tsiz_bm; }; union { volatile uint32_t diepdma; @@ -628,7 +676,7 @@ typedef struct { }; volatile uint32_t dtxfsts; uint32_t rsv1c; -}dwc2_dep_t; +} dwc2_dep_t; TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size"); @@ -637,156 +685,107 @@ TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size"); //-------------------------------------------------------------------- typedef struct { //------------- Core Global -------------// - union { - volatile uint32_t gotgctl; // 000 OTG Control and Status - volatile dwc2_gotgctl_t gotgctl_bm; - }; - union { - volatile uint32_t gotgint; // 004 OTG Interrupt - volatile dwc2_gotgint_t gotgint_bm; - }; - union { - volatile uint32_t gahbcfg; // 008 AHB Configuration - volatile dwc2_gahbcfg_t gahbcfg_bm; - }; - union { - volatile uint32_t gusbcfg; // 00c USB Configuration - volatile dwc2_gusbcfg_t gusbcfg_bm; - }; - union { - volatile uint32_t grstctl; // 010 Reset - volatile dwc2_grstctl_t grstctl_bm; - }; - volatile uint32_t gintsts; // 014 Interrupt - volatile uint32_t gintmsk; // 018 Interrupt Mask - volatile uint32_t grxstsr; // 01c Receive Status Debug Read - union { - volatile uint32_t grxstsp; // 020 Receive Status Read/Pop - volatile dwc2_grxstsp_t grxstsp_bm; - }; - volatile uint32_t grxfsiz; // 024 Receive FIFO Size + volatile uint32_t gotgctl; // 000 OTG Control and Status + volatile uint32_t gotgint; // 004 OTG Interrupt + volatile uint32_t gahbcfg; // 008 AHB Configuration + volatile uint32_t gusbcfg; // 00c USB Configuration + volatile uint32_t grstctl; // 010 Reset + volatile uint32_t gintsts; // 014 Interrupt + volatile uint32_t gintmsk; // 018 Interrupt Mask + volatile uint32_t grxstsr; // 01c Receive Status Debug Read + volatile uint32_t grxstsp; // 020 Receive Status Read/Pop + volatile uint32_t grxfsiz; // 024 Receive FIFO Size union { volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size volatile uint32_t gnptxfsiz; // 028 Non-periodic Transmit FIFO Size }; union { volatile uint32_t hnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status - volatile dwc2_hnptxsts_t hnptxsts_bm; volatile uint32_t gnptxsts; }; - volatile uint32_t gi2cctl; // 030 I2C Address - volatile uint32_t gpvndctl; // 034 PHY Vendor Control + volatile uint32_t gi2cctl; // 030 I2C Address + volatile uint32_t gpvndctl; // 034 PHY Vendor Control union { volatile uint32_t ggpio; // 038 General Purpose IO volatile uint32_t stm32_gccfg; // 038 STM32 General Core Configuration }; - volatile uint32_t guid; // 03C User (Application programmable) ID - volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version - volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep) - union { - volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2 - volatile dwc2_ghwcfg2_t ghwcfg2_bm; - }; - union { - volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3 - volatile dwc2_ghwcfg3_t ghwcfg3_bm; - }; + volatile uint32_t guid; // 03C User (Application programmable) ID + volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version + volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep) + volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2 + volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3 union { volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4 volatile dwc2_ghwcfg4_t ghwcfg4_bm; }; - volatile uint32_t glpmcfg; // 054 Core LPM Configuration - volatile uint32_t gpwrdn; // 058 Power Down - volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration - volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status - uint32_t reserved64[39]; // 064..0FF - volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size - volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size - uint32_t reserved140[176]; // 140..3FF + volatile uint32_t glpmcfg; // 054 Core LPM Configuration + volatile uint32_t gpwrdn; // 058 Power Down + volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration + volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status + uint32_t reserved64[39]; // 064..0FF + volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size + volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size + uint32_t reserved140[176]; // 140..3FF - //------------ Host -------------// - volatile uint32_t hcfg; // 400 Host Configuration - volatile uint32_t hfir; // 404 Host Frame Interval - union { - volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining - volatile dwc2_hfnum_t hfnum_bm; - }; - uint32_t reserved40c; // 40C - union { - volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status - volatile dwc2_hptxsts_t hptxsts_bm; - }; - volatile uint32_t haint; // 414 Host All Channels Interrupt - volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask - volatile uint32_t hflbaddr; // 41C Host Frame List Base Address - uint32_t reserved420[8]; // 420..43F - union { - volatile uint32_t hprt; // 440 Host Port Control and Status - volatile dwc2_hprt_t hprt_bm; - }; - uint32_t reserved444[47]; // 444..4FF + //------------ Host -------------// + volatile uint32_t hcfg; // 400 Host Configuration + volatile uint32_t hfir; // 404 Host Frame Interval + volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining + uint32_t reserved40c; // 40C + volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status + volatile uint32_t haint; // 414 Host All Channels Interrupt + volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask + volatile uint32_t hflbaddr; // 41C Host Frame List Base Address + uint32_t reserved420[8]; // 420..43F + volatile uint32_t hprt; // 440 Host Port Control and Status + uint32_t reserved444[47]; // 444..4FF - //------------- Host Channel -------------// - dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15 - uint32_t reserved700[64]; // 700..7FF + //------------- Host Channel -------------// + dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15 + uint32_t reserved700[64]; // 700..7FF - //------------- Device -----------// - union { - volatile uint32_t dcfg; // 800 Device Configuration - volatile dwc2_dcfg_t dcfg_bm; - }; - union { - volatile uint32_t dctl; // 804 Device Control - volatile dwc2_dctl_t dctl_bm; - }; - union { - volatile uint32_t dsts; // 808 Device Status (RO) - volatile dwc2_dsts_t dsts_bm; - }; - uint32_t reserved80c; // 80C - union { - volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask - volatile dwc2_diepint_t diepmsk_bm; - }; - union { - volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask - volatile dwc2_doepint_t doepmsk_bm; - }; - volatile uint32_t daint; // 818 Device All Endpoints Interrupt - volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask - volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1 - volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2 - volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time - volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time - volatile uint32_t dthrctl; // 830 Device threshold Control - volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask + //------------- Device -----------// + volatile uint32_t dcfg; // 800 Device Configuration + volatile uint32_t dctl; // 804 Device Control + volatile uint32_t dsts; // 808 Device Status (RO) + uint32_t reserved80c; // 80C + volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask + volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask + volatile uint32_t daint; // 818 Device All Endpoints Interrupt + volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask + volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1 + volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2 + volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time + volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time + volatile uint32_t dthrctl; // 830 Device threshold Control + volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask - // Device Each Endpoint (IN/OUT) Interrupt/Mask for generating dedicated EP interrupt line - // require OTG_MULTI_PROC_INTRPT=1 - volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt - volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt mask - volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask - volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask - uint32_t reserved8c0[16]; // 8C0..8FF + // Device Each Endpoint (IN/OUT) Interrupt/Mask for generating dedicated EP interrupt line + // require OTG_MULTI_PROC_INTRPT=1 + volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt + volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt mask + volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask + volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask + uint32_t reserved8c0[16]; // 8C0..8FF - //------------- Device Endpoint -------------// - union { - dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT - struct { - dwc2_dep_t epin[16]; // 900..AFF IN Endpoints - dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints - }; + //------------- Device Endpoint -------------// + union { + dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT + struct { + dwc2_dep_t epin[16]; // 900..AFF IN Endpoints + dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints }; - uint32_t reservedd00[64]; // D00..DFF + }; + uint32_t reservedd00[64]; // D00..DFF - //------------- Power Clock -------------// - volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control - volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1 - uint32_t reservede08[126]; // E08..FFF + //------------- Power Clock -------------// + volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control + volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1 + uint32_t reservede08[126]; // E08..FFF - //------------- FIFOs -------------// - // Word-accessed only using first pointer since it auto shift - volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO + //------------- FIFOs -------------// + // Word-accessed only using first pointer since it auto shift + volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO } dwc2_regs_t; TU_VERIFY_STATIC(offsetof(dwc2_regs_t, hcfg ) == 0x0400, "incorrect size"); diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index b13479b02..af17bb59a 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -44,7 +44,7 @@ #endif #define DWC2_CHANNEL_COUNT_MAX 16 // absolute max channel count -#define DWC2_CHANNEL_COUNT(_dwc2) tu_min8((_dwc2)->ghwcfg2_bm.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX) +#define DWC2_CHANNEL_COUNT(_dwc2) ({const dwc2_ghwcfg2_t ghwcfg2 = {.value = (_dwc2)->ghwcfg2}; tu_min8(ghwcfg2.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX);}) TU_VERIFY_STATIC(CFG_TUH_DWC2_ENDPOINT_MAX <= 255, "currently only use 8-bit for index"); @@ -118,7 +118,8 @@ hcd_data_t _hcd_data; //-------------------------------------------------------------------- TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc2) { tusb_speed_t speed; - switch(dwc2->hprt_bm.speed) { + const dwc2_hprt_t hprt = {.value = dwc2->hprt}; + switch(hprt.speed) { case HPRT_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break; case HPRT_SPEED_FULL: speed = TUSB_SPEED_FULL; break; case HPRT_SPEED_LOW : speed = TUSB_SPEED_LOW ; break; @@ -133,7 +134,8 @@ TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc2) { (void) dwc2; // Internal DMA only - return CFG_TUH_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA; + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + return CFG_TUH_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA; } #if CFG_TUH_MEM_DCACHE_ENABLE @@ -168,15 +170,18 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) { } // Check if is periodic (interrupt/isochronous) -TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_periodic(uint8_t ep_type) { - return ep_type == HCCHAR_EPTYPE_INTERRUPT || ep_type == HCCHAR_EPTYPE_ISOCHRONOUS; +TU_ATTR_ALWAYS_INLINE static inline bool channel_is_periodic(uint32_t hcchar) { + const dwc2_channel_char_t hcchar_bm = {.value = hcchar}; + return hcchar_bm.ep_type == HCCHAR_EPTYPE_INTERRUPT || hcchar_bm.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS; } TU_ATTR_ALWAYS_INLINE static inline uint8_t req_queue_avail(const dwc2_regs_t* dwc2, bool is_period) { if (is_period) { - return dwc2->hptxsts_bm.req_queue_available; + const dwc2_hptxsts_t hptxsts = {.value = dwc2->hptxsts}; + return hptxsts.req_queue_available; } else { - return dwc2->hnptxsts_bm.req_queue_available; + const dwc2_hnptxsts_t hnptxsts = {.value = dwc2->hnptxsts}; + return hnptxsts.req_queue_available; } } @@ -188,7 +193,7 @@ TU_ATTR_ALWAYS_INLINE static inline void channel_dealloc(dwc2_regs_t* dwc2, uint TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) { // disable also require request queue - TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type))); + TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar))); channel->hcintmsk |= HCINT_HALTED; channel->hcchar |= HCCHAR_CHDIS | HCCHAR_CHENA; // must set both CHDIS and CHENA return true; @@ -196,7 +201,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2 // attempt to send IN token to receive data TU_ATTR_ALWAYS_INLINE static inline bool channel_send_in_token(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) { - TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type))); + TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar))); channel->hcchar |= HCCHAR_CHENA; return true; } @@ -206,8 +211,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_find_enabled(dwc2_regs_t* dw const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2); for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { if (_hcd_data.xfer[ch_id].allocated) { - const dwc2_channel_char_t hcchar_bm = dwc2->channel[ch_id].hcchar_bm; - if (hcchar_bm.dev_addr == dev_addr && hcchar_bm.ep_num == ep_num && (ep_num == 0 || hcchar_bm.ep_dir == ep_dir)) { + const dwc2_channel_char_t hcchar = {.value = dwc2->channel[ch_id].hcchar}; + if (hcchar.dev_addr == dev_addr && hcchar.ep_num == ep_num && (ep_num == 0 || hcchar.ep_dir == ep_dir)) { return ch_id; } } @@ -304,12 +309,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t pa static void dfifo_host_init(uint8_t rhport) { const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport]; dwc2_regs_t* dwc2 = DWC2_REG(rhport); + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; // Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per channel const bool is_dma = dma_host_enabled(dwc2); uint16_t dfifo_top = dwc2_controller->ep_fifo_size/4; if (is_dma) { - dfifo_top -= dwc2->ghwcfg2_bm.num_host_ch; + dfifo_top -= ghwcfg2.num_host_ch; } // fixed allocation for now, improve later: @@ -319,7 +325,7 @@ static void dfifo_host_init(uint8_t rhport) { uint32_t ptx_largest = is_highspeed ? TUSB_EPSIZE_ISO_HS_MAX/4 : 256/4; uint16_t nptxfsiz = 2 * nptx_largest; - uint16_t rxfsiz = 2 * (ptx_largest + 2) + dwc2->ghwcfg2_bm.num_host_ch; + uint16_t rxfsiz = 2 * (ptx_largest + 2) + ghwcfg2.num_host_ch; TU_ASSERT(dfifo_top >= (nptxfsiz + rxfsiz),); uint16_t ptxfsiz = dfifo_top - (nptxfsiz + rxfsiz); @@ -509,10 +515,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* // clean up channel after part of transfer is done but the whole urb is not complete static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) { hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - dwc2_channel_t* channel = &dwc2->channel[ch_id]; + const dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; - edpt->next_pid = channel->hctsiz_bm.pid; // save PID + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + edpt->next_pid = hctsiz.pid; // save PID /* Since hctsiz.xfersize field reflects the number of bytes transferred via the AHB, not the USB) * For IN: we can use hctsiz.xfersize as remaining bytes. @@ -520,9 +527,10 @@ static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) { * number of packets that have been transferred via the USB. This is always an integral number of packets if the * transfer was halted before its normal completion. */ - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; - const uint16_t total_packets = cal_packet_count(edpt->buflen, channel->hcchar_bm.ep_size); - const uint16_t actual_bytes = (total_packets - remain_packets) * channel->hcchar_bm.ep_size; + const uint16_t remain_packets = hctsiz.packet_count; + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + const uint16_t total_packets = cal_packet_count(edpt->buflen, hcchar.ep_size); + const uint16_t actual_bytes = (total_packets - remain_packets) * hcchar.ep_size; xfer->fifo_bytes = 0; xfer->xferred_bytes += actual_bytes; @@ -535,7 +543,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm; dwc2_channel_t* channel = &dwc2->channel[ch_id]; - bool const is_period = edpt_is_periodic(hcchar_bm->ep_type); + bool const is_period = channel_is_periodic(hcchar_bm->ep_type); // clear previous state xfer->fifo_bytes = 0; @@ -548,12 +556,15 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { // hctsiz: zero length packet still count as 1 const uint16_t packet_count = cal_packet_count(edpt->buflen, hcchar_bm->ep_size); - uint32_t hctsiz = (edpt->next_pid << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | edpt->buflen; + dwc2_channel_tsize_t hctsiz = {.value = 0}; + hctsiz.pid = edpt->next_pid; // next PID is set in transfer complete interrupt + hctsiz.packet_count = packet_count; + hctsiz.xfer_size = edpt->buflen; if (edpt->do_ping && edpt->speed == TUSB_SPEED_HIGH && edpt->next_pid != HCTSIZ_PID_SETUP && hcchar_bm->ep_dir == TUSB_DIR_OUT) { - hctsiz |= HCTSIZ_DOPING; + hctsiz.do_ping = 1; } - channel->hctsiz = hctsiz; + channel->hctsiz = hctsiz.value; edpt->do_ping = 0; // pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet @@ -699,13 +710,16 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; - if (edpt_is_periodic(channel->hcchar_bm.ep_type)){ + if (channel_is_periodic(channel->hcchar)){ + const dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; // retry immediately for periodic split NYET if we haven't reach max retry - if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) { + if (hcsplt.split_en && hcsplt.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) { xfer->period_split_nyet_count++; xfer->halted_nyet = 0; if (xfer->period_split_nyet_count < HCD_XFER_PERIOD_SPLIT_NYET_MAX) { - channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + channel->hcchar = hcchar.value; channel_send_in_token(dwc2, channel); return; } else { @@ -715,7 +729,8 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci } // for periodic, de-allocate channel, enable SOF set frame counter for later transfer - edpt->next_pid = channel->hctsiz_bm.pid; // save PID + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + edpt->next_pid = hctsiz.pid; // save PID edpt->uframe_countdown = edpt->uframe_interval; dwc2->gintmsk |= GINTSTS_SOF; @@ -756,13 +771,13 @@ static void handle_rxflvl_irq(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Pop control word off FIFO - const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm; - const uint8_t ch_id = grxstsp_bm.ep_ch_num; + const dwc2_grxstsp_t grxstsp = {.value= dwc2->grxstsp}; + const uint8_t ch_id = grxstsp.ep_ch_num; - switch (grxstsp_bm.packet_status) { + switch (grxstsp.packet_status) { case GRXSTS_PKTSTS_RX_DATA: { // In packet received, pop this entry --> ACK interrupt - const uint16_t byte_count = grxstsp_bm.byte_count; + const uint16_t byte_count = grxstsp.byte_count; hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,); hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; @@ -796,25 +811,26 @@ static void handle_rxflvl_irq(uint8_t rhport) { // return true if there is still pending data and need more ISR static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) { // Use period txsts for both p/np to get request queue space available (1-bit difference, it is small enough) - volatile dwc2_hptxsts_t* txsts_bm = (volatile dwc2_hptxsts_t*) (is_periodic ? &dwc2->hptxsts : &dwc2->hnptxsts); + const dwc2_hptxsts_t txsts = {.value = (is_periodic ? dwc2->hptxsts : dwc2->hnptxsts)}; const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2); for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { dwc2_channel_t* channel = &dwc2->channel[ch_id]; + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; // skip writing to FIFO if channel is expecting halted. - if (!(channel->hcintmsk & HCINT_HALTED) && (channel->hcchar_bm.ep_dir == TUSB_DIR_OUT)) { + if (!(channel->hcintmsk & HCINT_HALTED) && (hcchar.ep_dir == TUSB_DIR_OUT)) { hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; - - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + const uint16_t remain_packets = hctsiz.packet_count; for (uint16_t i = 0; i < remain_packets; i++) { const uint16_t remain_bytes = edpt->buflen - xfer->fifo_bytes; - const uint16_t xact_bytes = tu_min16(remain_bytes, channel->hcchar_bm.ep_size); + const uint16_t xact_bytes = tu_min16(remain_bytes, hcchar.ep_size); // skip if there is not enough space in FIFO and RequestQueue. // Packet's last word written to FIFO will trigger a request queue - if ((xact_bytes > (txsts_bm->fifo_available << 2)) || (txsts_bm->req_queue_available == 0)) { + if ((xact_bytes > (txsts.fifo_available << 2)) || (txsts.req_queue_available == 0)) { return true; } @@ -831,23 +847,27 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; bool is_done = false; - // if (channel->hcsplt_bm.split_en) { + // if (hcsplt.split_en) { // if (edpt->hcchar_bm.ep_num == 1) { - // TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, channel->hcchar_bm.ep_num, hcint); + // TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, hcsplt.ep_num, hcint); // print_hcint(hcint); // } if (hcint & HCINT_XFER_COMPLETE) { if (edpt->hcchar_bm.ep_num != 0) { - edpt->next_pid = channel->hctsiz_bm.pid; // save pid (already toggled) + edpt->next_pid = hctsiz.pid; // save pid (already toggled) } - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; - if (channel->hcsplt_bm.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) { + const uint16_t remain_packets = hctsiz.packet_count; + if (hcsplt.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) { // Split can only complete 1 transaction (up to 1 packet) at a time, schedule more - channel->hcsplt_bm.split_compl = 0; + hcsplt.split_compl = 0; + channel->hcsplt = hcsplt.value; } else { xfer->result = XFER_RESULT_SUCCESS; } @@ -866,34 +886,38 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h channel_disable(dwc2, channel); } else if (hcint & HCINT_NYET) { // restart complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; xfer->halted_nyet = 1; channel_disable(dwc2, channel); } else if (hcint & HCINT_NAK) { // NAK received, re-enable channel if request queue is available - if (channel->hcsplt_bm.split_en) { - channel->hcsplt_bm.split_compl = 0; // restart with start-split + if (hcsplt.split_en) { + hcsplt.split_compl = 0; // restart with start-split + channel->hcsplt = hcsplt.value; } channel_disable(dwc2, channel); } else if (hcint & HCINT_ACK) { xfer->err_count = 0; - if (channel->hcsplt_bm.split_en) { - if (!channel->hcsplt_bm.split_compl) { + if (hcsplt.split_en) { + if (!hcsplt.split_compl) { // start split is ACK --> do complete split channel->hcintmsk |= HCINT_NYET; - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel_send_in_token(dwc2, channel); } else { // do nothing for complete split with DATA, this will trigger XferComplete and handled there } } else { // ACK with data - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; + const uint16_t remain_packets = hctsiz.packet_count; if (remain_packets) { // still more packet to receive, also reset to start split - channel->hcsplt_bm.split_compl = 0; + hcsplt.split_compl = 0; + channel->hcsplt = hcsplt.value; channel_send_in_token(dwc2, channel); } } @@ -922,6 +946,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; bool is_done = false; if (hcint & HCINT_XFER_COMPLETE) { @@ -933,9 +958,10 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t channel_disable(dwc2, channel); } else if (hcint & HCINT_NYET) { xfer->err_count = 0; - if (channel->hcsplt_bm.split_en) { + if (hcsplt.split_en) { // retry complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } else { edpt->do_ping = 1; @@ -968,9 +994,10 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t } else if (hcint & HCINT_ACK) { xfer->err_count = 0; channel->hcintmsk &= ~HCINT_ACK; - if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) { + if (hcsplt.split_en && !hcsplt.split_compl) { // start split is ACK --> do complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } } @@ -989,6 +1016,9 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; bool is_done = false; @@ -996,8 +1026,8 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci if (hcint & HCINT_HALTED) { if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL | HCINT_BABBLE_ERR)) { - const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size; - const uint16_t remain_packets = channel->hctsiz_bm.packet_count; + const uint16_t remain_bytes = (uint16_t) hctsiz.xfer_size; + const uint16_t remain_packets = hctsiz.packet_count; const uint16_t actual_len = edpt->buflen - remain_bytes; xfer->xferred_bytes += actual_len; @@ -1007,13 +1037,14 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci xfer->result = XFER_RESULT_STALLED; } else if (hcint & HCINT_BABBLE_ERR) { xfer->result = XFER_RESULT_FAILED; - } else if (channel->hcsplt_bm.split_en && remain_packets && actual_len == edpt->hcchar_bm.ep_size) { + } else if (hcsplt.split_en && remain_packets && actual_len == hcchar.ep_size) { // Split can only complete 1 transaction (up to 1 packet) at a time, schedule more is_done = false; edpt->buffer += actual_len; edpt->buflen -= actual_len; - channel->hcsplt_bm.split_compl = 0; + hcsplt.split_compl = 0; + channel->hcsplt = hcsplt.value; channel_xfer_in_retry(dwc2, ch_id, hcint); } else { xfer->result = XFER_RESULT_SUCCESS; @@ -1028,33 +1059,38 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci xfer->result = XFER_RESULT_FAILED; } else { channel->hcintmsk |= HCINT_ACK | HCINT_NAK | HCINT_DATATOGGLE_ERR; - channel->hcsplt_bm.split_compl = 0; + hcsplt.split_compl = 0; + channel->hcsplt = hcsplt.value; channel_xfer_in_retry(dwc2, ch_id, hcint); } } else if (hcint & HCINT_NYET) { // Must handle nyet before nak or ack. Could get a nyet at the same time as either of those on a BULK/CONTROL // OUT that started with a PING. The nyet takes precedence. - if (channel->hcsplt_bm.split_en) { + if (hcsplt.split_en) { // split not yet mean hub has no data, retry complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel_xfer_in_retry(dwc2, ch_id, hcint); } } else if (hcint & HCINT_ACK) { xfer->err_count = 0; channel->hcintmsk &= ~HCINT_ACK; - if (channel->hcsplt_bm.split_en) { + if (hcsplt.split_en) { // start split is ACK --> do complete split // TODO: for ISO must use xact_pos to plan complete split based on microframe (up to 187.5 bytes/uframe) - channel->hcsplt_bm.split_compl = 1; - if (edpt_is_periodic(channel->hcchar_bm.ep_type)) { - channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; + if (channel_is_periodic(channel->hcchar)) { + hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + channel->hcchar = hcchar.value; } channel_send_in_token(dwc2, channel); } } else if (hcint & (HCINT_NAK | HCINT_DATATOGGLE_ERR)) { xfer->err_count = 0; channel->hcintmsk &= ~(HCINT_NAK | HCINT_DATATOGGLE_ERR); - channel->hcsplt_bm.split_compl = 0; // restart with start-split + hcsplt.split_compl = 0; // restart with start-split + channel->hcsplt = hcsplt.value; channel_xfer_in_retry(dwc2, ch_id, hcint); } else if (hcint & HCINT_FARME_OVERRUN) { // retry start-split in next binterval @@ -1069,6 +1105,8 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; + dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; bool is_done = false; @@ -1104,16 +1142,18 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc } } } else if (hcint & HCINT_NYET) { - if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl) { + if (hcsplt.split_en && hcsplt.split_compl) { // split not yet mean hub has no data, retry complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } } else if (hcint & HCINT_ACK) { xfer->err_count = 0; - if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) { + if (hcsplt.split_en && !hcsplt.split_compl) { // start split is ACK --> do complete split - channel->hcsplt_bm.split_compl = 1; + hcsplt.split_compl = 1; + channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } } @@ -1136,7 +1176,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,); - dwc2_channel_char_t hcchar_bm = channel->hcchar_bm; + dwc2_channel_char_t hcchar = {.value = channel->hcchar}; const uint32_t hcint = channel->hcint; channel->hcint = hcint; // clear interrupt @@ -1144,7 +1184,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { bool is_done = false; if (is_dma) { #if CFG_TUH_DWC2_DMA_ENABLE - if (hcchar_bm.ep_dir == TUSB_DIR_OUT) { + if (hcchar.ep_dir == TUSB_DIR_OUT) { is_done = handle_channel_out_dma(dwc2, ch_id, hcint); } else { is_done = handle_channel_in_dma(dwc2, ch_id, hcint); @@ -1156,7 +1196,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { #endif } else { #if CFG_TUH_DWC2_SLAVE_ENABLE - if (hcchar_bm.ep_dir == TUSB_DIR_OUT) { + if (hcchar.ep_dir == TUSB_DIR_OUT) { is_done = handle_channel_out_slave(dwc2, ch_id, hcint); } else { is_done = handle_channel_in_slave(dwc2, ch_id, hcint); @@ -1165,8 +1205,8 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) { } if (is_done) { - const uint8_t ep_addr = tu_edpt_addr(hcchar_bm.ep_num, hcchar_bm.ep_dir); - hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, xfer->xferred_bytes, xfer->result, in_isr); + const uint8_t ep_addr = tu_edpt_addr(hcchar.ep_num, hcchar.ep_dir); + hcd_event_xfer_complete(hcchar.dev_addr, ep_addr, xfer->xferred_bytes, (xfer_result_t)xfer->result, in_isr); channel_dealloc(dwc2, ch_id); } } @@ -1185,7 +1225,7 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) { for(uint8_t ep_id = 0; ep_id < CFG_TUH_DWC2_ENDPOINT_MAX; ep_id++) { hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; - if (edpt->hcchar_bm.enable && edpt_is_periodic(edpt->hcchar_bm.ep_type) && edpt->uframe_countdown > 0) { + if (edpt->hcchar_bm.enable && channel_is_periodic(edpt->hcchar) && edpt->uframe_countdown > 0) { edpt->uframe_countdown -= tu_min32(ucount, edpt->uframe_countdown); if (edpt->uframe_countdown == 0) { if (!edpt_xfer_kickoff(dwc2, ep_id)) { @@ -1204,10 +1244,10 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) { static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) { uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL; - const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm; + const dwc2_gusbcfg_t gusbcfg = {.value = dwc2->gusbcfg}; uint32_t phy_clock; - if (gusbcfg_bm.phy_sel) { + if (gusbcfg.phy_sel) { phy_clock = 48; // dedicated FS is 48Mhz if (speed == TUSB_SPEED_LOW) { hcfg |= HCFG_FSLS_PHYCLK_SEL_6MHZ; @@ -1215,11 +1255,11 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) { hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ; } } else { - if (gusbcfg_bm.ulpi_utmi_sel) { + if (gusbcfg.ulpi_utmi_sel) { phy_clock = 60; // ULPI 8-bit is 60Mhz } else { // UTMI+ 16-bit is 30Mhz, 8-bit is 60Mhz - phy_clock = gusbcfg_bm.phy_if16 ? 30 : 60; + phy_clock = gusbcfg.phy_if16 ? 30 : 60; // Enable UTMI+ low power mode 48Mhz external clock if not highspeed if (speed == TUSB_SPEED_HIGH) { @@ -1252,7 +1292,7 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) { static void handle_hprt_irq(uint8_t rhport, bool in_isr) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK; - const dwc2_hprt_t hprt_bm = dwc2->hprt_bm; + const dwc2_hprt_t hprt_bm = {.value = hprt}; if (dwc2->hprt & HPRT_CONN_DETECT) { // Port Connect Detect From 3acaffd64d4e14a984c6d1e0c36e733a825f319d Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 8 Apr 2025 00:22:47 +0200 Subject: [PATCH 05/68] build fix. Signed-off-by: HiFiPhile --- hw/bsp/broadcom_32bit/family.cmake | 2 +- hw/bsp/broadcom_32bit/family.mk | 2 +- hw/bsp/broadcom_64bit/family.cmake | 2 +- hw/bsp/broadcom_64bit/family.mk | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/bsp/broadcom_32bit/family.cmake b/hw/bsp/broadcom_32bit/family.cmake index 5e57d8b1e..f1e8d12ff 100644 --- a/hw/bsp/broadcom_32bit/family.cmake +++ b/hw/bsp/broadcom_32bit/family.cmake @@ -42,7 +42,7 @@ function(add_board_target BOARD_TARGET) -ffreestanding -mgeneral-regs-only -fno-exceptions - -std=c17 + -std=gnu17 ) target_include_directories(${BOARD_TARGET} PUBLIC ${SDK_DIR} diff --git a/hw/bsp/broadcom_32bit/family.mk b/hw/bsp/broadcom_32bit/family.mk index a282e9961..6acdf1197 100644 --- a/hw/bsp/broadcom_32bit/family.mk +++ b/hw/bsp/broadcom_32bit/family.mk @@ -10,7 +10,7 @@ CFLAGS += \ -nostartfiles \ -mgeneral-regs-only \ -fno-exceptions \ - -std=c17 + -std=gnu17 CROSS_COMPILE = arm-none-eabi- diff --git a/hw/bsp/broadcom_64bit/family.cmake b/hw/bsp/broadcom_64bit/family.cmake index 1a088c2c0..16f8e1eae 100644 --- a/hw/bsp/broadcom_64bit/family.cmake +++ b/hw/bsp/broadcom_64bit/family.cmake @@ -43,7 +43,7 @@ function(add_board_target BOARD_TARGET) -ffreestanding -mgeneral-regs-only -fno-exceptions - -std=c17 + -std=gnu17 ) target_compile_definitions(${BOARD_TARGET} PUBLIC BCM_VERSION=${BCM_VERSION} diff --git a/hw/bsp/broadcom_64bit/family.mk b/hw/bsp/broadcom_64bit/family.mk index 37d381f9f..92b5f69a3 100644 --- a/hw/bsp/broadcom_64bit/family.mk +++ b/hw/bsp/broadcom_64bit/family.mk @@ -9,7 +9,7 @@ CFLAGS += \ -nostartfiles \ --specs=nosys.specs \ -mgeneral-regs-only \ - -std=c17 + -std=gnu17 CROSS_COMPILE = aarch64-none-elf- From 2aff61ccb3797b85b99d6a1f3c3fb04a52f0d4fc Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Wed, 9 Apr 2025 19:40:03 +0200 Subject: [PATCH 06/68] Fix CI. Signed-off-by: HiFiPhile --- src/portable/synopsys/dwc2/hcd_dwc2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index af17bb59a..f3dc23b9c 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -847,7 +847,6 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; - const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; bool is_done = false; From 72357cdb20ee7dca5a19d02ce9b7f14d237fb29e Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Fri, 11 Apr 2025 12:15:56 +0200 Subject: [PATCH 07/68] dwc2/host: HFIR: Fix timing off-by-one --- src/portable/synopsys/dwc2/hcd_dwc2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 7cbef05b7..6f7551ed7 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -1242,9 +1242,9 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) { uint32_t hfir = dwc2->hfir & ~HFIR_FRIVL_Msk; if (speed == TUSB_SPEED_HIGH) { - hfir |= 125*phy_clock; + hfir |= 125*phy_clock - 1; // The "- 1" is the correct value. The Synopsys databook was corrected in 3.30a } else { - hfir |= 1000*phy_clock; + hfir |= 1000*phy_clock - 1; } dwc2->hfir = hfir; From 2064ee470d6c7b434d6b3aafe017ed60c3b17ab5 Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Fri, 11 Apr 2025 12:14:07 +0200 Subject: [PATCH 08/68] dwc2/host: attach debouncing fixes --- src/host/usbh.c | 2 +- src/portable/synopsys/dwc2/hcd_dwc2.c | 26 +++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index e60db53da..4b0f4d488 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1038,7 +1038,7 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) // Check if dev0 is removed if ((event->rhport == _dev0.rhport) && (event->connection.hub_addr == _dev0.hub_addr) && (event->connection.hub_port == _dev0.hub_port)) { - _dev0.enumerating = 0; + //_dev0.enumerating = 0;// Causes assert in dwc2 process_enumeration() -> ENUM_ADDR0_DEVICE_DESC } break; diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 7cbef05b7..65288e30c 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -109,6 +109,7 @@ typedef struct { typedef struct { hcd_xfer_t xfer[DWC2_CHANNEL_COUNT_MAX]; hcd_endpoint_t edpt[CFG_TUH_DWC2_ENDPOINT_MAX]; + bool attach_debounce; // if true: wait for the debounce delay before issuing new attach events } hcd_data_t; hcd_data_t _hcd_data; @@ -413,6 +414,11 @@ uint32_t hcd_frame_number(uint8_t rhport) { // Get the current connect status of roothub port bool hcd_port_connect_status(uint8_t rhport) { + // this is called from enum_new_device() - after the debouncing delays + if (_hcd_data.attach_debounce) { + _hcd_data.attach_debounce = false; // allow new attach events again + } + dwc2_regs_t* dwc2 = DWC2_REG(rhport); return dwc2->hprt & HPRT_CONN_STATUS; } @@ -1265,9 +1271,10 @@ static void handle_hprt_irq(uint8_t rhport, bool in_isr) { hprt |= HPRT_CONN_DETECT; if (hprt_bm.conn_status) { - hcd_event_device_attach(rhport, in_isr); - } else { - hcd_event_device_remove(rhport, in_isr); + if (!_hcd_data.attach_debounce) { + _hcd_data.attach_debounce = true; // block new attach events until the debounce delay is over + hcd_event_device_attach(rhport, in_isr); + } } } @@ -1330,6 +1337,19 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { handle_channel_irq(rhport, in_isr); } + if (gintsts & GINTSTS_DISCINT) { + // Device disconnected + dwc2->gintsts = GINTSTS_DISCINT; + + // ignore device removal if attach debounce is active + // it will evaluate the port status after the debounce delay + if (!_hcd_data.attach_debounce) { + if (!(dwc2->hprt & HPRT_CONN_STATUS)) { + hcd_event_device_remove(rhport, in_isr); + } + } + } + #if CFG_TUH_DWC2_SLAVE_ENABLE // RxFIFO non-empty interrupt handling if (gintsts & GINTSTS_RXFLVL) { From 925010fd841c5442579c503a3b1aa211cc25e8b2 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 11 Apr 2025 17:02:42 +0200 Subject: [PATCH 09/68] host/dwc2: resume OUT transfer when PING ACKed Signed-off-by: HiFiPhile --- src/portable/synopsys/dwc2/hcd_dwc2.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 7cbef05b7..22f3bc70a 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -590,7 +590,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { hcintmsk |= HCINT_BABBLE_ERR | HCINT_DATATOGGLE_ERR | HCINT_ACK; } else { hcintmsk |= HCINT_NYET; - if (edpt->hcsplt_bm.split_en) { + if (edpt->hcsplt_bm.split_en || hctsiz & HCTSIZ_DOPING) { hcintmsk |= HCINT_ACK; } } @@ -973,10 +973,17 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t } else if (hcint & HCINT_ACK) { xfer->err_count = 0; channel->hcintmsk &= ~HCINT_ACK; - if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) { - // start split is ACK --> do complete split - channel->hcsplt_bm.split_compl = 1; - channel->hcchar |= HCCHAR_CHENA; + if (channel->hcsplt_bm.split_en) { + if(!channel->hcsplt_bm.split_compl) { + // start split is ACK --> do complete split + channel->hcsplt_bm.split_compl = 1; + channel->hcchar |= HCCHAR_CHENA; + } + } else { + // Device is ready, resume transfer + edpt->do_ping = 0; + xfer->err_count = 0; + TU_ASSERT(channel_xfer_start(dwc2, ch_id)); } } From 937b07cdc0bb9341db35b4d8444827b03d06e84a Mon Sep 17 00:00:00 2001 From: Patrick Plenefisch Date: Fri, 11 Apr 2025 18:19:39 -0400 Subject: [PATCH 10/68] Fix version string to actually be the version --- src/tusb_option.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tusb_option.h b/src/tusb_option.h index 29fdcb0d6..98f1a91b5 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -35,7 +35,7 @@ #define TUSB_VERSION_REVISION 0 #define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR * 10000 + TUSB_VERSION_MINOR * 100 + TUSB_VERSION_REVISION) -#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION) +#define TUSB_VERSION_STRING TU_XSTRING(TUSB_VERSION_MAJOR) "." TU_XSTRING(TUSB_VERSION_MINOR) "." TU_XSTRING(TUSB_VERSION_REVISION) //--------------------------------------------------------------------+ // Supported MCUs From aecfd3433c6c235d632636f2936c7df180e9d12a Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 12 Apr 2025 13:36:10 +0200 Subject: [PATCH 11/68] Fix handle_hprt_irq Signed-off-by: HiFiPhile --- src/portable/synopsys/dwc2/hcd_dwc2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index f3dc23b9c..3acdf580d 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -1290,10 +1290,10 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) { */ static void handle_hprt_irq(uint8_t rhport, bool in_isr) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK; - const dwc2_hprt_t hprt_bm = {.value = hprt}; + const dwc2_hprt_t hprt_bm = {.value = dwc2->hprt}; + uint32_t hprt = hprt_bm.value & ~HPRT_W1_MASK; - if (dwc2->hprt & HPRT_CONN_DETECT) { + if (hprt_bm.conn_detected) { // Port Connect Detect hprt |= HPRT_CONN_DETECT; @@ -1304,7 +1304,7 @@ static void handle_hprt_irq(uint8_t rhport, bool in_isr) { } } - if (dwc2->hprt & HPRT_ENABLE_CHANGE) { + if (hprt_bm.enable_change) { // Port enable change hprt |= HPRT_ENABLE_CHANGE; From af0c47e06ec079ffa80ea55ff5de58c08ac1e750 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 12 Apr 2025 15:21:19 +0200 Subject: [PATCH 12/68] Fix typo Signed-off-by: HiFiPhile --- src/portable/synopsys/dwc2/hcd_dwc2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 3acdf580d..8f1103415 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -543,7 +543,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm; dwc2_channel_t* channel = &dwc2->channel[ch_id]; - bool const is_period = channel_is_periodic(hcchar_bm->ep_type); + bool const is_period = channel_is_periodic(edpt->hcchar); // clear previous state xfer->fifo_bytes = 0; From d039d54a89d15b9d11f8f22f94279bedc8b28c09 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 14 Apr 2025 16:31:17 +0700 Subject: [PATCH 13/68] channge DWC2_CHANNEL_COUNT/DWC2_EP_COUNT to inline function --- hw/bsp/broadcom_32bit/family.cmake | 2 +- hw/bsp/broadcom_32bit/family.mk | 2 +- hw/bsp/broadcom_64bit/family.cmake | 2 +- hw/bsp/broadcom_64bit/family.mk | 2 +- src/portable/synopsys/dwc2/dcd_dwc2.c | 20 +- src/portable/synopsys/dwc2/dwc2_common.c | 2 +- src/portable/synopsys/dwc2/dwc2_type.h | 302 +++++++++++------------ src/portable/synopsys/dwc2/hcd_dwc2.c | 15 +- 8 files changed, 177 insertions(+), 170 deletions(-) diff --git a/hw/bsp/broadcom_32bit/family.cmake b/hw/bsp/broadcom_32bit/family.cmake index f1e8d12ff..5e57d8b1e 100644 --- a/hw/bsp/broadcom_32bit/family.cmake +++ b/hw/bsp/broadcom_32bit/family.cmake @@ -42,7 +42,7 @@ function(add_board_target BOARD_TARGET) -ffreestanding -mgeneral-regs-only -fno-exceptions - -std=gnu17 + -std=c17 ) target_include_directories(${BOARD_TARGET} PUBLIC ${SDK_DIR} diff --git a/hw/bsp/broadcom_32bit/family.mk b/hw/bsp/broadcom_32bit/family.mk index 6acdf1197..a282e9961 100644 --- a/hw/bsp/broadcom_32bit/family.mk +++ b/hw/bsp/broadcom_32bit/family.mk @@ -10,7 +10,7 @@ CFLAGS += \ -nostartfiles \ -mgeneral-regs-only \ -fno-exceptions \ - -std=gnu17 + -std=c17 CROSS_COMPILE = arm-none-eabi- diff --git a/hw/bsp/broadcom_64bit/family.cmake b/hw/bsp/broadcom_64bit/family.cmake index 16f8e1eae..1a088c2c0 100644 --- a/hw/bsp/broadcom_64bit/family.cmake +++ b/hw/bsp/broadcom_64bit/family.cmake @@ -43,7 +43,7 @@ function(add_board_target BOARD_TARGET) -ffreestanding -mgeneral-regs-only -fno-exceptions - -std=gnu17 + -std=c17 ) target_compile_definitions(${BOARD_TARGET} PUBLIC BCM_VERSION=${BCM_VERSION} diff --git a/hw/bsp/broadcom_64bit/family.mk b/hw/bsp/broadcom_64bit/family.mk index 92b5f69a3..37d381f9f 100644 --- a/hw/bsp/broadcom_64bit/family.mk +++ b/hw/bsp/broadcom_64bit/family.mk @@ -9,7 +9,7 @@ CFLAGS += \ -nostartfiles \ --specs=nosys.specs \ -mgeneral-regs-only \ - -std=gnu17 + -std=c17 CROSS_COMPILE = aarch64-none-elf- diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 83ebc18cb..52d675611 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -41,12 +41,6 @@ #include "device/dcd.h" #include "dwc2_common.h" -#if TU_CHECK_MCU(OPT_MCU_GD32VF103) - #define DWC2_EP_COUNT(_dwc2) DWC2_EP_MAX -#else - #define DWC2_EP_COUNT(_dwc2) ({const dwc2_ghwcfg2_t ghwcfg2 = {.value = (_dwc2)->ghwcfg2}; ghwcfg2.num_dev_ep + 1;}) -#endif - //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ @@ -79,6 +73,16 @@ CFG_TUD_MEM_SECTION static struct { TUD_EPBUF_DEF(setup_packet, 8); } _dcd_usbbuf; +TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_ep_count(const dwc2_regs_t* dwc2) { + #if TU_CHECK_MCU(OPT_MCU_GD32VF103) + return DWC2_EP_MAX; + #else + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + return ghwcfg2.num_dev_ep + 1; + #endif +} + + //-------------------------------------------------------------------- // DMA //-------------------------------------------------------------------- @@ -629,7 +633,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { // 7.4.1 Initialization on USB Reset static void handle_bus_reset(uint8_t rhport) { dwc2_regs_t *dwc2 = DWC2_REG(rhport); - const uint8_t ep_count = DWC2_EP_COUNT(dwc2); + const uint8_t ep_count = dwc2_ep_count(dwc2); tu_memclr(xfer_status, sizeof(xfer_status)); @@ -926,7 +930,7 @@ static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepin static void handle_ep_irq(uint8_t rhport, uint8_t dir) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); const bool is_dma = dma_device_enabled(dwc2); - const uint8_t ep_count = DWC2_EP_COUNT(dwc2); + const uint8_t ep_count = dwc2_ep_count(dwc2); const uint8_t daint_offset = (dir == TUSB_DIR_IN) ? DAINT_IEPINT_Pos : DAINT_OEPINT_Pos; dwc2_dep_t* ep_base = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][0]; diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c index 989a833ff..f6ed8fc98 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.c +++ b/src/portable/synopsys/dwc2/dwc2_common.c @@ -173,7 +173,6 @@ static bool check_dwc2(dwc2_regs_t* dwc2) { //-------------------------------------------------------------------- bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) { (void)dwc2; - const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; #if CFG_TUD_ENABLED if (role == TUSB_ROLE_DEVICE && !TUD_OPT_HIGH_SPEED) { return false; @@ -185,6 +184,7 @@ bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) { } #endif + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; return ghwcfg2.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED; } diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 5ecf9d487..34e046346 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -299,17 +299,17 @@ TU_VERIFY_STATIC(sizeof(dwc2_gusbcfg_t) == 4, "incorrect size"); typedef union { uint32_t value; struct TU_ATTR_PACKED { - uint32_t core_soft_rst : 1; // 0 Core Soft Reset - uint32_t piufs_soft_rst : 1; // 1 PIU FS Dedicated Controller Soft Reset - uint32_t frame_counter_rst : 1; // 2 Frame Counter Reset (host) - uint32_t intoken_q_flush : 1; // 3 IN Token Queue Flush - uint32_t rx_fifo_flush : 1; // 4 RX FIFO Flush - uint32_t tx_fifo_flush : 1; // 5 TX FIFO Flush - uint32_t tx_fifo_num : 5; // 6..10 TX FIFO Number - uint32_t rsv11_28 :18; // 11..28 Reserved - uint32_t core_soft_rst_done : 1; // 29 Core Soft Reset Done, from v4.20a - uint32_t dma_req : 1; // 30 DMA Request - uint32_t ahb_idle : 1; // 31 AHB Idle + uint32_t core_soft_rst : 1; // 0 Core Soft Reset + uint32_t piufs_soft_rst : 1; // 1 PIU FS Dedicated Controller Soft Reset + uint32_t frame_counter_rst : 1; // 2 Frame Counter Reset (host) + uint32_t intoken_q_flush : 1; // 3 IN Token Queue Flush + uint32_t rx_fifo_flush : 1; // 4 RX FIFO Flush + uint32_t tx_fifo_flush : 1; // 5 TX FIFO Flush + uint32_t tx_fifo_num : 5; // 6..10 TX FIFO Number + uint32_t rsv11_28 :18; // 11..28 Reserved + uint32_t core_soft_rst_done : 1; // 29 Core Soft Reset Done, from v4.20a + uint32_t dma_req : 1; // 30 DMA Request + uint32_t ahb_idle : 1; // 31 AHB Idle }; } dwc2_grstctl_t; TU_VERIFY_STATIC(sizeof(dwc2_grstctl_t) == 4, "incorrect size"); @@ -317,12 +317,12 @@ TU_VERIFY_STATIC(sizeof(dwc2_grstctl_t) == 4, "incorrect size"); typedef union { uint32_t value; struct TU_ATTR_PACKED { - uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number - uint32_t byte_count :11; // 4..14 Byte Count - uint32_t dpid : 2; // 15..16 Data PID - uint32_t packet_status : 4; // 17..20 Packet Status - uint32_t frame_number : 4; // 21..24 Frame Number - uint32_t rsv25_31 : 7; // 25..31 Reserved + uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number + uint32_t byte_count :11; // 4..14 Byte Count + uint32_t dpid : 2; // 15..16 Data PID + uint32_t packet_status : 4; // 17..20 Packet Status + uint32_t frame_number : 4; // 21..24 Frame Number + uint32_t rsv25_31 : 7; // 25..31 Reserved }; } dwc2_grxstsp_t; TU_VERIFY_STATIC(sizeof(dwc2_grxstsp_t) == 4, "incorrect size"); @@ -371,28 +371,28 @@ TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg3_t) == 4, "incorrect size"); typedef union { uint32_t value; struct TU_ATTR_PACKED { - uint32_t num_dev_period_in_ep : 4; // 0..3 Number of Device Periodic IN Endpoints - uint32_t partial_powerdown : 1; // 4 Partial Power Down Enabled - uint32_t ahb_freq_min : 1; // 5 1: minimum of AHB frequency is less than 60 MHz - uint32_t hibernation : 1; // 6 Hibernation feature is enabled - uint32_t extended_hibernation : 1; // 7 Extended Hibernation feature is enabled - uint32_t reserved8 : 1; // 8 Reserved - uint32_t enhanced_lpm_support1 : 1; // 9 Enhanced LPM Support1 - uint32_t service_interval_flow : 1; // 10 Service Interval flow is supported - uint32_t ipg_isoc_support : 1; // 11 Interpacket GAP ISO OUT worst-case is supported - uint32_t acg_support : 1; // 12 Active clock gating is supported - uint32_t enhanced_lpm_support : 1; // 13 Enhanced LPM Support - uint32_t phy_data_width : 2; // 14..15 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable - uint32_t ctrl_ep_num : 4; // 16..19 Number of Device control endpoints in addition to EP0 - uint32_t iddg_filter : 1; // 20 IDDG Filter Enabled - uint32_t vbus_valid_filter : 1; // 21 VBUS Valid Filter Enabled - uint32_t a_valid_filter : 1; // 22 A Valid Filter Enabled - uint32_t b_valid_filter : 1; // 23 B Valid Filter Enabled - uint32_t session_end_filter : 1; // 24 Session End Filter Enabled - uint32_t dedicated_fifos : 1; // 25 Dedicated tx fifo for device IN Endpoint - uint32_t num_dev_in_eps : 4; // 26..29 Number of Device IN Endpoints including EP0 - uint32_t dma_desc_enabled : 1; // scatter/gather DMA configuration enabled - uint32_t dma_desc_dynamic : 1; // Dynamic scatter/gather DMA + uint32_t num_dev_period_in_ep : 4; // 0..3 Number of Device Periodic IN Endpoints + uint32_t partial_powerdown : 1; // 4 Partial Power Down Enabled + uint32_t ahb_freq_min : 1; // 5 1: minimum of AHB frequency is less than 60 MHz + uint32_t hibernation : 1; // 6 Hibernation feature is enabled + uint32_t extended_hibernation : 1; // 7 Extended Hibernation feature is enabled + uint32_t reserved8 : 1; // 8 Reserved + uint32_t enhanced_lpm_support1 : 1; // 9 Enhanced LPM Support1 + uint32_t service_interval_flow : 1; // 10 Service Interval flow is supported + uint32_t ipg_isoc_support : 1; // 11 Interpacket GAP ISO OUT worst-case is supported + uint32_t acg_support : 1; // 12 Active clock gating is supported + uint32_t enhanced_lpm_support : 1; // 13 Enhanced LPM Support + uint32_t phy_data_width : 2; // 14..15 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable + uint32_t ctrl_ep_num : 4; // 16..19 Number of Device control endpoints in addition to EP0 + uint32_t iddg_filter : 1; // 20 IDDG Filter Enabled + uint32_t vbus_valid_filter : 1; // 21 VBUS Valid Filter Enabled + uint32_t a_valid_filter : 1; // 22 A Valid Filter Enabled + uint32_t b_valid_filter : 1; // 23 B Valid Filter Enabled + uint32_t session_end_filter : 1; // 24 Session End Filter Enabled + uint32_t dedicated_fifos : 1; // 25 Dedicated tx fifo for device IN Endpoint + uint32_t num_dev_in_eps : 4; // 26..29 Number of Device IN Endpoints including EP0 + uint32_t dma_desc_enabled : 1; // scatter/gather DMA configuration enabled + uint32_t dma_desc_dynamic : 1; // Dynamic scatter/gather DMA }; } dwc2_ghwcfg4_t; TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size"); @@ -402,7 +402,7 @@ typedef union { struct TU_ATTR_PACKED { uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO uint32_t req_queue_available : 8; // 16..23 Number of spaces available in the NPT transmit request queue for both IN and OU - // 24..31 is top entry in the request queue that is currently being processed by the MAC + // 24..31 is top entry in the request queue that is currently being processed by the MAC uint32_t qtop_terminate : 1; // 24 Last entry for selected channel uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command uint32_t qtop_ch_num : 4; // 27..30 Channel number @@ -413,7 +413,7 @@ TU_VERIFY_STATIC(sizeof(dwc2_hnptxsts_t) == 4, "incorrect size"); typedef union { uint32_t value; struct TU_ATTR_PACKED { - uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO + uint32_t fifo_available :16; // 0..15 Number of words available in the Tx FIFO uint32_t req_queue_available : 7; // 16..22 Number of spaces available in the PTX transmit request queue uint32_t qtop_terminate : 1; // 23 Last entry for selected channel uint32_t qtop_last_period : 1; // 24 Last entry for selected channel is a periodic entry @@ -467,12 +467,12 @@ TU_VERIFY_STATIC(sizeof(dwc2_channel_char_t) == 4, "incorrect size"); typedef union { uint32_t value; struct TU_ATTR_PACKED { - uint32_t hub_port : 7; // 0..6 Hub port number - uint32_t hub_addr : 7; // 7..13 Hub address - uint32_t xact_pos : 2; // 14..15 Transaction position - uint32_t split_compl : 1; // 16 Split completion - uint32_t rsv17_30 : 14; // 17..30 Reserved - uint32_t split_en : 1; // 31 Split enable + uint32_t hub_port : 7; // 0..6 Hub port number + uint32_t hub_addr : 7; // 7..13 Hub address + uint32_t xact_pos : 2; // 14..15 Transaction position + uint32_t split_compl : 1; // 16 Split completion + uint32_t rsv17_30 : 14; // 17..30 Reserved + uint32_t split_en : 1; // 31 Split enable }; } dwc2_channel_split_t; TU_VERIFY_STATIC(sizeof(dwc2_channel_split_t) == 4, "incorrect size"); @@ -480,10 +480,10 @@ TU_VERIFY_STATIC(sizeof(dwc2_channel_split_t) == 4, "incorrect size"); typedef union { uint32_t value; struct TU_ATTR_PACKED { - uint32_t xfer_size : 19; // 0..18 Transfer size in bytes - uint32_t packet_count : 10; // 19..28 Number of packets - uint32_t pid : 2; // 29..30 Packet ID - uint32_t do_ping : 1; // 31 Do PING + uint32_t xfer_size : 19; // 0..18 Transfer size in bytes + uint32_t packet_count : 10; // 19..28 Number of packets + uint32_t pid : 2; // 29..30 Packet ID + uint32_t do_ping : 1; // 31 Do PING }; } dwc2_channel_tsize_t; TU_VERIFY_STATIC(sizeof(dwc2_channel_tsize_t) == 4, "incorrect size"); @@ -499,14 +499,14 @@ TU_VERIFY_STATIC(sizeof(dwc2_hfnum_t) == 4, "incorrect size"); // Host Channel typedef struct { - volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics - volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control - volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt - volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask - volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size - volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address - uint32_t reserved518; // 518 + 20*ch - volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address + volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics + volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control + volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt + volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask + volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size + volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address + uint32_t reserved518; // 518 + 20*ch + volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address } dwc2_channel_t; //-------------------------------------------------------------------- @@ -565,7 +565,7 @@ typedef union { uint32_t enum_speed : 2; // 1..2 Enumerated speed uint32_t erratic_err : 1; // 3 Erratic error uint32_t rsv4_7 : 4; // 4..7 Reserved - uint32_t frame_number : 14; // 8..21 Frame/MicroFrame number + uint32_t frame_number :14; // 8..21 Frame/MicroFrame number uint32_t line_status : 2; // 22..23 Line status uint32_t rsv24_31 : 8; // 24..31 Reserved }; @@ -620,23 +620,23 @@ TU_VERIFY_STATIC(sizeof(dwc2_depctl_t) == 4, "incorrect size"); typedef union { uint32_t value; struct TU_ATTR_PACKED { - uint32_t xfer_complete : 1; // 0 Transfer complete - uint32_t disabled : 1; // 1 Endpoint disabled - uint32_t ahb_err : 1; // 2 AHB error - uint32_t setup_phase_done : 1; // 3 Setup phase done - uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled - uint32_t status_phase_rx : 1; // 5 Status phase received - uint32_t setup_b2b : 1; // 6 Setup packet back-to-back - uint32_t rsv7 : 1; // 7 Reserved - uint32_t out_packet_err : 1; // 8 OUT packet error - uint32_t bna : 1; // 9 Buffer not available - uint32_t rsv10 : 1; // 10 Reserved - uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status - uint32_t babble_err : 1; // 12 Babble error - uint32_t nak : 1; // 13 NAK - uint32_t nyet : 1; // 14 NYET - uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only) - uint32_t rsv16_31 :16; // 16..31 Reserved + uint32_t xfer_complete : 1; // 0 Transfer complete + uint32_t disabled : 1; // 1 Endpoint disabled + uint32_t ahb_err : 1; // 2 AHB error + uint32_t setup_phase_done : 1; // 3 Setup phase done + uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled + uint32_t status_phase_rx : 1; // 5 Status phase received + uint32_t setup_b2b : 1; // 6 Setup packet back-to-back + uint32_t rsv7 : 1; // 7 Reserved + uint32_t out_packet_err : 1; // 8 OUT packet error + uint32_t bna : 1; // 9 Buffer not available + uint32_t rsv10 : 1; // 10 Reserved + uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status + uint32_t babble_err : 1; // 12 Babble error + uint32_t nak : 1; // 13 NAK + uint32_t nyet : 1; // 14 NYET + uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only) + uint32_t rsv16_31 :16; // 16..31 Reserved }; } dwc2_doepint_t; TU_VERIFY_STATIC(sizeof(dwc2_doepint_t) == 4, "incorrect size"); @@ -684,17 +684,17 @@ TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size"); // CSR Register Map //-------------------------------------------------------------------- typedef struct { - //------------- Core Global -------------// - volatile uint32_t gotgctl; // 000 OTG Control and Status - volatile uint32_t gotgint; // 004 OTG Interrupt - volatile uint32_t gahbcfg; // 008 AHB Configuration - volatile uint32_t gusbcfg; // 00c USB Configuration - volatile uint32_t grstctl; // 010 Reset - volatile uint32_t gintsts; // 014 Interrupt - volatile uint32_t gintmsk; // 018 Interrupt Mask - volatile uint32_t grxstsr; // 01c Receive Status Debug Read - volatile uint32_t grxstsp; // 020 Receive Status Read/Pop - volatile uint32_t grxfsiz; // 024 Receive FIFO Size + //------------- Core Global ------------- + volatile uint32_t gotgctl; // 000 OTG Control and Status + volatile uint32_t gotgint; // 004 OTG Interrupt + volatile uint32_t gahbcfg; // 008 AHB Configuration + volatile uint32_t gusbcfg; // 00c USB Configuration + volatile uint32_t grstctl; // 010 Reset + volatile uint32_t gintsts; // 014 Interrupt + volatile uint32_t gintmsk; // 018 Interrupt Mask + volatile uint32_t grxstsr; // 01c Receive Status Debug Read + volatile uint32_t grxstsp; // 020 Receive Status Read/Pop + volatile uint32_t grxfsiz; // 024 Receive FIFO Size union { volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size volatile uint32_t gnptxfsiz; // 028 Non-periodic Transmit FIFO Size @@ -703,89 +703,89 @@ typedef struct { volatile uint32_t hnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status volatile uint32_t gnptxsts; }; - volatile uint32_t gi2cctl; // 030 I2C Address - volatile uint32_t gpvndctl; // 034 PHY Vendor Control + volatile uint32_t gi2cctl; // 030 I2C Address + volatile uint32_t gpvndctl; // 034 PHY Vendor Control union { volatile uint32_t ggpio; // 038 General Purpose IO volatile uint32_t stm32_gccfg; // 038 STM32 General Core Configuration }; - volatile uint32_t guid; // 03C User (Application programmable) ID - volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version - volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep) - volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2 - volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3 + volatile uint32_t guid; // 03C User (Application programmable) ID + volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version + volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep) + volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2 + volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3 union { volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4 volatile dwc2_ghwcfg4_t ghwcfg4_bm; }; - volatile uint32_t glpmcfg; // 054 Core LPM Configuration - volatile uint32_t gpwrdn; // 058 Power Down - volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration - volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status - uint32_t reserved64[39]; // 064..0FF - volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size - volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size - uint32_t reserved140[176]; // 140..3FF + volatile uint32_t glpmcfg; // 054 Core LPM Configuration + volatile uint32_t gpwrdn; // 058 Power Down + volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration + volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status + uint32_t reserved64[39]; // 064..0FF + volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size + volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size + uint32_t reserved140[176]; // 140..3FF - //------------ Host -------------// - volatile uint32_t hcfg; // 400 Host Configuration - volatile uint32_t hfir; // 404 Host Frame Interval - volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining - uint32_t reserved40c; // 40C - volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status - volatile uint32_t haint; // 414 Host All Channels Interrupt - volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask - volatile uint32_t hflbaddr; // 41C Host Frame List Base Address - uint32_t reserved420[8]; // 420..43F - volatile uint32_t hprt; // 440 Host Port Control and Status - uint32_t reserved444[47]; // 444..4FF + //------------ Host ------------- + volatile uint32_t hcfg; // 400 Host Configuration + volatile uint32_t hfir; // 404 Host Frame Interval + volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining + uint32_t reserved40c; // 40C + volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status + volatile uint32_t haint; // 414 Host All Channels Interrupt + volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask + volatile uint32_t hflbaddr; // 41C Host Frame List Base Address + uint32_t reserved420[8]; // 420..43F + volatile uint32_t hprt; // 440 Host Port Control and Status + uint32_t reserved444[47]; // 444..4FF - //------------- Host Channel -------------// - dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15 - uint32_t reserved700[64]; // 700..7FF + //------------- Host Channel -------- + dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15 + uint32_t reserved700[64]; // 700..7FF - //------------- Device -----------// - volatile uint32_t dcfg; // 800 Device Configuration - volatile uint32_t dctl; // 804 Device Control - volatile uint32_t dsts; // 808 Device Status (RO) - uint32_t reserved80c; // 80C - volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask - volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask - volatile uint32_t daint; // 818 Device All Endpoints Interrupt - volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask - volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1 - volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2 - volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time - volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time - volatile uint32_t dthrctl; // 830 Device threshold Control - volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask + //------------- Device ----------- + volatile uint32_t dcfg; // 800 Device Configuration + volatile uint32_t dctl; // 804 Device Control + volatile uint32_t dsts; // 808 Device Status (RO) + uint32_t reserved80c; // 80C + volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask + volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask + volatile uint32_t daint; // 818 Device All Endpoints Interrupt + volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask + volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1 + volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2 + volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time + volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time + volatile uint32_t dthrctl; // 830 Device threshold Control + volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask - // Device Each Endpoint (IN/OUT) Interrupt/Mask for generating dedicated EP interrupt line - // require OTG_MULTI_PROC_INTRPT=1 - volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt - volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt mask - volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask - volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask - uint32_t reserved8c0[16]; // 8C0..8FF + // Device Each Endpoint (IN/OUT) Interrupt/Mask for generating dedicated EP interrupt line require + // OTG_MULTI_PROC_INTRPT=1 + volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt + volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt mask + volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask + volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask + uint32_t reserved8c0[16]; // 8C0..8FF - //------------- Device Endpoint -------------// + //------------- Device Endpoint ----- union { - dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT + dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT struct { - dwc2_dep_t epin[16]; // 900..AFF IN Endpoints - dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints + dwc2_dep_t epin[16]; // 900..AFF IN Endpoints + dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints }; }; - uint32_t reservedd00[64]; // D00..DFF + uint32_t reservedd00[64]; // D00..DFF - //------------- Power Clock -------------// - volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control - volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1 - uint32_t reservede08[126]; // E08..FFF + //------------- Power Clock --------- + volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control + volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1 + uint32_t reservede08[126]; // E08..FFF - //------------- FIFOs -------------// + //------------- FIFOs ------------- // Word-accessed only using first pointer since it auto shift - volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO + volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO } dwc2_regs_t; TU_VERIFY_STATIC(offsetof(dwc2_regs_t, hcfg ) == 0x0400, "incorrect size"); diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 8f1103415..8d565d174 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -44,8 +44,6 @@ #endif #define DWC2_CHANNEL_COUNT_MAX 16 // absolute max channel count -#define DWC2_CHANNEL_COUNT(_dwc2) ({const dwc2_ghwcfg2_t ghwcfg2 = {.value = (_dwc2)->ghwcfg2}; tu_min8(ghwcfg2.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX);}) - TU_VERIFY_STATIC(CFG_TUH_DWC2_ENDPOINT_MAX <= 255, "currently only use 8-bit for index"); enum { @@ -116,6 +114,11 @@ hcd_data_t _hcd_data; //-------------------------------------------------------------------- // //-------------------------------------------------------------------- +TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_channel_count(const dwc2_regs_t* dwc2) { + const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2}; + return tu_min8(ghwcfg2.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX); +} + TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc2) { tusb_speed_t speed; const dwc2_hprt_t hprt = {.value = dwc2->hprt}; @@ -157,7 +160,7 @@ bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) { // Allocate a channel for new transfer TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) { - const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2); + const uint8_t max_channel = dwc2_channel_count(dwc2); for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; if (!xfer->allocated) { @@ -208,7 +211,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool channel_send_in_token(const dwc2_regs_t // Find currently enabled channel. Note: EP0 is bidirectional TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_find_enabled(dwc2_regs_t* dwc2, uint8_t dev_addr, uint8_t ep_num, uint8_t ep_dir) { - const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2); + const uint8_t max_channel = dwc2_channel_count(dwc2); for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { if (_hcd_data.xfer[ch_id].allocated) { const dwc2_channel_char_t hcchar = {.value = dwc2->channel[ch_id].hcchar}; @@ -813,7 +816,7 @@ static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) { // Use period txsts for both p/np to get request queue space available (1-bit difference, it is small enough) const dwc2_hptxsts_t txsts = {.value = (is_periodic ? dwc2->hptxsts : dwc2->hnptxsts)}; - const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2); + const uint8_t max_channel = dwc2_channel_count(dwc2); for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { dwc2_channel_t* channel = &dwc2->channel[ch_id]; const dwc2_channel_char_t hcchar = {.value = channel->hcchar}; @@ -1168,7 +1171,7 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc static void handle_channel_irq(uint8_t rhport, bool in_isr) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); const bool is_dma = dma_host_enabled(dwc2); - const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2); + const uint8_t max_channel = dwc2_channel_count(dwc2); for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) { if (tu_bit_test(dwc2->haint, ch_id)) { From 384e191fdc9346eb8718f1f3e50f4697f161cc88 Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Thu, 10 Apr 2025 10:29:45 +0200 Subject: [PATCH 14/68] dwc2/host: immediately retry IN token for bInterval=1 Signed-off-by: Maxime Vincent --- src/portable/synopsys/dwc2/hcd_dwc2.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 33c0edba1..6e2737afd 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -736,6 +736,14 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci } } + // immediately retry if bInterval is 1 - otherwise we'd waste a microframe before retrying + if ((hcint & HCINT_HALTED) && (edpt->uframe_interval == 1)) { + edpt->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + channel->hcchar = (edpt->hcchar & ~HCCHAR_CHENA); + channel_send_in_token(dwc2, channel); + return; + } + // for periodic, de-allocate channel, enable SOF set frame counter for later transfer const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; edpt->next_pid = hctsiz.pid; // save PID From 62d06e7b19d82dbbc3d1089b249913c13eb7fc2a Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Mon, 14 Apr 2025 09:24:54 +0200 Subject: [PATCH 15/68] dwc2/host: fix all retry intervals Signed-off-by: Maxime Vincent --- src/portable/synopsys/dwc2/hcd_dwc2.c | 31 +++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 6e2737afd..d2070e57c 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -736,23 +736,22 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci } } - // immediately retry if bInterval is 1 - otherwise we'd waste a microframe before retrying - if ((hcint & HCINT_HALTED) && (edpt->uframe_interval == 1)) { - edpt->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame - channel->hcchar = (edpt->hcchar & ~HCCHAR_CHENA); - channel_send_in_token(dwc2, channel); - return; - } - - // for periodic, de-allocate channel, enable SOF set frame counter for later transfer - const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; - edpt->next_pid = hctsiz.pid; // save PID - edpt->uframe_countdown = edpt->uframe_interval; - dwc2->gintmsk |= GINTSTS_SOF; - if (hcint & HCINT_HALTED) { - // already halted, de-allocate channel (called from DMA isr) - channel_dealloc(dwc2, ch_id); + const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH ? 1 : 8); + if (edpt->uframe_interval == ucount) { + // immediately retry if bInterval is 1 + edpt->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame + channel->hcchar = (edpt->hcchar & ~HCCHAR_CHENA); + channel_send_in_token(dwc2, channel); + } else { + // otherwise, de-allocate channel, enable SOF set frame counter for later transfer + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + edpt->next_pid = hctsiz.pid; // save PID + edpt->uframe_countdown = edpt->uframe_interval - ucount; + dwc2->gintmsk |= GINTSTS_SOF; + // already halted, de-allocate channel (called from DMA isr) + channel_dealloc(dwc2, ch_id); + } } else { // disable channel first if not halted (called slave isr) xfer->halted_sof_schedule = 1; From 0d2c08efd7145b160ab0ed373b2cf956699cfb74 Mon Sep 17 00:00:00 2001 From: Joel Michael Date: Wed, 16 Apr 2025 20:26:35 +1000 Subject: [PATCH 16/68] note potential issues using ep_desc in hcd_edpt_open() --- src/portable/template/hcd_template.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/portable/template/hcd_template.c b/src/portable/template/hcd_template.c index b073d6057..694fa8550 100644 --- a/src/portable/template/hcd_template.c +++ b/src/portable/template/hcd_template.c @@ -116,6 +116,10 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { (void) rhport; (void) dev_addr; + + // NOTE: ep_desc is allocated on the stack when called from usbh_edpt_control_open() + // If you need to persist any ep_desc values across HCD calls (eg ep_desc->wMaxPacketSize), + // then you need to copy the data into another variable inside this function. (void) ep_desc; return false; From 4d601545eba2793280752fb04ab6a7628a1a14ea Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 16 Apr 2025 21:15:07 +0700 Subject: [PATCH 17/68] add TS3USB30 to test s3 host with slave/dma --- hw/bsp/espressif/boards/espressif_p4_function_ev/board.h | 7 ++++--- hw/bsp/espressif/boards/espressif_s3_devkitm/board.h | 5 +++++ hw/bsp/espressif/boards/family.c | 8 ++++---- test/hil/tinyusb.json | 8 +++++--- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/hw/bsp/espressif/boards/espressif_p4_function_ev/board.h b/hw/bsp/espressif/boards/espressif_p4_function_ev/board.h index 6f3229b70..40c4963d9 100644 --- a/hw/bsp/espressif/boards/espressif_p4_function_ev/board.h +++ b/hw/bsp/espressif/boards/espressif_p4_function_ev/board.h @@ -41,9 +41,10 @@ #define BUTTON_PIN 35 #define BUTTON_STATE_ACTIVE 0 -// For CI hardware test, to test both device and host on the same HS port with help of -#define HIL_DEVICE_HOST_MUX_PIN 47 -#define HIL_DEVICE_STATE 1 +// For CI hardware test, to test both device and host on the same HS port with help of TS3USB30 +// https://www.adafruit.com/product/5871 +#define HIL_TS3USB30_MODE_PIN 47 +#define HIL_TS3USB30_MODE_DEVICE 1 #ifdef __cplusplus } diff --git a/hw/bsp/espressif/boards/espressif_s3_devkitm/board.h b/hw/bsp/espressif/boards/espressif_s3_devkitm/board.h index d01fdbe5b..5c1914ebe 100644 --- a/hw/bsp/espressif/boards/espressif_s3_devkitm/board.h +++ b/hw/bsp/espressif/boards/espressif_s3_devkitm/board.h @@ -49,6 +49,11 @@ #define MAX3421_CS_PIN 15 #define MAX3421_INTR_PIN 14 +// For CI hardware test, to test both device and host on the same HS port with help of TS3USB30 +// https://www.adafruit.com/product/5871 +#define HIL_TS3USB30_MODE_PIN 47 +#define HIL_TS3USB30_MODE_DEVICE 1 + #ifdef __cplusplus } #endif diff --git a/hw/bsp/espressif/boards/family.c b/hw/bsp/espressif/boards/family.c index 7049c0415..cf11e2441 100644 --- a/hw/bsp/espressif/boards/family.c +++ b/hw/bsp/espressif/boards/family.c @@ -92,10 +92,10 @@ void board_init(void) { usb_init(); #endif -#ifdef HIL_DEVICE_HOST_MUX_PIN - gpio_reset_pin(HIL_DEVICE_HOST_MUX_PIN); - gpio_set_direction(HIL_DEVICE_HOST_MUX_PIN, GPIO_MODE_OUTPUT); - gpio_set_level(HIL_DEVICE_HOST_MUX_PIN, CFG_TUD_ENABLED ? HIL_DEVICE_STATE : (1-HIL_DEVICE_STATE)); +#ifdef HIL_TS3USB30_MODE_PIN + gpio_reset_pin(HIL_TS3USB30_MODE_PIN); + gpio_set_direction(HIL_TS3USB30_MODE_PIN, GPIO_MODE_OUTPUT); + gpio_set_level(HIL_TS3USB30_MODE_PIN, CFG_TUD_ENABLED ? HIL_TS3USB30_MODE_DEVICE : (1-HIL_TS3USB30_MODE_DEVICE)); #endif #if CFG_TUH_ENABLED && CFG_TUH_MAX3421 diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index a9460bf9d..8f39eb32e 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -21,16 +21,18 @@ "name": "espressif_s3_devkitm", "uid": "84F703C084E4", "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"] + "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"] }, "tests": { - "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos"] + "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"], + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402"}] }, "flasher": { "name": "esptool", "uid": "3ea619acd1cdeb11a0a0b806e93fd3f1", "args": "-b 1500000" - } + }, + "comment": "Use TS3USB30 mux to test both device and host" }, { "name": "feather_nrf52840_express", From 7ef17a85cb5c6655e778e3385dfef20be00de199 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 16 Apr 2025 22:04:19 +0700 Subject: [PATCH 18/68] de-duplicate flash board_test for board with multiple flags_on --- test/hil/hil_test.py | 103 +++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 43 deletions(-) diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 8b89de66c..14ab4e63a 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -514,6 +514,63 @@ host_test = [ ] +def test_example(board, f1, example): + """ + Test example firmware + :param board: board dict + :param f1: flags on + :param example: example name + :return: 0 if success/skip, 1 if failed + """ + name = board['name'] + err_count = 0 + + f1_str = "" + if f1 != "": + f1_str = '-f1_' + f1.replace(' ', '_') + + fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{example}' + if not os.path.exists(fw_dir): + fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{example}' + fw_name = f'{fw_dir}/{os.path.basename(example)}' + print(f'{name+f1_str:40} {example:30} ... ', end='') + + if not os.path.exists(fw_dir) or not (os.path.exists(f'{fw_name}.elf') or os.path.exists(f'{fw_name}.bin')): + print('Skip (no binary)') + return 0 + + if verbose: + print(f'Flashing {fw_name}.elf') + + # flash firmware. It may fail randomly, retry a few times + max_rety = 2 + for i in range(max_rety): + ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, fw_name) + if ret.returncode == 0: + try: + globals()[f'test_{example.replace("/", "_")}'](board) + print('OK') + break + except Exception as e: + if i == max_rety - 1: + err_count += 1 + print(STATUS_FAILED) + print(f' {e}') + else: + print() + print(f' Test failed: {e}, retry {i+2}/{max_rety}') + time.sleep(1) + else: + print(f'Flashing failed, retry {i+2}/{max_rety}') + time.sleep(1) + + if ret.returncode != 0: + err_count += 1 + print(f'Flash {STATUS_FAILED}') + + return err_count + + def test_board(board): name = board['name'] flasher = board['flasher'] @@ -537,57 +594,17 @@ def test_board(board): test_list.remove(skip) print(f'{name:25} {skip:30} ... Skip') - # board_test is added last to disable board's usb - test_list.append('device/board_test') - err_count = 0 flags_on_list = [""] if 'build' in board and 'flags_on' in board['build']: flags_on_list = board['build']['flags_on'] for f1 in flags_on_list: - f1_str = "" - if f1 != "": - f1_str = '-f1_' + f1.replace(' ', '_') for test in test_list: - fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{test}' - if not os.path.exists(fw_dir): - fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{test}' - fw_name = f'{fw_dir}/{os.path.basename(test)}' - print(f'{name+f1_str:40} {test:30} ... ', end='') + err_count += test_example(board, f1, test) - if not os.path.exists(fw_dir) or not (os.path.exists(f'{fw_name}.elf') or os.path.exists(f'{fw_name}.bin')): - print('Skip (no binary)') - continue - - if verbose: - print(f'Flashing {fw_name}.elf') - - # flash firmware. It may fail randomly, retry a few times - max_rety = 2 - for i in range(max_rety): - ret = globals()[f'flash_{flasher["name"].lower()}'](board, fw_name) - if ret.returncode == 0: - try: - globals()[f'test_{test.replace("/", "_")}'](board) - print('OK') - break - except Exception as e: - if i == max_rety - 1: - err_count += 1 - print(STATUS_FAILED) - print(f' {e}') - else: - print() - print(f' Test failed: {e}, retry {i+2}/{max_rety}') - time.sleep(1) - else: - print(f'Flashing failed, retry {i+2}/{max_rety}') - time.sleep(1) - - if ret.returncode != 0: - err_count += 1 - print(f'Flash {STATUS_FAILED}') + # flash board_test last to disable board's usb + test_example(board, flags_on_list[0], 'device/board_test') return err_count From f479b02ea6110d2b7703ae96763535b7ec2bbde1 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 11:22:38 +0700 Subject: [PATCH 19/68] ci add pico_w for native host test --- .../boards/raspberry_pi_pico_w/board.cmake | 2 + .../rp2040/boards/raspberry_pi_pico_w/board.h | 70 +++++++++++++++++++ test/hil/tinyusb.json | 14 ++++ 3 files changed, 86 insertions(+) create mode 100644 hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.cmake create mode 100644 hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.h diff --git a/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.cmake b/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.cmake new file mode 100644 index 000000000..97621d855 --- /dev/null +++ b/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.cmake @@ -0,0 +1,2 @@ +set(PICO_PLATFORM rp2040) +set(PICO_BOARD pico_w) diff --git a/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.h b/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.h new file mode 100644 index 000000000..8af32fc9e --- /dev/null +++ b/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.h @@ -0,0 +1,70 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +/* metadata: + name: Pico + url: https://www.raspberrypi.com/products/raspberry-pi-pico/ +*/ + +#ifndef TUSB_BOARD_H +#define TUSB_BOARD_H + +#ifdef __cplusplus + extern "C" { +#endif + +// UART and LED are already defined in pico-sdk board + +//--------------------------------------------------------------------+ +// PIO_USB +//--------------------------------------------------------------------+ +// default to pico brain tester +#define PICO_DEFAULT_PIO_USB_DP_PIN 20 +#define PICO_DEFAULT_PIO_USB_VBUSEN_PIN 22 +#define PICO_DEFAULT_PIO_USB_VBUSEN_STATE 1 + +//-------------------------------------------------------------------- +// USB Host MAX3421E +//-------------------------------------------------------------------- + +#ifdef PICO_DEFAULT_SPI +#define MAX3421_SPI PICO_DEFAULT_SPI // sdk v2 +#else +#define MAX3421_SPI PICO_DEFAULT_SPI_INSTANCE // sdk v1 +#endif + +#define MAX3421_SCK_PIN PICO_DEFAULT_SPI_SCK_PIN +#define MAX3421_MOSI_PIN PICO_DEFAULT_SPI_TX_PIN +#define MAX3421_MISO_PIN PICO_DEFAULT_SPI_RX_PIN +#define MAX3421_CS_PIN 10 +#define MAX3421_INTR_PIN 9 + + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 8f39eb32e..8a835e4c0 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -126,6 +126,20 @@ "args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\"" } }, + { + "name": "raspberry_pi_pico_w", + "uid": "E6614C311B764A37", + "tests": { + "device": false, "host": true, "dual": false, + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934"}] + }, + "flasher": { + "name": "openocd", + "uid": "E6633861A3819D38", + "args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\"" + }, + "comment": "Test native host" + }, { "name": "raspberry_pi_pico2", "uid": "560AE75E1C7152C9", From ccb34dbbdb24638ab030e1966b956330c15a1b88 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 11:58:05 +0700 Subject: [PATCH 20/68] add toolchain.json for toolchain url --- .circleci/config2.yml | 12 +----------- .github/actions/setup_toolchain/action.yml | 9 +-------- .github/actions/setup_toolchain/toolchain.json | 9 +++++++++ 3 files changed, 11 insertions(+), 19 deletions(-) create mode 100644 .github/actions/setup_toolchain/toolchain.json diff --git a/.circleci/config2.yml b/.circleci/config2.yml index 3b0294168..c1f080556 100644 --- a/.circleci/config2.yml +++ b/.circleci/config2.yml @@ -10,17 +10,7 @@ commands: - run: name: Set toolchain url and key command: | - TOOLCHAIN_JSON='{ - "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz", - "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz", - "arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v13.2.1-1.1/xpack-arm-none-eabi-gcc-13.2.1-1.1-linux-x64.tar.gz", - "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2", - "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz", - "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run", - "arm-iar": "https://updates.iar.com/FileStore/STANDARD/001/003/322/cxarm-9.60.3.deb" - }' - toolchain_url=$(echo $TOOLCHAIN_JSON | jq -r '.["<< parameters.toolchain >>"]') - + toolchain_url=$(jq -r '."<< parameters.toolchain >>"' .github/actions/setup_toolchain/toolchain.json) # only cache if not a github link if [[ $toolchain_url != "https://github.com"* ]]; then echo "<< parameters.toolchain >>-$toolchain_url" > toolchain_key diff --git a/.github/actions/setup_toolchain/action.yml b/.github/actions/setup_toolchain/action.yml index 8305daa24..7c1f92c1a 100644 --- a/.github/actions/setup_toolchain/action.yml +++ b/.github/actions/setup_toolchain/action.yml @@ -32,14 +32,7 @@ runs: inputs.toolchain != 'esp-idf' id: set-toolchain-url run: | - TOOLCHAIN_JSON='{ - "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz", - "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz", - "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2", - "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz", - "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run" - }' - TOOLCHAIN_URL=$(echo $TOOLCHAIN_JSON | jq -r '.["${{ inputs.toolchain }}"]') + TOOLCHAIN_URL=$(jq -r '."${{ inputs.toolchain }}"' .github/actions/setup_toolchain/toolchain.json) echo "toolchain_url=$TOOLCHAIN_URL" echo "toolchain_url=$TOOLCHAIN_URL" >> $GITHUB_OUTPUT shell: bash diff --git a/.github/actions/setup_toolchain/toolchain.json b/.github/actions/setup_toolchain/toolchain.json new file mode 100644 index 000000000..4e65f1cbe --- /dev/null +++ b/.github/actions/setup_toolchain/toolchain.json @@ -0,0 +1,9 @@ +{ + "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz", + "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz", + "arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v13.2.1-1.1/xpack-arm-none-eabi-gcc-13.2.1-1.1-linux-x64.tar.gz", + "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2", + "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz", + "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run", + "arm-iar": "https://netstorage.iar.com/FileStore/STANDARD/001/003/583/cxarm-9.60.4.deb" +} From eea42fd1197bea01eb480363ccf573544f4c9551 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 13:05:18 +0700 Subject: [PATCH 21/68] update iar build --- .circleci/config.yml | 4 ++-- .circleci/config2.yml | 1 - .github/workflows/build.yml | 2 -- .github/workflows/hil_test.yml | 2 -- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fd5631e2e..a7ae6980f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,17 +20,17 @@ jobs: BUILDSYSTEM_TOOLCHAIN=( "cmake arm-clang" + "cmake esp-idf" "make aarch64-gcc" "make arm-gcc" "make msp430-gcc" "make riscv-gcc" "make rx-gcc" - "cmake esp-idf" ) # only build IAR if not forked PR, since IAR token is not shared if [ -z $CIRCLE_PR_USERNAME ]; then - BUILDSYSTEM_TOOLCHAIN+=("cmake arm-iar") + BUILDSYSTEM_TOOLCHAIN+=("make arm-iar") fi RESOURCE_LARGE='["nrf", "imxrt", "stm32f4", "stm32h7"]' diff --git a/.circleci/config2.yml b/.circleci/config2.yml index c1f080556..d86a3f662 100644 --- a/.circleci/config2.yml +++ b/.circleci/config2.yml @@ -111,7 +111,6 @@ commands: TOOLCHAIN_OPTION="--toolchain clang" elif [ << parameters.toolchain >> == arm-iar ]; then TOOLCHAIN_OPTION="--toolchain iar" - echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL iccarm --version elif [ << parameters.toolchain >> == arm-gcc ]; then TOOLCHAIN_OPTION="--toolchain gcc" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 547763bd8..f42499ef7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -119,7 +119,6 @@ jobs: runs-on: [self-hosted, Linux, X64, hifiphile] env: BUILD_ARGS: ${{ join(fromJSON(needs.set-matrix.outputs.json)['arm-iar'], ' ') }} - IAR_LMS_CLOUD_URL: ${{ vars.IAR_LMS_CLOUD_URL }} IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} steps: - name: Clean workspace @@ -130,7 +129,6 @@ jobs: - name: Toolchain version run: | - echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL iccarm --version - name: Checkout TinyUSB diff --git a/.github/workflows/hil_test.yml b/.github/workflows/hil_test.yml index c890933ec..257416213 100644 --- a/.github/workflows/hil_test.yml +++ b/.github/workflows/hil_test.yml @@ -96,7 +96,6 @@ jobs: if: github.repository_owner == 'hathach' && github.event.pull_request.head.repo.fork == false runs-on: [self-hosted, Linux, X64, hifiphile] env: - IAR_LMS_CLOUD_URL: ${{ vars.IAR_LMS_CLOUD_URL }} IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} steps: - name: Clean workspace @@ -107,7 +106,6 @@ jobs: - name: Toolchain version run: | - echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL iccarm --version - name: Checkout TinyUSB From b1eedf4d1d95d6e8c7de425080a107a33cbf0e5d Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 14:34:55 +0700 Subject: [PATCH 22/68] fix iar make build with wb and u5 --- examples/build_system/make/cpu/cortex-m4.mk | 4 ++-- examples/host/msc_file_explorer/Makefile | 2 +- hw/bsp/broadcom_32bit/family.mk | 2 +- hw/bsp/broadcom_64bit/family.mk | 2 +- .../boards/frdm_k32l2a4s/board.mk | 2 +- hw/bsp/lpc15/family.mk | 2 +- hw/bsp/lpc17/family.mk | 2 +- hw/bsp/lpc18/family.mk | 2 +- hw/bsp/lpc40/family.mk | 2 +- hw/bsp/lpc43/family.mk | 6 +++--- hw/bsp/stm32f4/family.mk | 1 - hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk | 4 +--- .../stm32u5/boards/stm32u545nucleo/board.mk | 4 +--- hw/bsp/stm32u5/boards/stm32u575eval/board.mk | 4 +--- .../stm32u5/boards/stm32u575nucleo/board.mk | 4 +--- .../stm32u5/boards/stm32u5a5nucleo/board.mk | 4 +--- hw/bsp/stm32u5/family.mk | 7 +++++++ hw/bsp/stm32wb/family.mk | 21 ++++++++++++------- src/class/msc/msc_device.c | 5 +++-- 19 files changed, 41 insertions(+), 39 deletions(-) diff --git a/examples/build_system/make/cpu/cortex-m4.mk b/examples/build_system/make/cpu/cortex-m4.mk index 4e16819d1..57d6e126d 100644 --- a/examples/build_system/make/cpu/cortex-m4.mk +++ b/examples/build_system/make/cpu/cortex-m4.mk @@ -12,8 +12,8 @@ else ifeq ($(TOOLCHAIN),clang) -mfpu=fpv4-sp-d16 \ else ifeq ($(TOOLCHAIN),iar) - CFLAGS += --cpu cortex-m4 --fpu VFPv4 - ASFLAGS += --cpu cortex-m4 --fpu VFPv4 + CFLAGS += --cpu cortex-m4 --fpu VFPv4-SP + ASFLAGS += --cpu cortex-m4 --fpu VFPv4-SP else $(error "TOOLCHAIN is not supported") diff --git a/examples/host/msc_file_explorer/Makefile b/examples/host/msc_file_explorer/Makefile index c7d6a7cae..f0872376f 100644 --- a/examples/host/msc_file_explorer/Makefile +++ b/examples/host/msc_file_explorer/Makefile @@ -22,6 +22,6 @@ SRC_C += \ $(FATFS_PATH)/ffunicode.c \ # suppress warning caused by fatfs -CFLAGS += -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=cast-qual include ../../build_system/make/rules.mk diff --git a/hw/bsp/broadcom_32bit/family.mk b/hw/bsp/broadcom_32bit/family.mk index a282e9961..9d4a3b76c 100644 --- a/hw/bsp/broadcom_32bit/family.mk +++ b/hw/bsp/broadcom_32bit/family.mk @@ -15,7 +15,7 @@ CFLAGS += \ CROSS_COMPILE = arm-none-eabi- # mcu driver cause following warnings -CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls +CFLAGS_GCC += -Wno-error=cast-qual -Wno-error=redundant-decls SRC_C += \ src/portable/synopsys/dwc2/dcd_dwc2.c \ diff --git a/hw/bsp/broadcom_64bit/family.mk b/hw/bsp/broadcom_64bit/family.mk index 37d381f9f..1ce80e22b 100644 --- a/hw/bsp/broadcom_64bit/family.mk +++ b/hw/bsp/broadcom_64bit/family.mk @@ -14,7 +14,7 @@ CFLAGS += \ CROSS_COMPILE = aarch64-none-elf- # mcu driver cause following warnings -CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls +CFLAGS_GCC += -Wno-error=cast-qual -Wno-error=redundant-decls SRC_C += \ src/portable/synopsys/dwc2/dcd_dwc2.c \ diff --git a/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk b/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk index c4dc65b63..fb3eb2a03 100644 --- a/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk +++ b/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk @@ -3,7 +3,7 @@ MCU = K32L2A41A CFLAGS += -DCPU_K32L2A41VLH1A # mcu driver cause following warnings -CFLAGS += -Wno-error=unused-parameter -Wno-error=redundant-decls -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=unused-parameter -Wno-error=redundant-decls -Wno-error=cast-qual # All source paths should be relative to the top level. LD_FILE = $(MCU_DIR)/gcc/K32L2A41xxxxA_flash.ld diff --git a/hw/bsp/lpc15/family.mk b/hw/bsp/lpc15/family.mk index b83e008e8..3b63580c0 100644 --- a/hw/bsp/lpc15/family.mk +++ b/hw/bsp/lpc15/family.mk @@ -15,7 +15,7 @@ CFLAGS += \ LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs # mcu driver cause following warnings -CFLAGS += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=cast-qual MCU_DIR = hw/mcu/nxp/lpcopen/lpc15xx/lpc_chip_15xx diff --git a/hw/bsp/lpc17/family.mk b/hw/bsp/lpc17/family.mk index d719a47b7..551eb9e62 100644 --- a/hw/bsp/lpc17/family.mk +++ b/hw/bsp/lpc17/family.mk @@ -13,7 +13,7 @@ CFLAGS += \ -DRTC_EV_SUPPORT=0 # lpc_types.h cause following errors -CFLAGS += -Wno-error=strict-prototypes -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=cast-qual # caused by freeRTOS port !! CFLAGS += -Wno-error=maybe-uninitialized diff --git a/hw/bsp/lpc18/family.mk b/hw/bsp/lpc18/family.mk index f120f63b2..87b831255 100644 --- a/hw/bsp/lpc18/family.mk +++ b/hw/bsp/lpc18/family.mk @@ -12,7 +12,7 @@ CFLAGS += \ -DCFG_TUSB_MCU=OPT_MCU_LPC18XX # mcu driver cause following warnings -CFLAGS += -Wno-error=unused-parameter -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=unused-parameter -Wno-error=cast-qual LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs diff --git a/hw/bsp/lpc40/family.mk b/hw/bsp/lpc40/family.mk index ef9fe57b2..06155c760 100644 --- a/hw/bsp/lpc40/family.mk +++ b/hw/bsp/lpc40/family.mk @@ -13,7 +13,7 @@ CFLAGS += \ -DCFG_TUSB_MCU=OPT_MCU_LPC40XX # mcu driver cause following warnings -CFLAGS += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=cast-qual LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs diff --git a/hw/bsp/lpc43/family.mk b/hw/bsp/lpc43/family.mk index e1406aae7..4a2ba6ec3 100644 --- a/hw/bsp/lpc43/family.mk +++ b/hw/bsp/lpc43/family.mk @@ -5,14 +5,14 @@ include ${TOP}/${BOARD_PATH}/board.mk CPU_CORE ?= cortex-m4 CFLAGS += \ - -flto \ - -nostdlib \ -DCORE_M4 \ -D__USE_LPCOPEN \ -DCFG_TUSB_MCU=OPT_MCU_LPC43XX # mcu driver cause following warnings -CFLAGS += \ +CFLAGS_GCC += \ + -flto \ + -nostdlib \ -Wno-error=unused-parameter \ -Wno-error=cast-qual \ -Wno-error=incompatible-pointer-types \ diff --git a/hw/bsp/stm32f4/family.mk b/hw/bsp/stm32f4/family.mk index 51ff43a60..c3c41dc3f 100644 --- a/hw/bsp/stm32f4/family.mk +++ b/hw/bsp/stm32f4/family.mk @@ -1,6 +1,5 @@ UF2_FAMILY_ID = 0x57755a57 ST_FAMILY = f4 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver diff --git a/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk b/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk index ae63afef3..0a2c47030 100644 --- a/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk +++ b/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk @@ -1,11 +1,9 @@ +MCU_VARIANT = stm32u585xx CFLAGS += \ -DSTM32U585xx \ # All source paths should be relative to the top level. LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s - -MCU_VARIANT = stm32u585xx # For flash-jlink target JLINK_DEVICE = stm32u585zi diff --git a/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk b/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk index 072c595fb..0aba57ce4 100644 --- a/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk +++ b/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk @@ -1,11 +1,9 @@ +MCU_VARIANT = stm32u545xx CFLAGS += \ -DSTM32U545xx \ # All source paths should be relative to the top level. LD_FILE = ${FAMILY_PATH}/linker/STM32U545xx_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u545xx.s - -MCU_VARIANT = stm32u545xx # For flash-jlink target JLINK_DEVICE = stm32u545re diff --git a/hw/bsp/stm32u5/boards/stm32u575eval/board.mk b/hw/bsp/stm32u5/boards/stm32u575eval/board.mk index fee56f2ba..4bc9fea10 100644 --- a/hw/bsp/stm32u5/boards/stm32u575eval/board.mk +++ b/hw/bsp/stm32u5/boards/stm32u575eval/board.mk @@ -1,11 +1,9 @@ +MCU_VARIANT = stm32u575xx CFLAGS += \ -DSTM32U575xx \ # All source paths should be relative to the top level. LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s - -MCU_VARIANT = stm32u575xx # For flash-jlink target JLINK_DEVICE = stm32u575ai diff --git a/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk b/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk index c83ec3999..d09dc5c46 100644 --- a/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk +++ b/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk @@ -1,11 +1,9 @@ +MCU_VARIANT = stm32u575xx CFLAGS += \ -DSTM32U575xx \ # All source paths should be relative to the top level. LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s - -MCU_VARIANT = stm32u575xx # For flash-jlink target JLINK_DEVICE = stm32u575zi diff --git a/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk b/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk index 4bebe3330..c9fdbac1a 100644 --- a/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk +++ b/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk @@ -1,3 +1,4 @@ +MCU_VARIANT = stm32u5a5xx CFLAGS += \ -DSTM32U5A5xx \ -DHSE_VALUE=16000000UL \ @@ -5,8 +6,5 @@ CFLAGS += \ # All source paths should be relative to the top level. LD_FILE = ${BOARD_PATH}/STM32U5A5ZJTXQ_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u5a5xx.s - -MCU_VARIANT = stm32u5a5xx # For flash-jlink target JLINK_DEVICE = stm32u575zi diff --git a/hw/bsp/stm32u5/family.mk b/hw/bsp/stm32u5/family.mk index 05fe4608a..7fc728dcf 100644 --- a/hw/bsp/stm32u5/family.mk +++ b/hw/bsp/stm32u5/family.mk @@ -57,5 +57,12 @@ INC += \ $(TOP)/$(ST_HAL_DRIVER)/Inc \ $(TOP)/$(BOARD_PATH) +# Startup +SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT).s +SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s + +# Linker +LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf + # flash target using on-board stlink flash: flash-stlink diff --git a/hw/bsp/stm32wb/family.mk b/hw/bsp/stm32wb/family.mk index de8372eea..a80ff6f5b 100644 --- a/hw/bsp/stm32wb/family.mk +++ b/hw/bsp/stm32wb/family.mk @@ -9,14 +9,12 @@ include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m4 CFLAGS += \ - -flto \ - -nostdlib -nostartfiles \ -DCFG_TUSB_MCU=OPT_MCU_STM32WB -# suppress warning caused by vendor mcu driver -CFLAGS += -Wno-error=cast-align -Wno-unused-parameter - -LD_FILE ?= ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash_cm4.ld +CFLAGS_GCC += \ + -flto \ + -nostdlib -nostartfiles \ + -Wno-error=cast-align -Wno-unused-parameter LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs @@ -25,19 +23,26 @@ SRC_C += \ $(ST_CMSIS)/Source/Templates/system_${ST_PREFIX}.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_cortex.c \ + $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr_ex.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc_ex.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_uart.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_gpio.c -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}_cm4.s - INC += \ $(TOP)/$(BOARD_PATH) \ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \ $(TOP)/$(ST_CMSIS)/Include \ $(TOP)/$(ST_HAL_DRIVER)/Inc +# Startup +SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT)_cm4.s +SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT)_cm4.s + +# Linker +LD_FILE_GCC ?= ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash_cm4.ld +LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash_cm4.icf + # flash target using on-board stlink flash: flash-stlink diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 6670045aa..87c77c9a7 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -344,7 +344,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t msc_csw_t * p_csw = &p_msc->csw; switch (p_msc->stage) { - case MSC_STAGE_CMD: + case MSC_STAGE_CMD: { //------------- new CBW received -------------// // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it if (ep_addr != p_msc->ep_out) { @@ -441,7 +441,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t } } } - break; + break; + } case MSC_STAGE_DATA: TU_LOG_DRV(" SCSI Data [Lun%u]\r\n", p_cbw->lun); From 9eb0ae7636d816545696575837c3bcb4a93029d4 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 15:15:07 +0700 Subject: [PATCH 23/68] fix iar make build with stm32 l0, f2, f3, u5, wb --- examples/device/cdc_msc/src/msc_disk.c | 193 +++++++----------- .../device/msc_dual_lun/src/msc_disk_dual.c | 29 +-- .../stm32f2/boards/stm32f207nucleo/board.mk | 7 +- hw/bsp/stm32f2/family.mk | 13 +- hw/bsp/stm32f3/boards/stm32f303disco/board.mk | 4 +- hw/bsp/stm32f3/family.mk | 18 +- hw/bsp/stm32l0/boards/stm32l052dap52/board.mk | 3 +- .../stm32l0/boards/stm32l0538disco/board.mk | 4 +- hw/bsp/stm32l0/family.mk | 19 +- 9 files changed, 119 insertions(+), 171 deletions(-) diff --git a/examples/device/cdc_msc/src/msc_disk.c b/examples/device/cdc_msc/src/msc_disk.c index d325d77fa..9645f4bfc 100644 --- a/examples/device/cdc_msc/src/msc_disk.c +++ b/examples/device/cdc_msc/src/msc_disk.c @@ -40,17 +40,15 @@ static bool ejected = false; If you find any bugs or get any questions, feel free to file an\r\n\ issue at github.com/hathach/tinyusb" -enum -{ - DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount +enum { + DISK_BLOCK_NUM = 16,// 8KB is the smallest size that windows allow to mount DISK_BLOCK_SIZE = 512 }; #ifdef CFG_EXAMPLE_MSC_READONLY const #endif -uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = -{ +uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { //------------- Block0: Boot Sector -------------// // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM; // sector_per_cluster = 1; reserved_sectors = 1; @@ -59,60 +57,59 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = // drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29; // filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC"; // FAT magic code at offset 510-511 - { - 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00, - 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' , - 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, +{ + 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00, + 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', + 'S', 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, - // Zero up to 2 last bytes of FAT magic code - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Zero up to 2 last bytes of FAT magic code + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA - }, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA}, //------------- Block1: FAT12 Table -------------// - { - 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file +{ + 0xF8, 0xFF, 0xFF, 0xFF, 0x0F// // first 2 entries must be F8FF, third entry is cluster end of readme file }, //------------- Block2: Root Directory -------------// - { - // first entry is volume label - 'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // second entry is readme file - 'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D, - 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00, - sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes) +{ + // first entry is volume label + 'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // second entry is readme file + 'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D, + 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00, + sizeof(README_CONTENTS) - 1, 0x00, 0x00, 0x00// readme's files size (4 Bytes) }, //------------- Block3: Readme Content -------------// @@ -121,23 +118,21 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = // Invoked when received SCSI_CMD_INQUIRY // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively -void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) -{ +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { (void) lun; const char vid[] = "TinyUSB"; const char pid[] = "Mass Storage"; const char rev[] = "1.0"; - memcpy(vendor_id , vid, strlen(vid)); - memcpy(product_id , pid, strlen(pid)); + memcpy(vendor_id, vid, strlen(vid)); + memcpy(product_id, pid, strlen(pid)); memcpy(product_rev, rev, strlen(rev)); } // Invoked when received Test Unit Ready command. // return true allowing host to read/write this LUN e.g SD card inserted -bool tud_msc_test_unit_ready_cb(uint8_t lun) -{ +bool tud_msc_test_unit_ready_cb(uint8_t lun) { (void) lun; // RAM disk is ready until ejected @@ -152,29 +147,24 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size // Application update block count and block size -void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) -{ +void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) { (void) lun; *block_count = DISK_BLOCK_NUM; - *block_size = DISK_BLOCK_SIZE; + *block_size = DISK_BLOCK_SIZE; } // Invoked when received Start Stop Unit command // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage // - Start = 1 : active mode, if load_eject = 1 : load disk storage -bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) -{ +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { (void) lun; (void) power_condition; - if ( load_eject ) - { - if (start) - { + if (load_eject) { + if (start) { // load disk storage - }else - { + } else { // unload disk storage ejected = true; } @@ -185,52 +175,51 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo // Callback invoked when received READ10 command. // Copy disk's data to buffer (up to bufsize) and return number of copied bytes. -int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) -{ +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) { (void) lun; // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) { + if (lba >= DISK_BLOCK_NUM) { return -1; } // Check for overflow of offset + bufsize - if ( offset + bufsize > DISK_BLOCK_SIZE ) { + if (offset + bufsize > DISK_BLOCK_SIZE) { return -1; } - uint8_t const* addr = msc_disk[lba] + offset; + uint8_t const *addr = msc_disk[lba] + offset; memcpy(buffer, addr, bufsize); return (int32_t) bufsize; } -bool tud_msc_is_writable_cb (uint8_t lun) -{ +bool tud_msc_is_writable_cb(uint8_t lun) { (void) lun; -#ifdef CFG_EXAMPLE_MSC_READONLY + #ifdef CFG_EXAMPLE_MSC_READONLY return false; -#else + #else return true; -#endif + #endif } // Callback invoked when received WRITE10 command. // Process data in buffer to disk's storage and return number of written bytes -int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) -{ +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) { (void) lun; // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) return -1; + if (lba >= DISK_BLOCK_NUM) return -1; -#ifndef CFG_EXAMPLE_MSC_READONLY - uint8_t* addr = msc_disk[lba] + offset; + #ifndef CFG_EXAMPLE_MSC_READONLY + uint8_t *addr = msc_disk[lba] + offset; memcpy(addr, buffer, bufsize); -#else - (void) lba; (void) offset; (void) buffer; -#endif + #else + (void) lba; + (void) offset; + (void) buffer; + #endif return (int32_t) bufsize; } @@ -238,42 +227,18 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* // Callback invoked when received an SCSI command not in built-in list below // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE // - READ10 and WRITE10 has their own callbacks -int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) -{ - // read10 & write10 has their own callback and MUST not be handled here +int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) { + (void) buffer; + (void) bufsize; - void const* response = NULL; - int32_t resplen = 0; - - // most scsi handled is input - bool in_xfer = true; - - switch (scsi_cmd[0]) - { + switch (scsi_cmd[0]) { default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // negative means error -> tinyusb could stall and/or response with failed status - resplen = -1; - break; + return -1; } - - // return resplen must not larger than bufsize - if ( resplen > bufsize ) resplen = bufsize; - - if ( response && (resplen > 0) ) - { - if(in_xfer) - { - memcpy(buffer, response, (size_t) resplen); - }else - { - // SCSI output - } - } - - return (int32_t) resplen; } #endif diff --git a/examples/device/msc_dual_lun/src/msc_disk_dual.c b/examples/device/msc_dual_lun/src/msc_disk_dual.c index b44b77c6c..1f7fb98c7 100644 --- a/examples/device/msc_dual_lun/src/msc_disk_dual.c +++ b/examples/device/msc_dual_lun/src/msc_disk_dual.c @@ -55,8 +55,7 @@ If you find any bugs or get any questions, feel free to file an\r\n\ issue at github.com/hathach/tinyusb" -MSC_CONST uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = -{ +MSC_CONST uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { //------------- Block0: Boot Sector -------------// // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM; // sector_per_cluster = 1; reserved_sectors = 1; @@ -283,9 +282,11 @@ bool tud_msc_is_writable_cb(uint8_t lun) { // Process data in buffer to disk's storage and return number of written bytes int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { // out of ramdisk - if (lba >= DISK_BLOCK_NUM) return -1; + if (lba >= DISK_BLOCK_NUM) { + return -1; + } -#if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY) + #if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY) (void) lun; (void) lba; (void) offset; @@ -302,11 +303,8 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE // - READ10 and WRITE10 has their own callbacks (MUST not be handled here) int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) { - void const* response = NULL; - int32_t resplen = 0; - - // most scsi handled is input - bool in_xfer = true; + (void) buffer; + (void) bufsize; switch (scsi_cmd[0]) { default: @@ -316,19 +314,6 @@ int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, u // negative means error -> tinyusb could stall and/or response with failed status return -1; } - - // return resplen must not larger than bufsize - if (resplen > bufsize) resplen = bufsize; - - if (response && (resplen > 0)) { - if (in_xfer) { - memcpy(buffer, response, (size_t) resplen); - } else { - // SCSI output - } - } - - return resplen; } #endif diff --git a/hw/bsp/stm32f2/boards/stm32f207nucleo/board.mk b/hw/bsp/stm32f2/boards/stm32f207nucleo/board.mk index ba185d199..6e681ef57 100644 --- a/hw/bsp/stm32f2/boards/stm32f207nucleo/board.mk +++ b/hw/bsp/stm32f2/boards/stm32f207nucleo/board.mk @@ -1,12 +1,9 @@ -CFLAGS += \ - -DSTM32F207xx \ +MCU_VARIANT = stm32f207xx +CFLAGS += -DSTM32F207xx # All source paths should be relative to the top level. LD_FILE = $(BOARD_PATH)/STM32F207ZGTx_FLASH.ld -SRC_S += \ - $(ST_CMSIS)/Source/Templates/gcc/startup_stm32f207xx.s - # For flash-jlink target JLINK_DEVICE = stm32f207zg diff --git a/hw/bsp/stm32f2/family.mk b/hw/bsp/stm32f2/family.mk index 7af9a76a0..e8f02548d 100644 --- a/hw/bsp/stm32f2/family.mk +++ b/hw/bsp/stm32f2/family.mk @@ -1,5 +1,4 @@ ST_FAMILY = f2 - ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver @@ -14,11 +13,10 @@ CPU_CORE ?= cortex-m3 CFLAGS += \ -DCFG_TUSB_MCU=OPT_MCU_STM32F2 +# mcu driver cause following warnings CFLAGS_GCC += \ -flto \ - -# mcu driver cause following warnings -CFLAGS_GCC += -Wno-error=sign-compare + -Wno-error=sign-compare LDFLAGS_GCC += \ -nostdlib -nostartfiles \ @@ -40,3 +38,10 @@ INC += \ $(TOP)/$(ST_CMSIS)/Include \ $(TOP)/$(ST_HAL_DRIVER)/Inc \ $(TOP)/$(BOARD_PATH) + +# Startup +SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s +SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s + +# Linker +LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf diff --git a/hw/bsp/stm32f3/boards/stm32f303disco/board.mk b/hw/bsp/stm32f3/boards/stm32f303disco/board.mk index e387f2d54..6b9a3e283 100644 --- a/hw/bsp/stm32f3/boards/stm32f303disco/board.mk +++ b/hw/bsp/stm32f3/boards/stm32f303disco/board.mk @@ -1,12 +1,10 @@ +MCU_VARIANT = stm32f303xc CFLAGS += \ -DSTM32F303xC \ # All source paths should be relative to the top level. LD_FILE = $(BOARD_PATH)/STM32F303VCTx_FLASH.ld -SRC_S += \ - $(ST_CMSIS)/Source/Templates/gcc/startup_stm32f303xc.s - # For flash-jlink target JLINK_DEVICE = stm32f303vc diff --git a/hw/bsp/stm32f3/family.mk b/hw/bsp/stm32f3/family.mk index 4fe3aa99d..13734583a 100644 --- a/hw/bsp/stm32f3/family.mk +++ b/hw/bsp/stm32f3/family.mk @@ -1,22 +1,17 @@ ST_FAMILY = f3 - ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver -DEPS_SUBMODULES += \ - lib/CMSIS_5 \ - $(ST_CMSIS) \ - $(ST_HAL_DRIVER) - include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m4 CFLAGS += \ - -flto \ -DCFG_TUSB_MCU=OPT_MCU_STM32F3 # mcu driver cause following warnings -CFLAGS += -Wno-error=unused-parameter +CFLAGS_GCC += \ + -flto \ + -Wno-error=unused-parameter LDFLAGS_GCC += \ -nostdlib -nostartfiles \ @@ -36,3 +31,10 @@ INC += \ $(TOP)/$(ST_CMSIS)/Include \ $(TOP)/$(ST_HAL_DRIVER)/Inc \ $(TOP)/$(BOARD_PATH) + +# Startup +SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s +SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s + +# Linker +LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf diff --git a/hw/bsp/stm32l0/boards/stm32l052dap52/board.mk b/hw/bsp/stm32l0/boards/stm32l052dap52/board.mk index 0b1348474..e63b41f12 100644 --- a/hw/bsp/stm32l0/boards/stm32l052dap52/board.mk +++ b/hw/bsp/stm32l0/boards/stm32l052dap52/board.mk @@ -1,10 +1,9 @@ +MCU_VARIANT = stm32l052xx CFLAGS += \ -DSTM32L052xx LD_FILE = $(BOARD_PATH)/STM32L052K8Ux_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32l052xx.s - # For flash-jlink target JLINK_DEVICE = stm32l052k8 diff --git a/hw/bsp/stm32l0/boards/stm32l0538disco/board.mk b/hw/bsp/stm32l0/boards/stm32l0538disco/board.mk index deed519ba..f3e6978b0 100644 --- a/hw/bsp/stm32l0/boards/stm32l0538disco/board.mk +++ b/hw/bsp/stm32l0/boards/stm32l0538disco/board.mk @@ -1,12 +1,10 @@ +MCU_VARIANT = stm32l053xx CFLAGS += \ -DSTM32L053xx # All source paths should be relative to the top level. LD_FILE = $(BOARD_PATH)/STM32L053C8Tx_FLASH.ld -SRC_S += \ - $(ST_CMSIS)/Source/Templates/gcc/startup_stm32l053xx.s - # For flash-jlink target JLINK_DEVICE = STM32L053R8 diff --git a/hw/bsp/stm32l0/family.mk b/hw/bsp/stm32l0/family.mk index fe7561fc2..921b1b413 100644 --- a/hw/bsp/stm32l0/family.mk +++ b/hw/bsp/stm32l0/family.mk @@ -1,9 +1,4 @@ ST_FAMILY = l0 -DEPS_SUBMODULES += \ - lib/CMSIS_5 \ - hw/mcu/st/cmsis_device_$(ST_FAMILY) \ - hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver - ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver @@ -11,20 +6,17 @@ include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m0plus CFLAGS += \ - -flto \ -DCFG_EXAMPLE_MSC_READONLY \ -DCFG_EXAMPLE_VIDEO_READONLY \ -DCFG_TUSB_MCU=OPT_MCU_STM32L0 # mcu driver cause following warnings CFLAGS_GCC += \ + -flto \ -Wno-error=unused-parameter \ -Wno-error=redundant-decls \ -Wno-error=cast-align \ - -ifeq ($(TOOLCHAIN),gcc) -CFLAGS_GCC += -Wno-error=maybe-uninitialized -endif + -Wno-error=maybe-uninitialized \ CFLAGS_CLANG += \ -Wno-error=parentheses-equality @@ -48,3 +40,10 @@ INC += \ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \ $(TOP)/$(ST_CMSIS)/Include \ $(TOP)/$(ST_HAL_DRIVER)/Inc + +# Startup +SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s +SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s + +# Linker +LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf From 3851c7c97a2a743b63d879ab622dd267b4195f08 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 16:07:10 +0700 Subject: [PATCH 24/68] - run arm-iar using github action - add skip_ci.txt to family folder to skip boards in ci run --- .github/workflows/build.yml | 62 +++++++++++++-------- .github/workflows/build_util.yml | 2 + hw/bsp/rp2040/skip_ci.txt | 7 +++ hw/bsp/stm32h7/boards/stm32h743eval/board.h | 10 ++-- hw/bsp/stm32h7/family.c | 4 +- tools/build.py | 7 ++- 6 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 hw/bsp/rp2040/skip_ci.txt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f42499ef7..6419efbe8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -110,35 +110,51 @@ jobs: one-per-family: true # --------------------------------------- - # Build IAR on HFP self-hosted + # Build IAR # Since IAR Token secret is not passed to forked PR, only build on PR from the same repo # --------------------------------------- arm-iar: if: github.repository_owner == 'hathach' && github.event_name == 'push' needs: set-matrix - runs-on: [self-hosted, Linux, X64, hifiphile] - env: - BUILD_ARGS: ${{ join(fromJSON(needs.set-matrix.outputs.json)['arm-iar'], ' ') }} - IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} - steps: - - name: Clean workspace - run: | - echo "Cleaning up previous run" - rm -rf "${{ github.workspace }}" - mkdir -p "${{ github.workspace }}" + uses: ./.github/workflows/build_util.yml + secrets: inherit + strategy: + fail-fast: false + matrix: + build-system: + - 'cmake' + with: + build-system: ${{ matrix.build-system }} + toolchain: 'arm-iar' + build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }} + one-per-family: ${{ github.event_name == 'push' }} - - name: Toolchain version - run: | - iccarm --version - - - name: Checkout TinyUSB - uses: actions/checkout@v4 - - - name: Get Dependencies - run: python3 tools/get_deps.py $BUILD_ARGS - - - name: Build - run: python3 tools/build.py --one-per-family --toolchain iar $BUILD_ARGS +# arm-iar: +# if: github.repository_owner == 'hathach' && github.event_name == 'push' +# needs: set-matrix +# runs-on: [self-hosted, Linux, X64, hifiphile] +# env: +# BUILD_ARGS: ${{ join(fromJSON(needs.set-matrix.outputs.json)['arm-iar'], ' ') }} +# IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} +# steps: +# - name: Clean workspace +# run: | +# echo "Cleaning up previous run" +# rm -rf "${{ github.workspace }}" +# mkdir -p "${{ github.workspace }}" +# +# - name: Toolchain version +# run: | +# iccarm --version +# +# - name: Checkout TinyUSB +# uses: actions/checkout@v4 +# +# - name: Get Dependencies +# run: python3 tools/get_deps.py $BUILD_ARGS +# +# - name: Build +# run: python3 tools/build.py --one-per-family --toolchain iar $BUILD_ARGS # --------------------------------------- # Zephyr diff --git a/.github/workflows/build_util.yml b/.github/workflows/build_util.yml index 2de68c6f3..a2c96f3c0 100644 --- a/.github/workflows/build_util.yml +++ b/.github/workflows/build_util.yml @@ -58,6 +58,8 @@ jobs: shell: bash - name: Build + env: + IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} run: | if [ "${{ inputs.toolchain }}" == "esp-idf" ]; then docker run --rm -v $PWD:/project -w /project espressif/idf:tinyusb python tools/build.py ${{ matrix.arg }} diff --git a/hw/bsp/rp2040/skip_ci.txt b/hw/bsp/rp2040/skip_ci.txt new file mode 100644 index 000000000..fe99c9f65 --- /dev/null +++ b/hw/bsp/rp2040/skip_ci.txt @@ -0,0 +1,7 @@ +# boards in this files are skipped when running CI with this family +adafruit_feather_rp2040_usb_host +adafruit_fruit_jam +adafruit_metro_rp2350 +feather_rp2040_max3421 +pico_sdk +raspberry_pi_pico_w diff --git a/hw/bsp/stm32h7/boards/stm32h743eval/board.h b/hw/bsp/stm32h7/boards/stm32h743eval/board.h index 334876e51..cb6d772e6 100644 --- a/hw/bsp/stm32h7/boards/stm32h743eval/board.h +++ b/hw/bsp/stm32h7/boards/stm32h743eval/board.h @@ -184,7 +184,7 @@ static MFXSTM32L152_Object_t mfx_obj = { 0 }; static MFXSTM32L152_IO_Mode_t* mfx_io = NULL; static uint32_t mfx_vbus_pin[2] = { MFXSTM32L152_GPIO_PIN_7, MFXSTM32L152_GPIO_PIN_9 }; -int32_t board_i2c_init(void) { +static int32_t board_i2c_init(void) { __HAL_RCC_I2C1_CLK_ENABLE(); __HAL_RCC_I2C1_FORCE_RESET(); __HAL_RCC_I2C1_RELEASE_RESET(); @@ -200,16 +200,16 @@ int32_t board_i2c_init(void) { return 0; } -int32_t board_i2c_deinit(void) { +static int32_t board_i2c_deinit(void) { return 0; } -int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { +static int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { TU_ASSERT (HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)); return 0; } -int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { +static int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { TU_ASSERT(HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)); return 0; } @@ -249,7 +249,7 @@ static inline void board_init2(void) { } // VBUS1 is actually controlled by USB3320C PHY (using dwc2 drivebus signal) -void board_vbus_set(uint8_t rhport, bool state) { +static void board_vbus_set(uint8_t rhport, bool state) { if (mfx_io) { mfx_io->IO_WritePin(&mfx_obj, mfx_vbus_pin[rhport], state); } diff --git a/hw/bsp/stm32h7/family.c b/hw/bsp/stm32h7/family.c index e5228b29b..f8723b0c7 100644 --- a/hw/bsp/stm32h7/family.c +++ b/hw/bsp/stm32h7/family.c @@ -80,7 +80,7 @@ void OTG_HS_IRQHandler(void) { } #ifdef TRACE_ETM -void trace_etm_init(void) { +static void trace_etm_init(void) { // H7 trace pin is PE2 to PE6 GPIO_InitTypeDef gpio_init; gpio_init.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6; @@ -94,7 +94,7 @@ void trace_etm_init(void) { DBGMCU->CR |= DBGMCU_CR_DBG_TRACECKEN | DBGMCU_CR_DBG_CKD1EN | DBGMCU_CR_DBG_CKD3EN; } #else - #define trace_etm_init() +#define trace_etm_init() #endif void board_init(void) { diff --git a/tools/build.py b/tools/build.py index 633d2b582..d28ddd929 100755 --- a/tools/build.py +++ b/tools/build.py @@ -182,9 +182,14 @@ def build_boards_list(boards, toolchain, build_system, build_flags_on): def build_family(family, toolchain, build_system, build_flags_on, one_per_family, boards): + skip_ci = ['pico_sdk'] + if os.getenv('GITHUB_ACTIONS') or os.getenv('CIRCLECI'): + skip_ci_file = Path(f"hw/bsp/{family}/skip_ci.txt") + if skip_ci_file.exists(): + skip_ci = skip_ci_file.read_text().split() all_boards = [] for entry in os.scandir(f"hw/bsp/{family}/boards"): - if entry.is_dir() and entry.name != 'pico_sdk': + if entry.is_dir() and not entry.name in skip_ci: all_boards.append(entry.name) all_boards.sort() From d4983acd3a207d9d81c2698e5f5d2ace9b88e016 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 16:41:22 +0700 Subject: [PATCH 25/68] github ci support setup/install iar toolchain --- .github/actions/setup_toolchain/action.yml | 2 -- .../actions/setup_toolchain/download/action.yml | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/actions/setup_toolchain/action.yml b/.github/actions/setup_toolchain/action.yml index 7c1f92c1a..850a3a06f 100644 --- a/.github/actions/setup_toolchain/action.yml +++ b/.github/actions/setup_toolchain/action.yml @@ -28,7 +28,6 @@ runs: - name: Get Toolchain URL if: >- inputs.toolchain != 'arm-gcc' && - inputs.toolchain != 'arm-iar' && inputs.toolchain != 'esp-idf' id: set-toolchain-url run: | @@ -40,7 +39,6 @@ runs: - name: Download Toolchain if: >- inputs.toolchain != 'arm-gcc' && - inputs.toolchain != 'arm-iar' && inputs.toolchain != 'esp-idf' uses: ./.github/actions/setup_toolchain/download with: diff --git a/.github/actions/setup_toolchain/download/action.yml b/.github/actions/setup_toolchain/download/action.yml index 813197208..ce9643010 100644 --- a/.github/actions/setup_toolchain/download/action.yml +++ b/.github/actions/setup_toolchain/download/action.yml @@ -23,17 +23,25 @@ runs: if: steps.cache-toolchain-download.outputs.cache-hit != 'true' run: | mkdir -p ~/cache/${{ inputs.toolchain }} - wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.tar.gz + if [[ ${{ inputs.toolchain }} == rx-gcc ]]; then - mv toolchain.tar.gz toolchain.run + wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.run chmod +x toolchain.run ./toolchain.run -p ~/cache/${{ inputs.toolchain }}/gnurx -y + elif [[ ${{ inputs.toolchain }} == arm-iar ]]; then + wget --progress=dot:giga ${{ inputs.toolchain_url }} -O ~/cache/${{ inputs.toolchain }}/cxarm.deb else + wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.tar.gz tar -C ~/cache/${{ inputs.toolchain }} -xaf toolchain.tar.gz fi shell: bash - - name: Set Toolchain Path + - name: Setup Toolchain run: | - echo >> $GITHUB_PATH `echo ~/cache/${{ inputs.toolchain }}/*/bin` + if [[ ${{ inputs.toolchain }} == arm-iar ]]; then + sudo apt-get install -y ~/cache/${{ inputs.toolchain }}/cxarm.deb + echo >> $GITHUB_PATH "/opt/iar/cxarm/arm/bin" + else + echo >> $GITHUB_PATH `echo ~/cache/${{ inputs.toolchain }}/*/bin` + fi shell: bash From 0220852a6e79b0ea33654f17dae56c1ca882ea60 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 16:58:26 +0700 Subject: [PATCH 26/68] - hil test max retry = 3 - fix h7 unused function --- hw/bsp/stm32h7/boards/stm32h743eval/board.h | 2 +- hw/bsp/stm32h7/family.mk | 4 +--- test/hil/hil_test.py | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/hw/bsp/stm32h7/boards/stm32h743eval/board.h b/hw/bsp/stm32h7/boards/stm32h743eval/board.h index cb6d772e6..7c3f6414a 100644 --- a/hw/bsp/stm32h7/boards/stm32h743eval/board.h +++ b/hw/bsp/stm32h7/boards/stm32h743eval/board.h @@ -249,7 +249,7 @@ static inline void board_init2(void) { } // VBUS1 is actually controlled by USB3320C PHY (using dwc2 drivebus signal) -static void board_vbus_set(uint8_t rhport, bool state) { +static void TU_ATTR_UNUSED board_vbus_set(uint8_t rhport, bool state) { if (mfx_io) { mfx_io->IO_WritePin(&mfx_obj, mfx_vbus_pin[rhport], state); } diff --git a/hw/bsp/stm32h7/family.mk b/hw/bsp/stm32h7/family.mk index 29b83cf7d..19a085424 100644 --- a/hw/bsp/stm32h7/family.mk +++ b/hw/bsp/stm32h7/family.mk @@ -45,11 +45,9 @@ CFLAGS += \ -DBOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} \ # GCC Flags -CFLAGS_GCC += \ - -flto \ - # suppress warning caused by vendor mcu driver CFLAGS_GCC += \ + -flto \ -Wno-error=cast-align \ -Wno-error=unused-parameter \ diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 14ab4e63a..f292bca15 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -543,7 +543,7 @@ def test_example(board, f1, example): print(f'Flashing {fw_name}.elf') # flash firmware. It may fail randomly, retry a few times - max_rety = 2 + max_rety = 3 for i in range(max_rety): ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, fw_name) if ret.returncode == 0: From 46d2d4199ea31babbffff51f9eaa65eda81c659b Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 17:26:36 +0700 Subject: [PATCH 27/68] run arm-iar with non-forked PR --- .circleci/config.yml | 2 +- .github/workflows/build.yml | 36 +++++----------------------------- .github/workflows/hil_test.yml | 2 +- 3 files changed, 7 insertions(+), 33 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a7ae6980f..0b11b50e4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -30,7 +30,7 @@ jobs: # only build IAR if not forked PR, since IAR token is not shared if [ -z $CIRCLE_PR_USERNAME ]; then - BUILDSYSTEM_TOOLCHAIN+=("make arm-iar") + BUILDSYSTEM_TOOLCHAIN+=("cmake arm-iar") fi RESOURCE_LARGE='["nrf", "imxrt", "stm32f4", "stm32h7"]' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6419efbe8..7fb13af74 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -111,10 +111,11 @@ jobs: # --------------------------------------- # Build IAR - # Since IAR Token secret is not passed to forked PR, only build on PR from the same repo + # Since IAR Token secret is not passed to forked PR, only build non-forked PR with make. + # cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family # --------------------------------------- arm-iar: - if: github.repository_owner == 'hathach' && github.event_name == 'push' + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false needs: set-matrix uses: ./.github/workflows/build_util.yml secrets: inherit @@ -122,39 +123,12 @@ jobs: fail-fast: false matrix: build-system: - - 'cmake' + - 'make' with: build-system: ${{ matrix.build-system }} toolchain: 'arm-iar' build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }} - one-per-family: ${{ github.event_name == 'push' }} - -# arm-iar: -# if: github.repository_owner == 'hathach' && github.event_name == 'push' -# needs: set-matrix -# runs-on: [self-hosted, Linux, X64, hifiphile] -# env: -# BUILD_ARGS: ${{ join(fromJSON(needs.set-matrix.outputs.json)['arm-iar'], ' ') }} -# IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} -# steps: -# - name: Clean workspace -# run: | -# echo "Cleaning up previous run" -# rm -rf "${{ github.workspace }}" -# mkdir -p "${{ github.workspace }}" -# -# - name: Toolchain version -# run: | -# iccarm --version -# -# - name: Checkout TinyUSB -# uses: actions/checkout@v4 -# -# - name: Get Dependencies -# run: python3 tools/get_deps.py $BUILD_ARGS -# -# - name: Build -# run: python3 tools/build.py --one-per-family --toolchain iar $BUILD_ARGS + one-per-family: true # --------------------------------------- # Zephyr diff --git a/.github/workflows/hil_test.yml b/.github/workflows/hil_test.yml index 257416213..0ad37ffce 100644 --- a/.github/workflows/hil_test.yml +++ b/.github/workflows/hil_test.yml @@ -90,7 +90,7 @@ jobs: # --------------------------------------- # Hardware in the loop (HIL) # self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json - # Since IAR Token secret is not passed to forked PR, only build on PR from the same repo + # Since IAR Token secret is not passed to forked PR, only build non-forked PR # --------------------------------------- hil-hfp: if: github.repository_owner == 'hathach' && github.event.pull_request.head.repo.fork == false From e8a84f90764f0f2603822f068a9961ceeade873d Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 14 Apr 2025 16:09:32 +0700 Subject: [PATCH 28/68] enum For string descriptor (langid, manufacturer product, serila): always get the first 2 bytes to determine the length first. otherwise, some device may have buffer overflow. --- .../boards/espressif_s3_devkitc/board.h | 2 +- hw/bsp/espressif/family.cmake | 2 +- src/common/tusb_debug.h | 6 +- src/host/usbh.c | 124 ++++++++++-------- 4 files changed, 76 insertions(+), 58 deletions(-) diff --git a/hw/bsp/espressif/boards/espressif_s3_devkitc/board.h b/hw/bsp/espressif/boards/espressif_s3_devkitc/board.h index 6d7a94668..d2483c84f 100644 --- a/hw/bsp/espressif/boards/espressif_s3_devkitc/board.h +++ b/hw/bsp/espressif/boards/espressif_s3_devkitc/board.h @@ -36,7 +36,7 @@ extern "C" { #endif -#define NEOPIXEL_PIN 48 +#define NEOPIXEL_PIN 38 #define BUTTON_PIN 0 #define BUTTON_STATE_ACTIVE 0 diff --git a/hw/bsp/espressif/family.cmake b/hw/bsp/espressif/family.cmake index daa12cdb4..b544689d9 100644 --- a/hw/bsp/espressif/family.cmake +++ b/hw/bsp/espressif/family.cmake @@ -34,6 +34,6 @@ endif () set(EXTRA_COMPONENT_DIRS "src" "${CMAKE_CURRENT_LIST_DIR}/boards" "${CMAKE_CURRENT_LIST_DIR}/components") # set SDKCONFIG for each IDF Target -set(SDKCONFIG ${CMAKE_SOURCE_DIR}/sdkconfig.${IDF_TARGET}) +set(SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig) include($ENV{IDF_PATH}/tools/cmake/project.cmake) diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h index 2e9f1d9cd..1d0c6f1ad 100644 --- a/src/common/tusb_debug.h +++ b/src/common/tusb_debug.h @@ -108,15 +108,13 @@ typedef struct { } tu_lookup_table_t; static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) { - tu_static char not_found[11]; - for(uint16_t i=0; icount; i++) { - if (p_table->items[i].key == key) return p_table->items[i].data; + if (p_table->items[i].key == key) { return p_table->items[i].data; } } // not found return the key value in hex + static char not_found[11]; snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key); - return not_found; } diff --git a/src/host/usbh.c b/src/host/usbh.c index e60db53da..157a7ab86 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1372,9 +1372,13 @@ enum { ENUM_HUB_CLEAR_RESET_2, ENUM_SET_ADDR, ENUM_GET_DEVICE_DESC, + ENUM_GET_STRING_LANGUAGE_ID_LEN, ENUM_GET_STRING_LANGUAGE_ID, + ENUM_GET_STRING_MANUFACTURER_LEN, ENUM_GET_STRING_MANUFACTURER, + ENUM_GET_STRING_PRODUCT_LEN, ENUM_GET_STRING_PRODUCT, + ENUM_GET_STRING_SERIAL_LEN, ENUM_GET_STRING_SERIAL, ENUM_GET_9BYTE_CONFIG_DESC, ENUM_GET_FULL_CONFIG_DESC, @@ -1416,6 +1420,9 @@ static void process_enumeration(tuh_xfer_t* xfer) { uint8_t const daddr = xfer->daddr; uintptr_t const state = xfer->user_data; usbh_device_t* dev = get_device(daddr); + if (daddr > 0) { + TU_ASSERT(dev,); + } uint16_t langid = 0x0409; // default is English switch (state) { @@ -1474,30 +1481,6 @@ static void process_enumeration(tuh_xfer_t* xfer) { break; } -#if 0 - case ENUM_RESET_2: - // TODO not used by now, but may be needed for some devices !? - // Reset device again before Set Address - TU_LOG_USBH("Port reset2 \r\n"); - if (_dev0.hub_addr == 0) { - // connected directly to roothub - hcd_port_reset( _dev0.rhport ); - tusb_time_delay_ms_api(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since - // sof of controller may not running while resetting - hcd_port_reset_end(_dev0.rhport); - // TODO: fall through to SET ADDRESS, refactor later - } -#if CFG_TUH_HUB - else { - // after RESET_DELAY the hub_port_reset() already complete - TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, - process_enumeration, ENUM_HUB_GET_STATUS_2), ); - break; - } -#endif - TU_ATTR_FALLTHROUGH; -#endif - case ENUM_SET_ADDR: enum_request_set_addr((tusb_desc_device_t*) _usbh_epbuf.ctrl); break; @@ -1520,14 +1503,15 @@ static void process_enumeration(tuh_xfer_t* xfer) { // Get full device descriptor TU_LOG_USBH("Get Device Descriptor\r\n"); TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), - process_enumeration, ENUM_GET_STRING_LANGUAGE_ID),); + process_enumeration, ENUM_GET_STRING_LANGUAGE_ID_LEN),); break; } - case ENUM_GET_STRING_LANGUAGE_ID: { + // For string descriptor (langid, manufacturer, product, serila): always get the first 2 bytes + // to determine the length first. otherwise, some device may have buffer overflow. + case ENUM_GET_STRING_LANGUAGE_ID_LEN: { // save the received device descriptor - TU_ASSERT(dev,); - tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl; + tusb_desc_device_t const *desc_device = (tusb_desc_device_t const *) _usbh_epbuf.ctrl; dev->vid = desc_device->idVendor; dev->pid = desc_device->idProduct; dev->i_manufacturer = desc_device->iManufacturer; @@ -1535,50 +1519,88 @@ static void process_enumeration(tuh_xfer_t* xfer) { dev->i_serial = desc_device->iSerialNumber; dev->bNumConfigurations = desc_device->bNumConfigurations; - tuh_enum_descriptor_device_cb(daddr, desc_device); // callback + tuh_enum_descriptor_device_cb(daddr, desc_device);// callback - tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, - process_enumeration, ENUM_GET_STRING_MANUFACTURER); + tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, 2, + process_enumeration, ENUM_GET_STRING_LANGUAGE_ID); break; } - case ENUM_GET_STRING_MANUFACTURER: { - TU_ASSERT(dev,); - const tusb_desc_string_t* desc_langid = (tusb_desc_string_t const*) _usbh_epbuf.ctrl; + case ENUM_GET_STRING_LANGUAGE_ID: { + const uint8_t str_len = xfer->buffer[0]; + tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, str_len, + process_enumeration, ENUM_GET_STRING_MANUFACTURER_LEN); + break; + } + + case ENUM_GET_STRING_MANUFACTURER_LEN: { + const tusb_desc_string_t* desc_langid = (const tusb_desc_string_t *) _usbh_epbuf.ctrl; if (desc_langid->bLength >= 4) { - langid = tu_le16toh(desc_langid->utf16le[0]); + langid = tu_le16toh(desc_langid->utf16le[0]); // previous request is langid } if (dev->i_manufacturer != 0) { - tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, + tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, 2, + process_enumeration, ENUM_GET_STRING_MANUFACTURER); + break; + }else { + TU_ATTR_FALLTHROUGH; + } + } + + case ENUM_GET_STRING_MANUFACTURER: { + if (dev->i_manufacturer != 0) { + langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request + const uint8_t str_len = xfer->buffer[0]; + tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, str_len, + process_enumeration, ENUM_GET_STRING_PRODUCT_LEN); + break; + } else { + TU_ATTR_FALLTHROUGH; + } + } + + case ENUM_GET_STRING_PRODUCT_LEN: + if (dev->i_product != 0) { + if (state == ENUM_GET_STRING_PRODUCT_LEN) { + langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through + } + tuh_descriptor_get_string(daddr, dev->i_product, langid, _usbh_epbuf.ctrl, 2, process_enumeration, ENUM_GET_STRING_PRODUCT); break; } else { TU_ATTR_FALLTHROUGH; } - } case ENUM_GET_STRING_PRODUCT: { - TU_ASSERT(dev,); - if (state == ENUM_GET_STRING_PRODUCT) { - langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet - } if (dev->i_product != 0) { - tuh_descriptor_get_string(daddr, dev->i_product, 0x0409, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, - process_enumeration, ENUM_GET_STRING_SERIAL); + langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request + const uint8_t str_len = xfer->buffer[0]; + tuh_descriptor_get_string(daddr, dev->i_product, langid, _usbh_epbuf.ctrl, str_len, + process_enumeration, ENUM_GET_STRING_SERIAL_LEN); break; } else { TU_ATTR_FALLTHROUGH; } } - case ENUM_GET_STRING_SERIAL: { - TU_ASSERT(dev,); - if (state == ENUM_GET_STRING_SERIAL) { - langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet - } + case ENUM_GET_STRING_SERIAL_LEN: if (dev->i_serial != 0) { - tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, - process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC); + if (state == ENUM_GET_STRING_SERIAL_LEN) { + langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through + } + tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, 2, + process_enumeration, ENUM_GET_STRING_SERIAL); + break; + } else { + TU_ATTR_FALLTHROUGH; + } + + case ENUM_GET_STRING_SERIAL: { + if (dev->i_serial != 0) { + langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request + const uint8_t str_len = xfer->buffer[0]; + tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, str_len, + process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC); break; } else { TU_ATTR_FALLTHROUGH; @@ -1627,8 +1649,6 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_CONFIG_DRIVER: { TU_LOG_USBH("Device configured\r\n"); - TU_ASSERT(dev,); - dev->configured = 1; // Parse configuration & set up drivers From 5c7ca2acad12c72112437b51fcdd9d5adf5fe985 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 18 Apr 2025 12:07:08 +0700 Subject: [PATCH 29/68] change gh ci iar to push event --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7fb13af74..a0e4725ce 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -115,7 +115,7 @@ jobs: # cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family # --------------------------------------- arm-iar: - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false + if: github.event_name == 'push' && github.repository_owner == 'hathach' needs: set-matrix uses: ./.github/workflows/build_util.yml secrets: inherit From ba45625ea4fe57625059b90e5d2c0f4602818737 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 18 Apr 2025 12:39:49 +0700 Subject: [PATCH 30/68] minor ci update --- .github/workflows/build.yml | 5 +++-- .github/workflows/ci_set_matrix.py | 7 ++++--- hw/bsp/espressif/boards/espressif_s2_devkitc/board.h | 10 ++++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a0e4725ce..17d578e4d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -85,7 +85,7 @@ jobs: - 'msp430-gcc' - 'riscv-gcc' - 'rx-gcc' - - 'esp-idf' # build-system is ignored + - 'esp-idf' with: build-system: 'make' toolchain: ${{ matrix.toolchain }} @@ -115,7 +115,8 @@ jobs: # cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family # --------------------------------------- arm-iar: - if: github.event_name == 'push' && github.repository_owner == 'hathach' + if: false # disable for now since we got reach capacity limit too often + #if: github.event_name == 'push' && github.repository_owner == 'hathach' needs: set-matrix uses: ./.github/workflows/build_util.yml secrets: inherit diff --git a/.github/workflows/ci_set_matrix.py b/.github/workflows/ci_set_matrix.py index 410508246..fa73dc1b6 100755 --- a/.github/workflows/ci_set_matrix.py +++ b/.github/workflows/ci_set_matrix.py @@ -44,9 +44,10 @@ family_list = { "stm32l0 stm32l4": ["arm-gcc", "arm-clang", "arm-iar"], "stm32u5 stm32wb": ["arm-gcc", "arm-clang", "arm-iar"], "xmc4000": ["arm-gcc"], - "-bespressif_kaluga_1": ["esp-idf"], - "-bespressif_s3_devkitm": ["esp-idf"], - "-bespressif_p4_function_ev": ["esp-idf"], + "-bespressif_s2_devkitc": ["esp-idf"], + # S3, P4 will be built by hil test + # "-bespressif_s3_devkitm": ["esp-idf"], + # "-bespressif_p4_function_ev": ["esp-idf"], } diff --git a/hw/bsp/espressif/boards/espressif_s2_devkitc/board.h b/hw/bsp/espressif/boards/espressif_s2_devkitc/board.h index 9c197591f..499a626a6 100644 --- a/hw/bsp/espressif/boards/espressif_s2_devkitc/board.h +++ b/hw/bsp/espressif/boards/espressif_s2_devkitc/board.h @@ -36,13 +36,19 @@ extern "C" { #endif -// Note: On the production version (v1.2) WS2812 is connected to GPIO 18, -// however earlier revision v1.1 WS2812 is connected to GPIO 17 #define NEOPIXEL_PIN 18 #define BUTTON_PIN 0 #define BUTTON_STATE_ACTIVE 0 +// SPI for USB host shield +#define MAX3421_SPI_HOST SPI2_HOST +#define MAX3421_SCK_PIN 36 +#define MAX3421_MOSI_PIN 35 +#define MAX3421_MISO_PIN 37 +#define MAX3421_CS_PIN 15 +#define MAX3421_INTR_PIN 14 + #ifdef __cplusplus } #endif From 713410997326269b4072dce906933f8f44fd0efe Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 18 Apr 2025 11:12:14 +0200 Subject: [PATCH 31/68] Update hcd_edpt_open() note. Signed-off-by: HiFiPhile --- src/portable/template/hcd_template.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/portable/template/hcd_template.c b/src/portable/template/hcd_template.c index 694fa8550..fd870c91e 100644 --- a/src/portable/template/hcd_template.c +++ b/src/portable/template/hcd_template.c @@ -118,8 +118,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const (void) dev_addr; // NOTE: ep_desc is allocated on the stack when called from usbh_edpt_control_open() - // If you need to persist any ep_desc values across HCD calls (eg ep_desc->wMaxPacketSize), - // then you need to copy the data into another variable inside this function. + // You need to copy the data into a local variable who maintains the state of the endpoint and transfer. + // Check _hcd_data in hcd_dwc2.c for example. (void) ep_desc; return false; From 1b888a3311f1c722978d3bcb8ee0f5d5d4debd55 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 18 Apr 2025 16:17:35 +0700 Subject: [PATCH 32/68] clean up, remove halted_sof_schedule flags since channel_xfer_in_retry() is only called when channel is halted. --- src/portable/synopsys/dwc2/hcd_dwc2.c | 48 +++++++++++---------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index d2070e57c..a95cc5e10 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -95,7 +95,6 @@ typedef struct { uint8_t err_count : 3; uint8_t period_split_nyet_count : 3; uint8_t halted_nyet : 1; - uint8_t halted_sof_schedule : 1; }; uint8_t result; @@ -713,19 +712,21 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { //-------------------------------------------------------------------- // HCD Event Handler //-------------------------------------------------------------------- + +// retry an IN transfer, channel must be halted static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) { hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - dwc2_channel_t* channel = &dwc2->channel[ch_id]; hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; + dwc2_channel_t* channel = &dwc2->channel[ch_id]; + dwc2_channel_char_t hcchar = {.value = channel->hcchar}; - if (channel_is_periodic(channel->hcchar)){ + if (channel_is_periodic(hcchar.value)){ const dwc2_channel_split_t hcsplt = {.value = channel->hcsplt}; // retry immediately for periodic split NYET if we haven't reach max retry if (hcsplt.split_en && hcsplt.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) { xfer->period_split_nyet_count++; xfer->halted_nyet = 0; if (xfer->period_split_nyet_count < HCD_XFER_PERIOD_SPLIT_NYET_MAX) { - dwc2_channel_char_t hcchar = {.value = channel->hcchar}; hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame channel->hcchar = hcchar.value; channel_send_in_token(dwc2, channel); @@ -736,26 +737,20 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci } } - if (hcint & HCINT_HALTED) { - const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH ? 1 : 8); - if (edpt->uframe_interval == ucount) { - // immediately retry if bInterval is 1 - edpt->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame - channel->hcchar = (edpt->hcchar & ~HCCHAR_CHENA); - channel_send_in_token(dwc2, channel); - } else { - // otherwise, de-allocate channel, enable SOF set frame counter for later transfer - const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; - edpt->next_pid = hctsiz.pid; // save PID - edpt->uframe_countdown = edpt->uframe_interval - ucount; - dwc2->gintmsk |= GINTSTS_SOF; - // already halted, de-allocate channel (called from DMA isr) - channel_dealloc(dwc2, ch_id); - } + const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH ? 1 : 8); + if (edpt->uframe_interval == ucount) { + // retry on next frame if bInterval is 1 + hcchar.odd_frame = 1 - (dwc2->hfnum & 1); + channel->hcchar = hcchar.value; + channel_send_in_token(dwc2, channel); } else { - // disable channel first if not halted (called slave isr) - xfer->halted_sof_schedule = 1; - channel_disable(dwc2, channel); + // otherwise, de-allocate channel, enable SOF set frame counter for later transfer + const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; + edpt->next_pid = hctsiz.pid; // save PID + edpt->uframe_countdown = edpt->uframe_interval - ucount; + dwc2->gintmsk |= GINTSTS_SOF; + // already halted, de-allocate channel (called from DMA isr) + channel_dealloc(dwc2, ch_id); } } else { // for control/bulk: retry immediately @@ -905,7 +900,7 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h xfer->halted_nyet = 1; channel_disable(dwc2, channel); } else if (hcint & HCINT_NAK) { - // NAK received, re-enable channel if request queue is available + // NAK received, disable channel to flush all posted request and try again if (hcsplt.split_en) { hcsplt.split_compl = 0; // restart with start-split channel->hcsplt = hcsplt.value; @@ -937,10 +932,7 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h } } else if (hcint & HCINT_HALTED) { channel->hcintmsk &= ~HCINT_HALTED; - if (xfer->halted_sof_schedule) { - // de-allocate channel but does not complete xfer, we schedule it in the SOF interrupt - channel_dealloc(dwc2, ch_id); - } else if (xfer->result != XFER_RESULT_INVALID) { + if (xfer->result != XFER_RESULT_INVALID) { is_done = true; } else if (xfer->err_count == HCD_XFER_ERROR_MAX) { xfer->result = XFER_RESULT_FAILED; From b7a26cc33c793a3fc03ee54e27f48d276405af0d Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 18 Apr 2025 12:42:18 +0200 Subject: [PATCH 33/68] Fix 1st nak retry one frame shorter. Signed-off-by: HiFiPhile --- src/portable/synopsys/dwc2/hcd_dwc2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index a68455daa..be653fab0 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -748,6 +748,7 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; edpt->next_pid = hctsiz.pid; // save PID edpt->uframe_countdown = edpt->uframe_interval - ucount; + dwc2->gintsts = GINTSTS_SOF; // SOF flag is probably pending dwc2->gintmsk |= GINTSTS_SOF; // already halted, de-allocate channel (called from DMA isr) channel_dealloc(dwc2, ch_id); From 8111e53ff067ca3a55f06389e4571fd57554ae5a Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 18 Apr 2025 18:21:42 +0700 Subject: [PATCH 34/68] minor rename --- src/portable/synopsys/dwc2/hcd_dwc2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 1238a68e0..e1035fa55 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -75,9 +75,9 @@ typedef struct { struct TU_ATTR_PACKED { uint32_t uframe_interval : 18; // micro-frame interval - uint32_t speed : 2; - uint32_t next_pid : 2; - uint32_t do_ping : 1; + uint32_t speed : 2; + uint32_t next_pid : 2; // PID for next transfer + uint32_t next_do_ping : 1; // Do PING for next transfer if possible (highspeed OUT) // uint32_t : 9; }; @@ -567,12 +567,12 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) { hctsiz.pid = edpt->next_pid; // next PID is set in transfer complete interrupt hctsiz.packet_count = packet_count; hctsiz.xfer_size = edpt->buflen; - if (edpt->do_ping && edpt->speed == TUSB_SPEED_HIGH && + if (edpt->next_do_ping && edpt->speed == TUSB_SPEED_HIGH && edpt->next_pid != HCTSIZ_PID_SETUP && hcchar_bm->ep_dir == TUSB_DIR_OUT) { hctsiz.do_ping = 1; } channel->hctsiz = hctsiz.value; - edpt->do_ping = 0; + edpt->next_do_ping = 0; // pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet if (hcchar_bm->ep_num == 0) { @@ -970,7 +970,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } else { - edpt->do_ping = 1; + edpt->next_do_ping = 1; channel_xfer_out_wrapup(dwc2, ch_id); channel_disable(dwc2, channel); } @@ -983,7 +983,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t channel->hcintmsk |= HCINT_ACK; } else { // NAK disable channel to flush all posted request and try again - edpt->do_ping = 1; + edpt->next_do_ping = 1; xfer->err_count = 0; } } else if (hcint & HCINT_HALTED) { @@ -1009,7 +1009,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t } } else { // Device is ready, resume transfer - edpt->do_ping = 0; + edpt->next_do_ping = 0; xfer->err_count = 0; TU_ASSERT(channel_xfer_start(dwc2, ch_id)); } From b3d20442e2252b95f674caf5572d7c392fefb080 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 18 Apr 2025 14:57:53 +0200 Subject: [PATCH 35/68] Fix usbh racing later. Signed-off-by: HiFiPhile --- src/host/usbh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 5ce325762..157a7ab86 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1038,7 +1038,7 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) // Check if dev0 is removed if ((event->rhport == _dev0.rhport) && (event->connection.hub_addr == _dev0.hub_addr) && (event->connection.hub_port == _dev0.hub_port)) { - //_dev0.enumerating = 0;// Causes assert in dwc2 process_enumeration() -> ENUM_ADDR0_DEVICE_DESC + _dev0.enumerating = 0; } break; From d51863d1a006f01f9d4ab9e9863dd6c6fdf8f13b Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 18 Apr 2025 22:39:59 +0700 Subject: [PATCH 36/68] - correctly do_ping if received nyet as transfer complete e.g msc 31 byte command - correctly carry out OUT transfer when PING is ack --- src/portable/synopsys/dwc2/dwc2_type.h | 6 +++--- src/portable/synopsys/dwc2/hcd_dwc2.c | 14 +++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h index 34e046346..0a8dacf5f 100644 --- a/src/portable/synopsys/dwc2/dwc2_type.h +++ b/src/portable/synopsys/dwc2/dwc2_type.h @@ -2088,9 +2088,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size"); #define HCTSIZ_DOPING_Pos (31U) #define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000 #define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING -#define HCTSIZ_PID_Pos (29U) -#define HCTSIZ_PID_Msk (0x3UL << HCTSIZ_PID_Pos) // 0x60000000 -#define HCTSIZ_PID HCTSIZ_PID_Msk // Data PID +#define HCTSIZ_PID_Pos (29U) +#define HCTSIZ_PID_Msk (0x3UL << HCTSIZ_PID_Pos) // 0x60000000 +#define HCTSIZ_PID HCTSIZ_PID_Msk // Data PID /******************** Bit definition for DIEPDMA register ********************/ #define DIEPDMA_DMAADDR_Pos (0U) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index e1035fa55..1845c5e19 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -959,6 +959,10 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t is_done = true; xfer->result = XFER_RESULT_SUCCESS; channel->hcintmsk &= ~HCINT_ACK; + if (hcint & HCINT_NYET) { + // complete transfer with NYET, do ping next time + edpt->next_do_ping = 1; + } } else if (hcint & HCINT_STALL) { xfer->result = XFER_RESULT_STALLED; channel_disable(dwc2, channel); @@ -1002,16 +1006,16 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t channel->hcintmsk &= ~HCINT_ACK; if (hcsplt.split_en) { if (!hcsplt.split_compl) { - // start split is ACK --> do complete split + // ACK for start split --> do complete split hcsplt.split_compl = 1; channel->hcsplt = hcsplt.value; channel->hcchar |= HCCHAR_CHENA; } } else { - // Device is ready, resume transfer - edpt->next_do_ping = 0; - xfer->err_count = 0; - TU_ASSERT(channel_xfer_start(dwc2, ch_id)); + // ACK interrupt is only enabled for Split and PING + // ACK for PING, which mean device is ready to receive data + channel->hctsiz &= ~HCTSIZ_DOPING; // HC already cleared PING bit, but we clear anyway + channel->hcchar |= HCCHAR_CHENA; } } From b3a9b6e37ffb21dba2f6da5fdd4ac5cd90c94442 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 19 Apr 2025 11:43:28 +0200 Subject: [PATCH 37/68] enable SOF interrupt only if not already enabled Signed-off-by: HiFiPhile --- src/portable/synopsys/dwc2/hcd_dwc2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index be653fab0..378c2742b 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -748,8 +748,11 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz}; edpt->next_pid = hctsiz.pid; // save PID edpt->uframe_countdown = edpt->uframe_interval - ucount; - dwc2->gintsts = GINTSTS_SOF; // SOF flag is probably pending - dwc2->gintmsk |= GINTSTS_SOF; + // enable SOF interrupt if not already enabled + if (!(dwc2->gintmsk & GINTMSK_SOFM)) { + dwc2->gintsts = GINTSTS_SOF; + dwc2->gintmsk |= GINTMSK_SOFM; + } // already halted, de-allocate channel (called from DMA isr) channel_dealloc(dwc2, ch_id); } From 5725d33121d483162730c7bb06cada3faf0da9af Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 21 Apr 2025 20:39:23 +0700 Subject: [PATCH 38/68] improve usbh stability with failed setup send, prevent control stage locked out --- src/host/usbh.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 157a7ab86..d6d974371 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -647,6 +647,21 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) { *((xfer_result_t*) xfer->user_data) = xfer->result; } +TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) { + (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); + _ctrl_xfer.stage = stage; + (void) osal_mutex_unlock(_usbh_mutex); +} + +TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const uint8_t setup_packet[8]) { + const uint8_t rhport = usbh_get_rhport(daddr); + const bool ret = hcd_setup_send(rhport, daddr, setup_packet); + if (!ret) { + _control_set_xfer_stage(CONTROL_STAGE_IDLE); + } + return ret; +} + // TODO timeout_ms is not supported yet bool tuh_control_xfer (tuh_xfer_t* xfer) { TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // EP0 with setup packet @@ -673,15 +688,13 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { (void) osal_mutex_unlock(_usbh_mutex); TU_VERIFY(is_idle); - const uint8_t rhport = usbh_get_rhport(daddr); - TU_LOG_USBH("[%u:%u] %s: ", rhport, daddr, (xfer->setup->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME) ? tu_str_std_request[xfer->setup->bRequest] : "Class Request"); TU_LOG_BUF_USBH(xfer->setup, 8); if (xfer->complete_cb) { - TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t const *) &_usbh_epbuf.request)); + TU_ASSERT(usbh_setup_send(daddr, (uint8_t const *) &_usbh_epbuf.request)); }else { // blocking if complete callback is not provided // change callback to internal blocking, and result as user argument @@ -691,7 +704,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { _ctrl_xfer.user_data = (uintptr_t) &result; _ctrl_xfer.complete_cb = _control_blocking_complete_cb; - TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t *) &_usbh_epbuf.request)); + TU_ASSERT(usbh_setup_send(daddr, (uint8_t const *) &_usbh_epbuf.request)); while (result == XFER_RESULT_INVALID) { // Note: this can be called within an callback ie. part of tuh_task() @@ -713,12 +726,6 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { return true; } -TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage) { - (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); - _ctrl_xfer.stage = stage; - (void) osal_mutex_unlock(_usbh_mutex); -} - static void _control_xfer_complete(uint8_t daddr, xfer_result_t result) { TU_LOG_USBH("\r\n"); @@ -735,7 +742,7 @@ static void _control_xfer_complete(uint8_t daddr, xfer_result_t result) { .user_data = _ctrl_xfer.user_data }; - _set_control_xfer_stage(CONTROL_STAGE_IDLE); + _control_set_xfer_stage(CONTROL_STAGE_IDLE); if (xfer_temp.complete_cb) { xfer_temp.complete_cb(&xfer_temp); @@ -764,7 +771,7 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t _ctrl_xfer.actual_len = 0; // reset actual_len (void) osal_mutex_unlock(_usbh_mutex); - TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t const *) request)); + TU_ASSERT(usbh_setup_send(daddr, (uint8_t const *) request)); } else { TU_LOG_USBH("[%u:%u] Control FAILED, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, xferred_bytes); TU_LOG_BUF_USBH(request, 8); @@ -777,8 +784,8 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t case CONTROL_STAGE_SETUP: if (request->wLength) { // DATA stage: initial data toggle is always 1 - _set_control_xfer_stage(CONTROL_STAGE_DATA); - TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) ); + _control_set_xfer_stage(CONTROL_STAGE_DATA); + TU_ASSERT(hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength)); return true; } TU_ATTR_FALLTHROUGH; @@ -792,7 +799,7 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t _ctrl_xfer.actual_len = (uint16_t) xferred_bytes; // ACK stage: toggle is always 1 - _set_control_xfer_stage(CONTROL_STAGE_ACK); + _control_set_xfer_stage(CONTROL_STAGE_ACK); TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction), NULL, 0) ); break; @@ -854,7 +861,7 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { // control transfer: only 1 control at a time, check if we are aborting the current one TU_VERIFY(daddr == _ctrl_xfer.daddr && _ctrl_xfer.stage != CONTROL_STAGE_IDLE); hcd_edpt_abort_xfer(rhport, daddr, ep_addr); - _set_control_xfer_stage(CONTROL_STAGE_IDLE); // reset control transfer state to idle + _control_set_xfer_stage(CONTROL_STAGE_IDLE); // reset control transfer state to idle } else { usbh_device_t* dev = get_device(daddr); TU_VERIFY(dev); @@ -1321,7 +1328,9 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu clear_device(dev); // abort on-going control xfer on this device if any - if (_ctrl_xfer.daddr == daddr) _set_control_xfer_stage(CONTROL_STAGE_IDLE); + if (_ctrl_xfer.daddr == daddr) { + _control_set_xfer_stage(CONTROL_STAGE_IDLE); + } } } From 9f096ac56b637423ba7c4a4004f6f95006c12e95 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 12 Apr 2025 20:00:00 +0200 Subject: [PATCH 39/68] host: fix enumerate racing - if a previous enumeration failed _ctrl_xfer status could stuck, it needs to be cleared before next attempt. - after _dev0.enumerating is reset in hcd_event_handler(), if an attach event arrived before _ctrl_xfer clean up in remove event, a racing condition will happen. Signed-off-by: HiFiPhile --- src/host/usbh.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index d6d974371..69784ed47 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -311,6 +311,12 @@ TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) return &_usbh_devices[dev_addr-1]; } +TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage) { + (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); + _ctrl_xfer.stage = stage; + (void) osal_mutex_unlock(_usbh_mutex); +} + static bool enum_new_device(hcd_event_t* event); static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port); static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size); @@ -557,6 +563,13 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); process_removing_device(event.rhport, event.connection.hub_addr, event.connection.hub_port); + if ((event.rhport == _dev0.rhport) && (event.connection.hub_addr == _dev0.hub_addr) && + (event.connection.hub_port == _dev0.hub_port)) { + _dev0.enumerating = 0; + if (_ctrl_xfer.daddr == 0) { + _set_control_xfer_stage(CONTROL_STAGE_IDLE); + } + } #if CFG_TUH_HUB // TODO remove if (event.connection.hub_addr != 0 && event.connection.hub_port != 0) { @@ -1042,11 +1055,6 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) // FIXME device remove from a hub need an HCD API for hcd to free up endpoint // mark device as removing to prevent further xfer before the event is processed in usbh task - // Check if dev0 is removed - if ((event->rhport == _dev0.rhport) && (event->connection.hub_addr == _dev0.hub_addr) && - (event->connection.hub_port == _dev0.hub_port)) { - _dev0.enumerating = 0; - } break; default: break; From 3c4e6a779d65ad2d28e0eef0284df88e39bec6bc Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 18 Apr 2025 17:41:41 +0200 Subject: [PATCH 40/68] Move decouncing delay before USB reset. Signed-off-by: HiFiPhile --- src/host/usbh.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 69784ed47..c38afa3be 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1692,6 +1692,15 @@ static bool enum_new_device(hcd_event_t* event) { _dev0.hub_port = event->connection.hub_port; if (_dev0.hub_addr == 0) { + // wait until device connection is stable TODO non blocking + tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); + + // device unplugged while delaying + if (!hcd_port_connect_status(_dev0.rhport)) { + enum_full_complete(); + return true; + } + // connected directly to roothub hcd_port_reset(_dev0.rhport); @@ -1701,9 +1710,6 @@ static bool enum_new_device(hcd_event_t* event) { hcd_port_reset_end(_dev0.rhport); - // wait until device connection is stable TODO non blocking - tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); - // device unplugged while delaying if (!hcd_port_connect_status(_dev0.rhport)) { enum_full_complete(); From 7ba63a63022ed5ed2e92daca1cd011dd55547d39 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 18 Apr 2025 17:47:53 +0200 Subject: [PATCH 41/68] Also cleanup unaddressed device. Signed-off-by: HiFiPhile --- src/host/usbh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/host/usbh.c b/src/host/usbh.c index c38afa3be..712f10f0d 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -566,6 +566,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { if ((event.rhport == _dev0.rhport) && (event.connection.hub_addr == _dev0.hub_addr) && (event.connection.hub_port == _dev0.hub_port)) { _dev0.enumerating = 0; + hcd_device_close(_dev0.rhport, _dev0.hub_addr); if (_ctrl_xfer.daddr == 0) { _set_control_xfer_stage(CONTROL_STAGE_IDLE); } From 940fe43e68eaa6d8c38404410896574ed8147421 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 22 Apr 2025 17:33:37 +0700 Subject: [PATCH 42/68] move removing dev0 to process_removing_device() --- src/host/usbh.c | 59 ++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 712f10f0d..0a78177ea 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -311,12 +311,6 @@ TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) return &_usbh_devices[dev_addr-1]; } -TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage) { - (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); - _ctrl_xfer.stage = stage; - (void) osal_mutex_unlock(_usbh_mutex); -} - static bool enum_new_device(hcd_event_t* event); static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port); static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size); @@ -563,14 +557,6 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); process_removing_device(event.rhport, event.connection.hub_addr, event.connection.hub_port); - if ((event.rhport == _dev0.rhport) && (event.connection.hub_addr == _dev0.hub_addr) && - (event.connection.hub_port == _dev0.hub_port)) { - _dev0.enumerating = 0; - hcd_device_close(_dev0.rhport, _dev0.hub_addr); - if (_ctrl_xfer.daddr == 0) { - _set_control_xfer_stage(CONTROL_STAGE_IDLE); - } - } #if CFG_TUH_HUB // TODO remove if (event.connection.hub_addr != 0 && event.connection.hub_port != 0) { @@ -662,9 +648,11 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) { } TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) { - (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); - _ctrl_xfer.stage = stage; - (void) osal_mutex_unlock(_usbh_mutex); + if (_ctrl_xfer.stage != stage) { + (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); + _ctrl_xfer.stage = stage; + (void) osal_mutex_unlock(_usbh_mutex); + } } TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const uint8_t setup_packet[8]) { @@ -1279,30 +1267,19 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) { return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX); } -//static void mark_removing_device_isr(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { -// for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) { -// usbh_device_t *dev = &_usbh_devices[dev_id]; -// uint8_t const daddr = dev_id + 1; -// -// // hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub -// if (dev->rhport == rhport && dev->connected && -// (hub_addr == 0 || dev->hub_addr == hub_addr) && -// (hub_port == 0 || dev->hub_port == hub_port)) { -// if (is_hub_addr(daddr)) { -// // If the device itself is a usb hub, mark all downstream devices. -// // FIXME recursive calls -// mark_removing_device_isr(rhport, daddr, 0); -// } -// -// dev->removing = 1; -// } -// } -//} - // a device unplugged from rhport:hub_addr:hub_port static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { + // dev0 is unplugged + if (_dev0.enumerating && (rhport == _dev0.rhport) && (hub_addr == _dev0.hub_addr) && (hub_port == _dev0.hub_port)) { + hcd_device_close(_dev0.rhport, 0); + if (_ctrl_xfer.daddr == 0) { + _control_set_xfer_stage(CONTROL_STAGE_IDLE); + } + _dev0.enumerating = 0; + return; + } + //------------- find the all devices (star-network) under port that is unplugged -------------// - // TODO mark as disconnected in ISR, also handle dev0 uint32_t removing_hubs = 0; do { for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) { @@ -1343,9 +1320,11 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu } } - // if removing a hub, we need to remove its downstream devices + // if removing a hub, we need to remove all of its downstream devices #if CFG_TUH_HUB - if (removing_hubs == 0) break; + if (removing_hubs == 0) { + break; + } // find a marked hub to process for (uint8_t h_id = 0; h_id < CFG_TUH_HUB; h_id++) { From 8f9ef7dfbe41e29d4275be4ca2130d70d163f100 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 22 Apr 2025 22:09:06 +0700 Subject: [PATCH 43/68] reduce ENUM_DEBOUNCING_DELAY_MS to 200ms replace dev0.enumerating by enumerating_daddr for better clean up on unplugging while enumerating move controller_id & enumerating_daddr into _usbh_data struct --- src/host/usbh.c | 95 +++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 0a78177ea..bb4669718 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -96,12 +96,7 @@ typedef struct { uint8_t rhport; uint8_t hub_addr; uint8_t hub_port; - - struct TU_ATTR_PACKED { - uint8_t speed : 4; // packed speed to save footprint - volatile uint8_t enumerating : 1; // enumeration is in progress, false if not connected or all interfaces are configured - uint8_t TU_RESERVED : 3; - }; + uint8_t speed; } usbh_dev0_t; typedef struct { @@ -117,7 +112,6 @@ typedef struct { volatile uint8_t addressed : 1; // After SET_ADDR volatile uint8_t configured : 1; // After SET_CONFIG and all drivers are configured volatile uint8_t suspended : 1; // Bus suspended - // volatile uint8_t removing : 1; // Physically disconnected, waiting to be processed by usbh }; @@ -261,8 +255,6 @@ static inline usbh_class_driver_t const *get_driver(uint8_t drv_id) { // sum of end device + hub #define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB) -static uint8_t _usbh_controller = TUSB_INDEX_INVALID_8; - // Device with address = 0 for enumeration static usbh_dev0_t _dev0; @@ -279,8 +271,7 @@ static usbh_device_t _usbh_devices[TOTAL_DEVICES]; #define _usbh_mutex NULL #endif -// Event queue -// usbh_int_set is used as mutex in OS NONE config +// Event queue: usbh_int_set() is used as mutex in OS NONE config OSAL_QUEUE_DEF(usbh_int_set, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t); static osal_queue_t _usbh_q; @@ -305,6 +296,15 @@ typedef struct { CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf; +typedef struct { + uint8_t controller_id; // controller ID + uint8_t enumerating_daddr; // device address of the device being enumerated +} usbh_data_t; + +static usbh_data_t _usbh_data = { + .controller_id = TUSB_INDEX_INVALID_8, +}; + //------------- Helper Function -------------// TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) { TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL); @@ -334,7 +334,7 @@ bool tuh_mounted(uint8_t dev_addr) { bool tuh_connected(uint8_t daddr) { if (daddr == 0) { - return _dev0.enumerating; // dev0 is connected if still enumerating + return _usbh_data.enumerating_daddr == 0; } else { const usbh_device_t* dev = get_device(daddr); return dev && dev->connected; @@ -359,7 +359,7 @@ tusb_speed_t tuh_speed_get(uint8_t dev_addr) { } bool tuh_rhport_is_active(uint8_t rhport) { - return _usbh_controller == rhport; + return _usbh_data.controller_id == rhport; } bool tuh_rhport_reset_bus(uint8_t rhport, bool active) { @@ -387,7 +387,7 @@ static void clear_device(usbh_device_t* dev) { } bool tuh_inited(void) { - return _usbh_controller != TUSB_INDEX_INVALID_8; + return _usbh_data.controller_id != TUSB_INDEX_INVALID_8; } bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { @@ -427,6 +427,9 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { tu_memclr(_usbh_devices, sizeof(_usbh_devices)); tu_memclr(&_ctrl_xfer, sizeof(_ctrl_xfer)); + _usbh_data.controller_id = TUSB_INDEX_INVALID_8; + _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; + for (uint8_t i = 0; i < TOTAL_DEVICES; i++) { clear_device(&_usbh_devices[i]); } @@ -442,7 +445,7 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } // Init host controller - _usbh_controller = rhport; + _usbh_data.controller_id = rhport; TU_ASSERT(hcd_init(rhport, rh_init)); hcd_int_enable(rhport); @@ -457,7 +460,7 @@ bool tuh_deinit(uint8_t rhport) { // deinit host controller hcd_int_disable(rhport); hcd_deinit(rhport); - _usbh_controller = TUSB_INDEX_INVALID_8; + _usbh_data.controller_id = TUSB_INDEX_INVALID_8; // "unplug" all devices on this rhport (hub_addr = 0, hub_port = 0) process_removing_device(rhport, 0, 0); @@ -524,20 +527,19 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { switch (event.event_id) { case HCD_EVENT_DEVICE_ATTACH: - // due to the shared control buffer, we must complete enumerating one device before enumerating another one. + // due to the shared control buffer, we must fully complete enumerating one device first. // TODO better to have an separated queue for newly attached devices - if (_dev0.enumerating) { - // Some device can cause multiple duplicated attach events - // drop current enumerating and start over for a proper port reset - if (event.rhport == _dev0.rhport && event.connection.hub_addr == _dev0.hub_addr && - event.connection.hub_port == _dev0.hub_port) { + if (_usbh_data.enumerating_daddr != TUSB_INDEX_INVALID_8) { + if (event.rhport == _dev0.rhport && + event.connection.hub_addr == _dev0.hub_addr && event.connection.hub_port == _dev0.hub_port) { + // Some device can cause multiple duplicated attach events + // drop current enumerating and start over for a proper port reset // abort/cancel current enumeration and start new one TU_LOG1("[%u:] USBH Device Attach (duplicated)\r\n", event.rhport); tuh_edpt_abort_xfer(0, 0); enum_new_device(&event); } else { TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport); - bool is_empty = osal_queue_empty(_usbh_q); queue_event(&event, in_isr); @@ -548,7 +550,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { } } else { TU_LOG1("[%u:] USBH Device Attach\r\n", event.rhport); - _dev0.enumerating = 1; + _usbh_data.enumerating_daddr = 0; enum_new_device(&event); } break; @@ -668,7 +670,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const ui bool tuh_control_xfer (tuh_xfer_t* xfer) { TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // EP0 with setup packet const uint8_t daddr = xfer->daddr; - TU_VERIFY(tuh_connected(daddr)); // Check if device is still connected (enumerating for dev0) + TU_VERIFY(tuh_connected(daddr)); // pre-check to help reducing mutex lock TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE); @@ -895,9 +897,9 @@ uint8_t *usbh_get_enum_buf(void) { void usbh_int_set(bool enabled) { // TODO all host controller if multiple are used since they shared the same event queue if (enabled) { - hcd_int_enable(_usbh_controller); + hcd_int_enable(_usbh_data.controller_id); } else { - hcd_int_disable(_usbh_controller); + hcd_int_disable(_usbh_data.controller_id); } } @@ -906,7 +908,6 @@ void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr) { event.event_id = USBH_EVENT_FUNC_CALL; event.func_call.func = func; event.func_call.param = param; - queue_event(&event, in_isr); } @@ -1043,7 +1044,6 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) case HCD_EVENT_DEVICE_REMOVE: // FIXME device remove from a hub need an HCD API for hcd to free up endpoint // mark device as removing to prevent further xfer before the event is processed in usbh task - break; default: break; @@ -1270,12 +1270,13 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) { // a device unplugged from rhport:hub_addr:hub_port static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { // dev0 is unplugged - if (_dev0.enumerating && (rhport == _dev0.rhport) && (hub_addr == _dev0.hub_addr) && (hub_port == _dev0.hub_port)) { + if ((_usbh_data.enumerating_daddr == 0) && (rhport == _dev0.rhport) && + (hub_addr == _dev0.hub_addr) && (hub_port == _dev0.hub_port)) { hcd_device_close(_dev0.rhport, 0); if (_ctrl_xfer.daddr == 0) { _control_set_xfer_stage(CONTROL_STAGE_IDLE); } - _dev0.enumerating = 0; + _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; return; } @@ -1314,9 +1315,13 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu clear_device(dev); // abort on-going control xfer on this device if any - if (_ctrl_xfer.daddr == daddr) { + if (daddr == _ctrl_xfer.daddr) { _control_set_xfer_stage(CONTROL_STAGE_IDLE); } + + if (daddr == _usbh_data.enumerating_daddr) { + _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; + } } } @@ -1353,9 +1358,9 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu //--------------------------------------------------------------------+ enum { - ENUM_RESET_DELAY_MS = 50, // USB specs: 10 to 50ms - ENUM_DEBOUNCING_DELAY_MS = 450, // when plug/unplug a device, physical connection can be bouncing and may + ENUM_DEBOUNCING_DELAY_MS = 200, // when plug/unplug a device, physical connection can be bouncing and may // generate a series of attach/detach event. This delay wait for stable connection + ENUM_RESET_DELAY_MS = 50, // USB specs: 10 to 50ms }; enum { @@ -1399,7 +1404,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { // retry if not reaching max attempt failed_count++; - bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX); + bool retry = (_usbh_data.enumerating_daddr != TUSB_INDEX_INVALID_8) && (failed_count < ATTEMPT_COUNT_MAX); if (retry) { tusb_time_delay_ms_api(ATTEMPT_DELAY_MS); // delay a bit TU_LOG1("Enumeration attempt %u/%u\r\n", failed_count+1, ATTEMPT_COUNT_MAX); @@ -1409,7 +1414,6 @@ static void process_enumeration(tuh_xfer_t* xfer) { if (!retry) { enum_full_complete(); // complete as failed } - return; } failed_count = 0; @@ -1425,7 +1429,6 @@ static void process_enumeration(tuh_xfer_t* xfer) { switch (state) { #if CFG_TUH_HUB //case ENUM_HUB_GET_STATUS_1: break; - case ENUM_HUB_CLEAR_RESET_1: { hub_port_status_response_t port_status; memcpy(&port_status, _usbh_epbuf.ctrl, sizeof(hub_port_status_response_t)); @@ -1490,14 +1493,12 @@ static void process_enumeration(tuh_xfer_t* xfer) { usbh_device_t* new_dev = get_device(new_addr); TU_ASSERT(new_dev,); new_dev->addressed = 1; + _usbh_data.enumerating_daddr = new_addr; - // Close device 0 - hcd_device_close(_dev0.rhport, 0); + hcd_device_close(_dev0.rhport, 0); // close dev0 - // open control pipe for new address - TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); + TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint - // Get full device descriptor TU_LOG_USBH("Get Device Descriptor\r\n"); TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), process_enumeration, ENUM_GET_STRING_LANGUAGE_ID_LEN),); @@ -1516,8 +1517,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { dev->i_serial = desc_device->iSerialNumber; dev->bNumConfigurations = desc_device->bNumConfigurations; - tuh_enum_descriptor_device_cb(daddr, desc_device);// callback - + tuh_enum_descriptor_device_cb(daddr, desc_device); // callback tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, 2, process_enumeration, ENUM_GET_STRING_LANGUAGE_ID); break; @@ -1672,6 +1672,8 @@ static bool enum_new_device(hcd_event_t* event) { _dev0.hub_port = event->connection.hub_port; if (_dev0.hub_addr == 0) { + // connected directly to roothub + // wait until device connection is stable TODO non blocking tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); @@ -1681,8 +1683,7 @@ static bool enum_new_device(hcd_event_t* event) { return true; } - // connected directly to roothub - hcd_port_reset(_dev0.rhport); + hcd_port_reset(_dev0.rhport); // reset device // Since we are in middle of rhport reset, frame number is not available yet. // need to depend on tusb_time_millis_api() @@ -1905,7 +1906,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) { static void enum_full_complete(void) { // mark enumeration as complete - _dev0.enumerating = 0; + _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; #if CFG_TUH_HUB if (_dev0.hub_addr) { From b6170c965f83a4f59ec7c165c502d812ceafea3f Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 22 Apr 2025 21:14:04 +0200 Subject: [PATCH 44/68] Compile fix. Signed-off-by: HiFiPhile --- src/host/usbh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index bb4669718..0492fb2f2 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -692,7 +692,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { (void) osal_mutex_unlock(_usbh_mutex); TU_VERIFY(is_idle); - TU_LOG_USBH("[%u:%u] %s: ", rhport, daddr, + TU_LOG_USBH("[%u:%u] %s: ", usbh_get_rhport(daddr), daddr, (xfer->setup->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME) ? tu_str_std_request[xfer->setup->bRequest] : "Class Request"); TU_LOG_BUF_USBH(xfer->setup, 8); From 741cb3cf029e37682634eeb355c20420c0816c8d Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 23 Apr 2025 12:35:32 +0700 Subject: [PATCH 45/68] rename hcd_devtree_info_t to tuh_bus_info_t, hcd_devtree_get_info to hcd_bus_info_get streamline bus info to usbh_devies, also replace dev0 (renamed to dev0_bus) --- .idea/debugServers/esp32s2.xml | 14 ++ .idea/debugServers/rp2350.xml | 2 +- .idea/debugServers/stm32f769.xml | 13 ++ .idea/debugServers/stm32h563.xml | 13 ++ .idea/debugServers/stm32h743.xml | 13 ++ examples/host/cdc_msc_hid/src/msc_app.c | 12 +- src/host/hcd.h | 12 +- src/host/usbh.c | 127 ++++++++---------- src/host/usbh_pvt.h | 2 +- src/portable/ehci/ehci.c | 10 +- src/portable/mentor/musb/hcd_musb.c | 24 ++-- src/portable/ohci/ohci.c | 6 +- .../raspberrypi/pio_usb/hcd_pio_usb.c | 6 +- src/portable/renesas/rusb2/hcd_rusb2.c | 6 +- src/portable/synopsys/dwc2/hcd_dwc2.c | 18 +-- 15 files changed, 152 insertions(+), 126 deletions(-) create mode 100644 .idea/debugServers/esp32s2.xml create mode 100644 .idea/debugServers/stm32f769.xml create mode 100644 .idea/debugServers/stm32h563.xml create mode 100644 .idea/debugServers/stm32h743.xml diff --git a/.idea/debugServers/esp32s2.xml b/.idea/debugServers/esp32s2.xml new file mode 100644 index 000000000..6a4aff3da --- /dev/null +++ b/.idea/debugServers/esp32s2.xml @@ -0,0 +1,14 @@ + + + + $USER_HOME$/.espressif/tools/xtensa-esp-elf-gdb/14.2_20240403/xtensa-esp-elf-gdb/bin/xtensa-esp32s2-elf-gdb + + + + + + + + + + \ No newline at end of file diff --git a/.idea/debugServers/rp2350.xml b/.idea/debugServers/rp2350.xml index 5e092f3c4..52243a297 100644 --- a/.idea/debugServers/rp2350.xml +++ b/.idea/debugServers/rp2350.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/debugServers/stm32f769.xml b/.idea/debugServers/stm32f769.xml new file mode 100644 index 000000000..2fb322a0f --- /dev/null +++ b/.idea/debugServers/stm32f769.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/debugServers/stm32h563.xml b/.idea/debugServers/stm32h563.xml new file mode 100644 index 000000000..9bf6db6e9 --- /dev/null +++ b/.idea/debugServers/stm32h563.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/debugServers/stm32h743.xml b/.idea/debugServers/stm32h743.xml new file mode 100644 index 000000000..63680b78c --- /dev/null +++ b/.idea/debugServers/stm32h743.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c index 1d7e18e6e..0e9c99766 100644 --- a/examples/host/cdc_msc_hid/src/msc_app.c +++ b/examples/host/cdc_msc_hid/src/msc_app.c @@ -30,13 +30,11 @@ //--------------------------------------------------------------------+ static scsi_inquiry_resp_t inquiry_resp; -bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ +static bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { msc_cbw_t const* cbw = cb_data->cbw; msc_csw_t const* csw = cb_data->csw; - if (csw->status != 0) - { + if (csw->status != 0) { printf("Inquiry failed\r\n"); return false; } @@ -55,16 +53,14 @@ bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_da } //------------- IMPLEMENTATION -------------// -void tuh_msc_mount_cb(uint8_t dev_addr) -{ +void tuh_msc_mount_cb(uint8_t dev_addr) { printf("A MassStorage device is mounted\r\n"); uint8_t const lun = 0; tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0); } -void tuh_msc_umount_cb(uint8_t dev_addr) -{ +void tuh_msc_umount_cb(uint8_t dev_addr) { (void) dev_addr; printf("A MassStorage device is unmounted\r\n"); } diff --git a/src/host/hcd.h b/src/host/hcd.h index b20d96d54..1f2704a10 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -95,7 +95,7 @@ typedef struct { uint8_t hub_addr; uint8_t hub_port; uint8_t speed; -} hcd_devtree_info_t; +} tuh_bus_info_t; //--------------------------------------------------------------------+ // Memory API @@ -186,12 +186,8 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr); // USBH implemented API //--------------------------------------------------------------------+ -// Get device tree information of a device -// USB device tree can be complicated and manged by USBH, this help HCD to retrieve -// needed topology info to carry out its work -extern void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info); - -//------------- Event API -------------// +// Get device port information +extern bool hcd_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info); // Called by HCD to notify stack extern void hcd_event_handler(hcd_event_t const* event, bool in_isr); @@ -239,4 +235,4 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred } #endif -#endif /* _TUSB_HCD_H_ */ +#endif diff --git a/src/host/usbh.c b/src/host/usbh.c index 0492fb2f2..c063c97f9 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -92,19 +92,7 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si // USBH-HCD common data structure //--------------------------------------------------------------------+ typedef struct { - // port - uint8_t rhport; - uint8_t hub_addr; - uint8_t hub_port; - uint8_t speed; -} usbh_dev0_t; - -typedef struct { - // port, must be same layout as usbh_dev0_t - uint8_t rhport; - uint8_t hub_addr; - uint8_t hub_port; - uint8_t speed; + tuh_bus_info_t bus_info; // Device State struct TU_ATTR_PACKED { @@ -231,8 +219,8 @@ static usbh_class_driver_t const usbh_class_drivers[] = { enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) }; // Additional class drivers implemented by application -tu_static usbh_class_driver_t const * _app_driver = NULL; -tu_static uint8_t _app_driver_count = 0; +static usbh_class_driver_t const * _app_driver = NULL; +static uint8_t _app_driver_count = 0; #define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) @@ -255,9 +243,6 @@ static inline usbh_class_driver_t const *get_driver(uint8_t drv_id) { // sum of end device + hub #define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB) -// Device with address = 0 for enumeration -static usbh_dev0_t _dev0; - // all devices excluding zero-address // hub address start from CFG_TUH_DEVICE_MAX+1 // TODO: hub can has its own simpler struct to save memory @@ -299,6 +284,8 @@ CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf; typedef struct { uint8_t controller_id; // controller ID uint8_t enumerating_daddr; // device address of the device being enumerated + + tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration } usbh_data_t; static usbh_data_t _usbh_data = { @@ -353,9 +340,10 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) { return true; } -tusb_speed_t tuh_speed_get(uint8_t dev_addr) { - usbh_device_t *dev = get_device(dev_addr); - return (tusb_speed_t) (dev ? get_device(dev_addr)->speed : _dev0.speed); +tusb_speed_t tuh_speed_get(uint8_t daddr) { + tuh_bus_info_t bus_info; + hcd_bus_info_get(daddr, &bus_info); + return bus_info.speed; } bool tuh_rhport_is_active(uint8_t rhport) { @@ -423,9 +411,9 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } // Device - tu_memclr(&_dev0, sizeof(_dev0)); tu_memclr(_usbh_devices, sizeof(_usbh_devices)); tu_memclr(&_ctrl_xfer, sizeof(_ctrl_xfer)); + tu_memclr(&_usbh_data, sizeof(_usbh_data)); _usbh_data.controller_id = TUSB_INDEX_INVALID_8; _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; @@ -530,8 +518,8 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { // due to the shared control buffer, we must fully complete enumerating one device first. // TODO better to have an separated queue for newly attached devices if (_usbh_data.enumerating_daddr != TUSB_INDEX_INVALID_8) { - if (event.rhport == _dev0.rhport && - event.connection.hub_addr == _dev0.hub_addr && event.connection.hub_port == _dev0.hub_port) { + if (event.rhport == _usbh_data.dev0_bus.rhport && + event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr && event.connection.hub_port == _usbh_data.dev0_bus.hub_port) { // Some device can cause multiple duplicated attach events // drop current enumerating and start over for a proper port reset // abort/cancel current enumeration and start new one @@ -859,7 +847,7 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { const uint8_t dir = tu_edpt_dir(ep_addr); if (epnum == 0) { - // Also include dev0 for aborting enumerating + // Also include dev0_bus for aborting enumerating const uint8_t rhport = usbh_get_rhport(daddr); // control transfer: only 1 control at a time, check if we are aborting the current one @@ -871,7 +859,7 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { TU_VERIFY(dev); TU_VERIFY(dev->ep_status[epnum][dir].busy); // non-control skip if not busy - hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr); + hcd_edpt_abort_xfer(dev->bus_info.rhport, daddr, ep_addr); // mark as ready and release endpoint if transfer is aborted dev->ep_status[epnum][dir].busy = false; @@ -885,9 +873,10 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { // USBH API For Class Driver //--------------------------------------------------------------------+ -uint8_t usbh_get_rhport(uint8_t dev_addr) { - usbh_device_t *dev = get_device(dev_addr); - return dev ? dev->rhport : _dev0.rhport; +uint8_t usbh_get_rhport(uint8_t daddr) { + tuh_bus_info_t bus_info; + hcd_bus_info_get(daddr, &bus_info); + return bus_info.rhport; } uint8_t *usbh_get_enum_buf(void) { @@ -972,7 +961,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t* bu dev->ep_callback[epnum][dir].user_data = user_data; #endif - if (hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes)) { + if (hcd_edpt_xfer(dev->bus_info.rhport, dev_addr, ep_addr, buffer, total_bytes)) { TU_LOG_USBH("OK\r\n"); return true; } else { @@ -1024,19 +1013,14 @@ bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) { // HCD Event Handler //--------------------------------------------------------------------+ -void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info) { - usbh_device_t const* dev = get_device(dev_addr); +bool hcd_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info) { + usbh_device_t const* dev = get_device(daddr); if (dev) { - devtree_info->rhport = dev->rhport; - devtree_info->hub_addr = dev->hub_addr; - devtree_info->hub_port = dev->hub_port; - devtree_info->speed = dev->speed; + *bus_info = dev->bus_info; } else { - devtree_info->rhport = _dev0.rhport; - devtree_info->hub_addr = _dev0.hub_addr; - devtree_info->hub_port = _dev0.hub_port; - devtree_info->speed = _dev0.speed; + *bus_info = _usbh_data.dev0_bus; } + return true; } TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) { @@ -1269,10 +1253,10 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) { // a device unplugged from rhport:hub_addr:hub_port static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { - // dev0 is unplugged - if ((_usbh_data.enumerating_daddr == 0) && (rhport == _dev0.rhport) && - (hub_addr == _dev0.hub_addr) && (hub_port == _dev0.hub_port)) { - hcd_device_close(_dev0.rhport, 0); + // dev0_bus is unplugged + if ((_usbh_data.enumerating_daddr == 0) && (rhport == _usbh_data.dev0_bus.rhport) && + (hub_addr == _usbh_data.dev0_bus.hub_addr) && (hub_port == _usbh_data.dev0_bus.hub_port)) { + hcd_device_close(_usbh_data.dev0_bus.rhport, 0); if (_ctrl_xfer.daddr == 0) { _control_set_xfer_stage(CONTROL_STAGE_IDLE); } @@ -1288,9 +1272,9 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu uint8_t const daddr = dev_id + 1; // hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub - if (dev->rhport == rhport && dev->connected && - (hub_addr == 0 || dev->hub_addr == hub_addr) && - (hub_port == 0 || dev->hub_port == hub_port)) { + if (dev->bus_info.rhport == rhport && dev->connected && + (hub_addr == 0 || dev->bus_info.hub_addr == hub_addr) && + (hub_port == 0 || dev->bus_info.hub_port == hub_port)) { TU_LOG_USBH("[%u:%u:%u] unplugged address = %u\r\n", rhport, hub_addr, hub_port, daddr); if (is_hub_addr(daddr)) { @@ -1439,12 +1423,12 @@ static void process_enumeration(tuh_xfer_t* xfer) { return; } - _dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : + _usbh_data.dev0_bus.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; // Acknowledge Port Reset Change if (port_status.change.reset) { - hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port, + hub_port_clear_reset_change(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, process_enumeration, ENUM_ADDR0_DEVICE_DESC); } break; @@ -1452,7 +1436,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_HUB_GET_STATUS_2: tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); - TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl, + TU_ASSERT(hub_port_get_status(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, _usbh_epbuf.ctrl, process_enumeration, ENUM_HUB_CLEAR_RESET_2),); break; @@ -1462,7 +1446,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { // Acknowledge Port Reset Change if Reset Successful if (port_status.change.reset) { - TU_ASSERT(hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port, + TU_ASSERT(hub_port_clear_reset_change(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, process_enumeration, ENUM_SET_ADDR),); } break; @@ -1495,7 +1479,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { new_dev->addressed = 1; _usbh_data.enumerating_daddr = new_addr; - hcd_device_close(_dev0.rhport, 0); // close dev0 + hcd_device_close(_usbh_data.dev0_bus.rhport, 0); // close dev0_bus TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint @@ -1667,38 +1651,38 @@ static void process_enumeration(tuh_xfer_t* xfer) { } static bool enum_new_device(hcd_event_t* event) { - _dev0.rhport = event->rhport; - _dev0.hub_addr = event->connection.hub_addr; - _dev0.hub_port = event->connection.hub_port; + _usbh_data.dev0_bus.rhport = event->rhport; + _usbh_data.dev0_bus.hub_addr = event->connection.hub_addr; + _usbh_data.dev0_bus.hub_port = event->connection.hub_port; - if (_dev0.hub_addr == 0) { + if (_usbh_data.dev0_bus.hub_addr == 0) { // connected directly to roothub // wait until device connection is stable TODO non blocking tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); // device unplugged while delaying - if (!hcd_port_connect_status(_dev0.rhport)) { + if (!hcd_port_connect_status(_usbh_data.dev0_bus.rhport)) { enum_full_complete(); return true; } - hcd_port_reset(_dev0.rhport); // reset device + hcd_port_reset(_usbh_data.dev0_bus.rhport); // reset device // Since we are in middle of rhport reset, frame number is not available yet. // need to depend on tusb_time_millis_api() tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); - hcd_port_reset_end(_dev0.rhport); + hcd_port_reset_end(_usbh_data.dev0_bus.rhport); // device unplugged while delaying - if (!hcd_port_connect_status(_dev0.rhport)) { + if (!hcd_port_connect_status(_usbh_data.dev0_bus.rhport)) { enum_full_complete(); return true; } - _dev0.speed = hcd_port_speed_get(_dev0.rhport); - TU_LOG_USBH("%s Speed\r\n", tu_str_speed[_dev0.speed]); + _usbh_data.dev0_bus.speed = hcd_port_speed_get(_usbh_data.dev0_bus.rhport); + TU_LOG_USBH("%s Speed\r\n", tu_str_speed[_usbh_data.dev0.speed]); // fake transfer to kick-off the enumeration process tuh_xfer_t xfer; @@ -1715,7 +1699,7 @@ static bool enum_new_device(hcd_event_t* event) { tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); // ENUM_HUB_GET_STATUS - TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl, + TU_ASSERT(hub_port_get_status(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, _usbh_epbuf.ctrl, process_enumeration, ENUM_HUB_CLEAR_RESET_1)); } #endif // hub @@ -1749,10 +1733,7 @@ static bool enum_request_set_addr(tusb_desc_device_t const* desc_device) { TU_LOG_USBH("Set Address = %d\r\n", new_addr); usbh_device_t* new_dev = get_device(new_addr); - new_dev->rhport = _dev0.rhport; - new_dev->hub_addr = _dev0.hub_addr; - new_dev->hub_port = _dev0.hub_port; - new_dev->speed = _dev0.speed; + new_dev->bus_info = _usbh_data.dev0_bus; new_dev->connected = 1; new_dev->ep0_size = desc_device->bMaxPacketSize0; @@ -1768,7 +1749,7 @@ static bool enum_request_set_addr(tusb_desc_device_t const* desc_device) { .wLength = 0 }; tuh_xfer_t xfer = { - .daddr = 0, // dev0 + .daddr = 0, .ep_addr = 0, .setup = &request, .buffer = NULL, @@ -1841,7 +1822,7 @@ static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configurat // Find driver for this interface for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) { usbh_class_driver_t const * driver = get_driver(drv_id); - if (driver && driver->open(dev->rhport, dev_addr, desc_itf, drv_len) ) { + if (driver && driver->open(dev->bus_info.rhport, dev_addr, desc_itf, drv_len) ) { // open successfully TU_LOG_USBH(" %s opened\r\n", driver->name); @@ -1860,9 +1841,9 @@ static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configurat break; // exit driver find loop } - if ( drv_id == TOTAL_DRIVER_COUNT - 1 ) { + if (drv_id == TOTAL_DRIVER_COUNT - 1) { TU_LOG_USBH("[%u:%u] Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n", - dev->rhport, dev_addr, desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol); + dev->bus_info.rhport, dev_addr, desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol); } } @@ -1909,8 +1890,8 @@ static void enum_full_complete(void) { _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; #if CFG_TUH_HUB - if (_dev0.hub_addr) { - hub_edpt_status_xfer(_dev0.hub_addr); // get next hub status + if (_usbh_data.dev0_bus.hub_addr != 0) { + hub_edpt_status_xfer(_usbh_data.dev0_bus.hub_addr); // get next hub status } #endif diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h index bfa1fb2ba..61b012493 100644 --- a/src/host/usbh_pvt.h +++ b/src/host/usbh_pvt.h @@ -63,7 +63,7 @@ usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count) TU_ATTR // Call by class driver to tell USBH that it has complete the enumeration void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num); -uint8_t usbh_get_rhport(uint8_t dev_addr); +uint8_t usbh_get_rhport(uint8_t daddr); uint8_t* usbh_get_enum_buf(void); diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c index 7451f69a3..141a2c026 100644 --- a/src/portable/ehci/ehci.c +++ b/src/portable/ehci/ehci.c @@ -837,8 +837,8 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c tu_memclr(p_qhd, sizeof(ehci_qhd_t)); } - hcd_devtree_info_t devtree_info; - hcd_devtree_get_info(dev_addr, &devtree_info); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); uint8_t const xfer_type = ep_desc->bmAttributes.xfer; uint8_t const interval = ep_desc->bInterval; @@ -846,7 +846,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c p_qhd->dev_addr = dev_addr; p_qhd->fl_inactive_next_xact = 0; p_qhd->ep_number = tu_edpt_number(ep_desc->bEndpointAddress); - p_qhd->ep_speed = devtree_info.speed; + p_qhd->ep_speed = bus_info.speed; p_qhd->data_toggle_control= (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0; p_qhd->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static async list head p_qhd->max_packet_size = tu_edpt_packet_size(ep_desc); @@ -887,8 +887,8 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c default: break; } - p_qhd->fl_hub_addr = devtree_info.hub_addr; - p_qhd->fl_hub_port = devtree_info.hub_port; + p_qhd->fl_hub_addr = bus_info.hub_addr; + p_qhd->fl_hub_port = bus_info.hub_port; p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet //------------- HCD Management Data -------------// diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c index 811043d74..97ef46152 100644 --- a/src/portable/mentor/musb/hcd_musb.c +++ b/src/portable/mentor/musb/hcd_musb.c @@ -695,16 +695,16 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet _hcd.pipe0.length = 8; _hcd.pipe0.remaining = 0; - hcd_devtree_info_t devtree; - hcd_devtree_get_info(dev_addr, &devtree); - switch (devtree.speed) { + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); + switch (bus_info.speed) { default: return false; case TUSB_SPEED_LOW: USB0->TYPE0 = USB_TYPE0_SPEED_LOW; break; case TUSB_SPEED_FULL: USB0->TYPE0 = USB_TYPE0_SPEED_FULL; break; case TUSB_SPEED_HIGH: USB0->TYPE0 = USB_TYPE0_SPEED_HIGH; break; } - USB0->TXHUBADDR0 = devtree.hub_addr; - USB0->TXHUBPORT0 = devtree.hub_port; + USB0->TXHUBADDR0 = bus_info.hub_addr; + USB0->TXHUBPORT0 = bus_info.hub_port; USB0->TXFUNCADDR0 = dev_addr; USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_SETUP; return true; @@ -744,9 +744,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const pipe->remaining = 0; uint8_t pipe_type = 0; - hcd_devtree_info_t devtree; - hcd_devtree_get_info(dev_addr, &devtree); - switch (devtree.speed) { + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); + switch (bus_info.speed) { default: return false; case TUSB_SPEED_LOW: pipe_type |= USB_TXTYPE1_SPEED_LOW; break; case TUSB_SPEED_FULL: pipe_type |= USB_TXTYPE1_SPEED_FULL; break; @@ -763,8 +763,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1); if (dir_tx) { fadr->TXFUNCADDR = dev_addr; - fadr->TXHUBADDR = devtree.hub_addr; - fadr->TXHUBPORT = devtree.hub_port; + fadr->TXHUBADDR = bus_info.hub_addr; + fadr->TXHUBPORT = bus_info.hub_port; regs->TXMAXP = mps; regs->TXTYPE = pipe_type | epn; regs->TXINTERVAL = ep_desc->bInterval; @@ -775,8 +775,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const USB0->TXIE |= TU_BIT(pipenum); } else { fadr->RXFUNCADDR = dev_addr; - fadr->RXHUBADDR = devtree.hub_addr; - fadr->RXHUBPORT = devtree.hub_port; + fadr->RXHUBADDR = bus_info.hub_addr; + fadr->RXHUBPORT = bus_info.hub_port; regs->RXMAXP = mps; regs->RXTYPE = pipe_type | epn; regs->RXINTERVAL = ep_desc->bInterval; diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 672ad0443..465b6731c 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -328,13 +328,13 @@ static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t tu_memclr(p_ed, sizeof(ohci_ed_t)); } - hcd_devtree_info_t devtree_info; - hcd_devtree_get_info(dev_addr, &devtree_info); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); p_ed->dev_addr = dev_addr; p_ed->ep_number = ep_addr & 0x0F; p_ed->pid = (xfer_type == TUSB_XFER_CONTROL) ? PID_FROM_TD : (tu_edpt_dir(ep_addr) ? PID_IN : PID_OUT); - p_ed->speed = devtree_info.speed; + p_ed->speed = bus_info.speed; p_ed->is_iso = (xfer_type == TUSB_XFER_ISOCHRONOUS) ? 1 : 0; p_ed->max_packet_size = ep_size; diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c index 225a44dcf..0e3d0d31a 100644 --- a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c @@ -114,9 +114,9 @@ void hcd_int_disable(uint8_t rhport) { //--------------------------------------------------------------------+ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *desc_ep) { - hcd_devtree_info_t dev_tree; - hcd_devtree_get_info(dev_addr, &dev_tree); - bool const need_pre = (dev_tree.hub_addr && dev_tree.speed == TUSB_SPEED_LOW); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); + bool const need_pre = (bus_info.hub_addr && bus_info.speed == TUSB_SPEED_LOW); uint8_t const pio_rhport = RHPORT_PIO(rhport); return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const *) desc_ep, need_pre); diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c index 3e4b36981..e6975287d 100644 --- a/src/portable/renesas/rusb2/hcd_rusb2.c +++ b/src/portable/renesas/rusb2/hcd_rusb2.c @@ -662,13 +662,13 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const if (0 == epn) { rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK; - hcd_devtree_info_t devtree; - hcd_devtree_get_info(dev_addr, &devtree); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t) &rusb->DEVADD[0]; devadd += dev_addr; while (rusb->DCPCTR_b.PBUSY) {} rusb->DCPMAXP = (dev_addr << 12) | mps; - *devadd = (TUSB_SPEED_FULL == devtree.speed) ? RUSB2_DEVADD_USBSPD_FS : RUSB2_DEVADD_USBSPD_LS; + *devadd = (TUSB_SPEED_FULL == bus_info.speed) ? RUSB2_DEVADD_USBSPD_FS : RUSB2_DEVADD_USBSPD_LS; _hcd.ctl_mps[dev_addr] = mps; return true; } diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 53bc0b059..6fd343686 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -475,8 +475,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* dwc2_regs_t* dwc2 = DWC2_REG(rhport); const tusb_speed_t rh_speed = hprt_speed_get(dwc2); - hcd_devtree_info_t devtree_info; - hcd_devtree_get_info(dev_addr, &devtree_info); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); // find a free endpoint const uint8_t ep_id = edpt_alloc(); @@ -487,7 +487,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* hcchar_bm->ep_size = tu_edpt_packet_size(desc_ep); hcchar_bm->ep_num = tu_edpt_number(desc_ep->bEndpointAddress); hcchar_bm->ep_dir = tu_edpt_dir(desc_ep->bEndpointAddress); - hcchar_bm->low_speed_dev = (devtree_info.speed == TUSB_SPEED_LOW) ? 1 : 0; + hcchar_bm->low_speed_dev = (bus_info.speed == TUSB_SPEED_LOW) ? 1 : 0; hcchar_bm->ep_type = desc_ep->bmAttributes.xfer; // ep_type matches TUSB_XFER_* hcchar_bm->err_multi_count = 0; hcchar_bm->dev_addr = dev_addr; @@ -496,21 +496,21 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* hcchar_bm->enable = 1; dwc2_channel_split_t* hcsplt_bm = &edpt->hcsplt_bm; - hcsplt_bm->hub_port = devtree_info.hub_port; - hcsplt_bm->hub_addr = devtree_info.hub_addr; + hcsplt_bm->hub_port = bus_info.hub_port; + hcsplt_bm->hub_addr = bus_info.hub_addr; hcsplt_bm->xact_pos = 0; hcsplt_bm->split_compl = 0; - hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && devtree_info.speed != TUSB_SPEED_HIGH) ? 1 : 0; + hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && bus_info.speed != TUSB_SPEED_HIGH) ? 1 : 0; - edpt->speed = devtree_info.speed; + edpt->speed = bus_info.speed; edpt->next_pid = HCTSIZ_PID_DATA0; if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { edpt->uframe_interval = 1 << (desc_ep->bInterval - 1); - if (devtree_info.speed == TUSB_SPEED_FULL) { + if (bus_info.speed == TUSB_SPEED_FULL) { edpt->uframe_interval <<= 3; } } else if (desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) { - if (devtree_info.speed == TUSB_SPEED_HIGH) { + if (bus_info.speed == TUSB_SPEED_HIGH) { edpt->uframe_interval = 1 << (desc_ep->bInterval - 1); } else { edpt->uframe_interval = desc_ep->bInterval << 3; From a2da575793a14fdfc5137a02843af0fd8f8b772a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 23 Apr 2025 16:03:40 +0700 Subject: [PATCH 46/68] rename and expose tuh_bus_info_get() to application --- src/host/hcd.h | 10 ---------- src/host/usbh.c | 10 +++++----- src/host/usbh.h | 14 +++++++++++++- src/portable/chipidea/ci_hs/hcd_ci_hs.c | 1 + src/portable/ehci/ehci.c | 3 ++- src/portable/mentor/musb/hcd_musb.c | 5 +++-- src/portable/nxp/khci/hcd_khci.c | 1 + src/portable/nxp/lpc17_40/hcd_lpc17_40.c | 1 + src/portable/ohci/ohci.c | 3 ++- src/portable/raspberrypi/pio_usb/hcd_pio_usb.c | 2 +- src/portable/renesas/rusb2/hcd_rusb2.c | 3 ++- src/portable/synopsys/dwc2/dwc2_common.c | 1 + src/portable/synopsys/dwc2/hcd_dwc2.c | 3 ++- src/portable/template/hcd_template.c | 1 + 14 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/host/hcd.h b/src/host/hcd.h index 1f2704a10..d3551bf5b 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -90,13 +90,6 @@ typedef struct { }; } hcd_event_t; -typedef struct { - uint8_t rhport; - uint8_t hub_addr; - uint8_t hub_port; - uint8_t speed; -} tuh_bus_info_t; - //--------------------------------------------------------------------+ // Memory API //--------------------------------------------------------------------+ @@ -186,9 +179,6 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr); // USBH implemented API //--------------------------------------------------------------------+ -// Get device port information -extern bool hcd_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info); - // Called by HCD to notify stack extern void hcd_event_handler(hcd_event_t const* event, bool in_isr); diff --git a/src/host/usbh.c b/src/host/usbh.c index c063c97f9..0a208816c 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -28,9 +28,9 @@ #if CFG_TUH_ENABLED -#include "host/hcd.h" +#include "hcd.h" #include "tusb.h" -#include "host/usbh_pvt.h" +#include "usbh_pvt.h" #include "hub.h" //--------------------------------------------------------------------+ @@ -342,7 +342,7 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) { tusb_speed_t tuh_speed_get(uint8_t daddr) { tuh_bus_info_t bus_info; - hcd_bus_info_get(daddr, &bus_info); + tuh_bus_info_get(daddr, &bus_info); return bus_info.speed; } @@ -875,7 +875,7 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { uint8_t usbh_get_rhport(uint8_t daddr) { tuh_bus_info_t bus_info; - hcd_bus_info_get(daddr, &bus_info); + tuh_bus_info_get(daddr, &bus_info); return bus_info.rhport; } @@ -1013,7 +1013,7 @@ bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) { // HCD Event Handler //--------------------------------------------------------------------+ -bool hcd_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info) { +bool tuh_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info) { usbh_device_t const* dev = get_device(daddr); if (dev) { *bus_info = dev->bus_info; diff --git a/src/host/usbh.h b/src/host/usbh.h index 4829a8183..063b20539 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -47,7 +47,6 @@ // forward declaration struct tuh_xfer_s; typedef struct tuh_xfer_s tuh_xfer_t; - typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer); // Note1: layout and order of this will be changed in near future @@ -80,6 +79,14 @@ typedef struct { tusb_desc_interface_t desc; } tuh_itf_info_t; +typedef struct { + uint8_t rhport; + uint8_t hub_addr; + uint8_t hub_port; + uint8_t speed; +} tuh_bus_info_t; + + // ConfigID for tuh_configure() enum { TUH_CFGID_INVALID = 0, @@ -177,6 +184,8 @@ extern void hcd_int_handler(uint8_t rhport, bool in_isr); #define _tuh_int_handler_arg0() TU_VERIFY_STATIC(false, "tuh_int_handler() must have 1 or 2 arguments") #define _tuh_int_handler_arg1(_rhport) hcd_int_handler(_rhport, true) #define _tuh_int_handler_arg2(_rhport, _in_isr) hcd_int_handler(_rhport, _in_isr) + +// 1st argument is rhport (mandatory), 2nd argument in_isr (optional) #define tuh_int_handler(...) TU_FUNC_OPTIONAL_ARG(_tuh_int_handler, __VA_ARGS__) // Check if roothub port is initialized and active as a host @@ -214,6 +223,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_ready(uint8_t daddr) { return tuh_mounted(daddr) && !tuh_suspended(daddr); } +// Get bus information of device +bool tuh_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info); + //--------------------------------------------------------------------+ // Transfer API //--------------------------------------------------------------------+ diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c index c4c342a70..22eb22690 100644 --- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c @@ -35,6 +35,7 @@ //--------------------------------------------------------------------+ #include "common/tusb_common.h" #include "host/hcd.h" +#include "host/usbh.h" #include "portable/ehci/ehci_api.h" #include "ci_hs_type.h" diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c index 141a2c026..da9f49d29 100644 --- a/src/portable/ehci/ehci.c +++ b/src/portable/ehci/ehci.c @@ -34,6 +34,7 @@ #include "osal/osal.h" #include "host/hcd.h" +#include "host/usbh.h" #include "ehci_api.h" #include "ehci.h" @@ -838,7 +839,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c } tuh_bus_info_t bus_info; - hcd_bus_info_get(dev_addr, &bus_info); + tuh_bus_info_get(dev_addr, &bus_info); uint8_t const xfer_type = ep_desc->bmAttributes.xfer; uint8_t const interval = ep_desc->bInterval; diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c index 97ef46152..dcc023e0b 100644 --- a/src/portable/mentor/musb/hcd_musb.c +++ b/src/portable/mentor/musb/hcd_musb.c @@ -36,6 +36,7 @@ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\""); #endif #include "host/hcd.h" +#include "host/usbh.h" #include "musb_type.h" @@ -696,7 +697,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet _hcd.pipe0.remaining = 0; tuh_bus_info_t bus_info; - hcd_bus_info_get(dev_addr, &bus_info); + tuh_bus_info_get(dev_addr, &bus_info); switch (bus_info.speed) { default: return false; case TUSB_SPEED_LOW: USB0->TYPE0 = USB_TYPE0_SPEED_LOW; break; @@ -745,7 +746,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const uint8_t pipe_type = 0; tuh_bus_info_t bus_info; - hcd_bus_info_get(dev_addr, &bus_info); + tuh_bus_info_get(dev_addr, &bus_info); switch (bus_info.speed) { default: return false; case TUSB_SPEED_LOW: pipe_type |= USB_TXTYPE1_SPEED_LOW; break; diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/nxp/khci/hcd_khci.c index c3c901c5d..45732a866 100644 --- a/src/portable/nxp/khci/hcd_khci.c +++ b/src/portable/nxp/khci/hcd_khci.c @@ -36,6 +36,7 @@ #endif #include "host/hcd.h" +#include "host/usbh.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION diff --git a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c index 090d1ba69..fea3e2a66 100644 --- a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c @@ -31,6 +31,7 @@ #include "chip.h" #include "host/hcd.h" +#include "host/usbh.h" void hcd_int_enable(uint8_t rhport) { diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 465b6731c..81091c9a7 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -38,6 +38,7 @@ #include "osal/osal.h" #include "host/hcd.h" +#include "host/usbh.h" #include "ohci.h" // TODO remove @@ -329,7 +330,7 @@ static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t } tuh_bus_info_t bus_info; - hcd_bus_info_get(dev_addr, &bus_info); + tuh_bus_info_get(dev_addr, &bus_info); p_ed->dev_addr = dev_addr; p_ed->ep_number = ep_addr & 0x0F; diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c index 0e3d0d31a..d59a2b4ee 100644 --- a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c @@ -115,7 +115,7 @@ void hcd_int_disable(uint8_t rhport) { bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *desc_ep) { tuh_bus_info_t bus_info; - hcd_bus_info_get(dev_addr, &bus_info); + tuh_bus_info_get(dev_addr, &bus_info); bool const need_pre = (bus_info.hub_addr && bus_info.speed == TUSB_SPEED_LOW); uint8_t const pio_rhport = RHPORT_PIO(rhport); diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c index e6975287d..6f6d27d0e 100644 --- a/src/portable/renesas/rusb2/hcd_rusb2.c +++ b/src/portable/renesas/rusb2/hcd_rusb2.c @@ -30,6 +30,7 @@ #if CFG_TUH_ENABLED && defined(TUP_USBIP_RUSB2) #include "host/hcd.h" +#include "host/usbh.h" #include "rusb2_type.h" #if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) @@ -663,7 +664,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const if (0 == epn) { rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK; tuh_bus_info_t bus_info; - hcd_bus_info_get(dev_addr, &bus_info); + tuh_bus_info_get(dev_addr, &bus_info); uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t) &rusb->DEVADD[0]; devadd += dev_addr; while (rusb->DCPCTR_b.PBUSY) {} diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c index f6ed8fc98..e1e7d5c1a 100644 --- a/src/portable/synopsys/dwc2/dwc2_common.c +++ b/src/portable/synopsys/dwc2/dwc2_common.c @@ -36,6 +36,7 @@ #if CFG_TUH_ENABLED #include "host/hcd.h" +#include "host/usbh.h" #endif #include "dwc2_common.h" diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 6fd343686..7c29a03cf 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -36,6 +36,7 @@ #define DWC2_DEBUG 2 #include "host/hcd.h" +#include "host/usbh.h" #include "dwc2_common.h" // Max number of endpoints application can open, can be larger than DWC2_CHANNEL_COUNT_MAX @@ -476,7 +477,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* const tusb_speed_t rh_speed = hprt_speed_get(dwc2); tuh_bus_info_t bus_info; - hcd_bus_info_get(dev_addr, &bus_info); + tuh_bus_info_get(dev_addr, &bus_info); // find a free endpoint const uint8_t ep_id = edpt_alloc(); diff --git a/src/portable/template/hcd_template.c b/src/portable/template/hcd_template.c index 22ea22e63..d2f304407 100644 --- a/src/portable/template/hcd_template.c +++ b/src/portable/template/hcd_template.c @@ -29,6 +29,7 @@ #if CFG_TUH_ENABLED && CFG_TUSB_MCU == OPT_MCU_NONE #include "host/hcd.h" +#include "host/usbh.h" //--------------------------------------------------------------------+ // Controller API From 9a1f690ec44dc7cc3e0dbb35e1db8ba89cd3de88 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 23 Apr 2025 16:50:58 +0700 Subject: [PATCH 47/68] move usbh ctrl_xfer into usbh_data --- src/host/usbh.c | 169 ++++++++++++++++++++++++------------------------ 1 file changed, 85 insertions(+), 84 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 0a208816c..9cf07213b 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -263,7 +263,7 @@ static osal_queue_t _usbh_q; // Control transfers: since most controllers do not support multiple control transfers // on multiple devices concurrently and control transfers are not used much except for // enumeration, we will only execute control transfers one at a time. -static struct { +typedef struct { uint8_t* buffer; tuh_xfer_cb_t complete_cb; uintptr_t user_data; @@ -272,26 +272,25 @@ static struct { uint8_t daddr; volatile uint16_t actual_len; uint8_t failed_count; -} _ctrl_xfer; +} usbh_ctrl_xfer_info_t; typedef struct { - TUH_EPBUF_TYPE_DEF(tusb_control_request_t, request); - TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE); -} usbh_epbuf_t; - -CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf; - -typedef struct { - uint8_t controller_id; // controller ID - uint8_t enumerating_daddr; // device address of the device being enumerated - - tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration + uint8_t controller_id; // controller ID + uint8_t enumerating_daddr; // device address of the device being enumerated + tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration + usbh_ctrl_xfer_info_t ctrl_xfer_info; // control transfer } usbh_data_t; static usbh_data_t _usbh_data = { .controller_id = TUSB_INDEX_INVALID_8, }; +typedef struct { + TUH_EPBUF_TYPE_DEF(tusb_control_request_t, request); + TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE); +} usbh_epbuf_t; +CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf; + //------------- Helper Function -------------// TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) { TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL); @@ -299,7 +298,7 @@ TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) } static bool enum_new_device(hcd_event_t* event); -static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port); +static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port); static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size); static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); @@ -388,9 +387,9 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Init host stack if not already if (!tuh_inited()) { + TU_LOG_INT_USBH(sizeof(usbh_data_t)); TU_LOG_INT_USBH(sizeof(usbh_device_t)); TU_LOG_INT_USBH(sizeof(hcd_event_t)); - TU_LOG_INT_USBH(sizeof(_ctrl_xfer)); TU_LOG_INT_USBH(sizeof(tuh_xfer_t)); TU_LOG_INT_USBH(sizeof(tu_fifo_t)); TU_LOG_INT_USBH(sizeof(tu_edpt_stream_t)); @@ -412,7 +411,6 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Device tu_memclr(_usbh_devices, sizeof(_usbh_devices)); - tu_memclr(&_ctrl_xfer, sizeof(_ctrl_xfer)); tu_memclr(&_usbh_data, sizeof(_usbh_data)); _usbh_data.controller_id = TUSB_INDEX_INVALID_8; @@ -451,7 +449,7 @@ bool tuh_deinit(uint8_t rhport) { _usbh_data.controller_id = TUSB_INDEX_INVALID_8; // "unplug" all devices on this rhport (hub_addr = 0, hub_port = 0) - process_removing_device(rhport, 0, 0); + process_removed_device(rhport, 0, 0); // deinit host stack if no controller is active if (!tuh_inited()) { @@ -545,7 +543,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { case HCD_EVENT_DEVICE_REMOVE: TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); - process_removing_device(event.rhport, event.connection.hub_addr, event.connection.hub_port); + process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port); #if CFG_TUH_HUB // TODO remove @@ -638,9 +636,9 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) { } TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) { - if (_ctrl_xfer.stage != stage) { + if (_usbh_data.ctrl_xfer_info.stage != stage) { (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); - _ctrl_xfer.stage = stage; + _usbh_data.ctrl_xfer_info.stage = stage; (void) osal_mutex_unlock(_usbh_mutex); } } @@ -660,23 +658,22 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { const uint8_t daddr = xfer->daddr; TU_VERIFY(tuh_connected(daddr)); - // pre-check to help reducing mutex lock - TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE); + usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info; + + TU_VERIFY(ctrl_info->stage == CONTROL_STAGE_IDLE); // pre-check to help reducing mutex lock (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); - - bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE); + bool const is_idle = (ctrl_info->stage == CONTROL_STAGE_IDLE); if (is_idle) { - _ctrl_xfer.stage = CONTROL_STAGE_SETUP; - _ctrl_xfer.daddr = daddr; - _ctrl_xfer.actual_len = 0; - _ctrl_xfer.failed_count = 0; + ctrl_info->stage = CONTROL_STAGE_SETUP; + ctrl_info->daddr = daddr; + ctrl_info->actual_len = 0; + ctrl_info->failed_count = 0; - _ctrl_xfer.buffer = xfer->buffer; - _ctrl_xfer.complete_cb = xfer->complete_cb; - _ctrl_xfer.user_data = xfer->user_data; + ctrl_info->buffer = xfer->buffer; + ctrl_info->complete_cb = xfer->complete_cb; + ctrl_info->user_data = xfer->user_data; _usbh_epbuf.request = (*xfer->setup); } - (void) osal_mutex_unlock(_usbh_mutex); TU_VERIFY(is_idle); @@ -693,8 +690,8 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { volatile xfer_result_t result = XFER_RESULT_INVALID; // use user_data to point to xfer_result_t - _ctrl_xfer.user_data = (uintptr_t) &result; - _ctrl_xfer.complete_cb = _control_blocking_complete_cb; + ctrl_info->user_data = (uintptr_t) &result; + ctrl_info->complete_cb = _control_blocking_complete_cb; TU_ASSERT(usbh_setup_send(daddr, (uint8_t const *) &_usbh_epbuf.request)); @@ -712,7 +709,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { *((xfer_result_t*) xfer->user_data) = result; } xfer->result = result; - xfer->actual_len = _ctrl_xfer.actual_len; + xfer->actual_len = ctrl_info->actual_len; } return true; @@ -720,6 +717,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { static void _control_xfer_complete(uint8_t daddr, xfer_result_t result) { TU_LOG_USBH("\r\n"); + usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info; // duplicate xfer since user can execute control transfer within callback tusb_control_request_t const request = _usbh_epbuf.request; @@ -728,10 +726,10 @@ static void _control_xfer_complete(uint8_t daddr, xfer_result_t result) { .ep_addr = 0, .result = result, .setup = &request, - .actual_len = (uint32_t) _ctrl_xfer.actual_len, - .buffer = _ctrl_xfer.buffer, - .complete_cb = _ctrl_xfer.complete_cb, - .user_data = _ctrl_xfer.user_data + .actual_len = (uint32_t) ctrl_info->actual_len, + .buffer = ctrl_info->buffer, + .complete_cb = ctrl_info->complete_cb, + .user_data = ctrl_info->user_data }; _control_set_xfer_stage(CONTROL_STAGE_IDLE); @@ -746,6 +744,7 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t const uint8_t rhport = usbh_get_rhport(daddr); tusb_control_request_t const * request = &_usbh_epbuf.request; + usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info; switch (result) { case XFER_RESULT_STALLED: @@ -755,12 +754,12 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t break; case XFER_RESULT_FAILED: - if (tuh_connected(daddr) && _ctrl_xfer.failed_count < USBH_CONTROL_RETRY_MAX) { - TU_LOG_USBH("[%u:%u] Control FAILED %u/%u, retrying\r\n", rhport, daddr, _ctrl_xfer.failed_count+1, USBH_CONTROL_RETRY_MAX); + if (tuh_connected(daddr) && ctrl_info->failed_count < USBH_CONTROL_RETRY_MAX) { + TU_LOG_USBH("[%u:%u] Control FAILED %u/%u, retrying\r\n", rhport, daddr, ctrl_info->failed_count+1, USBH_CONTROL_RETRY_MAX); (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); - _ctrl_xfer.stage = CONTROL_STAGE_SETUP; - _ctrl_xfer.failed_count++; - _ctrl_xfer.actual_len = 0; // reset actual_len + ctrl_info->stage = CONTROL_STAGE_SETUP; + ctrl_info->failed_count++; + ctrl_info->actual_len = 0; // reset actual_len (void) osal_mutex_unlock(_usbh_mutex); TU_ASSERT(usbh_setup_send(daddr, (uint8_t const *) request)); @@ -772,28 +771,29 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t break; case XFER_RESULT_SUCCESS: - switch(_ctrl_xfer.stage) { + switch(ctrl_info->stage) { case CONTROL_STAGE_SETUP: if (request->wLength) { // DATA stage: initial data toggle is always 1 _control_set_xfer_stage(CONTROL_STAGE_DATA); - TU_ASSERT(hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength)); + const uint8_t ep_data = tu_edpt_addr(0, request->bmRequestType_bit.direction); + TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_data, ctrl_info->buffer, request->wLength)); return true; } - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; case CONTROL_STAGE_DATA: if (request->wLength) { TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, daddr); - TU_LOG_MEM_USBH(_ctrl_xfer.buffer, xferred_bytes, 2); + TU_LOG_MEM_USBH(ctrl_info->buffer, xferred_bytes, 2); } + ctrl_info->actual_len = (uint16_t) xferred_bytes; - _ctrl_xfer.actual_len = (uint16_t) xferred_bytes; - - // ACK stage: toggle is always 1 - _control_set_xfer_stage(CONTROL_STAGE_ACK); - TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction), NULL, 0) ); - break; + // ACK stage: toggle is always 1 + _control_set_xfer_stage(CONTROL_STAGE_ACK); + const uint8_t ep_status = tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction); + TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_status, NULL, 0)); + break; case CONTROL_STAGE_ACK: { // Abort all pending transfers if SET_CONFIGURATION request @@ -842,16 +842,16 @@ bool tuh_edpt_xfer(tuh_xfer_t* xfer) { bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { TU_LOG_USBH("[%u] Aborted transfer on EP %02X\r\n", daddr, ep_addr); - const uint8_t epnum = tu_edpt_number(ep_addr); const uint8_t dir = tu_edpt_dir(ep_addr); if (epnum == 0) { - // Also include dev0_bus for aborting enumerating + // Also include dev0 for aborting enumerating const uint8_t rhport = usbh_get_rhport(daddr); // control transfer: only 1 control at a time, check if we are aborting the current one - TU_VERIFY(daddr == _ctrl_xfer.daddr && _ctrl_xfer.stage != CONTROL_STAGE_IDLE); + const usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info; + TU_VERIFY(daddr == ctrl_info->daddr && ctrl_info->stage != CONTROL_STAGE_IDLE); hcd_edpt_abort_xfer(rhport, daddr, ep_addr); _control_set_xfer_stage(CONTROL_STAGE_IDLE); // reset control transfer state to idle } else { @@ -859,9 +859,8 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { TU_VERIFY(dev); TU_VERIFY(dev->ep_status[epnum][dir].busy); // non-control skip if not busy + // abort then mark as ready and release endpoint hcd_edpt_abort_xfer(dev->bus_info.rhport, daddr, ep_addr); - - // mark as ready and release endpoint if transfer is aborted dev->ep_status[epnum][dir].busy = false; tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex); } @@ -1252,16 +1251,18 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) { } // a device unplugged from rhport:hub_addr:hub_port -static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { - // dev0_bus is unplugged - if ((_usbh_data.enumerating_daddr == 0) && (rhport == _usbh_data.dev0_bus.rhport) && - (hub_addr == _usbh_data.dev0_bus.hub_addr) && (hub_port == _usbh_data.dev0_bus.hub_port)) { - hcd_device_close(_usbh_data.dev0_bus.rhport, 0); - if (_ctrl_xfer.daddr == 0) { - _control_set_xfer_stage(CONTROL_STAGE_IDLE); +static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { + // if dev0 is unplugged while enumerating (not yet assigned an address) + if (_usbh_data.enumerating_daddr == 0) { + const tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus; + if ((rhport == dev0_bus->rhport) && (hub_addr == dev0_bus->hub_addr) && (hub_port == dev0_bus->hub_port)) { + hcd_device_close(dev0_bus->rhport, 0); + if (_usbh_data.ctrl_xfer_info.daddr == 0) { + _control_set_xfer_stage(CONTROL_STAGE_IDLE); + } + _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; + return; } - _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; - return; } //------------- find the all devices (star-network) under port that is unplugged -------------// @@ -1298,8 +1299,8 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu hcd_device_close(rhport, daddr); clear_device(dev); - // abort on-going control xfer on this device if any - if (daddr == _ctrl_xfer.daddr) { + // abort ongoing control xfer on this device if any + if (daddr == _usbh_data.ctrl_xfer_info.daddr) { _control_set_xfer_stage(CONTROL_STAGE_IDLE); } @@ -1651,45 +1652,45 @@ static void process_enumeration(tuh_xfer_t* xfer) { } static bool enum_new_device(hcd_event_t* event) { - _usbh_data.dev0_bus.rhport = event->rhport; - _usbh_data.dev0_bus.hub_addr = event->connection.hub_addr; - _usbh_data.dev0_bus.hub_port = event->connection.hub_port; + tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus; + dev0_bus->rhport = event->rhport; + dev0_bus->hub_addr = event->connection.hub_addr; + dev0_bus->hub_port = event->connection.hub_port; - if (_usbh_data.dev0_bus.hub_addr == 0) { + if (dev0_bus->hub_addr == 0) { // connected directly to roothub // wait until device connection is stable TODO non blocking tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); - // device unplugged while delaying - if (!hcd_port_connect_status(_usbh_data.dev0_bus.rhport)) { + if (!hcd_port_connect_status(dev0_bus->rhport)) { + TU_LOG_USBH("Device unplugged while debouncing\r\n"); enum_full_complete(); return true; } - hcd_port_reset(_usbh_data.dev0_bus.rhport); // reset device + hcd_port_reset(dev0_bus->rhport); // reset device // Since we are in middle of rhport reset, frame number is not available yet. - // need to depend on tusb_time_millis_api() + // need to depend on tusb_time_millis_api() TODO non blocking tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); - hcd_port_reset_end(_usbh_data.dev0_bus.rhport); + hcd_port_reset_end(dev0_bus->rhport); // device unplugged while delaying - if (!hcd_port_connect_status(_usbh_data.dev0_bus.rhport)) { + if (!hcd_port_connect_status(dev0_bus->rhport)) { enum_full_complete(); return true; } - _usbh_data.dev0_bus.speed = hcd_port_speed_get(_usbh_data.dev0_bus.rhport); - TU_LOG_USBH("%s Speed\r\n", tu_str_speed[_usbh_data.dev0.speed]); + dev0_bus->speed = hcd_port_speed_get(dev0_bus->rhport); + TU_LOG_USBH("%s Speed\r\n", tu_str_speed[dev0_bus->speed]); // fake transfer to kick-off the enumeration process tuh_xfer_t xfer; xfer.daddr = 0; xfer.result = XFER_RESULT_SUCCESS; xfer.user_data = ENUM_ADDR0_DEVICE_DESC; - process_enumeration(&xfer); } #if CFG_TUH_HUB @@ -1699,7 +1700,7 @@ static bool enum_new_device(hcd_event_t* event) { tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); // ENUM_HUB_GET_STATUS - TU_ASSERT(hub_port_get_status(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, _usbh_epbuf.ctrl, + TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, _usbh_epbuf.ctrl, process_enumeration, ENUM_HUB_CLEAR_RESET_1)); } #endif // hub From 736b1d50bc4082e27b3dce0fcb95a90e202cd4d3 Mon Sep 17 00:00:00 2001 From: fenugrec Date: Wed, 23 Apr 2025 16:01:24 -0400 Subject: [PATCH 48/68] examples cmake: fix gcc flag -mcpu=cortex-m0 --- examples/build_system/cmake/cpu/cortex-m0.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/build_system/cmake/cpu/cortex-m0.cmake b/examples/build_system/cmake/cpu/cortex-m0.cmake index 62019d90d..f837c7eb8 100644 --- a/examples/build_system/cmake/cpu/cortex-m0.cmake +++ b/examples/build_system/cmake/cpu/cortex-m0.cmake @@ -1,7 +1,7 @@ if (TOOLCHAIN STREQUAL "gcc") set(TOOLCHAIN_COMMON_FLAGS -mthumb - -mcpu=cortex-m0plus + -mcpu=cortex-m0 -mfloat-abi=soft ) set(FREERTOS_PORT GCC_ARM_CM0 CACHE INTERNAL "") From 89f8d0cffbe259baed3163a22a42390c21ba1f53 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 24 Apr 2025 10:41:00 +0700 Subject: [PATCH 49/68] add tuh_address_set() API minor rename and move code around --- src/host/usbh.c | 160 ++++++++++++++++++++++++------------------------ src/host/usbh.h | 4 ++ 2 files changed, 83 insertions(+), 81 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 9cf07213b..f4a6e1697 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -105,13 +105,11 @@ typedef struct { // Device Descriptor uint8_t ep0_size; - - uint16_t vid; - uint16_t pid; - - uint8_t i_manufacturer; - uint8_t i_product; - uint8_t i_serial; + uint16_t idVendor; + uint16_t idProduct; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; uint8_t bNumConfigurations; // Configuration Descriptor @@ -331,10 +329,10 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) { *vid = *pid = 0; usbh_device_t const *dev = get_device(dev_addr); - TU_VERIFY(dev && dev->addressed && dev->vid != 0); + TU_VERIFY(dev && dev->addressed && dev->idVendor != 0); - *vid = dev->vid; - *pid = dev->pid; + *vid = dev->idVendor; + *pid = dev->idProduct; return true; } @@ -1094,24 +1092,24 @@ bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { usbh_device_t const* dev = get_device(daddr); - TU_VERIFY(dev && dev->i_manufacturer); - return tuh_descriptor_get_string(daddr, dev->i_manufacturer, language_id, buffer, len, complete_cb, user_data); + TU_VERIFY(dev && dev->iManufacturer); + return tuh_descriptor_get_string(daddr, dev->iManufacturer, language_id, buffer, len, complete_cb, user_data); } // Get product string descriptor bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { usbh_device_t const* dev = get_device(daddr); - TU_VERIFY(dev && dev->i_product); - return tuh_descriptor_get_string(daddr, dev->i_product, language_id, buffer, len, complete_cb, user_data); + TU_VERIFY(dev && dev->iProduct); + return tuh_descriptor_get_string(daddr, dev->iProduct, language_id, buffer, len, complete_cb, user_data); } // Get serial string descriptor bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { usbh_device_t const* dev = get_device(daddr); - TU_VERIFY(dev && dev->i_serial); - return tuh_descriptor_get_string(daddr, dev->i_serial, language_id, buffer, len, complete_cb, user_data); + TU_VERIFY(dev && dev->iSerialNumber); + return tuh_descriptor_get_string(daddr, dev->iSerialNumber, language_id, buffer, len, complete_cb, user_data); } // Get HID report descriptor @@ -1142,6 +1140,33 @@ bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_ return tuh_control_xfer(&xfer); } +bool tuh_address_set(uint8_t daddr, uint8_t new_addr, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_USBH("Set Address = %d\r\n", new_addr); + const tusb_control_request_t request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_OUT + }, + .bRequest = TUSB_REQ_SET_ADDRESS, + .wValue = tu_htole16(new_addr), + .wIndex = 0, + .wLength = 0 + }; + tuh_xfer_t xfer = { + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data + }; + + TU_ASSERT(tuh_control_xfer(&xfer)); + return true; +} + bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_USBH("Set Configuration = %d\r\n", config_num); @@ -1373,7 +1398,7 @@ enum { ENUM_CONFIG_DRIVER }; -static bool enum_request_set_addr(tusb_desc_device_t const* desc_device); +static uint8_t enum_get_new_address(bool is_hub); static bool enum_parse_configuration_desc (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg); static void enum_full_complete(void); @@ -1425,7 +1450,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { } _usbh_data.dev0_bus.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : - (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; + (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; // Acknowledge Port Reset Change if (port_status.change.reset) { @@ -1466,9 +1491,19 @@ static void process_enumeration(tuh_xfer_t* xfer) { break; } - case ENUM_SET_ADDR: - enum_request_set_addr((tusb_desc_device_t*) _usbh_epbuf.ctrl); + case ENUM_SET_ADDR: { + const tusb_desc_device_t *desc_device = (const tusb_desc_device_t *) _usbh_epbuf.ctrl; + const uint8_t new_addr = enum_get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB); + TU_ASSERT(new_addr != 0,); + + usbh_device_t* new_dev = get_device(new_addr); + new_dev->bus_info = _usbh_data.dev0_bus; + new_dev->connected = 1; + new_dev->ep0_size = desc_device->bMaxPacketSize0; + + TU_ASSERT(tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC),); break; + } case ENUM_GET_DEVICE_DESC: { // Allow 2ms for address recovery time, Ref USB Spec 9.2.6.3 @@ -1495,11 +1530,11 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_GET_STRING_LANGUAGE_ID_LEN: { // save the received device descriptor tusb_desc_device_t const *desc_device = (tusb_desc_device_t const *) _usbh_epbuf.ctrl; - dev->vid = desc_device->idVendor; - dev->pid = desc_device->idProduct; - dev->i_manufacturer = desc_device->iManufacturer; - dev->i_product = desc_device->iProduct; - dev->i_serial = desc_device->iSerialNumber; + dev->idVendor = desc_device->idVendor; + dev->idProduct = desc_device->idProduct; + dev->iManufacturer = desc_device->iManufacturer; + dev->iProduct = desc_device->iProduct; + dev->iSerialNumber = desc_device->iSerialNumber; dev->bNumConfigurations = desc_device->bNumConfigurations; tuh_enum_descriptor_device_cb(daddr, desc_device); // callback @@ -1520,8 +1555,8 @@ static void process_enumeration(tuh_xfer_t* xfer) { if (desc_langid->bLength >= 4) { langid = tu_le16toh(desc_langid->utf16le[0]); // previous request is langid } - if (dev->i_manufacturer != 0) { - tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, 2, + if (dev->iManufacturer != 0) { + tuh_descriptor_get_string(daddr, dev->iManufacturer, langid, _usbh_epbuf.ctrl, 2, process_enumeration, ENUM_GET_STRING_MANUFACTURER); break; }else { @@ -1530,10 +1565,10 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_GET_STRING_MANUFACTURER: { - if (dev->i_manufacturer != 0) { + if (dev->iManufacturer != 0) { langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request const uint8_t str_len = xfer->buffer[0]; - tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, str_len, + tuh_descriptor_get_string(daddr, dev->iManufacturer, langid, _usbh_epbuf.ctrl, str_len, process_enumeration, ENUM_GET_STRING_PRODUCT_LEN); break; } else { @@ -1542,11 +1577,11 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_GET_STRING_PRODUCT_LEN: - if (dev->i_product != 0) { + if (dev->iProduct != 0) { if (state == ENUM_GET_STRING_PRODUCT_LEN) { langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through } - tuh_descriptor_get_string(daddr, dev->i_product, langid, _usbh_epbuf.ctrl, 2, + tuh_descriptor_get_string(daddr, dev->iProduct, langid, _usbh_epbuf.ctrl, 2, process_enumeration, ENUM_GET_STRING_PRODUCT); break; } else { @@ -1554,10 +1589,10 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_GET_STRING_PRODUCT: { - if (dev->i_product != 0) { + if (dev->iProduct != 0) { langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request const uint8_t str_len = xfer->buffer[0]; - tuh_descriptor_get_string(daddr, dev->i_product, langid, _usbh_epbuf.ctrl, str_len, + tuh_descriptor_get_string(daddr, dev->iProduct, langid, _usbh_epbuf.ctrl, str_len, process_enumeration, ENUM_GET_STRING_SERIAL_LEN); break; } else { @@ -1566,11 +1601,11 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_GET_STRING_SERIAL_LEN: - if (dev->i_serial != 0) { + if (dev->iSerialNumber != 0) { if (state == ENUM_GET_STRING_SERIAL_LEN) { langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through } - tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, 2, + tuh_descriptor_get_string(daddr, dev->iSerialNumber, langid, _usbh_epbuf.ctrl, 2, process_enumeration, ENUM_GET_STRING_SERIAL); break; } else { @@ -1578,10 +1613,10 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_GET_STRING_SERIAL: { - if (dev->i_serial != 0) { + if (dev->iSerialNumber != 0) { langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request const uint8_t str_len = xfer->buffer[0]; - tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, str_len, + tuh_descriptor_get_string(daddr, dev->iSerialNumber, langid, _usbh_epbuf.ctrl, str_len, process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC); break; } else { @@ -1657,12 +1692,12 @@ static bool enum_new_device(hcd_event_t* event) { dev0_bus->hub_addr = event->connection.hub_addr; dev0_bus->hub_port = event->connection.hub_port; + // wait until device connection is stable TODO non blocking + tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); + if (dev0_bus->hub_addr == 0) { // connected directly to roothub - // wait until device connection is stable TODO non blocking - tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); - if (!hcd_port_connect_status(dev0_bus->rhport)) { TU_LOG_USBH("Device unplugged while debouncing\r\n"); enum_full_complete(); @@ -1696,10 +1731,6 @@ static bool enum_new_device(hcd_event_t* event) { #if CFG_TUH_HUB else { // connected via external hub - // wait until device connection is stable TODO non blocking - tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); - - // ENUM_HUB_GET_STATUS TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, _usbh_epbuf.ctrl, process_enumeration, ENUM_HUB_CLEAR_RESET_1)); } @@ -1708,7 +1739,7 @@ static bool enum_new_device(hcd_event_t* event) { return true; } -static uint8_t get_new_address(bool is_hub) { +static uint8_t enum_get_new_address(bool is_hub) { uint8_t start; uint8_t end; @@ -1721,47 +1752,14 @@ static uint8_t get_new_address(bool is_hub) { } for (uint8_t idx = start; idx < end; idx++) { - if (!_usbh_devices[idx].connected) return (idx+1); + if (!_usbh_devices[idx].connected) { + return (idx + 1); + } } return 0; // invalid address } -static bool enum_request_set_addr(tusb_desc_device_t const* desc_device) { - // Get new address - uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB); - TU_ASSERT(new_addr != 0); - TU_LOG_USBH("Set Address = %d\r\n", new_addr); - - usbh_device_t* new_dev = get_device(new_addr); - new_dev->bus_info = _usbh_data.dev0_bus; - new_dev->connected = 1; - new_dev->ep0_size = desc_device->bMaxPacketSize0; - - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_DEVICE, - .type = TUSB_REQ_TYPE_STANDARD, - .direction = TUSB_DIR_OUT - }, - .bRequest = TUSB_REQ_SET_ADDRESS, - .wValue = tu_htole16(new_addr), - .wIndex = 0, - .wLength = 0 - }; - tuh_xfer_t xfer = { - .daddr = 0, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = process_enumeration, - .user_data = ENUM_GET_DEVICE_DESC - }; - - TU_ASSERT(tuh_control_xfer(&xfer)); - return true; -} - static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) { usbh_device_t* dev = get_device(dev_addr); uint16_t const total_len = tu_le16toh(desc_cfg->wTotalLength); diff --git a/src/host/usbh.h b/src/host/usbh.h index 063b20539..6f09f0c80 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -250,6 +250,10 @@ bool tuh_edpt_close(uint8_t daddr, uint8_t ep_addr); // Return true if a queued transfer is aborted, false if there is no transfer to abort bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr); +// Set Address (control transfer) +bool tuh_address_set(uint8_t daddr, uint8_t new_addr, + tuh_xfer_cb_t complete_cb, uintptr_t user_data); + // Set Configuration (control transfer) // config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1 // true on success, false if there is on-going control transfer or incorrect parameters From 0f784e8a072d30aaa6f4c6ef0a8f22a085ea2516 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 24 Apr 2025 17:59:45 +0700 Subject: [PATCH 50/68] refactor hub driver and move port reset on connection change to usbh. hub: add hub_port_get_status_local(), ignore resp in hub_port_get_status(pot != 0) usbh properly deboucning with hub/rootport accordingly to usb specs, also add 10ms of reset recovery --- src/host/hub.c | 230 ++++++++++++++++++++++++------------------------ src/host/hub.h | 8 +- src/host/usbh.c | 208 +++++++++++++++++++++---------------------- 3 files changed, 225 insertions(+), 221 deletions(-) diff --git a/src/host/hub.c b/src/host/hub.c index 61efa8ba5..c87289a14 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -57,9 +57,11 @@ typedef struct { TUH_EPBUF_DEF(ctrl_buf, CFG_TUH_HUB_BUFSIZE); } hub_epbuf_t; +static tuh_xfer_cb_t user_complete_cb = NULL; static hub_interface_t hub_itfs[CFG_TUH_HUB]; CFG_TUH_MEM_SECTION static hub_epbuf_t hub_epbufs[CFG_TUH_HUB]; + TU_ATTR_ALWAYS_INLINE static inline hub_interface_t* get_hub_itf(uint8_t daddr) { return &hub_itfs[daddr-1-CFG_TUH_DEVICE_MAX]; } @@ -142,10 +144,23 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, }; TU_LOG_DRV("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port); - TU_ASSERT( tuh_control_xfer(&xfer) ); + TU_ASSERT(tuh_control_xfer(&xfer)); return true; } +static void port_get_status_complete (tuh_xfer_t* xfer) { + if (xfer->result == XFER_RESULT_SUCCESS) { + hub_interface_t* p_hub = get_hub_itf(xfer->daddr); + p_hub->port_status = *((const hub_port_status_response_t *) (uintptr_t) xfer->buffer); + } + + xfer->complete_cb = user_complete_cb; + user_complete_cb = NULL; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request = { @@ -169,8 +184,26 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, .user_data = user_data }; + if (hub_port != 0) { + // intercept complete callback to save port status, ignore resp + hub_epbuf_t* p_epbuf = get_hub_epbuf(hub_addr); + xfer.complete_cb = port_get_status_complete; + xfer.buffer = p_epbuf->ctrl_buf; + user_complete_cb = complete_cb; + } else { + user_complete_cb = NULL; + } + TU_LOG_DRV("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port); - TU_VERIFY( tuh_control_xfer(&xfer) ); + TU_VERIFY(tuh_control_xfer(&xfer)); + return true; +} + +bool hub_port_get_status_local(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp) { + (void) hub_port; + TU_VERIFY(hub_addr > CFG_TUH_DEVICE_MAX); + hub_interface_t* p_hub = get_hub_itf(hub_addr); + *resp = p_hub->port_status; return true; } @@ -238,10 +271,10 @@ bool hub_edpt_status_xfer(uint8_t daddr) { static void config_set_port_power (tuh_xfer_t* xfer); static void config_port_power_complete (tuh_xfer_t* xfer); -bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) { - hub_interface_t* p_hub = get_hub_itf(dev_addr); +bool hub_set_config(uint8_t daddr, uint8_t itf_num) { + hub_interface_t* p_hub = get_hub_itf(daddr); TU_ASSERT(itf_num == p_hub->itf_num); - hub_epbuf_t* p_epbuf = get_hub_epbuf(dev_addr); + hub_epbuf_t* p_epbuf = get_hub_epbuf(daddr); // Get Hub Descriptor tusb_control_request_t const request = { @@ -257,7 +290,7 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) { }; tuh_xfer_t xfer = { - .daddr = dev_addr, + .daddr = daddr, .ep_addr = 0, .setup = &request, .buffer = p_epbuf->ctrl_buf, @@ -312,11 +345,15 @@ static void config_port_power_complete (tuh_xfer_t* xfer) { //--------------------------------------------------------------------+ // Connection Changes //--------------------------------------------------------------------+ -static void get_status_complete (tuh_xfer_t* xfer); -static void port_get_status_complete (tuh_xfer_t* xfer); -static void port_clear_feature_complete_stub(tuh_xfer_t* xfer); -static void connection_clear_conn_change_complete (tuh_xfer_t* xfer); -static void connection_port_reset_complete (tuh_xfer_t* xfer); +enum { + STATE_IDLE = 0, + STATE_HUB_STATUS, + STATE_CLEAR_CHANGE, + STATE_CHECK_CONN, + STATE_COMPLETE +}; + +static void process_new_status(tuh_xfer_t* xfer); // callback as response of interrupt endpoint polling bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { @@ -337,12 +374,12 @@ bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t processed = false; } else if (tu_bit_test(status_change, 0)) { // Hub bit 0 is for the hub device events - processed = hub_get_status(daddr, p_epbuf->ctrl_buf, get_status_complete, 0); + processed = hub_get_status(daddr, p_epbuf->ctrl_buf, process_new_status, STATE_HUB_STATUS); } else { // Hub bits 1 to n are hub port events for (uint8_t port=1; port <= p_hub->bNbrPorts; port++) { if (tu_bit_test(status_change, port)) { - processed = hub_port_get_status(daddr, port, p_epbuf->ctrl_buf, port_get_status_complete, 0); + processed = hub_port_get_status(daddr, port, NULL, process_new_status, STATE_CLEAR_CHANGE); break; // after completely processed one port, we will re-queue the status poll and handle next one } } @@ -358,117 +395,84 @@ bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t return true; } -static void port_clear_feature_complete_stub(tuh_xfer_t* xfer) { - hub_edpt_status_xfer(xfer->daddr); -} - -static void get_status_complete(tuh_xfer_t *xfer) { - const uint8_t daddr = xfer->daddr; - - bool processed = false; // true if new status is processed - if (xfer->result == XFER_RESULT_SUCCESS) { - hub_status_response_t hub_status = *((const hub_status_response_t *) (uintptr_t) xfer->buffer); - - TU_LOG_DRV("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, hub_status.change.value); - - if (hub_status.change.local_power_source) { - TU_LOG_DRV(" Local Power Change\r\n"); - processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE, port_clear_feature_complete_stub, 0); - } else if (hub_status.change.over_current) { - TU_LOG_DRV(" Over Current\r\n"); - processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE, port_clear_feature_complete_stub, 0); - } - } - - if (!processed) { - TU_ASSERT(hub_edpt_status_xfer(daddr), ); - } -} - -static void port_get_status_complete(tuh_xfer_t *xfer) { - const uint8_t daddr = xfer->daddr; - bool processed = false; // true if new status is processed - - if (xfer->result == XFER_RESULT_SUCCESS) { - const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - hub_interface_t *p_hub = get_hub_itf(daddr); - p_hub->port_status = *((const hub_port_status_response_t *) (uintptr_t) xfer->buffer); - - // Clear port status change interrupts - if (p_hub->port_status.change.connection) { - // Connection change - // Port is powered and enabled - //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, ); - - // Acknowledge Port Connection Change - processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0); - } else if (p_hub->port_status.change.port_enable) { - processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE, port_clear_feature_complete_stub, 0); - } else if (p_hub->port_status.change.suspend) { - processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE, port_clear_feature_complete_stub, 0); - } else if (p_hub->port_status.change.over_current) { - processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE, port_clear_feature_complete_stub, 0); - } else if (p_hub->port_status.change.reset) { - processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE, port_clear_feature_complete_stub, 0); - } - } - - if (!processed) { - TU_ASSERT(hub_edpt_status_xfer(daddr), ); - } -} - -static void connection_clear_conn_change_complete (tuh_xfer_t* xfer) { +static void process_new_status(tuh_xfer_t* xfer) { const uint8_t daddr = xfer->daddr; if (xfer->result != XFER_RESULT_SUCCESS) { - TU_ASSERT(hub_edpt_status_xfer(daddr), ); + TU_ASSERT(hub_edpt_status_xfer(daddr),); return; } + const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); hub_interface_t *p_hub = get_hub_itf(daddr); - const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + const uintptr_t state = xfer->user_data; + bool processed = false; // true if new status is processed - if (p_hub->port_status.status.connection) { - // Reset port if attach event - hub_port_reset(daddr, port_num, connection_port_reset_complete, 0); - } else { - // submit detach event - const hcd_event_t event = { - .rhport = usbh_get_rhport(daddr), - .event_id = HCD_EVENT_DEVICE_REMOVE, - .connection = { - .hub_addr = daddr, - .hub_port = port_num - } - }; - hcd_event_handler(&event, false); - } -} - -static void connection_port_reset_complete (tuh_xfer_t* xfer) { - const uint8_t daddr = xfer->daddr; - - if (xfer->result != XFER_RESULT_SUCCESS) { - // retry port reset if failed - if (!tuh_control_xfer(xfer)) { - TU_ASSERT(hub_edpt_status_xfer(daddr), ); // back to status poll if failed to queue request + switch (state) { + case STATE_HUB_STATUS: { + hub_status_response_t hub_status = *((const hub_status_response_t *) (uintptr_t) xfer->buffer); + TU_LOG_DRV("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, hub_status.change.value); + if (hub_status.change.local_power_source) { + TU_LOG_DRV(" Local Power Change\r\n"); + processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE, + process_new_status, STATE_COMPLETE); + } else if (hub_status.change.over_current) { + TU_LOG_DRV(" Over Current\r\n"); + processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE, + process_new_status, STATE_COMPLETE); + } + break; } - return; + + case STATE_CLEAR_CHANGE: + // Get port status complete --> clear change + if (p_hub->port_status.change.connection) { + // Connection change + // Port is powered and enabled + //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, ); + + // Acknowledge Port Connection Change + processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, + process_new_status, STATE_CHECK_CONN); + } else if (p_hub->port_status.change.port_enable) { + processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE, + process_new_status, STATE_COMPLETE); + } else if (p_hub->port_status.change.suspend) { + processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE, + process_new_status, STATE_COMPLETE); + } else if (p_hub->port_status.change.over_current) { + processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE, + process_new_status, STATE_COMPLETE); + } else if (p_hub->port_status.change.reset) { + processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE, + process_new_status, STATE_COMPLETE); + } + break; + + case STATE_CHECK_CONN: { + const hcd_event_t event = { + .rhport = usbh_get_rhport(daddr), + .event_id = p_hub->port_status.status.connection ? HCD_EVENT_DEVICE_ATTACH : HCD_EVENT_DEVICE_REMOVE, + .connection = { + .hub_addr = daddr, + .hub_port = port_num + } + }; + hcd_event_handler(&event, false); + processed = true; // usbh queue status after handled this in (de)enumeration + break; + } + + case STATE_COMPLETE: + default: + processed = false; // complete this status, queue next status + break; + } - const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - - // submit attach event - hcd_event_t event = { - .rhport = usbh_get_rhport(daddr), - .event_id = HCD_EVENT_DEVICE_ATTACH, - .connection = { - .hub_addr = daddr, - .hub_port = port_num - } - }; - hcd_event_handler(&event, false); + if (!processed) { + TU_ASSERT(hub_edpt_status_xfer(daddr),); + } } #endif diff --git a/src/host/hub.h b/src/host/hub.h index e4e576661..3587f0ee3 100644 --- a/src/host/hub.h +++ b/src/host/hub.h @@ -170,9 +170,13 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Get port status +// If hub_port != 0, resp is ignored. hub_port_get_status_local() can be used to retrieve the status bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void *resp, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +// Get port status from local cache. This does not send a request to the device +bool hub_port_get_status_local(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp); + // Get status from Interrupt endpoint bool hub_edpt_status_xfer(uint8_t daddr); @@ -188,7 +192,7 @@ bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_port, tuh_xfer_cb return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_data); } -// Get Hub status +// Get Hub status (port = 0) TU_ATTR_ALWAYS_INLINE static inline bool hub_get_status(uint8_t hub_addr, void* resp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return hub_port_get_status(hub_addr, 0, resp, complete_cb, user_data); @@ -205,7 +209,7 @@ bool hub_clear_feature(uint8_t hub_addr, uint8_t feature, tuh_xfer_cb_t complete bool hub_init (void); bool hub_deinit (void); bool hub_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); -bool hub_set_config (uint8_t dev_addr, uint8_t itf_num); +bool hub_set_config (uint8_t daddr, uint8_t itf_num); bool hub_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); void hub_close (uint8_t dev_addr); diff --git a/src/host/usbh.c b/src/host/usbh.c index f4a6e1697..94a1fa247 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -360,7 +360,6 @@ bool tuh_rhport_reset_bus(uint8_t rhport, bool active) { //--------------------------------------------------------------------+ // PUBLIC API (Parameter Verification is required) //--------------------------------------------------------------------+ - bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) { return hcd_configure(rhport, cfg_id, cfg_param); } @@ -534,7 +533,6 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { } } else { TU_LOG1("[%u:] USBH Device Attach\r\n", event.rhport); - _usbh_data.enumerating_daddr = 0; enum_new_device(&event); } break; @@ -1022,9 +1020,11 @@ bool tuh_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info) { TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) { switch (event->event_id) { + case HCD_EVENT_DEVICE_ATTACH: + + break; + case HCD_EVENT_DEVICE_REMOVE: - // FIXME device remove from a hub need an HCD API for hcd to free up endpoint - // mark device as removing to prevent further xfer before the event is processed in usbh task break; default: break; @@ -1228,8 +1228,7 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt, TU_VERIFY(_async_func(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \ return (uint8_t) result -uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, - void* buffer, uint16_t len) { +uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len) { _CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len); } @@ -1237,33 +1236,27 @@ uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len _CONTROL_SYNC_API(tuh_descriptor_get_device, daddr, buffer, len); } -uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, - void* buffer, uint16_t len) { +uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) { _CONTROL_SYNC_API(tuh_descriptor_get_configuration, daddr, index, buffer, len); } -uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, - void* buffer, uint16_t len) { +uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len) { _CONTROL_SYNC_API(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len); } -uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, - void* buffer, uint16_t len) { +uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len) { _CONTROL_SYNC_API(tuh_descriptor_get_string, daddr, index, language_id, buffer, len); } -uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, - void* buffer, uint16_t len) { +uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) { _CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len); } -uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, - void* buffer, uint16_t len) { +uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) { _CONTROL_SYNC_API(tuh_descriptor_get_product_string, daddr, language_id, buffer, len); } -uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, - void* buffer, uint16_t len) { +uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) { _CONTROL_SYNC_API(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len); } @@ -1361,27 +1354,24 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub //--------------------------------------------------------------------+ // Enumeration Process -// is a lengthy process with a series of control transfer to configure -// newly attached device. +// is a lengthy process with a series of control transfer to configure newly attached device. // NOTE: due to the shared control buffer, we must complete enumerating // one device before enumerating another one. //--------------------------------------------------------------------+ - -enum { - ENUM_DEBOUNCING_DELAY_MS = 200, // when plug/unplug a device, physical connection can be bouncing and may - // generate a series of attach/detach event. This delay wait for stable connection - ENUM_RESET_DELAY_MS = 50, // USB specs: 10 to 50ms +enum { // USB 2.0 specs 7.1.7 for timing + ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection + ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port + ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset + ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery }; enum { ENUM_IDLE, - ENUM_RESET_1, // 1st reset when attached - //ENUM_HUB_GET_STATUS_1, - ENUM_HUB_CLEAR_RESET_1, + ENUM_HUB_RERSET, + ENUM_HUB_GET_STATUS_AFTER_RESET, + ENUM_HUB_CLEAR_RESET, + ENUM_ADDR0_DEVICE_DESC, - ENUM_RESET_2, // 2nd reset before set address (not used) - ENUM_HUB_GET_STATUS_2, - ENUM_HUB_CLEAR_RESET_2, ENUM_SET_ADDR, ENUM_GET_DEVICE_DESC, ENUM_GET_STRING_LANGUAGE_ID_LEN, @@ -1401,6 +1391,63 @@ enum { static uint8_t enum_get_new_address(bool is_hub); static bool enum_parse_configuration_desc (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg); static void enum_full_complete(void); +static void process_enumeration(tuh_xfer_t* xfer); + +// start a new enumeration process +static bool enum_new_device(hcd_event_t* event) { + tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus; + dev0_bus->rhport = event->rhport; + dev0_bus->hub_addr = event->connection.hub_addr; + dev0_bus->hub_port = event->connection.hub_port; + + _usbh_data.enumerating_daddr = 0; + + // wait until device connection is stable TODO non blocking + tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); + + if (dev0_bus->hub_addr == 0) { + // connected directly to roothub + // USB bus not active and frame number is not available yet. + // need to depend on tusb_time_millis_api() TODO non blocking + + if (!hcd_port_connect_status(dev0_bus->rhport)) { + TU_LOG_USBH("Device unplugged while debouncing\r\n"); + enum_full_complete(); + return true; + } + + // reset device + hcd_port_reset(dev0_bus->rhport); + tusb_time_delay_ms_api(ENUM_RESET_ROOT_DELAY_MS); + hcd_port_reset_end(dev0_bus->rhport); + + if (!hcd_port_connect_status(dev0_bus->rhport)) { + // device unplugged while delaying + enum_full_complete(); + return true; + } + + dev0_bus->speed = hcd_port_speed_get(dev0_bus->rhport); + TU_LOG_USBH("%s Speed\r\n", tu_str_speed[dev0_bus->speed]); + + // fake transfer to kick-off the enumeration process + tuh_xfer_t xfer; + xfer.daddr = 0; + xfer.result = XFER_RESULT_SUCCESS; + xfer.user_data = ENUM_ADDR0_DEVICE_DESC; + process_enumeration(&xfer); + } + #if CFG_TUH_HUB + else { + // connected via hub + TU_VERIFY(dev0_bus->hub_port != 0); + TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, + process_enumeration, ENUM_HUB_RERSET)); + } + #endif // hub + + return true; +} // process device enumeration static void process_enumeration(tuh_xfer_t* xfer) { @@ -1431,6 +1478,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { uint8_t const daddr = xfer->daddr; uintptr_t const state = xfer->user_data; usbh_device_t* dev = get_device(daddr); + tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus; if (daddr > 0) { TU_ASSERT(dev,); } @@ -1438,53 +1486,54 @@ static void process_enumeration(tuh_xfer_t* xfer) { switch (state) { #if CFG_TUH_HUB - //case ENUM_HUB_GET_STATUS_1: break; - case ENUM_HUB_CLEAR_RESET_1: { + case ENUM_HUB_RERSET: { hub_port_status_response_t port_status; - memcpy(&port_status, _usbh_epbuf.ctrl, sizeof(hub_port_status_response_t)); + hub_port_get_status_local(dev0_bus->hub_addr, dev0_bus->hub_port, &port_status); if (!port_status.status.connection) { - // device unplugged while delaying, nothing else to do + TU_LOG_USBH("Device unplugged from hub while debouncing\r\n"); enum_full_complete(); return; } - _usbh_data.dev0_bus.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : - (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; - - // Acknowledge Port Reset Change - if (port_status.change.reset) { - hub_port_clear_reset_change(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, - process_enumeration, ENUM_ADDR0_DEVICE_DESC); - } + TU_ASSERT(hub_port_reset(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, ENUM_HUB_GET_STATUS_AFTER_RESET),); break; } - case ENUM_HUB_GET_STATUS_2: - tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); - TU_ASSERT(hub_port_get_status(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, _usbh_epbuf.ctrl, - process_enumeration, ENUM_HUB_CLEAR_RESET_2),); + case ENUM_HUB_GET_STATUS_AFTER_RESET: { + tusb_time_delay_ms_api(ENUM_RESET_HUB_DELAY_MS); // wait for reset to take effect + + // get status to check for reset change + TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, ENUM_HUB_CLEAR_RESET),); break; + } - case ENUM_HUB_CLEAR_RESET_2: { + case ENUM_HUB_CLEAR_RESET: { hub_port_status_response_t port_status; - memcpy(&port_status, _usbh_epbuf.ctrl, sizeof(hub_port_status_response_t)); + hub_port_get_status_local(dev0_bus->hub_addr, dev0_bus->hub_port, &port_status); + dev0_bus->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : + (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; - // Acknowledge Port Reset Change if Reset Successful if (port_status.change.reset) { - TU_ASSERT(hub_port_clear_reset_change(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, - process_enumeration, ENUM_SET_ADDR),); + // Acknowledge Port Reset Change + TU_ASSERT(hub_port_clear_reset_change(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, ENUM_ADDR0_DEVICE_DESC),); + } else { + // maybe retry if reset change not set but we need timeout to prevent infinite loop + // TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, ENUM_HUB_CLEAR_RESET),); } + break; } #endif case ENUM_ADDR0_DEVICE_DESC: { + tusb_time_delay_ms_api(ENUM_RESET_RECOVERY_DELAY_MS); // reset recovery + // TODO probably doesn't need to open/close each enumeration uint8_t const addr0 = 0; TU_ASSERT(usbh_edpt_control_open(addr0, 8),); - // Get first 8 bytes of device descriptor for Control Endpoint size + // Get first 8 bytes of device descriptor for control endpoint size TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n"); TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_epbuf.ctrl, 8, process_enumeration, ENUM_SET_ADDR),); @@ -1686,59 +1735,6 @@ static void process_enumeration(tuh_xfer_t* xfer) { } } -static bool enum_new_device(hcd_event_t* event) { - tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus; - dev0_bus->rhport = event->rhport; - dev0_bus->hub_addr = event->connection.hub_addr; - dev0_bus->hub_port = event->connection.hub_port; - - // wait until device connection is stable TODO non blocking - tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); - - if (dev0_bus->hub_addr == 0) { - // connected directly to roothub - - if (!hcd_port_connect_status(dev0_bus->rhport)) { - TU_LOG_USBH("Device unplugged while debouncing\r\n"); - enum_full_complete(); - return true; - } - - hcd_port_reset(dev0_bus->rhport); // reset device - - // Since we are in middle of rhport reset, frame number is not available yet. - // need to depend on tusb_time_millis_api() TODO non blocking - tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); - - hcd_port_reset_end(dev0_bus->rhport); - - // device unplugged while delaying - if (!hcd_port_connect_status(dev0_bus->rhport)) { - enum_full_complete(); - return true; - } - - dev0_bus->speed = hcd_port_speed_get(dev0_bus->rhport); - TU_LOG_USBH("%s Speed\r\n", tu_str_speed[dev0_bus->speed]); - - // fake transfer to kick-off the enumeration process - tuh_xfer_t xfer; - xfer.daddr = 0; - xfer.result = XFER_RESULT_SUCCESS; - xfer.user_data = ENUM_ADDR0_DEVICE_DESC; - process_enumeration(&xfer); - } -#if CFG_TUH_HUB - else { - // connected via external hub - TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, _usbh_epbuf.ctrl, - process_enumeration, ENUM_HUB_CLEAR_RESET_1)); - } -#endif // hub - - return true; -} - static uint8_t enum_get_new_address(bool is_hub) { uint8_t start; uint8_t end; From 093720f60b2b849f7129e532f8efef94c04d408b Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 24 Apr 2025 18:08:00 +0700 Subject: [PATCH 51/68] fix build --- src/host/usbh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 94a1fa247..25942315b 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1546,7 +1546,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { TU_ASSERT(new_addr != 0,); usbh_device_t* new_dev = get_device(new_addr); - new_dev->bus_info = _usbh_data.dev0_bus; + new_dev->bus_info = *dev0_bus; new_dev->connected = 1; new_dev->ep0_size = desc_device->bMaxPacketSize0; @@ -1564,7 +1564,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { new_dev->addressed = 1; _usbh_data.enumerating_daddr = new_addr; - hcd_device_close(_usbh_data.dev0_bus.rhport, 0); // close dev0_bus + hcd_device_close(dev0_bus->rhport, 0); // close dev0 TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint From b5b7a4be60428193a773c1177456f138c21e48ad Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 24 Apr 2025 21:53:57 +0700 Subject: [PATCH 52/68] hub check status before get 1st device descriptor --- .idea/cmake.xml | 4 ++-- src/host/usbh.c | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.idea/cmake.xml b/.idea/cmake.xml index 7365e13a8..b8383a5ff 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -6,9 +6,9 @@ - - + + diff --git a/src/host/usbh.c b/src/host/usbh.c index 25942315b..8469aee83 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1370,6 +1370,7 @@ enum { ENUM_HUB_RERSET, ENUM_HUB_GET_STATUS_AFTER_RESET, ENUM_HUB_CLEAR_RESET, + ENUM_HUB_CLEAR_RESET_COMPLETE, ENUM_ADDR0_DEVICE_DESC, ENUM_SET_ADDR, @@ -1511,19 +1512,33 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_HUB_CLEAR_RESET: { hub_port_status_response_t port_status; hub_port_get_status_local(dev0_bus->hub_addr, dev0_bus->hub_port, &port_status); - dev0_bus->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : - (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; if (port_status.change.reset) { // Acknowledge Port Reset Change - TU_ASSERT(hub_port_clear_reset_change(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, ENUM_ADDR0_DEVICE_DESC),); + TU_ASSERT(hub_port_clear_reset_change(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, ENUM_HUB_CLEAR_RESET_COMPLETE),); } else { // maybe retry if reset change not set but we need timeout to prevent infinite loop - // TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, ENUM_HUB_CLEAR_RESET),); + // TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, ENUM_HUB_CLEAR_RESET_COMPLETE),); } break; } + + case ENUM_HUB_CLEAR_RESET_COMPLETE: { + hub_port_status_response_t port_status; + hub_port_get_status_local(dev0_bus->hub_addr, dev0_bus->hub_port, &port_status); + + if (!port_status.status.connection) { + TU_LOG_USBH("Device unplugged from hub (not addressed yet)\r\n"); + enum_full_complete(); + return; + } + + dev0_bus->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : + (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; + + TU_ATTR_FALLTHROUGH; + } #endif case ENUM_ADDR0_DEVICE_DESC: { From 0937a2b2d3dbc0b5595c6ea3a6acc8a691f73941 Mon Sep 17 00:00:00 2001 From: Eli Hughes Date: Sat, 26 Apr 2025 13:04:39 -0400 Subject: [PATCH 53/68] using get-deps from tinyuf2 --- tools/get_deps.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/get_deps.py b/tools/get_deps.py index ba9dc23ce..d89c1b2b1 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -243,11 +243,13 @@ def get_a_dep(d): p.mkdir(parents=True) run_cmd(f"{git_cmd} init") run_cmd(f"{git_cmd} remote add origin {url}") + head = None + else: + # Check if commit is already fetched + result = run_cmd(f"{git_cmd} rev-parse HEAD") + head = result.stdout.decode("utf-8").splitlines()[0] + run_cmd(f"{git_cmd} reset --hard") - # Check if commit is already fetched - result = run_cmd(f"{git_cmd} rev-parse HEAD") - head = result.stdout.decode("utf-8").splitlines()[0] - run_cmd(f"{git_cmd} reset --hard") if commit != head: run_cmd(f"{git_cmd} fetch --depth 1 origin {commit}") run_cmd(f"{git_cmd} checkout FETCH_HEAD") From 2c1414b4c18518a179560a097aada40609303693 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 28 Apr 2025 12:59:59 +0700 Subject: [PATCH 54/68] usbh: add roothub debounncing flag to ignore attach/remove event on the roothub that is currently doing debouncing delay --- src/host/usbh.c | 22 ++++++++++++++++++---- src/portable/synopsys/dwc2/hcd_dwc2.c | 19 +++---------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 8469aee83..8852bdda4 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -275,6 +275,7 @@ typedef struct { typedef struct { uint8_t controller_id; // controller ID uint8_t enumerating_daddr; // device address of the device being enumerated + uint8_t attach_debouncing_bm; // bitmask for roothub port attach debouncing tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration usbh_ctrl_xfer_info_t ctrl_xfer_info; // control transfer } usbh_data_t; @@ -349,7 +350,7 @@ bool tuh_rhport_is_active(uint8_t rhport) { bool tuh_rhport_reset_bus(uint8_t rhport, bool active) { TU_VERIFY(tuh_rhport_is_active(rhport)); - if ( active ) { + if (active) { hcd_port_reset(rhport); } else { hcd_port_reset_end(rhport); @@ -1021,10 +1022,18 @@ bool tuh_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info) { TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) { switch (event->event_id) { case HCD_EVENT_DEVICE_ATTACH: - - break; - case HCD_EVENT_DEVICE_REMOVE: + // Attach debouncing on roothub: skip attach/remove while debouncing delay + if (event->connection.hub_addr == 0) { + if (tu_bit_test(_usbh_data.attach_debouncing_bm, event->rhport)) { + return; + } + + if (event->event_id == HCD_EVENT_DEVICE_ATTACH) { + // No debouncing, set flag if attach event + _usbh_data.attach_debouncing_bm |= TU_BIT(event->rhport); + } + } break; default: break; @@ -1406,6 +1415,11 @@ static bool enum_new_device(hcd_event_t* event) { // wait until device connection is stable TODO non blocking tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); + // clear roothub debouncing delay + if (dev0_bus->hub_addr == 0) { + _usbh_data.attach_debouncing_bm &= (uint8_t) ~TU_BIT(dev0_bus->rhport); + } + if (dev0_bus->hub_addr == 0) { // connected directly to roothub // USB bus not active and frame number is not available yet. diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 7c29a03cf..2de15068a 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -107,7 +107,6 @@ typedef struct { typedef struct { hcd_xfer_t xfer[DWC2_CHANNEL_COUNT_MAX]; hcd_endpoint_t edpt[CFG_TUH_DWC2_ENDPOINT_MAX]; - bool attach_debounce; // if true: wait for the debounce delay before issuing new attach events } hcd_data_t; hcd_data_t _hcd_data; @@ -423,11 +422,6 @@ uint32_t hcd_frame_number(uint8_t rhport) { // Get the current connect status of roothub port bool hcd_port_connect_status(uint8_t rhport) { - // this is called from enum_new_device() - after the debouncing delays - if (_hcd_data.attach_debounce) { - _hcd_data.attach_debounce = false; // allow new attach events again - } - dwc2_regs_t* dwc2 = DWC2_REG(rhport); return dwc2->hprt & HPRT_CONN_STATUS; } @@ -1328,10 +1322,7 @@ static void handle_hprt_irq(uint8_t rhport, bool in_isr) { hprt |= HPRT_CONN_DETECT; if (hprt_bm.conn_status) { - if (!_hcd_data.attach_debounce) { - _hcd_data.attach_debounce = true; // block new attach events until the debounce delay is over - hcd_event_device_attach(rhport, in_isr); - } + hcd_event_device_attach(rhport, in_isr); } } @@ -1398,12 +1389,8 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { // Device disconnected dwc2->gintsts = GINTSTS_DISCINT; - // ignore device removal if attach debounce is active - // it will evaluate the port status after the debounce delay - if (!_hcd_data.attach_debounce) { - if (!(dwc2->hprt & HPRT_CONN_STATUS)) { - hcd_event_device_remove(rhport, in_isr); - } + if (!(dwc2->hprt & HPRT_CONN_STATUS)) { + hcd_event_device_remove(rhport, in_isr); } } From 42d4f7c81e65a2d39b8e108b1ef8ed58945b7617 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 28 Apr 2025 15:10:03 +0700 Subject: [PATCH 55/68] remove the old attach duplicated logic, debouncing skip should take care of it. --- src/host/usbh.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 8852bdda4..6f875c80b 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -513,28 +513,19 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { case HCD_EVENT_DEVICE_ATTACH: // due to the shared control buffer, we must fully complete enumerating one device first. // TODO better to have an separated queue for newly attached devices - if (_usbh_data.enumerating_daddr != TUSB_INDEX_INVALID_8) { - if (event.rhport == _usbh_data.dev0_bus.rhport && - event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr && event.connection.hub_port == _usbh_data.dev0_bus.hub_port) { - // Some device can cause multiple duplicated attach events - // drop current enumerating and start over for a proper port reset - // abort/cancel current enumeration and start new one - TU_LOG1("[%u:] USBH Device Attach (duplicated)\r\n", event.rhport); - tuh_edpt_abort_xfer(0, 0); - enum_new_device(&event); - } else { - TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport); - bool is_empty = osal_queue_empty(_usbh_q); - queue_event(&event, in_isr); - - if (is_empty) { - // Exit if this is the only event in the queue, otherwise we may loop forever - return; - } - } - } else { + if (_usbh_data.enumerating_daddr == TUSB_INDEX_INVALID_8) { + // New device attached and we are ready TU_LOG1("[%u:] USBH Device Attach\r\n", event.rhport); + _usbh_data.enumerating_daddr = 0; // enumerate new device with address 0 enum_new_device(&event); + } else { + // currently enumerating another device + TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport); + const bool is_empty = osal_queue_empty(_usbh_q); + queue_event(&event, in_isr); + if (is_empty) { + return; // Exit if this is the only event in the queue, otherwise we loop forever + } } break; @@ -1410,8 +1401,6 @@ static bool enum_new_device(hcd_event_t* event) { dev0_bus->hub_addr = event->connection.hub_addr; dev0_bus->hub_port = event->connection.hub_port; - _usbh_data.enumerating_daddr = 0; - // wait until device connection is stable TODO non blocking tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); From fc43eeddf2b3d045431d56cc50bb0e2d6fdf5b98 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 29 Apr 2025 10:11:20 +0700 Subject: [PATCH 56/68] attach debouncing fixed issue with port1 highspeed on imxrt --- .idea/debugServers/rt1060.xml | 2 +- .idea/debugServers/rt1064.xml | 2 +- .idea/debugServers/sam21.xml | 2 +- .idea/debugServers/sam51.xml | 2 +- .idea/debugServers/stm32f769.xml | 4 ++-- .idea/debugServers/stm32h563.xml | 2 +- .idea/debugServers/stm32h743.xml | 2 +- src/portable/chipidea/ci_hs/hcd_ci_hs.c | 6 ------ 8 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.idea/debugServers/rt1060.xml b/.idea/debugServers/rt1060.xml index 3325cc81f..cbd295b4e 100644 --- a/.idea/debugServers/rt1060.xml +++ b/.idea/debugServers/rt1060.xml @@ -5,7 +5,7 @@ - + diff --git a/.idea/debugServers/rt1064.xml b/.idea/debugServers/rt1064.xml index 4dc38ef63..691066f9d 100644 --- a/.idea/debugServers/rt1064.xml +++ b/.idea/debugServers/rt1064.xml @@ -5,7 +5,7 @@ - + diff --git a/.idea/debugServers/sam21.xml b/.idea/debugServers/sam21.xml index d8763b33b..3f6735bd1 100644 --- a/.idea/debugServers/sam21.xml +++ b/.idea/debugServers/sam21.xml @@ -5,7 +5,7 @@ - + diff --git a/.idea/debugServers/sam51.xml b/.idea/debugServers/sam51.xml index 0d15ff856..99a92c174 100644 --- a/.idea/debugServers/sam51.xml +++ b/.idea/debugServers/sam51.xml @@ -5,7 +5,7 @@ - + diff --git a/.idea/debugServers/stm32f769.xml b/.idea/debugServers/stm32f769.xml index 2fb322a0f..22a452218 100644 --- a/.idea/debugServers/stm32f769.xml +++ b/.idea/debugServers/stm32f769.xml @@ -1,11 +1,11 @@ - + - + diff --git a/.idea/debugServers/stm32h563.xml b/.idea/debugServers/stm32h563.xml index 9bf6db6e9..637839314 100644 --- a/.idea/debugServers/stm32h563.xml +++ b/.idea/debugServers/stm32h563.xml @@ -5,7 +5,7 @@ - + diff --git a/.idea/debugServers/stm32h743.xml b/.idea/debugServers/stm32h743.xml index 63680b78c..b04e4a708 100644 --- a/.idea/debugServers/stm32h743.xml +++ b/.idea/debugServers/stm32h743.xml @@ -5,7 +5,7 @@ - + diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c index 22eb22690..b5324a754 100644 --- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c @@ -93,12 +93,6 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { hcd_reg->USBMODE = USBMODE_CM_HOST; #endif - // FIXME force full speed, still have issue with Highspeed enumeration - // probably due to physical connection bouncing when plug/unplug - // 1. Have issue when plug/unplug devices, maybe the port is not reset properly - // 2. Also does not seems to detect disconnection - hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED; - return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD); } From e7d4b5c9e718b1e72df8aadb884d2f36ab9d158c Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 29 Apr 2025 17:04:10 +0700 Subject: [PATCH 57/68] add enum for set addr recovery --- .idea/cmake.xml | 6 +++--- .idea/debugServers/rt1064.xml | 4 ++-- src/host/usbh.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.idea/cmake.xml b/.idea/cmake.xml index b8383a5ff..dd219bc77 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -12,7 +12,7 @@ - + @@ -94,7 +94,8 @@ - + + @@ -166,7 +167,6 @@ - \ No newline at end of file diff --git a/.idea/debugServers/rt1064.xml b/.idea/debugServers/rt1064.xml index 691066f9d..b908b59e2 100644 --- a/.idea/debugServers/rt1064.xml +++ b/.idea/debugServers/rt1064.xml @@ -1,11 +1,11 @@ - + - + diff --git a/src/host/usbh.c b/src/host/usbh.c index 6f875c80b..fbb61e10e 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1363,6 +1363,7 @@ enum { // USB 2.0 specs 7.1.7 for timing ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery + ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms }; enum { @@ -1573,8 +1574,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_GET_DEVICE_DESC: { - // Allow 2ms for address recovery time, Ref USB Spec 9.2.6.3 - tusb_time_delay_ms_api(2); + tusb_time_delay_ms_api(ENUM_SET_ADDRESS_RECOVERY_DELAY_MS); // set address recovery const uint8_t new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue); usbh_device_t* new_dev = get_device(new_addr); From 2abd3c54c4141e5e6e0bd4fea38849cb150fb161 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 29 Apr 2025 20:49:47 +0700 Subject: [PATCH 58/68] define hcd_devtree_info_t forr backward compatible --- src/host/usbh.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/host/usbh.h b/src/host/usbh.h index 6f09f0c80..6f34d8bb3 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -86,6 +86,9 @@ typedef struct { uint8_t speed; } tuh_bus_info_t; +// backward compatibility for hcd_devtree_info_t, maybe removed in the future +#define hcd_devtree_info_t tuh_bus_info_t +#define hcd_devtree_get_info(_daddr, _bus_info) tuh_bus_info_get(_daddr, _bus_info) // ConfigID for tuh_configure() enum { From bc37ed6e3e9158a811ed07479638d3db8437344e Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 May 2025 15:23:23 +0700 Subject: [PATCH 59/68] usbh: force removed device in the same bus info, before setting address. usbh: move code around hub: queue status endpoint for detach/remove event --- src/host/hub.c | 3 +- src/host/usbh.c | 233 +++++++++++++++++++++++------------------------- 2 files changed, 115 insertions(+), 121 deletions(-) diff --git a/src/host/hub.c b/src/host/hub.c index c87289a14..0ed0e0c42 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -459,7 +459,8 @@ static void process_new_status(tuh_xfer_t* xfer) { } }; hcd_event_handler(&event, false); - processed = true; // usbh queue status after handled this in (de)enumeration + // skip status for attach event, usbh will do it after handled this enumeration + processed = (event.event_id == HCD_EVENT_DEVICE_ATTACH); break; } diff --git a/src/host/usbh.c b/src/host/usbh.c index fbb61e10e..92c254a9e 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -34,7 +34,7 @@ #include "hub.h" //--------------------------------------------------------------------+ -// USBH Configuration +// Configuration //--------------------------------------------------------------------+ #ifndef CFG_TUH_TASK_QUEUE_SZ #define CFG_TUH_TASK_QUEUE_SZ 16 @@ -89,7 +89,7 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si } //--------------------------------------------------------------------+ -// USBH-HCD common data structure +// Data Structure //--------------------------------------------------------------------+ typedef struct { tuh_bus_info_t bus_info; @@ -131,8 +131,60 @@ typedef struct { } usbh_device_t; +// sum of end device + hub +#define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB) + +// all devices excluding zero-address +// hub address start from CFG_TUH_DEVICE_MAX+1 +// TODO: hub can has its own simpler struct to save memory +static usbh_device_t _usbh_devices[TOTAL_DEVICES]; + +// Mutex for claiming endpoint +#if OSAL_MUTEX_REQUIRED +static osal_mutex_def_t _usbh_mutexdef; +static osal_mutex_t _usbh_mutex; +#else +#define _usbh_mutex NULL +#endif + +// Event queue: usbh_int_set() is used as mutex in OS NONE config +OSAL_QUEUE_DEF(usbh_int_set, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t); +static osal_queue_t _usbh_q; + +// Control transfers: since most controllers do not support multiple control transfers +// on multiple devices concurrently and control transfers are not used much except for +// enumeration, we will only execute control transfers one at a time. +typedef struct { + uint8_t* buffer; + tuh_xfer_cb_t complete_cb; + uintptr_t user_data; + + volatile uint8_t stage; + uint8_t daddr; + volatile uint16_t actual_len; + uint8_t failed_count; +} usbh_ctrl_xfer_info_t; + +typedef struct { + uint8_t controller_id; // controller ID + uint8_t enumerating_daddr; // device address of the device being enumerated + uint8_t attach_debouncing_bm; // bitmask for roothub port attach debouncing + tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration + usbh_ctrl_xfer_info_t ctrl_xfer_info; // control transfer +} usbh_data_t; + +static usbh_data_t _usbh_data = { + .controller_id = TUSB_INDEX_INVALID_8, +}; + +typedef struct { + TUH_EPBUF_TYPE_DEF(tusb_control_request_t, request); + TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE); +} usbh_epbuf_t; +CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf; + //--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF +// Class Driver //--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL #define DRIVER_NAME(_name) _name @@ -235,82 +287,58 @@ static inline usbh_class_driver_t const *get_driver(uint8_t drv_id) { } //--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION +// Function Inline and Prototypes //--------------------------------------------------------------------+ - -// sum of end device + hub -#define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB) - -// all devices excluding zero-address -// hub address start from CFG_TUH_DEVICE_MAX+1 -// TODO: hub can has its own simpler struct to save memory -static usbh_device_t _usbh_devices[TOTAL_DEVICES]; - -// Mutex for claiming endpoint -#if OSAL_MUTEX_REQUIRED - static osal_mutex_def_t _usbh_mutexdef; - static osal_mutex_t _usbh_mutex; -#else - #define _usbh_mutex NULL -#endif - -// Event queue: usbh_int_set() is used as mutex in OS NONE config -OSAL_QUEUE_DEF(usbh_int_set, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t); -static osal_queue_t _usbh_q; - -// Control transfers: since most controllers do not support multiple control transfers -// on multiple devices concurrently and control transfers are not used much except for -// enumeration, we will only execute control transfers one at a time. -typedef struct { - uint8_t* buffer; - tuh_xfer_cb_t complete_cb; - uintptr_t user_data; - - volatile uint8_t stage; - uint8_t daddr; - volatile uint16_t actual_len; - uint8_t failed_count; -} usbh_ctrl_xfer_info_t; - -typedef struct { - uint8_t controller_id; // controller ID - uint8_t enumerating_daddr; // device address of the device being enumerated - uint8_t attach_debouncing_bm; // bitmask for roothub port attach debouncing - tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration - usbh_ctrl_xfer_info_t ctrl_xfer_info; // control transfer -} usbh_data_t; - -static usbh_data_t _usbh_data = { - .controller_id = TUSB_INDEX_INVALID_8, -}; - -typedef struct { - TUH_EPBUF_TYPE_DEF(tusb_control_request_t, request); - TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE); -} usbh_epbuf_t; -CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf; - -//------------- Helper Function -------------// -TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) { - TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL); - return &_usbh_devices[dev_addr-1]; -} - static bool enum_new_device(hcd_event_t* event); static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port); static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size); static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) { + TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL); + return &_usbh_devices[dev_addr-1]; +} + TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event, bool in_isr) { TU_ASSERT(osal_queue_send(_usbh_q, event, in_isr)); tuh_event_hook_cb(event->rhport, event->event_id, in_isr); return true; } +TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) { + if (_usbh_data.ctrl_xfer_info.stage != stage) { + (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); + _usbh_data.ctrl_xfer_info.stage = stage; + (void) osal_mutex_unlock(_usbh_mutex); + } +} + +TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const uint8_t setup_packet[8]) { + const uint8_t rhport = usbh_get_rhport(daddr); + const bool ret = hcd_setup_send(rhport, daddr, setup_packet); + if (!ret) { + _control_set_xfer_stage(CONTROL_STAGE_IDLE); + } + return ret; +} + +TU_ATTR_ALWAYS_INLINE static inline void usbh_device_close(uint8_t rhport, uint8_t daddr) { + hcd_device_close(rhport, daddr); + + // abort any ongoing control transfer + if (daddr == _usbh_data.ctrl_xfer_info.daddr) { + _control_set_xfer_stage(CONTROL_STAGE_IDLE); + } + + // invalidate if enumerating + if (daddr == _usbh_data.enumerating_daddr) { + _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; + } +} + //--------------------------------------------------------------------+ // Device API //--------------------------------------------------------------------+ - bool tuh_mounted(uint8_t dev_addr) { usbh_device_t *dev = get_device(dev_addr); TU_VERIFY(dev); @@ -530,16 +558,16 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { break; case HCD_EVENT_DEVICE_REMOVE: - TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); - process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port); - - #if CFG_TUH_HUB - // TODO remove - if (event.connection.hub_addr != 0 && event.connection.hub_port != 0) { - // done with hub, waiting for next data on status pipe - (void) hub_edpt_status_xfer(event.connection.hub_addr); + TU_LOG1("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); + if (_usbh_data.enumerating_daddr == 0 && + event.rhport == _usbh_data.dev0_bus.rhport && + event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr && + event.connection.hub_port == _usbh_data.dev0_bus.hub_port) { + // dev0 is unplugged while enumerating (not yet assigned an address) + usbh_device_close(_usbh_data.dev0_bus.rhport, 0); + } else { + process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port); } - #endif break; case HCD_EVENT_XFER_COMPLETE: { @@ -623,23 +651,6 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) { *((xfer_result_t*) xfer->user_data) = xfer->result; } -TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) { - if (_usbh_data.ctrl_xfer_info.stage != stage) { - (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); - _usbh_data.ctrl_xfer_info.stage = stage; - (void) osal_mutex_unlock(_usbh_mutex); - } -} - -TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const uint8_t setup_packet[8]) { - const uint8_t rhport = usbh_get_rhport(daddr); - const bool ret = hcd_setup_send(rhport, daddr, setup_packet); - if (!ret) { - _control_set_xfer_stage(CONTROL_STAGE_IDLE); - } - return ret; -} - // TODO timeout_ms is not supported yet bool tuh_control_xfer (tuh_xfer_t* xfer) { TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // EP0 with setup packet @@ -1270,21 +1281,8 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) { // a device unplugged from rhport:hub_addr:hub_port static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { - // if dev0 is unplugged while enumerating (not yet assigned an address) - if (_usbh_data.enumerating_daddr == 0) { - const tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus; - if ((rhport == dev0_bus->rhport) && (hub_addr == dev0_bus->hub_addr) && (hub_port == dev0_bus->hub_port)) { - hcd_device_close(dev0_bus->rhport, 0); - if (_usbh_data.ctrl_xfer_info.daddr == 0) { - _control_set_xfer_stage(CONTROL_STAGE_IDLE); - } - _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; - return; - } - } - - //------------- find the all devices (star-network) under port that is unplugged -------------// - uint32_t removing_hubs = 0; + // Find the all devices (star-network) under port that is unplugged + uint32_t removing_hubs_bm = 0; do { for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) { usbh_device_t* dev = &_usbh_devices[dev_id]; @@ -1298,7 +1296,7 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub if (is_hub_addr(daddr)) { TU_LOG_USBH(" is a HUB device %u\r\n", daddr); - removing_hubs |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX); + removing_hubs_bm |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX); } else { // Invoke callback before closing driver (maybe call it later ?) if (tuh_umount_cb) { @@ -1314,30 +1312,21 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub } } - hcd_device_close(rhport, daddr); + usbh_device_close(rhport, daddr); clear_device(dev); - - // abort ongoing control xfer on this device if any - if (daddr == _usbh_data.ctrl_xfer_info.daddr) { - _control_set_xfer_stage(CONTROL_STAGE_IDLE); - } - - if (daddr == _usbh_data.enumerating_daddr) { - _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; - } } } // if removing a hub, we need to remove all of its downstream devices #if CFG_TUH_HUB - if (removing_hubs == 0) { + if (removing_hubs_bm == 0) { break; } // find a marked hub to process for (uint8_t h_id = 0; h_id < CFG_TUH_HUB; h_id++) { - if (tu_bit_test(removing_hubs, h_id)) { - removing_hubs &= ~TU_BIT(h_id); + if (tu_bit_test(removing_hubs_bm, h_id)) { + removing_hubs_bm &= ~TU_BIT(h_id); // update hub_addr and hub_port for next loop hub_addr = h_id + 1 + CFG_TUH_DEVICE_MAX; @@ -1560,6 +1549,10 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_SET_ADDR: { + // Due to physical debouncing, some devices can cause multiple attaches (actually reset) without detach event + // Force remove currently mounted with the same bus info (rhport, hub addr, hub port) if exists + process_removed_device(dev0_bus->rhport, dev0_bus->hub_addr, dev0_bus->hub_port); + const tusb_desc_device_t *desc_device = (const tusb_desc_device_t *) _usbh_epbuf.ctrl; const uint8_t new_addr = enum_get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB); TU_ASSERT(new_addr != 0,); @@ -1582,7 +1575,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { new_dev->addressed = 1; _usbh_data.enumerating_daddr = new_addr; - hcd_device_close(dev0_bus->rhport, 0); // close dev0 + usbh_device_close(dev0_bus->rhport, 0); // close dev0 TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint From 809af3e74ca37495d6c385acd33a488c2984a093 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 May 2025 15:44:00 +0700 Subject: [PATCH 60/68] chore(usbh): change removing_hubs to array instead of bitmask --- .idea/debugServers/rt1064.xml | 2 +- src/host/usbh.c | 37 ++++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/.idea/debugServers/rt1064.xml b/.idea/debugServers/rt1064.xml index b908b59e2..4fb2fdf6a 100644 --- a/.idea/debugServers/rt1064.xml +++ b/.idea/debugServers/rt1064.xml @@ -1,5 +1,5 @@ - + diff --git a/src/host/usbh.c b/src/host/usbh.c index 92c254a9e..a3d79a105 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -299,6 +299,10 @@ TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) return &_usbh_devices[dev_addr-1]; } +TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) { + return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX); +} + TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event, bool in_isr) { TU_ASSERT(osal_queue_send(_usbh_q, event, in_isr)); tuh_event_hook_cb(event->rhport, event->event_id, in_isr); @@ -1274,15 +1278,13 @@ uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_i //--------------------------------------------------------------------+ // Detaching //--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) { - return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX); -} - // a device unplugged from rhport:hub_addr:hub_port static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { // Find the all devices (star-network) under port that is unplugged - uint32_t removing_hubs_bm = 0; + #if CFG_TUH_HUB + uint8_t removing_hubs[CFG_TUH_HUB] = { 0 }; + #endif + do { for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) { usbh_device_t* dev = &_usbh_devices[dev_id]; @@ -1294,10 +1296,13 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub (hub_port == 0 || dev->bus_info.hub_port == hub_port)) { TU_LOG_USBH("[%u:%u:%u] unplugged address = %u\r\n", rhport, hub_addr, hub_port, daddr); + #if CFG_TUH_HUB if (is_hub_addr(daddr)) { TU_LOG_USBH(" is a HUB device %u\r\n", daddr); - removing_hubs_bm |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX); - } else { + removing_hubs[dev_id - CFG_TUH_DEVICE_MAX] = 1; + } else + #endif + { // Invoke callback before closing driver (maybe call it later ?) if (tuh_umount_cb) { tuh_umount_cb(daddr); @@ -1317,16 +1322,16 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub } } - // if removing a hub, we need to remove all of its downstream devices - #if CFG_TUH_HUB - if (removing_hubs_bm == 0) { +#if CFG_TUH_HUB + // if a hub is removed, we need to remove all of its downstream devices + if (tu_mem_is_zero(removing_hubs, CFG_TUH_HUB)) { break; } // find a marked hub to process for (uint8_t h_id = 0; h_id < CFG_TUH_HUB; h_id++) { - if (tu_bit_test(removing_hubs_bm, h_id)) { - removing_hubs_bm &= ~TU_BIT(h_id); + if (removing_hubs[h_id]) { + removing_hubs[h_id] = 0; // update hub_addr and hub_port for next loop hub_addr = h_id + 1 + CFG_TUH_DEVICE_MAX; @@ -1334,10 +1339,10 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub break; } } - #else - (void) removing_hubs; +#else break; - #endif +#endif + } while(1); } From fb2214dea63daa8d9f44ac2a6df5835d8eabba80 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 May 2025 16:30:34 +0700 Subject: [PATCH 61/68] move hil into build workflow --- .github/workflows/build.yml | 132 ++++++++++++++++++++++++++++++++- .github/workflows/hil_test.yml | 128 -------------------------------- 2 files changed, 130 insertions(+), 130 deletions(-) delete mode 100644 .github/workflows/hil_test.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 17d578e4d..3406fb3c2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,8 +8,8 @@ on: - 'examples/**' - 'lib/**' - 'hw/**' - - 'tools/get_deps.py' - 'tools/build.py' + - 'tools/get_deps.py' - '.github/actions/**' - '.github/workflows/build.yml' - '.github/workflows/build_util.yml' @@ -21,8 +21,9 @@ on: - 'examples/**' - 'lib/**' - 'hw/**' - - 'tools/get_deps.py' + - 'test/hil/**' - 'tools/build.py' + - 'tools/get_deps.py' - '.github/actions/**' - '.github/workflows/build.yml' - '.github/workflows/build_util.yml' @@ -31,7 +32,15 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + HIL_JSON: test/hil/tinyusb.json + jobs: + # --------------------------------------- + # + # Build + # + # --------------------------------------- set-matrix: runs-on: ubuntu-latest outputs: @@ -151,3 +160,122 @@ jobs: run: | west build -b pca10056 -d examples/device/cdc_msc/build examples/device/cdc_msc -- -DRTOS=zephyr west build -b pca10056 -d examples/device/msc_dual_lun/build examples/device/msc_dual_lun -- -DRTOS=zephyr + + # --------------------------------------- + # + # Hardware in the loop (HIL) + # Run on PR only (hil-tinyusb), hil-hfp only run on non-forked PR + # --------------------------------------- + hil-set-matrix: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' + outputs: + json: ${{ steps.set-matrix-json.outputs.matrix }} + steps: + - name: Checkout TinyUSB + uses: actions/checkout@v4 + + - name: Generate matrix json + id: set-matrix-json + run: | + MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py ${{ env.HIL_JSON }}) + echo "matrix=$MATRIX_JSON" + echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT + + # --------------------------------------- + # Build arm-gcc + # --------------------------------------- + hil-build: + if: | + github.repository_owner == 'hathach' && + (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') + needs: hil-set-matrix + uses: ./.github/workflows/build_util.yml + strategy: + fail-fast: false + matrix: + toolchain: + - 'arm-gcc' + - 'esp-idf' + with: + build-system: 'cmake' + toolchain: ${{ matrix.toolchain }} + build-args: ${{ toJSON(fromJSON(needs.hil-set-matrix.outputs.json)[matrix.toolchain]) }} + one-per-family: true + upload-artifacts: true + + # --------------------------------------- + # Hardware in the loop (HIL) + # self-hosted on local VM, for attached hardware checkout HIL_JSON + # --------------------------------------- + hil-tinyusb: + if: | + github.repository_owner == 'hathach' && + (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') + needs: hil-build + runs-on: [self-hosted, X64, hathach, hardware-in-the-loop] + steps: + - name: Clean workspace + run: | + echo "Cleaning up previous run" + rm -rf "${{ github.workspace }}" + mkdir -p "${{ github.workspace }}" + + - name: Checkout TinyUSB + uses: actions/checkout@v4 + with: + sparse-checkout: test/hil + + - name: Download Artifacts + uses: actions/download-artifact@v4 + with: + path: cmake-build + merge-multiple: true + + - name: Test on actual hardware + run: | + ls cmake-build/ + python3 test/hil/hil_test.py ${{ env.HIL_JSON }} + + # --------------------------------------- + # Hardware in the loop (HIL) + # self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json + # Since IAR Token secret is not passed to forked PR, only build non-forked PR + # --------------------------------------- + hil-hfp: + if: | + github.repository_owner == 'hathach' && + github.event.pull_request.head.repo.fork == false && + (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') + runs-on: [self-hosted, Linux, X64, hifiphile] + env: + IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} + steps: + - name: Clean workspace + run: | + echo "Cleaning up previous run" + rm -rf "${{ github.workspace }}" + mkdir -p "${{ github.workspace }}" + + - name: Toolchain version + run: | + iccarm --version + + - name: Checkout TinyUSB + uses: actions/checkout@v4 + + - name: Get build boards + run: | + MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py test/hil/hfp.json) + BUILD_ARGS=$(echo $MATRIX_JSON | jq -r '.["arm-gcc"] | join(" ")') + echo "BUILD_ARGS=$BUILD_ARGS" + echo "BUILD_ARGS=$BUILD_ARGS" >> $GITHUB_ENV + + - name: Get Dependencies + run: python3 tools/get_deps.py $BUILD_ARGS + + - name: Build + run: python3 tools/build.py --toolchain iar $BUILD_ARGS + + - name: Test on actual hardware (hardware in the loop) + run: python3 test/hil/hil_test.py hfp.json diff --git a/.github/workflows/hil_test.yml b/.github/workflows/hil_test.yml deleted file mode 100644 index 0ad37ffce..000000000 --- a/.github/workflows/hil_test.yml +++ /dev/null @@ -1,128 +0,0 @@ -name: Hardware Test - -on: - workflow_dispatch: - pull_request: - branches: [ master ] - paths: - - 'src/**' - - 'examples/**' - - 'lib/**' - - 'hw/**' - - 'test/hil/**' - - 'tools/get_deps.py' - - '.github/actions/**' - - '.github/workflows/hil_test.yml' -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - HIL_JSON: test/hil/tinyusb.json - -jobs: - set-matrix: - runs-on: ubuntu-latest - outputs: - json: ${{ steps.set-matrix-json.outputs.matrix }} - steps: - - name: Checkout TinyUSB - uses: actions/checkout@v4 - - - name: Generate matrix json - id: set-matrix-json - run: | - MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py ${{ env.HIL_JSON }}) - echo "matrix=$MATRIX_JSON" - echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT - - # --------------------------------------- - # Build arm-gcc - # --------------------------------------- - build: - if: github.repository_owner == 'hathach' - needs: set-matrix - uses: ./.github/workflows/build_util.yml - strategy: - fail-fast: false - matrix: - toolchain: - - 'arm-gcc' - - 'esp-idf' - with: - build-system: 'cmake' - toolchain: ${{ matrix.toolchain }} - build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }} - one-per-family: true - upload-artifacts: true - - # --------------------------------------- - # Hardware in the loop (HIL) - # self-hosted on local VM, for attached hardware checkout HIL_JSON - # --------------------------------------- - hil-tinyusb: - if: github.repository_owner == 'hathach' - needs: build - runs-on: [self-hosted, X64, hathach, hardware-in-the-loop] - steps: - - name: Clean workspace - run: | - echo "Cleaning up previous run" - rm -rf "${{ github.workspace }}" - mkdir -p "${{ github.workspace }}" - - - name: Checkout TinyUSB - uses: actions/checkout@v4 - with: - sparse-checkout: test/hil - - - name: Download Artifacts - uses: actions/download-artifact@v4 - with: - path: cmake-build - merge-multiple: true - - - name: Test on actual hardware - run: | - ls cmake-build/ - python3 test/hil/hil_test.py ${{ env.HIL_JSON }} - - # --------------------------------------- - # Hardware in the loop (HIL) - # self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json - # Since IAR Token secret is not passed to forked PR, only build non-forked PR - # --------------------------------------- - hil-hfp: - if: github.repository_owner == 'hathach' && github.event.pull_request.head.repo.fork == false - runs-on: [self-hosted, Linux, X64, hifiphile] - env: - IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} - steps: - - name: Clean workspace - run: | - echo "Cleaning up previous run" - rm -rf "${{ github.workspace }}" - mkdir -p "${{ github.workspace }}" - - - name: Toolchain version - run: | - iccarm --version - - - name: Checkout TinyUSB - uses: actions/checkout@v4 - - - name: Get build boards - run: | - MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py test/hil/hfp.json) - BUILD_ARGS=$(echo $MATRIX_JSON | jq -r '.["arm-gcc"] | join(" ")') - echo "BUILD_ARGS=$BUILD_ARGS" - echo "BUILD_ARGS=$BUILD_ARGS" >> $GITHUB_ENV - - - name: Get Dependencies - run: python3 tools/get_deps.py $BUILD_ARGS - - - name: Build - run: python3 tools/build.py --toolchain iar $BUILD_ARGS - - - name: Test on actual hardware (hardware in the loop) - run: python3 test/hil/hil_test.py hfp.json From a05fc504615edb6db2519baf97382902a9e0a60c Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 May 2025 18:01:30 +0700 Subject: [PATCH 62/68] clean up ci --- .github/workflows/build.yml | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3406fb3c2..28447cc80 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,6 +45,7 @@ jobs: runs-on: ubuntu-latest outputs: json: ${{ steps.set-matrix-json.outputs.matrix }} + hil_json: ${{ steps.set-matrix-json.outputs.hil_matrix }} steps: - name: Checkout TinyUSB uses: actions/checkout@v4 @@ -52,9 +53,14 @@ jobs: - name: Generate matrix json id: set-matrix-json run: | + # build matrix MATRIX_JSON=$(python .github/workflows/ci_set_matrix.py) echo "matrix=$MATRIX_JSON" echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT + # hil matrix + HIL_MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py ${{ env.HIL_JSON }}) + echo "hil_matrix=$HIL_MATRIX_JSON" + echo "hil_matrix=$HIL_MATRIX_JSON" >> $GITHUB_OUTPUT # --------------------------------------- # Build CMake @@ -166,21 +172,6 @@ jobs: # Hardware in the loop (HIL) # Run on PR only (hil-tinyusb), hil-hfp only run on non-forked PR # --------------------------------------- - hil-set-matrix: - runs-on: ubuntu-latest - if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' - outputs: - json: ${{ steps.set-matrix-json.outputs.matrix }} - steps: - - name: Checkout TinyUSB - uses: actions/checkout@v4 - - - name: Generate matrix json - id: set-matrix-json - run: | - MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py ${{ env.HIL_JSON }}) - echo "matrix=$MATRIX_JSON" - echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT # --------------------------------------- # Build arm-gcc @@ -189,7 +180,7 @@ jobs: if: | github.repository_owner == 'hathach' && (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') - needs: hil-set-matrix + needs: set-matrix uses: ./.github/workflows/build_util.yml strategy: fail-fast: false @@ -200,7 +191,7 @@ jobs: with: build-system: 'cmake' toolchain: ${{ matrix.toolchain }} - build-args: ${{ toJSON(fromJSON(needs.hil-set-matrix.outputs.json)[matrix.toolchain]) }} + build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.hil_json)[matrix.toolchain]) }} one-per-family: true upload-artifacts: true @@ -254,7 +245,7 @@ jobs: - name: Clean workspace run: | echo "Cleaning up previous run" - rm -rf "${{ github.workspace }}" + rm -rf "${{ github.workspace }}"3 mkdir -p "${{ github.workspace }}" - name: Toolchain version From 228b2dec1c29de2db531cc4eff98444b4221ca46 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 12 May 2025 15:40:58 +0700 Subject: [PATCH 63/68] bump ci to gcc 14 --- .github/actions/setup_toolchain/action.yml | 2 +- .github/actions/setup_toolchain/toolchain.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup_toolchain/action.yml b/.github/actions/setup_toolchain/action.yml index 850a3a06f..6fd5c9d4e 100644 --- a/.github/actions/setup_toolchain/action.yml +++ b/.github/actions/setup_toolchain/action.yml @@ -17,7 +17,7 @@ runs: if: inputs.toolchain == 'arm-gcc' uses: carlosperate/arm-none-eabi-gcc-action@v1 with: - release: '13.2.Rel1' + release: '14.2.Rel1' - name: Pull ESP-IDF docker if: inputs.toolchain == 'esp-idf' diff --git a/.github/actions/setup_toolchain/toolchain.json b/.github/actions/setup_toolchain/toolchain.json index 4e65f1cbe..ea07ca344 100644 --- a/.github/actions/setup_toolchain/toolchain.json +++ b/.github/actions/setup_toolchain/toolchain.json @@ -1,7 +1,7 @@ { "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz", "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz", - "arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v13.2.1-1.1/xpack-arm-none-eabi-gcc-13.2.1-1.1-linux-x64.tar.gz", + "arm-gcc": "https://github.com/xpack-dev-tools/gcc-xpack/releases/download/v14.2.0-1/xpack-gcc-14.2.0-1-linux-x64.tar.gz", "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2", "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz", "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run", From baf67539fc2d328a6274c35c18c90da27c37bc60 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 13 May 2025 10:28:42 +0700 Subject: [PATCH 64/68] fix warnings, minor clean up --- .../actions/setup_toolchain/toolchain.json | 2 +- examples/host/cdc_msc_hid/src/hid_app.c | 100 ++++++------------ src/class/cdc/cdc_host.c | 2 +- src/class/hid/hid_host.c | 6 +- src/host/hub.c | 1 - src/host/usbh.c | 5 +- 6 files changed, 41 insertions(+), 75 deletions(-) diff --git a/.github/actions/setup_toolchain/toolchain.json b/.github/actions/setup_toolchain/toolchain.json index ea07ca344..f7123ef11 100644 --- a/.github/actions/setup_toolchain/toolchain.json +++ b/.github/actions/setup_toolchain/toolchain.json @@ -1,7 +1,7 @@ { "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz", "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz", - "arm-gcc": "https://github.com/xpack-dev-tools/gcc-xpack/releases/download/v14.2.0-1/xpack-gcc-14.2.0-1-linux-x64.tar.gz", + "arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v14.2.1-1.1/xpack-arm-none-eabi-gcc-14.2.1-1.1-linux-x64.tar.gz", "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2", "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz", "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run", diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index a751c9c80..6f01d6f45 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -29,14 +29,9 @@ //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ +#define MAX_REPORT 4 -// If your host terminal support ansi escape code such as TeraTerm -// it can be use to simulate mouse cursor movement within terminal -#define USE_ANSI_ESCAPE 0 - -#define MAX_REPORT 4 - -static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII }; +static uint8_t const keycode2ascii[128][2] = {HID_KEYCODE_TO_ASCII}; // Each HID instance can has multiple reports static struct { @@ -45,8 +40,8 @@ static struct { } hid_info[CFG_TUH_HID]; static void process_kbd_report(hid_keyboard_report_t const *report); -static void process_mouse_report(hid_mouse_report_t const * report); -static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); +static void process_mouse_report(hid_mouse_report_t const *report); +static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len); void hid_app_task(void) { // nothing to do @@ -70,7 +65,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]); - // By default host stack will use activate boot protocol on supported interface. + // By default, host stack will use boot protocol on supported interface. // Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser) if (itf_protocol == HID_ITF_PROTOCOL_NONE) { hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len); @@ -121,7 +116,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons //--------------------------------------------------------------------+ // look up new key in previous keys -static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8_t keycode) { +static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode) { for (uint8_t i = 0; i < 6; i++) { if (report->keycode[i] == keycode) { return true; @@ -130,28 +125,25 @@ static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8 return false; } -static void process_kbd_report(hid_keyboard_report_t const *report) -{ - static hid_keyboard_report_t prev_report = { 0, 0, {0} }; // previous report to check key released +static void process_kbd_report(hid_keyboard_report_t const *report) { + static hid_keyboard_report_t prev_report = {0, 0, {0}};// previous report to check key released //------------- example code ignore control (non-printable) key affects -------------// - for(uint8_t i=0; i<6; i++) - { - if ( report->keycode[i] ) - { - if ( find_key_in_report(&prev_report, report->keycode[i]) ) - { + for (uint8_t i = 0; i < 6; i++) { + if (report->keycode[i]) { + if (find_key_in_report(&prev_report, report->keycode[i])) { // exist in previous report means the current key is holding - }else - { + } else { // not existed in previous report means the current key is pressed bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT); uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0]; putchar(ch); - if ( ch == '\r' ) putchar('\n'); // added new line for enter key + if (ch == '\r') { + putchar('\n'); + } - #ifndef __ICCARM__ // TODO IAR doesn't support stream control ? - fflush(stdout); // flush right away, else nanolib will wait for newline + #ifndef __ICCARM__ // TODO IAR doesn't support stream control ? + fflush(stdout);// flush right away, else nanolib will wait for newline #endif } } @@ -166,55 +158,22 @@ static void process_kbd_report(hid_keyboard_report_t const *report) //--------------------------------------------------------------------+ static void cursor_movement(int8_t x, int8_t y, int8_t wheel) { -#if USE_ANSI_ESCAPE - // Move X using ansi escape - if ( x < 0) - { - printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left - }else if ( x > 0) - { - printf(ANSI_CURSOR_FORWARD(%d), x); // move right - } - - // Move Y using ansi escape - if ( y < 0) - { - printf(ANSI_CURSOR_UP(%d), (-y)); // move up - }else if ( y > 0) - { - printf(ANSI_CURSOR_DOWN(%d), y); // move down - } - - // Scroll using ansi escape - if (wheel < 0) - { - printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up - }else if (wheel > 0) - { - printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down - } - - printf("\r\n"); -#else printf("(%d %d %d)\r\n", x, y, wheel); -#endif } -static void process_mouse_report(hid_mouse_report_t const * report) -{ - static hid_mouse_report_t prev_report = { 0 }; +static void process_mouse_report(hid_mouse_report_t const *report) { + static hid_mouse_report_t prev_report = {0}; - //------------- button state -------------// + // button state uint8_t button_changed_mask = report->buttons ^ prev_report.buttons; - if ( button_changed_mask & report->buttons) - { + if (button_changed_mask & report->buttons) { printf(" %c%c%c ", - report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-', - report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-', - report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-'); + report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-', + report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-', + report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-'); } - //------------- cursor movement -------------// + // cursor movement cursor_movement(report->x, report->y, report->wheel); } @@ -263,18 +222,23 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c if (rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP) { switch (rpt_info->usage) { case HID_USAGE_DESKTOP_KEYBOARD: - TU_LOG1("HID receive keyboard report\r\n"); + TU_LOG2("HID receive keyboard report\r\n"); // Assume keyboard follow boot report layout process_kbd_report((hid_keyboard_report_t const *) report); break; case HID_USAGE_DESKTOP_MOUSE: - TU_LOG1("HID receive mouse report\r\n"); + TU_LOG2("HID receive mouse report\r\n"); // Assume mouse follow boot report layout process_mouse_report((hid_mouse_report_t const *) report); break; default: + printf("report[%u] ", rpt_info->report_id); + for (uint8_t i = 0; i < len; i++) { + printf("%02X ", report[i]); + } + printf("\r\n"); break; } } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4058857c5..bf245db3f 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -672,7 +672,7 @@ void cdch_close(uint8_t daddr) { bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { // TODO handle stall response, retry failed transfer ... - TU_ASSERT(event == XFER_RESULT_SUCCESS); + TU_VERIFY(event == XFER_RESULT_SUCCESS); uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); cdch_interface_t * p_cdc = get_itf(idx); diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index a3cc7d6d7..57e437196 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -444,7 +444,7 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t hidh_epbuf_t* epbuf = get_hid_epbuf(idx); if (dir == TUSB_DIR_IN) { - TU_LOG_DRV(" Get Report callback (%u, %u)\r\n", daddr, idx); + TU_LOG_DRV(" [idx=%u] Get Report callback\r\n", idx); TU_LOG3_MEM(epbuf->epin, xferred_bytes, 2); tuh_hid_report_received_cb(daddr, idx, epbuf->epin, (uint16_t) xferred_bytes); } else { @@ -461,7 +461,9 @@ void hidh_close(uint8_t daddr) { hidh_interface_t* p_hid = &_hidh_itf[i]; if (p_hid->daddr == daddr) { TU_LOG_DRV(" HIDh close addr = %u index = %u\r\n", daddr, i); - if (tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i); + if (tuh_hid_umount_cb) { + tuh_hid_umount_cb(daddr, i); + } tu_memclr(p_hid, sizeof(hidh_interface_t)); } } diff --git a/src/host/hub.c b/src/host/hub.c index 0ed0e0c42..0b172a596 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -201,7 +201,6 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, bool hub_port_get_status_local(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp) { (void) hub_port; - TU_VERIFY(hub_addr > CFG_TUH_DEVICE_MAX); hub_interface_t* p_hub = get_hub_itf(hub_addr); *resp = p_hub->port_status; return true; diff --git a/src/host/usbh.c b/src/host/usbh.c index a3d79a105..8ab1402dc 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -579,7 +579,8 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr); - TU_LOG_USBH("on EP %02X with %u bytes: %s\r\n", ep_addr, (unsigned int) event.xfer_complete.len, tu_str_xfer_result[event.xfer_complete.result]); + TU_LOG_USBH("[:%u] on EP %02X with %u bytes: %s\r\n", + event.dev_addr, ep_addr, (unsigned int) event.xfer_complete.len, tu_str_xfer_result[event.xfer_complete.result]); if (event.dev_addr == 0) { // device 0 only has control endpoint @@ -618,7 +619,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { uint8_t drv_id = dev->ep2drv[epnum][ep_dir]; usbh_class_driver_t const* driver = get_driver(drv_id); if (driver) { - TU_LOG_USBH("%s xfer callback\r\n", driver->name); + TU_LOG_USBH(" %s xfer callback\r\n", driver->name); driver->xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len); } else { From ed087b9ed83814e81d303c956de1541e9a82bb47 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 13 May 2025 16:13:50 +0700 Subject: [PATCH 65/68] pump up pico-pio-usb and cmsis_device_wb --- tools/get_deps.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/get_deps.py b/tools/get_deps.py index d89c1b2b1..1f46a8e05 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -59,7 +59,7 @@ deps_optional = { '144f1eb7ea8c06512e12f12b27383601c0272410', 'kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt'], 'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/hathach/Pico-PIO-USB.git', - '810653f66adadba3e0e4b4b56d5167ac4f7fdbf7', + 'd15f0c62ac22348a8708e1626525fdba9466e1ee', 'rp2040'], 'hw/mcu/renesas/fsp': ['https://github.com/renesas/fsp.git', 'edcc97d684b6f716728a60d7a6fea049d9870bd6', @@ -122,7 +122,7 @@ deps_optional = { '5ad9797c54ec3e55eff770fc9b3cd4a1aefc1309', 'stm32u5'], 'hw/mcu/st/cmsis_device_wb': ['https://github.com/STMicroelectronics/cmsis_device_wb.git', - '9c5d1920dd9fabbe2548e10561d63db829bb744f', + 'd6a7fa2e7de084f5e5e47f2ab88b022fe9b50e5a', 'stm32wb'], 'hw/mcu/st/stm32-mfxstm32l152': ['https://github.com/STMicroelectronics/stm32-mfxstm32l152.git', '7f4389efee9c6a655b55e5df3fceef5586b35f9b', From fe4446090e5ab872faa973cae55839cf6929bf7e Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 13 May 2025 16:27:26 +0700 Subject: [PATCH 66/68] fix dual example for rp2350 conflict printf and cdc_printf --- .../dual/host_hid_to_device_cdc/src/main.c | 8 +++- .../dual/host_info_to_device_cdc/src/main.c | 44 ++++++++++--------- src/host/usbh.c | 6 +-- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/examples/dual/host_hid_to_device_cdc/src/main.c b/examples/dual/host_hid_to_device_cdc/src/main.c index 633f7a6ac..6f30ca381 100644 --- a/examples/dual/host_hid_to_device_cdc/src/main.c +++ b/examples/dual/host_hid_to_device_cdc/src/main.c @@ -190,7 +190,9 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { // look up new key in previous keys static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8_t keycode) { for (uint8_t i = 0; i < 6; i++) { - if (report->keycode[i] == keycode) return true; + if (report->keycode[i] == keycode) { + return true; + } } return false; @@ -230,7 +232,9 @@ static void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const* re // TODO example skips key released } - if (flush) tud_cdc_write_flush(); + if (flush) { + tud_cdc_write_flush(); + } prev_report = *report; } diff --git a/examples/dual/host_info_to_device_cdc/src/main.c b/examples/dual/host_info_to_device_cdc/src/main.c index 7e593f234..82a48fc61 100644 --- a/examples/dual/host_info_to_device_cdc/src/main.c +++ b/examples/dual/host_info_to_device_cdc/src/main.c @@ -78,6 +78,22 @@ static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_devi void led_blinking_task(void); void cdc_task(void); +#define cdc_printf(...) \ + do { \ + char _tempbuf[256]; \ + char* _bufptr = _tempbuf; \ + uint32_t count = (uint32_t) sprintf(_tempbuf, __VA_ARGS__); \ + while (count > 0) { \ + uint32_t wr_count = tud_cdc_write(_bufptr, count); \ + count -= wr_count; \ + _bufptr += wr_count; \ + if (count > 0){ \ + tud_task(); \ + tud_cdc_write_flush(); \ + } \ + } \ + } while(0) + /*------------- MAIN -------------*/ int main(void) { board_init(); @@ -160,22 +176,6 @@ void cdc_task(void) { //--------------------------------------------------------------------+ // Host Get device information //--------------------------------------------------------------------+ -#define cdc_printf(...) \ - do { \ - char _tempbuf[256]; \ - char* _bufptr = _tempbuf; \ - uint32_t count = (uint32_t) sprintf(_tempbuf, __VA_ARGS__); \ - while (count > 0) { \ - uint32_t wr_count = tud_cdc_write(_bufptr, count); \ - count -= wr_count; \ - _bufptr += wr_count; \ - if (count > 0){ \ - tud_task();\ - tud_cdc_write_flush(); \ - } \ - } \ - } while(0) - static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_device) { // Get String descriptor using Sync API uint16_t serial[64]; @@ -232,12 +232,12 @@ void tuh_enum_descriptor_device_cb(uint8_t daddr, tusb_desc_device_t const* desc } void tuh_mount_cb(uint8_t daddr) { - printf("mounted device %u\r\n", daddr); + cdc_printf("mounted device %u\r\n", daddr); is_print[daddr] = true; } void tuh_umount_cb(uint8_t daddr) { - printf("unmounted device %u\r\n", daddr); + cdc_printf("unmounted device %u\r\n", daddr); is_print[daddr] = false; } @@ -249,7 +249,9 @@ void led_blinking_task(void) { static bool led_state = false; // Blink every interval ms - if (board_millis() - start_ms < blink_interval_ms) return; // not enough time + if (board_millis() - start_ms < blink_interval_ms) { + return;// not enough time + } start_ms += blink_interval_ms; board_led_write(led_state); @@ -300,7 +302,9 @@ static int _count_utf8_bytes(const uint16_t *buf, size_t len) { } static void print_utf16(uint16_t *temp_buf, size_t buf_len) { - if ((temp_buf[0] & 0xff) == 0) return; // empty + if ((temp_buf[0] & 0xff) == 0) { + return;// empty + } size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t); size_t utf8_len = (size_t) _count_utf8_bytes(temp_buf + 1, utf16_len); _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len); diff --git a/src/host/usbh.c b/src/host/usbh.c index 8ab1402dc..b7d5a05f2 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -547,7 +547,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { // TODO better to have an separated queue for newly attached devices if (_usbh_data.enumerating_daddr == TUSB_INDEX_INVALID_8) { // New device attached and we are ready - TU_LOG1("[%u:] USBH Device Attach\r\n", event.rhport); + TU_LOG_USBH("[%u:] USBH Device Attach\r\n", event.rhport); _usbh_data.enumerating_daddr = 0; // enumerate new device with address 0 enum_new_device(&event); } else { @@ -562,7 +562,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { break; case HCD_EVENT_DEVICE_REMOVE: - TU_LOG1("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); + TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); if (_usbh_data.enumerating_daddr == 0 && event.rhport == _usbh_data.dev0_bus.rhport && event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr && @@ -1464,7 +1464,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { bool retry = (_usbh_data.enumerating_daddr != TUSB_INDEX_INVALID_8) && (failed_count < ATTEMPT_COUNT_MAX); if (retry) { tusb_time_delay_ms_api(ATTEMPT_DELAY_MS); // delay a bit - TU_LOG1("Enumeration attempt %u/%u\r\n", failed_count+1, ATTEMPT_COUNT_MAX); + TU_LOG_USBH("Enumeration attempt %u/%u\r\n", failed_count+1, ATTEMPT_COUNT_MAX); retry = tuh_control_xfer(xfer); } From 0ebc91ec97d27c719f14708ea97053b2d46f0eed Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 14 May 2025 15:28:29 +0700 Subject: [PATCH 67/68] update stm32wb linker to match new startup --- .../dual/host_info_to_device_cdc/src/main.c | 2 + .../stm32wb55nucleo/stm32wb55xx_flash_cm4.ld | 45 ++++++++++++------- hw/bsp/stm32wb/family.c | 5 +-- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/examples/dual/host_info_to_device_cdc/src/main.c b/examples/dual/host_info_to_device_cdc/src/main.c index 82a48fc61..a2a505952 100644 --- a/examples/dual/host_info_to_device_cdc/src/main.c +++ b/examples/dual/host_info_to_device_cdc/src/main.c @@ -233,11 +233,13 @@ void tuh_enum_descriptor_device_cb(uint8_t daddr, tusb_desc_device_t const* desc void tuh_mount_cb(uint8_t daddr) { cdc_printf("mounted device %u\r\n", daddr); + tud_cdc_write_flush(); is_print[daddr] = true; } void tuh_umount_cb(uint8_t daddr) { cdc_printf("unmounted device %u\r\n", daddr); + tud_cdc_write_flush(); is_print[daddr] = false; } diff --git a/hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld b/hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld index 916f11866..c16235586 100644 --- a/hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld +++ b/hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld @@ -3,21 +3,26 @@ ** ** File : stm32wb55xx_flash_cm4.ld ** -** Abstract : System Workbench Minimal System calls file +** Author : STM32CubeIDE ** -** For more information about which c-functions -** need which of these lowlevel functions -** please consult the Newlib libc-manual +** Abstract : Linker script for STM32WB55xx Device +** 1024Kbytes FLASH +** 128Kbytes RAM ** -** Environment : System Workbench for MCU +** Set heap size, stack size and stack location according +** to application requirements. ** -** Distribution: The file is distributed “as is,” without any warranty +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed as is without any warranty ** of any kind. ** ***************************************************************************** ** @attention ** -** Copyright (c) 2019 STMicroelectronics. +** Copyright (c) 2019-2022 STMicroelectronics. ** All rights reserved. ** ** This software is licensed under terms that can be found in the LICENSE file @@ -33,7 +38,7 @@ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _estack = 0x20030000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ -_Min_Heap_Size = 0x400; /* required amount of heap */ +_Min_Heap_Size = 0x400; /* required amount of heap */ _Min_Stack_Size = 0x1000; /* required amount of stack */ /* Specify the memory areas */ @@ -81,14 +86,17 @@ SECTIONS . = ALIGN(4); } >FLASH - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } >FLASH .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } >FLASH - .preinit_array : + .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array*)) @@ -124,7 +132,6 @@ SECTIONS _edata = .; /* define a global symbol at data end */ } >RAM1 AT> FLASH - /* Uninitialized data section */ . = ALIGN(4); .bss : @@ -152,8 +159,6 @@ SECTIONS . = ALIGN(8); } >RAM1 - - /* Remove information from the standard libraries */ /DISCARD/ : { @@ -163,7 +168,15 @@ SECTIONS } .ARM.attributes 0 : { *(.ARM.attributes) } - MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED - MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED - MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED + + /* used by the startup to initialize .MB_MEM2 data */ + _siMB_MEM2 = LOADADDR(.MB_MEM2); + .MB_MEM2 : + { + _sMB_MEM2 = . ; + *(MB_MEM2) ; + _eMB_MEM2 = . ; + } >RAM_SHARED AT> FLASH } diff --git a/hw/bsp/stm32wb/family.c b/hw/bsp/stm32wb/family.c index ba37b7cc3..93aba02fa 100644 --- a/hw/bsp/stm32wb/family.c +++ b/hw/bsp/stm32wb/family.c @@ -184,8 +184,7 @@ void HardFault_Handler(void) { asm("bkpt 1"); } -// Required by __libc_init_array in startup code if we are compiling using -// -nostdlib/-nostartfiles. +// Required by __libc_init_array in startup code if we are compiling using -nostdlib/-nostartfiles. +void _init(void); void _init(void) { - } From 38e5a67461cf7c819e845a110ef67184c2becbe4 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 15 May 2025 10:27:00 +0700 Subject: [PATCH 68/68] bump up pio-usb and codeql version --- .github/workflows/codeql.yml | 6 +++--- tools/get_deps.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index be4c2dd87..a22c65c79 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -66,7 +66,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -93,7 +93,7 @@ jobs: ./.github/workflows/codeql-buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" upload: false @@ -129,7 +129,7 @@ jobs: sarif_file: ${{ steps.step1.outputs.sarif-output }} category: "/language:${{matrix.language}}" - - name: Archive CodeQL results + - name: Upload CodeQL results as an artifact uses: actions/upload-artifact@v4 with: name: codeql-results diff --git a/tools/get_deps.py b/tools/get_deps.py index 1f46a8e05..df8dbb6e1 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -59,7 +59,7 @@ deps_optional = { '144f1eb7ea8c06512e12f12b27383601c0272410', 'kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt'], 'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/hathach/Pico-PIO-USB.git', - 'd15f0c62ac22348a8708e1626525fdba9466e1ee', + '032a469e79f6a4ba40760d7868e6db26e15002d7', 'rp2040'], 'hw/mcu/renesas/fsp': ['https://github.com/renesas/fsp.git', 'edcc97d684b6f716728a60d7a6fea049d9870bd6',