From 73e787ae418df76b79ac0fd31bb0674a72e68c88 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 12 Aug 2026 20:40:15 +0930 Subject: ohci: fix double allocation of dummy TDs in gtd_find_free --- src/portable/ohci/ohci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index e2c5956b3..a294c5f5f 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -400,6 +400,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { static ohci_gtd_t* gtd_find_free(void) { for (uint8_t i = 0; i < GTD_MAX; i++) { if (!ohci_data.gtd_pool[i].used) { + ohci_data.gtd_pool[i].used = 1; return &ohci_data.gtd_pool[i]; } } -- cgit v1.3.1 From 18bb2d650404432d0c6c61c26e98c7074f46ec6b Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 12 Aug 2026 21:49:00 +0930 Subject: ohci: reclaim orphaned TDs on device disconnect --- src/portable/ohci/ohci.c | 77 ++++++++++++++++++++++++++++++++++++++++++++---- src/portable/ohci/ohci.h | 3 +- 2 files changed, 73 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index a294c5f5f..7ede1ac72 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -378,7 +378,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { ohci_ed_t* p_prev = p_head; while (p_prev->next) { - ohci_ed_t* ed = (ohci_ed_t*)_virt_addr((void*)p_prev->next); + ohci_ed_t* ed = hcd_dcache_uncached((ohci_ed_t*)_virt_addr((void*)p_prev->next)); if (ed->w0.dev_addr == dev_addr) { // Prevent Host Controller from processing this ED while we remove it @@ -387,12 +387,24 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { // unlink ed, will also move up p_prev p_prev->next = ed->next; - // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED - ed->next = (uint32_t)_phys_addr(p_head); - ed->w0.used = 0; - ed->w0.skip = 0; + // Control endpoints (EP number 0) are statically allocated with the device which are only reused + // after connection of another device long after HC has finished with them now, these can be freed immediately. + if (ed->w0.ep_number != 0) { + ed->w0.is_reclaiming = 1; + + // 5.2.7.1.2 Removing. Disable list processing for bulk + if (p_head == p_ed_head[TUSB_XFER_BULK]) { + OHCI_REG->control &= ~OHCI_CONTROL_LIST_BULK_ENABLE_MASK; + } + + // Temporarily enable SOF IRQ. ED and TD Memory will be reclaimed in the SOF IRQ. + OHCI_REG->interrupt_enable = OHCI_INT_SOF_MASK; + } else { + ed->w0.used = 0; + ed->w0.skip = 0; + } } else { - p_prev = (ohci_ed_t*)_virt_addr((void*)p_prev->next); + p_prev = ed; } } } @@ -653,6 +665,59 @@ void hcd_int_handler(uint8_t hostid, bool in_isr) { // Disable MIE as per OHCI spec 5.3 OHCI_REG->interrupt_disable = OHCI_INT_MASTER_ENABLE_MASK; + // Start of frame (SOF) + if (int_status & OHCI_INT_SOF_MASK) { + OHCI_REG->interrupt_disable = OHCI_INT_SOF_MASK; + + bool re_enable_lists = false; + + for (size_t i = 0; i < ED_MAX; i++) { + ohci_ed_t* ed = hcd_dcache_uncached(&ohci_data.ed_pool[i]); + if (ed->w0.used && ed->w0.is_reclaiming) { + TU_ASSERT(ed->w0.skip == 1, ); + TU_ASSERT(ed->w0.ep_number != 0, ); + + // Reclaim orphaned TDs + uint32_t td_addr = ed->td_head.address & ~0x0F; + while (td_addr) { + if (!ed->w0.is_iso) { + ohci_gtd_t *gtd = (ohci_gtd_t*)_virt_addr((void*)(uintptr_t)td_addr); + gtd->used = 0; + } else { + // TODO: Free ITD once implemented + } + + if (td_addr == ed->td_tail) { + break; + } + td_addr = ((ohci_td_item_t*)_virt_addr((void*)(uintptr_t)td_addr))->next; + } + + ed->w0.is_reclaiming = 0; + ed->w0.used = 0; + ed->w0.skip = 0; + + re_enable_lists = true; + } + } + + if (re_enable_lists) { + // 5.2.7.1.2 Removing + // Reset current ED pointers and re-enable lists + // Once the next frame has started, the HcControlCurrentED or HcBulkCurrentED register should be adjusted so + // that it does not point to the Endpoint Descriptor being removed (for simplicity you may just write + // a zero to the register); + if (!(OHCI_REG->control & OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK)) { + OHCI_REG->control_current_ed = 0; + OHCI_REG->control |= OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK; + } + if (!(OHCI_REG->control & OHCI_CONTROL_LIST_BULK_ENABLE_MASK)) { + OHCI_REG->bulk_current_ed = 0; + OHCI_REG->control |= OHCI_CONTROL_LIST_BULK_ENABLE_MASK; + } + } + } + // Frame number overflow if (int_status & OHCI_INT_FRAME_OVERFLOW_MASK) { ohci_data.frame_number_hi++; diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index 84ae04b0f..c66954502 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -107,7 +107,8 @@ typedef union { // HCD: make use of 5 reserved bits uint32_t used : 1; uint32_t is_interrupt_xfer : 1; - uint32_t : 3; + uint32_t is_reclaiming : 1; + uint32_t : 2; }; uint32_t value; } ohci_ed_word0_t; -- cgit v1.3.1 From 9b05c706272c5344284f7f8b4b53b1aefe082968 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Tue, 18 Aug 2026 15:37:18 +0200 Subject: UAC2: Add more terminal types This adds more standard terminal types that can be used in descriptors to improve end user experience when operating system can present more acurate image for audio device terminal. Signed-off-by: Jerzy Kasenberg --- src/class/audio/audio.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'src') diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index 7981396c2..4a47bbe60 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -83,6 +83,71 @@ typedef enum { AUDIO_TERM_TYPE_OUT_LOW_FRQ_EFFECTS_SPEAKER = 0x0307, } audio_terminal_output_type_t; +/// 2.4 - Audio Class-Bi-directional Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_BI_DIRECTORAL_UNDEFINED = 0x0400, + AUDIO_TERM_TYPE_BI_DIRECTORAL_HEADSET_HAND_HELD = 0x0401, + AUDIO_TERM_TYPE_BI_DIRECTORAL_HEADSET_MOUNTED = 0x0402, + AUDIO_TERM_TYPE_BI_DIRECTORAL_SPEAKERPHONE = 0x0403, + AUDIO_TERM_TYPE_BI_DIRECTORAL_SPEAKERPHONE_ECHO_SUPPRESS = 0x0404, + AUDIO_TERM_TYPE_BI_DIRECTORAL_SPEAKERPHONE_ECHO_CANCLE = 0x0405, +} audio_terminal_bi_directorial_type_t; + +/// 2.5 - Audio Class-Telephone Terminal Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_TELEPHONE_UNDEFINED = 0x0500, + AUDIO_TERM_TYPE_TELEPHONE_PHONE_LINE = 0x0501, + AUDIO_TERM_TYPE_TELEPHONE_TELEPHONE = 0x0502, + AUDIO_TERM_TYPE_TELEPHONE_DOWN_LINE_PHONE = 0x0503, +} audio_terminal_telephony_type_t; + +/// 2.6 - Audio Class-External Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_EXTERNAL_UNDEFINED = 0x0600, + AUDIO_TERM_TYPE_EXTERNAL_ANALOG_CONECTOR = 0x0601, + AUDIO_TERM_TYPE_EXTERNAL_DIGITAL_AUDIO = 0x0602, + AUDIO_TERM_TYPE_EXTERNAL_LINE_CONNECTOR = 0x0603, + AUDIO_TERM_TYPE_EXTERNAL_LEGACY_ADUIO_CONNECTOR = 0x0604, + AUDIO_TERM_TYPE_EXTERNAL_SPDIF_INTERFACE = 0x0605, + AUDIO_TERM_TYPE_EXTERNAL_1394_DA_STREAM = 0x0606, + AUDIO_TERM_TYPE_EXTERNAL_1394_DA_STREAM_SOUNDTRACK = 0x0607, + AUDIO_TERM_TYPE_EXTERNAL_ADAT_LIGHTPIPE = 0x0608, + AUDIO_TERM_TYPE_EXTERNAL_TDIF = 0x0609, + AUDIO_TERM_TYPE_EXTERNAL_MADI = 0x060A, +} audio_terminal_external_type_t; + +/// 2.7 - Audio Class-Embedded Types UAC2 +typedef enum +{ + AUDIO_TERM_TYPE_EMBEDDED_UNDEFINED = 0x0700, + AUDIO_TERM_TYPE_EMBEDDED_LEVEL_CALIBRATION_NOISE_SOURCE = 0x0701, + AUDIO_TERM_TYPE_EMBEDDED_EQUALIZATION_NOISE = 0x0702, + AUDIO_TERM_TYPE_EMBEDDED_CD_PLAYER = 0x0703, + AUDIO_TERM_TYPE_EMBEDDED_DAT = 0x0704, + AUDIO_TERM_TYPE_EMBEDDED_DCC = 0x0705, + AUDIO_TERM_TYPE_EMBEDDED_COMPRESSED_AUDIO_PLAYER = 0x0706, + AUDIO_TERM_TYPE_EMBEDDED_ANALOG_TAPE = 0x0707, + AUDIO_TERM_TYPE_EMBEDDED_PHONOGRAPH = 0x0708, + AUDIO_TERM_TYPE_EMBEDDED_VCR_AUDIO = 0x0709, + AUDIO_TERM_TYPE_EMBEDDED_VIDEO_DISC_AUDIO = 0x070A, + AUDIO_TERM_TYPE_EMBEDDED_DVD_AUDIO = 0x070B, + AUDIO_TERM_TYPE_EMBEDDED_TV_TUNER_AUDIO = 0x070C, + AUDIO_TERM_TYPE_EMBEDDED_SATELITE_RECEIVER_AUDIO = 0x070D, + AUDIO_TERM_TYPE_EMBEDDED_CABLE_TUNER_AUDIO = 0x070E, + AUDIO_TERM_TYPE_EMBEDDED_DSS_AUDIO = 0x070F, + AUDIO_TERM_TYPE_EMBEDDED_RADIO_RECEIVER = 0x0710, + AUDIO_TERM_TYPE_EMBEDDED_RADIO_TRANSMITTER = 0x0711, + AUDIO_TERM_TYPE_EMBEDDED_MULTI_TRACK_RECORDER = 0x0712, + AUDIO_TERM_TYPE_EMBEDDED_SYNTHESIZER = 0x0713, + AUDIO_TERM_TYPE_EMBEDDED_PIANO = 0x0714, + AUDIO_TERM_TYPE_EMBEDDED_GUITAR = 0x0715, + AUDIO_TERM_TYPE_EMBEDDED_DRUMS = 0x0716, + AUDIO_TERM_TYPE_EMBEDDED_OTHER_MUSICAL_INSTRUMENT = 0x0717, +} audio_terminal_embedded_type_t; + /// Rest is yet to be implemented //--------------------------------------------------------------------+ -- cgit v1.3.1 From 8c3b880735f11c37828d6c8b700170e6b6e405ce Mon Sep 17 00:00:00 2001 From: HiFiPHile Date: Wed, 19 Aug 2026 04:57:27 +0200 Subject: Fix audio terminal type typos --- src/class/audio/audio.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index 4a47bbe60..82db9ed9e 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -86,13 +86,13 @@ typedef enum { /// 2.4 - Audio Class-Bi-directional Terminal Types UAC2 typedef enum { - AUDIO_TERM_TYPE_BI_DIRECTORAL_UNDEFINED = 0x0400, - AUDIO_TERM_TYPE_BI_DIRECTORAL_HEADSET_HAND_HELD = 0x0401, - AUDIO_TERM_TYPE_BI_DIRECTORAL_HEADSET_MOUNTED = 0x0402, - AUDIO_TERM_TYPE_BI_DIRECTORAL_SPEAKERPHONE = 0x0403, - AUDIO_TERM_TYPE_BI_DIRECTORAL_SPEAKERPHONE_ECHO_SUPPRESS = 0x0404, - AUDIO_TERM_TYPE_BI_DIRECTORAL_SPEAKERPHONE_ECHO_CANCLE = 0x0405, -} audio_terminal_bi_directorial_type_t; + AUDIO_TERM_TYPE_BI_DIRECTIONAL_UNDEFINED = 0x0400, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_HEADSET_HAND_HELD = 0x0401, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_HEADSET_MOUNTED = 0x0402, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_SPEAKERPHONE = 0x0403, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_SPEAKERPHONE_ECHO_SUPPRESS = 0x0404, + AUDIO_TERM_TYPE_BI_DIRECTIONAL_SPEAKERPHONE_ECHO_CANCEL = 0x0405, +} audio_terminal_bi_directional_type_t; /// 2.5 - Audio Class-Telephone Terminal Types UAC2 typedef enum @@ -107,13 +107,13 @@ typedef enum typedef enum { AUDIO_TERM_TYPE_EXTERNAL_UNDEFINED = 0x0600, - AUDIO_TERM_TYPE_EXTERNAL_ANALOG_CONECTOR = 0x0601, + AUDIO_TERM_TYPE_EXTERNAL_ANALOG_CONNECTOR = 0x0601, AUDIO_TERM_TYPE_EXTERNAL_DIGITAL_AUDIO = 0x0602, AUDIO_TERM_TYPE_EXTERNAL_LINE_CONNECTOR = 0x0603, - AUDIO_TERM_TYPE_EXTERNAL_LEGACY_ADUIO_CONNECTOR = 0x0604, + AUDIO_TERM_TYPE_EXTERNAL_LEGACY_AUDIO_CONNECTOR = 0x0604, AUDIO_TERM_TYPE_EXTERNAL_SPDIF_INTERFACE = 0x0605, AUDIO_TERM_TYPE_EXTERNAL_1394_DA_STREAM = 0x0606, - AUDIO_TERM_TYPE_EXTERNAL_1394_DA_STREAM_SOUNDTRACK = 0x0607, + AUDIO_TERM_TYPE_EXTERNAL_1394_DV_STREAM_SOUNDTRACK = 0x0607, AUDIO_TERM_TYPE_EXTERNAL_ADAT_LIGHTPIPE = 0x0608, AUDIO_TERM_TYPE_EXTERNAL_TDIF = 0x0609, AUDIO_TERM_TYPE_EXTERNAL_MADI = 0x060A, @@ -135,7 +135,7 @@ typedef enum AUDIO_TERM_TYPE_EMBEDDED_VIDEO_DISC_AUDIO = 0x070A, AUDIO_TERM_TYPE_EMBEDDED_DVD_AUDIO = 0x070B, AUDIO_TERM_TYPE_EMBEDDED_TV_TUNER_AUDIO = 0x070C, - AUDIO_TERM_TYPE_EMBEDDED_SATELITE_RECEIVER_AUDIO = 0x070D, + AUDIO_TERM_TYPE_EMBEDDED_SATELLITE_RECEIVER_AUDIO = 0x070D, AUDIO_TERM_TYPE_EMBEDDED_CABLE_TUNER_AUDIO = 0x070E, AUDIO_TERM_TYPE_EMBEDDED_DSS_AUDIO = 0x070F, AUDIO_TERM_TYPE_EMBEDDED_RADIO_RECEIVER = 0x0710, -- cgit v1.3.1 From f065f280284a6f1b5b4c4d2849db4bff4a3ce70c Mon Sep 17 00:00:00 2001 From: HiFiPHile Date: Wed, 19 Aug 2026 05:06:04 +0200 Subject: ohci: defer descriptor reclaim until next frame --- src/portable/ohci/ohci.c | 11 ++++++++--- src/portable/ohci/ohci.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 7ede1ac72..2a174e46c 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -390,6 +390,9 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { // Control endpoints (EP number 0) are statically allocated with the device which are only reused // after connection of another device long after HC has finished with them now, these can be freed immediately. if (ed->w0.ep_number != 0) { + // Wait until the next frame before reclaiming the ED and its TDs. Set the deadline before + // publishing is_reclaiming so a pending SOF IRQ cannot use an older deadline for this ED. + ohci_data.reclaim_frame = (uint16_t)(OHCI_REG->frame_number + 1); ed->w0.is_reclaiming = 1; // 5.2.7.1.2 Removing. Disable list processing for bulk @@ -397,7 +400,8 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { OHCI_REG->control &= ~OHCI_CONTROL_LIST_BULK_ENABLE_MASK; } - // Temporarily enable SOF IRQ. ED and TD Memory will be reclaimed in the SOF IRQ. + // Temporarily enable SOF IRQ. Clear any pending SOF first to wait for the next frame. + OHCI_REG->interrupt_status = OHCI_INT_SOF_MASK; OHCI_REG->interrupt_enable = OHCI_INT_SOF_MASK; } else { ed->w0.used = 0; @@ -665,8 +669,9 @@ void hcd_int_handler(uint8_t hostid, bool in_isr) { // Disable MIE as per OHCI spec 5.3 OHCI_REG->interrupt_disable = OHCI_INT_MASTER_ENABLE_MASK; - // Start of frame (SOF) - if (int_status & OHCI_INT_SOF_MASK) { + // Start of frame (SOF). Signed subtraction handles frame number rollover and delayed interrupts. + if ((int_status & OHCI_INT_SOF_MASK) && + ((int16_t)((uint16_t)OHCI_REG->frame_number - ohci_data.reclaim_frame) >= 0)) { OHCI_REG->interrupt_disable = OHCI_INT_SOF_MASK; bool re_enable_lists = false; diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index c66954502..e28c6404f 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -183,6 +183,7 @@ typedef struct TU_ATTR_ALIGNED(256) { gtd_extra_data_t gtd_extra[GTD_MAX]; volatile uint16_t frame_number_hi; + volatile uint16_t reclaim_frame; } ohci_data_t; //--------------------------------------------------------------------+ -- cgit v1.3.1 From 75a01f561438c16677b48f3a59fda80a2b096ad8 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 19 Aug 2026 12:29:45 +0700 Subject: dcd(ci_hs): stage the device address before priming the status stage IMXRT1060RM 42.7.23 and UM10503 Table 478 both ask for the DEVICEADDR write with USBADRA=1 to happen after the SET_ADDRESS data phase and before the prime of the status stage, so the controller loads USBADR from its holding register when the status stage is ACKed. The driver did it the other way round, leaving a window between the ENDPTPRIME store and the DEVICEADDR store: an IN answered inside that window ACKs with USBADRA still 0, so the holding register is never consulted and the device keeps answering on address 0 while the host has moved to the new one. Instruction timing alone cannot open that window, but dcd_set_address() runs in task context, so any interrupt landing between the two stores stretches it past a microframe. Hardware discards a staged address on a SETUP or OUT to endpoint 0 and zeroes USBADR on a bus reset, which covers a superseded SET_ADDRESS. What it cannot cover is a SETUP latched before this write and still unconsumed after the full CI_HS_BUSY_SPIN spin, which refuses the prime: condition 2 already fired for that earlier SETUP, so the stage would survive and load USBADR on the next EP0 IN ACK of an unrelated transfer. USB 2.0 9.4.6 is explicit that "the USB device does not change its device address until after the Status stage of this request is completed successfully", so the refused-prime path restores the previous USBADR rather than leaving a stage armed. Restoring the previous value rather than writing zero keeps 9.4.6's Address-state row correct, where a device already at a non-zero address must stay there; on Linux that write is always a no-op, since hub_set_address only issues SET_ADDRESS from USB_STATE_DEFAULT. Cast dev_addr before the shift: it is uint8_t, promoted to int, so an address of 64 or more reached the sign bit of a 32-bit int. No errata applies: IMXRT1060CE_A Rev 1.3 lists only ERR050101 and ERR010661 for USB, IMXRT1060CE_B Rev 1.1 only ERR010661. Validated on mimxrt1064_evk: 18/19 device+host tests, 6x usbtest 30/30, and a 100-iteration forced re-enumeration A/B that is clean on both this change and its parent (0/100 each). All 19 ci_hs boards build; unit tests 63/63; PVS drops one diagnostic (the sign-bit shift) and adds none. --- src/portable/chipidea/ci_hs/ci_hs_type.h | 8 ++++++++ src/portable/chipidea/ci_hs/dcd_ci_hs.c | 17 +++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/portable/chipidea/ci_hs/ci_hs_type.h b/src/portable/chipidea/ci_hs/ci_hs_type.h index 5baa14821..b3ef3b6af 100644 --- a/src/portable/chipidea/ci_hs/ci_hs_type.h +++ b/src/portable/chipidea/ci_hs/ci_hs_type.h @@ -29,6 +29,14 @@ enum { USBCMD_INTR_THRESHOLD_MASK = 0x00FF0000u, // Interrupt Threshold bit 23:16 }; +// DEVICEADDR +#define DEVICEADDR_USBADR_POS 25 + +enum { + DEVICEADDR_USBADRA = TU_BIT(24), ///< Device Address Advance: stage USBADR until the next EP0 IN is ACKed + DEVICEADDR_USBADR_MASK = 0xFE000000u, ///< Device Address bit 31:25 +}; + // PORTSC1 #define PORTSC1_PORT_SPEED_POS 26 diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c index 6ab28e0be..f1c333280 100644 --- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c @@ -361,12 +361,17 @@ void dcd_int_disable(uint8_t rhport) { } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - // Response with status first before changing device address. A refused prime means a new - // setup superseded this transfer; staging an address whose ACK will never arrive would - // leave the device answering on it, so only arm the address when the status went out. - if (dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false)) { - ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); - dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24); + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + const uint32_t prev = dcd_reg->DEVICEADDR & DEVICEADDR_USBADR_MASK; + + // IMXRT1060RM 42.7.23 / UM10503 Table 478: stage the address before priming the status stage so + // hardware loads USBADR at the status ACK. Priming first races that ACK against this write. + dcd_reg->DEVICEADDR = ((uint32_t)dev_addr << DEVICEADDR_USBADR_POS) | DEVICEADDR_USBADRA; + + if (!dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false)) { + // USB 2.0 9.4.6: the address changes only after the status stage completes successfully. The + // status never went out, so drop the stage - USBADRA=0 takes effect instantly. + dcd_reg->DEVICEADDR = prev; } } -- cgit v1.3.1 From a57f857f811e054e7a240fc55520648192349c2b Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 21 Aug 2026 11:06:14 +0700 Subject: vendor: remove the obsolete host vendor driver vendor_host.c/.h implemented a CFG_TUH_VENDOR class driver that no example, board or test ever enabled: usbh's driver table entry was compiled out everywhere, and the six tusb_config.h files that mentioned the macro all set it to 0. Maintainer call - dead code, not a shrinking of supported classes. Removes the sources, the usbh driver-table entry, the CFG_TUH_VENDOR default in tusb_option.h, the tusb.h include, both build-system source lists, the rp2040 family.cmake entry and the IAR project template rows. --- examples/dual/dynamic_switch/src/tusb_config.h | 1 - examples/host/cdc_msc_hid/src/tusb_config.h | 1 - .../host/cdc_msc_hid_freertos/src/tusb_config.h | 1 - examples/host/hid_controller/src/tusb_config.h | 1 - examples/host/msc_file_explorer/src/tusb_config.h | 1 - .../msc_file_explorer_freertos/src/tusb_config.h | 1 - hw/bsp/rp2040/family.cmake | 1 - src/CMakeLists.txt | 1 - src/class/vendor/vendor_host.c | 127 --------------------- src/class/vendor/vendor_host.h | 48 -------- src/host/usbh.c | 11 -- src/tinyusb.mk | 1 - src/tusb.h | 3 - src/tusb_option.h | 3 - tools/iar_template.ipcf | 2 - 15 files changed, 203 deletions(-) delete mode 100644 src/class/vendor/vendor_host.c delete mode 100644 src/class/vendor/vendor_host.h (limited to 'src') diff --git a/examples/dual/dynamic_switch/src/tusb_config.h b/examples/dual/dynamic_switch/src/tusb_config.h index f3e016305..c570a2499 100644 --- a/examples/dual/dynamic_switch/src/tusb_config.h +++ b/examples/dual/dynamic_switch/src/tusb_config.h @@ -148,7 +148,6 @@ extern "C" { #define CFG_TUH_CDC 0 #define CFG_TUH_HID 0 #define CFG_TUH_MSC 0 -#define CFG_TUH_VENDOR 0 // max endpoint pair supported by each device #define CFG_TUH_ENDPOINT_MAX 16 diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 26fcdd1cb..a05fcc9bb 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -113,7 +113,6 @@ #define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 1 -#define CFG_TUH_VENDOR 0 // max device support (excluding hub device): 1 hub typically has 4 ports #define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1) diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index 8583e7176..e269357b0 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -115,7 +115,6 @@ #define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 1 -#define CFG_TUH_VENDOR 0 // max device support (excluding hub device): 1 hub typically has 4 ports #define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1) diff --git a/examples/host/hid_controller/src/tusb_config.h b/examples/host/hid_controller/src/tusb_config.h index a5c202fda..e12ff36c8 100644 --- a/examples/host/hid_controller/src/tusb_config.h +++ b/examples/host/hid_controller/src/tusb_config.h @@ -106,7 +106,6 @@ #define CFG_TUH_CDC 0 #define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 0 -#define CFG_TUH_VENDOR 0 // max device support (excluding hub device): 1 hub typically has 4 ports #define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1) diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h index a9d24c89f..f929d49fb 100644 --- a/examples/host/msc_file_explorer/src/tusb_config.h +++ b/examples/host/msc_file_explorer/src/tusb_config.h @@ -106,7 +106,6 @@ #define CFG_TUH_MSC 1 #define CFG_TUH_CDC 0 #define CFG_TUH_HID 0 // typical keyboard + mouse device can have 3-4 HID interfaces -#define CFG_TUH_VENDOR 0 // max device support (excluding hub device): 1 hub typically has 4 ports #define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1) diff --git a/examples/host/msc_file_explorer_freertos/src/tusb_config.h b/examples/host/msc_file_explorer_freertos/src/tusb_config.h index c3fc4624f..905aeba0b 100644 --- a/examples/host/msc_file_explorer_freertos/src/tusb_config.h +++ b/examples/host/msc_file_explorer_freertos/src/tusb_config.h @@ -111,7 +111,6 @@ #define CFG_TUH_MSC 1 #define CFG_TUH_CDC 0 #define CFG_TUH_HID 0 // typical keyboard + mouse device can have 3-4 HID interfaces -#define CFG_TUH_VENDOR 0 // max device support (excluding hub device): 1 hub typically has 4 ports #define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1) diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake index 43b1dc234..57be416a2 100644 --- a/hw/bsp/rp2040/family.cmake +++ b/hw/bsp/rp2040/family.cmake @@ -126,7 +126,6 @@ target_sources(tinyusb_host_base INTERFACE ${TOP}/src/class/midi/midi_host.c ${TOP}/src/class/midi/midi2_host.c ${TOP}/src/class/msc/msc_host.c - ${TOP}/src/class/vendor/vendor_host.c ) # Sometimes have to do host specific actions in mostly common functions diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b3e05f60f..e113f2d88 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,7 +31,6 @@ function(tinyusb_sources_get OUTPUT_VAR) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/midi/midi_host.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/midi/midi2_host.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/msc/msc_host.c - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/vendor/vendor_host.c # typec ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/typec/usbc.c PARENT_SCOPE diff --git a/src/class/vendor/vendor_host.c b/src/class/vendor/vendor_host.c deleted file mode 100644 index dd2c5ac5d..000000000 --- a/src/class/vendor/vendor_host.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) - * SPDX-License-Identifier: MIT - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (CFG_TUH_ENABLED && CFG_TUH_VENDOR) - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "host/usbh.h" -#include "vendor_host.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -custom_interface_info_t custom_interface[CFG_TUH_DEVICE_MAX]; - -static tusb_error_t cush_validate_paras(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) -{ - if ( !tusbh_custom_is_mounted(dev_addr, vendor_id, product_id) ) - { - return TUSB_ERROR_DEVICE_NOT_READY; - } - - TU_ASSERT( p_buffer != NULL && length != 0, TUSB_ERROR_INVALID_PARA); - - return TUSB_ERROR_NONE; -} -//--------------------------------------------------------------------+ -// APPLICATION API (need to check parameters) -//--------------------------------------------------------------------+ -tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length) -{ - TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_buffer, length) ); - - if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_in) ) - { - return TUSB_ERROR_INTERFACE_IS_BUSY; - } - - (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_in, p_buffer, length); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length) -{ - TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_data, length) ); - - if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_out) ) - { - return TUSB_ERROR_INTERFACE_IS_BUSY; - } - - (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_out, p_data, length); - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// USBH-CLASS API -//--------------------------------------------------------------------+ -void cush_init(void) -{ - tu_memclr(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUH_DEVICE_MAX); -} - -tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) -{ - // FIXME quick hack to test lpc1k custom class with 2 bulk endpoints - uint8_t const *p_desc = (uint8_t const *) p_interface_desc; - p_desc = tu_desc_next(p_desc); - - //------------- Bulk Endpoints Descriptor -------------// - for(uint32_t i=0; i<2; i++) - { - tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_INVALID_PARA); - - pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ? - &custom_interface[dev_addr-1].pipe_in : &custom_interface[dev_addr-1].pipe_out; - *p_pipe_hdl = usbh_edpt_open(dev_addr, p_endpoint, TUSB_CLASS_VENDOR_SPECIFIC); - TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED ); - - p_desc = tu_desc_next(p_desc); - } - - (*p_length) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); - return TUSB_ERROR_NONE; -} - -void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event) -{ - -} - -void cush_close(uint8_t dev_addr) -{ - tusb_error_t err1, err2; - custom_interface_info_t * p_interface = &custom_interface[dev_addr-1]; - - // TODO re-consider to check pipe valid before calling pipe_close - if( pipehandle_is_valid( p_interface->pipe_in ) ) - { - err1 = hcd_pipe_close( p_interface->pipe_in ); - } - - if ( pipehandle_is_valid( p_interface->pipe_out ) ) - { - err2 = hcd_pipe_close( p_interface->pipe_out ); - } - - tu_memclr(p_interface, sizeof(custom_interface_info_t)); - - TU_ASSERT(err1 == TUSB_ERROR_NONE && err2 == TUSB_ERROR_NONE, (void) 0 ); -} - -#endif diff --git a/src/class/vendor/vendor_host.h b/src/class/vendor/vendor_host.h deleted file mode 100644 index dc55663b9..000000000 --- a/src/class/vendor/vendor_host.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) - * SPDX-License-Identifier: MIT - * - * This file is part of the TinyUSB stack. - */ - -#ifndef TUSB_VENDOR_HOST_H_ -#define TUSB_VENDOR_HOST_H_ - -#include "common/tusb_common.h" - -#ifdef __cplusplus - extern "C" { -#endif - -typedef struct { - pipe_handle_t pipe_in; - pipe_handle_t pipe_out; -}custom_interface_info_t; - -//--------------------------------------------------------------------+ -// USBH-CLASS DRIVER API -//--------------------------------------------------------------------+ -static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id) -{ - (void) vendor_id; // TODO check this later - (void) product_id; -// return (tusbh_device_get_mounted_class_flag(dev_addr) & TU_BIT(TUSB_CLASS_MAPPED_INDEX_END-1) ) != 0; - return false; -} - -bool tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length); -bool tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void cush_init(void); -bool cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length); -void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event); -void cush_close(uint8_t dev_addr); - -#ifdef __cplusplus - } -#endif - -#endif /* TUSB_VENDOR_HOST_H_ */ diff --git a/src/host/usbh.c b/src/host/usbh.c index e307bb5e5..44819b016 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -306,17 +306,6 @@ static usbh_class_driver_t const usbh_class_drivers[] = { }, #endif - #if CFG_TUH_VENDOR - { - .name = DRIVER_NAME("VENDOR"), - .init = cush_init, - .deinit = cush_deinit, - .open = cush_open, - .set_config = cush_set_config, - .xfer_cb = cush_isr, - .close = cush_close - } - #endif }; // Additional class drivers implemented by application diff --git a/src/tinyusb.mk b/src/tinyusb.mk index 365043927..941791670 100644 --- a/src/tinyusb.mk +++ b/src/tinyusb.mk @@ -26,4 +26,3 @@ TINYUSB_SRC_C += \ src/class/midi/midi_host.c \ src/class/midi/midi2_host.c \ src/class/msc/msc_host.c \ - src/class/vendor/vendor_host.c \ diff --git a/src/tusb.h b/src/tusb.h index 6a30f7c13..cdf6f8171 100644 --- a/src/tusb.h +++ b/src/tusb.h @@ -48,9 +48,6 @@ #include "class/midi/midi2_host.h" #endif - #if CFG_TUH_VENDOR - #include "class/vendor/vendor_host.h" - #endif #else #ifndef tuh_int_handler #define tuh_int_handler(...) diff --git a/src/tusb_option.h b/src/tusb_option.h index 24f802b73..1eb23fb00 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -894,9 +894,6 @@ #define CFG_TUH_MSC 0 #endif -#ifndef CFG_TUH_VENDOR - #define CFG_TUH_VENDOR 0 -#endif #ifndef CFG_TUH_API_EDPT_XFER #define CFG_TUH_API_EDPT_XFER 0 diff --git a/tools/iar_template.ipcf b/tools/iar_template.ipcf index 035e40b94..922b22426 100644 --- a/tools/iar_template.ipcf +++ b/tools/iar_template.ipcf @@ -81,9 +81,7 @@ $TUSB_DIR$/src/class/vendor/vendor_device.c - $TUSB_DIR$/src/class/vendor/vendor_host.c $TUSB_DIR$/src/class/vendor/vendor_device.h - $TUSB_DIR$/src/class/vendor/vendor_host.h $TUSB_DIR$/src/class/video/video_device.c -- cgit v1.3.1