diff options
| author | hathach <[email protected]> | 2025-06-11 16:23:54 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2025-06-11 16:23:54 +0700 |
| commit | d3d505e8f7872871185029b91588ae41ac037288 (patch) | |
| tree | 92a2ea3f40efd05f71abd6819dbe5a71a32b27fd /src | |
| parent | 6346fbec16739d91fc9ece57216d40ca1c091936 (diff) | |
| parent | 8e252203697bc74f622d31a0de113e0ad01c9704 (diff) | |
Merge branch 'master' into fork/HiFiPhile/h7rs
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/class/net/ecm_rndis_device.c | 51 | ||||
| -rw-r--r-- | src/class/net/ncm_device.c | 36 | ||||
| -rw-r--r-- | src/class/net/net_device.h | 5 | ||||
| -rw-r--r-- | src/class/vendor/vendor_device.c | 40 | ||||
| -rw-r--r-- | src/common/tusb_mcu.h | 7 | ||||
| -rw-r--r-- | src/common/tusb_types.h | 6 | ||||
| -rw-r--r-- | src/device/usbd.c | 31 | ||||
| -rw-r--r-- | src/device/usbd_pvt.h | 2 | ||||
| -rw-r--r-- | src/host/usbh.c | 13 | ||||
| -rw-r--r-- | src/host/usbh.h | 2 | ||||
| -rw-r--r-- | src/host/usbh_pvt.h | 3 | ||||
| -rw-r--r-- | src/osal/osal.h | 4 | ||||
| -rw-r--r-- | src/osal/osal_freertos.h | 107 | ||||
| -rw-r--r-- | src/osal/osal_mynewt.h | 26 | ||||
| -rw-r--r-- | src/osal/osal_none.h | 27 | ||||
| -rw-r--r-- | src/osal/osal_pico.h | 21 | ||||
| -rw-r--r-- | src/osal/osal_rtthread.h | 26 | ||||
| -rw-r--r-- | src/osal/osal_rtx4.h | 19 | ||||
| -rw-r--r-- | src/osal/osal_zephyr.h | 29 | ||||
| -rw-r--r-- | src/portable/analog/max3421/hcd_max3421.c | 69 | ||||
| -rw-r--r-- | src/portable/chipidea/ci_hs/dcd_ci_hs.c | 4 | ||||
| -rw-r--r-- | src/portable/synopsys/dwc2/dcd_dwc2.c | 71 | ||||
| -rw-r--r-- | src/portable/synopsys/dwc2/dwc2_esp32.h | 4 | ||||
| -rw-r--r-- | src/tusb_option.h | 10 |
25 files changed, 499 insertions, 119 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 55c52033c..99d3059fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,6 @@ -# TODO more docs and example on how to use this file -# TINYUSB_TARGET_PREFIX and TINYUSB_TARGET_SUFFIX can be used to change the name of the target - cmake_minimum_required(VERSION 3.20) -# Add tinyusb to a existing target +# Add tinyusb to a existing target, DCD and HCD drivers are not included function(tinyusb_target_add TARGET) target_sources(${TARGET} PRIVATE # common diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c index a54e6d662..299eb97c8 100644 --- a/src/class/net/ecm_rndis_device.c +++ b/src/class/net/ecm_rndis_device.c @@ -81,6 +81,7 @@ typedef struct { static netd_interface_t _netd_itf; CFG_TUD_MEM_SECTION static netd_epbuf_t _netd_epbuf; static bool can_xmit; +static bool ecm_link_is_up = true; // Store link state for ECM mode void tud_network_recv_renew(void) { usbd_edpt_xfer(0, _netd_itf.ep_out, _netd_epbuf.rx, NETD_PACKET_SIZE); @@ -95,7 +96,11 @@ void netd_report(uint8_t *buf, uint16_t len) { const uint8_t rhport = 0; len = tu_min16(len, sizeof(ecm_notify_t)); - TU_VERIFY(usbd_edpt_claim(rhport, _netd_itf.ep_notif), ); + if (!usbd_edpt_claim(rhport, _netd_itf.ep_notif)) { + TU_LOG1("ECM: Failed to claim notification endpoint\n"); + return; + } + memcpy(_netd_epbuf.notify, buf, len); usbd_edpt_xfer(rhport, _netd_itf.ep_notif, _netd_epbuf.notify, len); } @@ -181,8 +186,6 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 // Open endpoint pair for RNDIS TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0); - tud_network_init_cb(); - // we are ready to transmit a packet can_xmit = true; @@ -196,11 +199,11 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 } static void ecm_report(bool nc) { - const ecm_notify_t ecm_notify_nc = { + ecm_notify_t ecm_notify_nc = { .header = { .bmRequestType = 0xA1, .bRequest = 0, /* NETWORK_CONNECTION aka NetworkConnection */ - .wValue = 1, /* Connected */ + .wValue = ecm_link_is_up ? 1 : 0, /* Use current link state */ .wLength = 0, }, }; @@ -259,7 +262,6 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t // TODO should be merge with RNDIS's after endpoint opened // Also should have opposite callback for application to disable network !! - tud_network_init_cb(); can_xmit = true; // we are ready to transmit a packet tud_network_recv_renew(); // prepare for incoming packets } @@ -286,7 +288,10 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) { tud_control_xfer(rhport, request, NULL, 0); - ecm_report(true); + // Only send connection notification if link is up + if (ecm_link_is_up) { + ecm_report(true); + } } } else { if (request->bmRequestType_bit.direction == TUSB_DIR_IN) { @@ -363,9 +368,8 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } if (_netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif)) { - if (sizeof(tusb_control_request_t) == xferred_bytes) { - ecm_report(false); - } + // Notification transfer complete - endpoint is now free + // Don't automatically send speed change notification after link state changes } return true; @@ -398,4 +402,31 @@ void tud_network_xmit(void *ref, uint16_t arg) { do_in_xfer(_netd_epbuf.tx, len); } +// Set the network link state (up/down) and notify the host +void tud_network_link_state(uint8_t rhport, bool is_up) { + (void)rhport; + + if (_netd_itf.ecm_mode) { + ecm_link_is_up = is_up; + + // For ECM mode, send network connection notification only + // Don't trigger speed change notification for link state changes + ecm_notify_t notify = { + .header = { + .bmRequestType = 0xA1, + .bRequest = 0, /* NETWORK_CONNECTION */ + .wValue = is_up ? 1 : 0, /* 0 = disconnected, 1 = connected */ + .wLength = 0, + }, + }; + notify.header.wIndex = _netd_itf.itf_num; + netd_report((uint8_t *)¬ify, sizeof(notify.header)); + } else { + // For RNDIS mode, we would need to implement RNDIS status indication + // This is more complex and requires RNDIS_INDICATE_STATUS_MSG + // For now, RNDIS doesn't support dynamic link state changes + (void)is_up; + } +} + #endif diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index f9fda0698..02833c5f1 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -110,6 +110,7 @@ typedef struct { NOTIFICATION_DONE } notification_xmit_state; // state of notification transmission bool notification_xmit_is_running; // notification is currently transmitted + bool link_is_up; // current link state // misc bool tud_network_recv_renew_active; // tud_network_recv_renew() is active (avoid recursive invocations) @@ -218,7 +219,7 @@ static void notification_xmit(uint8_t rhport, bool force_next) { .direction = TUSB_DIR_IN }, .bRequest = CDC_NOTIF_NETWORK_CONNECTION, - .wValue = 1 /* Connected */, + .wValue = ncm_interface.link_is_up ? 1 : 0, /* Dynamic link state */ .wIndex = ncm_interface.itf_num, .wLength = 0, }, @@ -232,6 +233,7 @@ static void notification_xmit(uint8_t rhport, bool force_next) { ncm_interface.notification_xmit_is_running = true; } else { TU_LOG_DRV(" NOTIFICATION_FINISHED\n"); + ncm_interface.notification_xmit_is_running = false; } } // notification_xmit @@ -755,6 +757,32 @@ static void tud_network_recv_renew_r(uint8_t rhport) { tud_network_recv_renew(); } // tud_network_recv_renew +/** + * Set the link state and send notification to host + */ +void tud_network_link_state(uint8_t rhport, bool is_up) { + TU_LOG_DRV("tud_network_link_state(%d, %d)\n", rhport, is_up); + + if (ncm_interface.link_is_up == is_up) { + // No change in link state + return; + } + + ncm_interface.link_is_up = is_up; + + // Only send notification if we have an active data interface + if (ncm_interface.itf_data_alt != 1) { + TU_LOG_DRV(" link state notification skipped (interface not active)\n"); + return; + } + + // Reset notification state to send link state update + ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED; + + // Trigger notification transmission + notification_xmit(rhport, false); +} + //----------------------------------------------------------------------------- // // all the netd_*() stuff (interface TinyUSB -> driver) @@ -774,6 +802,12 @@ void netd_init(void) { for (int i = 0; i < RECV_NTB_N; ++i) { ncm_interface.recv_free_ntb[i] = &ncm_epbuf.recv[i].ntb; } + // Default link state - can be configured via CFG_TUD_NCM_DEFAULT_LINK_UP + #ifdef CFG_TUD_NCM_DEFAULT_LINK_UP + ncm_interface.link_is_up = CFG_TUD_NCM_DEFAULT_LINK_UP; + #else + ncm_interface.link_is_up = true; // Default to link up if not set. + #endif } // netd_init /** diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h index 4c9a92f2d..fff2623b7 100644 --- a/src/class/net/net_device.h +++ b/src/class/net/net_device.h @@ -87,6 +87,11 @@ void tud_network_init_cb(void); // TODO removed later since it is not part of tinyusb stack extern uint8_t tud_network_mac_address[6]; +//------------- NCM -------------// + +// Set the network link state (up/down) and notify the host +void tud_network_link_state(uint8_t rhport, bool is_up); + //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 2fc0ac944..7f1fd8c41 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -196,8 +196,8 @@ void vendord_reset(uint8_t rhport) { uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); + const uint8_t* desc_end = (const uint8_t*)desc_itf + max_len; const uint8_t* p_desc = tu_desc_next(desc_itf); - const uint8_t* desc_end = (uint8_t const*)desc_itf + max_len; // Find available interface vendord_interface_t* p_vendor = NULL; @@ -210,26 +210,26 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin TU_VERIFY(p_vendor, 0); p_vendor->itf_num = desc_itf->bInterfaceNumber; - uint8_t found_ep = 0; - while (found_ep < desc_itf->bNumEndpoints) { - // skip non-endpoint descriptors - while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) ) { - p_desc = tu_desc_next(p_desc); - } - if (p_desc >= desc_end) { - break; - } - - const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; - TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); - found_ep++; + while (tu_desc_is_valid(p_desc, desc_end)) { + const uint8_t desc_type = tu_desc_type(p_desc); + if (desc_type == TUSB_DESC_INTERFACE || desc_type == TUSB_DESC_INTERFACE_ASSOCIATION) { + break; // end of this interface + } else if (desc_type == TUSB_DESC_ENDPOINT) { + const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); - if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { - tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); - tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); - } else { - tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep); - TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data + // open endpoint stream, skip if already opened + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { + if (p_vendor->tx.stream.ep_addr == 0) { + tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); + tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); + } + } else { + if (p_vendor->rx.stream.ep_addr == 0) { + tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep); + TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data + } + } } p_desc = tu_desc_next(p_desc); diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index a0175d664..6678265b5 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -369,6 +369,10 @@ #define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/ + #if CFG_TUSB_MCU == OPT_MCU_ESP32S3 + #define TUP_MCU_MULTIPLE_CORE 1 + #endif + // Disable slave if DMA is enabled #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE @@ -381,6 +385,8 @@ #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/ + #define TUP_MCU_MULTIPLE_CORE 1 + // Disable slave if DMA is enabled #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE @@ -410,6 +416,7 @@ #elif TU_CHECK_MCU(OPT_MCU_RP2040) #define TUP_DCD_EDPT_ISO_ALLOC #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_MCU_MULTIPLE_CORE 1 #define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb"))) diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index e000a4bd3..fd7f01b67 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -586,6 +586,12 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_subtype(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_SUBTYPE]; } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_is_valid(void const* desc, uint8_t const* desc_end) { + const uint8_t* desc8 = (uint8_t const*) desc; + return (desc8 < desc_end) && (tu_desc_next(desc) <= desc_end); +} + + // find descriptor that match byte1 (type) uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1); diff --git a/src/device/usbd.c b/src/device/usbd.c index 9c381d5e0..6e5fcf3b6 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -340,15 +340,16 @@ TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8 enum { RHPORT_INVALID = 0xFFu }; tu_static uint8_t _usbd_rhport = RHPORT_INVALID; -// Event queue -// usbd_int_set() is used as mutex in OS NONE config +static OSAL_SPINLOCK_DEF(_usbd_spin, usbd_int_set); + +// Event queue: usbd_int_set() is used as mutex in OS NONE config OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t); -tu_static osal_queue_t _usbd_q; +static osal_queue_t _usbd_q; // Mutex for claiming endpoint #if OSAL_MUTEX_REQUIRED - tu_static osal_mutex_def_t _ubsd_mutexdef; - tu_static osal_mutex_t _usbd_mutex; + static osal_mutex_def_t _ubsd_mutexdef; + static osal_mutex_t _usbd_mutex; #else #define _usbd_mutex NULL #endif @@ -466,7 +467,7 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { TU_ASSERT(rh_init); TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport, - rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full"); + rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full"); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t)); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t)); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t)); @@ -475,6 +476,8 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { tu_varclr(&_usbd_dev); _usbd_queued_setup = 0; + osal_spin_init(&_usbd_spin); + #if OSAL_MUTEX_REQUIRED // Init device mutex _usbd_mutex = osal_mutex_create(&_ubsd_mutexdef); @@ -1242,17 +1245,21 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) // USBD API For Class Driver //--------------------------------------------------------------------+ -void usbd_int_set(bool enabled) -{ - if (enabled) - { +void usbd_int_set(bool enabled) { + if (enabled) { dcd_int_enable(_usbd_rhport); - }else - { + } else { dcd_int_disable(_usbd_rhport); } } +void usbd_spin_lock(bool in_isr) { + osal_spin_lock(&_usbd_spin, in_isr); +} +void usbd_spin_unlock(bool in_isr) { + osal_spin_unlock(&_usbd_spin, in_isr); +} + // Parse consecutive endpoint descriptors (IN & OUT) bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in) { diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 190d6fd7f..5c6f9dbee 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -68,6 +68,8 @@ usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR typedef bool (*usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); void usbd_int_set(bool enabled); +void usbd_spin_lock(bool in_isr); +void usbd_spin_unlock(bool in_isr); //--------------------------------------------------------------------+ // USBD Endpoint API diff --git a/src/host/usbh.c b/src/host/usbh.c index b7d5a05f2..f2e5c1f0e 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -147,6 +147,9 @@ static osal_mutex_t _usbh_mutex; #define _usbh_mutex NULL #endif +// Spinlock for interrupt handler +static OSAL_SPINLOCK_DEF(_usbh_spin, usbh_int_set); + // 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; @@ -424,6 +427,8 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { TU_LOG_INT_USBH(sizeof(tu_fifo_t)); TU_LOG_INT_USBH(sizeof(tu_edpt_stream_t)); + osal_spin_init(&_usbh_spin); + // Event queue _usbh_q = osal_queue_create(&_usbh_qdef); TU_ASSERT(_usbh_q != NULL); @@ -895,6 +900,14 @@ void usbh_int_set(bool enabled) { } } +void usbh_spin_lock(bool in_isr) { + osal_spin_lock(&_usbh_spin, in_isr); +} + +void usbh_spin_unlock(bool in_isr) { + osal_spin_unlock(&_usbh_spin, in_isr); +} + void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr) { hcd_event_t event = { 0 }; event.event_id = USBH_EVENT_FUNC_CALL; diff --git a/src/host/usbh.h b/src/host/usbh.h index 6f34d8bb3..13eede869 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -42,7 +42,7 @@ //--------------------------------------------------------------------+ // Endpoint Bulk size depending on host mx speed -#define TUH_EPSIZE_BULK_MPS (TUD_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS) +#define TUH_EPSIZE_BULK_MPS (TUH_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS) // forward declaration struct tuh_xfer_s; diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h index 61b012493..cb092e5f3 100644 --- a/src/host/usbh_pvt.h +++ b/src/host/usbh_pvt.h @@ -71,6 +71,9 @@ void usbh_int_set(bool enabled); void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr); +void usbh_spin_lock(bool in_isr); +void usbh_spin_unlock(bool in_isr); + //--------------------------------------------------------------------+ // USBH Endpoint API //--------------------------------------------------------------------+ diff --git a/src/osal/osal.h b/src/osal/osal.h index 38d45da44..a33280425 100644 --- a/src/osal/osal.h +++ b/src/osal/osal.h @@ -75,6 +75,10 @@ typedef void (*osal_task_func_t)( void * ); // OSAL Porting API // Should be implemented as static inline function in osal_port.h header /* + void osal_spin_init(osal_spinlock_t *ctx); + void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) + void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr); + osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef); bool osal_semaphore_delete(osal_semaphore_t semd_hdl); bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr); diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h index a3a0f3a3f..bde5ec010 100644 --- a/src/osal/osal_freertos.h +++ b/src/osal/osal_freertos.h @@ -42,20 +42,20 @@ extern "C" { //--------------------------------------------------------------------+ #if configSUPPORT_STATIC_ALLOCATION - typedef StaticSemaphore_t osal_semaphore_def_t; - typedef StaticSemaphore_t osal_mutex_def_t; +typedef StaticSemaphore_t osal_semaphore_def_t; +typedef StaticSemaphore_t osal_mutex_def_t; #else - // not used therefore defined to smallest possible type to save space - typedef uint8_t osal_semaphore_def_t; - typedef uint8_t osal_mutex_def_t; + +// not used therefore defined to the smallest possible type to save space +typedef uint8_t osal_semaphore_def_t; +typedef uint8_t osal_mutex_def_t; #endif typedef SemaphoreHandle_t osal_semaphore_t; typedef SemaphoreHandle_t osal_mutex_t; typedef QueueHandle_t osal_queue_t; -typedef struct -{ +typedef struct { uint16_t depth; uint16_t item_sz; void* buf; @@ -83,16 +83,14 @@ typedef struct //--------------------------------------------------------------------+ // TASK API //--------------------------------------------------------------------+ - TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) { - if ( msec == OSAL_TIMEOUT_WAIT_FOREVER ) return portMAX_DELAY; - if ( msec == 0 ) return 0; + if (msec == OSAL_TIMEOUT_WAIT_FOREVER) { return portMAX_DELAY; } + if (msec == 0) { return 0; } uint32_t ticks = pdMS_TO_TICKS(msec); - // configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms - // we still need to delay at least 1 tick - if ( ticks == 0 ) ticks = 1; + // If configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms, we still need to delay at least 1 tick + if (ticks == 0) { ticks = 1; } return ticks; } @@ -102,9 +100,70 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { } //--------------------------------------------------------------------+ -// Semaphore API +// Spinlock API //--------------------------------------------------------------------+ +#define OSAL_SPINLOCK_DEF(_name, _int_set) \ + osal_spinlock_t _name + +#if TUSB_MCU_VENDOR_ESPRESSIF +// Espressif critical take spinlock as argument and does not use in_isr +typedef portMUX_TYPE osal_spinlock_t; + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { + spinlock_initialize(ctx); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { + if (!TUP_MCU_MULTIPLE_CORE && in_isr) { + return; // single core MCU does not need to lock in ISR + } + portENTER_CRITICAL(ctx); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) { + if (!TUP_MCU_MULTIPLE_CORE && in_isr) { + return; // single core MCU does not need to lock in ISR + } + portEXIT_CRITICAL(ctx); +} + +#else + +typedef UBaseType_t osal_spinlock_t; + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { + (void) ctx; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { + if (in_isr) { + if (!TUP_MCU_MULTIPLE_CORE) { + (void) ctx; + return; // single core MCU does not need to lock in ISR + } + *ctx = taskENTER_CRITICAL_FROM_ISR(); + } else { + taskENTER_CRITICAL(); + } +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) { + if (in_isr) { + if (!TUP_MCU_MULTIPLE_CORE) { + (void) ctx; + return; // single core MCU does not need to lock in ISR + } + taskEXIT_CRITICAL_FROM_ISR(*ctx); + } else { + taskEXIT_CRITICAL(); + } +} +#endif + +//--------------------------------------------------------------------+ +// Semaphore API +//--------------------------------------------------------------------+ TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) { #if configSUPPORT_STATIC_ALLOCATION return xSemaphoreCreateBinaryStatic(semdef); @@ -120,19 +179,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t } TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) { - if ( !in_isr ) { + if (!in_isr) { return xSemaphoreGive(sem_hdl) != 0; } else { BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken); - -#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 - // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 - if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); -#else portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -#endif - return res != 0; } } @@ -148,7 +200,6 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t c //--------------------------------------------------------------------+ // MUTEX API (priority inheritance) //--------------------------------------------------------------------+ - TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) { #if configSUPPORT_STATIC_ALLOCATION return xSemaphoreCreateMutexStatic(mdef); @@ -174,7 +225,6 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd //--------------------------------------------------------------------+ // QUEUE API //--------------------------------------------------------------------+ - TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) { osal_queue_t q; @@ -201,19 +251,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v } TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) { - if ( !in_isr ) { + if (!in_isr) { return xQueueSendToBack(qhdl, data, OSAL_TIMEOUT_WAIT_FOREVER) != 0; } else { BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken); - -#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 - // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 (IDF v5) - if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR(); -#else portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -#endif - return res != 0; } } diff --git a/src/osal/osal_mynewt.h b/src/osal/osal_mynewt.h index 16def0d2a..ee95e684f 100644 --- a/src/osal/osal_mynewt.h +++ b/src/osal/osal_mynewt.h @@ -41,6 +41,32 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { } //--------------------------------------------------------------------+ +// Spinlock API +//--------------------------------------------------------------------+ +typedef os_sr_t osal_spinlock_t; + +#define OSAL_SPINLOCK_DEF(_name, _int_set) \ + osal_spinlock_t _name + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { + (void) ctx; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { + if (!TUP_MCU_MULTIPLE_CORE && in_isr) { + return; // single core MCU does not need to lock in ISR + } + OS_ENTER_CRITICAL(*ctx); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) { + if (!TUP_MCU_MULTIPLE_CORE && in_isr) { + return; // single core MCU does not need to lock in ISR + } + OS_ENTER_CRITICAL(*ctx); +} + +//--------------------------------------------------------------------+ // Semaphore API //--------------------------------------------------------------------+ typedef struct os_sem osal_semaphore_def_t; diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h index 40e9bb83a..a8eb1042b 100644 --- a/src/osal/osal_none.h +++ b/src/osal/osal_none.h @@ -41,6 +41,33 @@ TU_ATTR_WEAK void osal_task_delay(uint32_t msec); #endif //--------------------------------------------------------------------+ +// Spinlock API +//--------------------------------------------------------------------+ +typedef struct { + void (* interrupt_set)(bool); +} osal_spinlock_t; + +// For SMP, spinlock must be locked by hardware, cannot just use interrupt +#define OSAL_SPINLOCK_DEF(_name, _int_set) \ + osal_spinlock_t _name = { .interrupt_set = _int_set } + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { + (void) ctx; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { + if (!in_isr) { + ctx->interrupt_set(false); + } +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) { + if (!in_isr) { + ctx->interrupt_set(true); + } +} + +//--------------------------------------------------------------------+ // Binary Semaphore API //--------------------------------------------------------------------+ typedef struct { diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h index 315de0950..ace5907d7 100644 --- a/src/osal/osal_pico.h +++ b/src/osal/osal_pico.h @@ -44,6 +44,27 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { } //--------------------------------------------------------------------+ +// Spinlock API +//--------------------------------------------------------------------+ +typedef critical_section_t osal_spinlock_t; // pico implement critical section with spinlock +#define OSAL_SPINLOCK_DEF(_name, _int_set) \ + osal_spinlock_t _name + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { + critical_section_init(ctx); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { + (void) in_isr; + critical_section_enter_blocking(ctx); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) { + (void) in_isr; + critical_section_exit(ctx); +} + +//--------------------------------------------------------------------+ // Binary Semaphore API //--------------------------------------------------------------------+ typedef struct semaphore osal_semaphore_def_t, * osal_semaphore_t; diff --git a/src/osal/osal_rtthread.h b/src/osal/osal_rtthread.h index c27814835..a778f5425 100644 --- a/src/osal/osal_rtthread.h +++ b/src/osal/osal_rtthread.h @@ -43,6 +43,32 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { } //--------------------------------------------------------------------+ +// Spinlock API +//--------------------------------------------------------------------+ +typedef struct rt_spinlock osal_spinlock_t; + +#define OSAL_SPINLOCK_DEF(_name, _int_set) \ + osal_spinlock_t _name + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { + rt_spin_lock_init(ctx); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { + if (!TUP_MCU_MULTIPLE_CORE && in_isr) { + return; // single core MCU does not need to lock in ISR + } + rt_spin_lock(ctx); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) { + if (!TUP_MCU_MULTIPLE_CORE && in_isr) { + return; // single core MCU does not need to lock in ISR + } + rt_spin_unlock(ctx); +} + +//--------------------------------------------------------------------+ // Semaphore API //--------------------------------------------------------------------+ typedef struct rt_semaphore osal_semaphore_def_t; diff --git a/src/osal/osal_rtx4.h b/src/osal/osal_rtx4.h index 35909e4d6..35860ddd5 100644 --- a/src/osal/osal_rtx4.h +++ b/src/osal/osal_rtx4.h @@ -57,6 +57,25 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) { } //--------------------------------------------------------------------+ +// Spinlock API, stub not implemented +//--------------------------------------------------------------------+ +typedef uint8_t osal_spinlock_t; +#define OSAL_SPINLOCK_DEF(_name, _int_set) \ + osal_spinlock_t _name + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { + (void) ctx; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { + (void) ctx; (void) in_isr; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) { + (void) ctx; (void) in_isr; +} + +//--------------------------------------------------------------------+ // Semaphore API //--------------------------------------------------------------------+ typedef OS_SEM osal_semaphore_def_t; diff --git a/src/osal/osal_zephyr.h b/src/osal/osal_zephyr.h index 8ecb13c6d..91f225f79 100644 --- a/src/osal/osal_zephyr.h +++ b/src/osal/osal_zephyr.h @@ -36,6 +36,35 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) { } //--------------------------------------------------------------------+ +// Spinlock API +//--------------------------------------------------------------------+ +typedef struct { + struct k_spinlock lock; + k_spinlock_key_t key; +} osal_spinlock_t; + +#define OSAL_SPINLOCK_DEF(_name, _int_set) \ + osal_spinlock_t _name + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { + (void) ctx; +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { + if (!TUP_MCU_MULTIPLE_CORE && in_isr) { + return; // single core MCU does not need to lock in ISR + } + ctx->key = k_spin_lock(&ctx->lock); +} + +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) { + if (!TUP_MCU_MULTIPLE_CORE && in_isr) { + return; // single core MCU does not need to lock in ISR + } + k_spin_unlock(&ctx->lock, ctx->key); +} + +//--------------------------------------------------------------------+ // Binary Semaphore API //--------------------------------------------------------------------+ typedef struct k_sem osal_semaphore_def_t, * osal_semaphore_t; diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index bb33200f2..971dbd62e 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -28,9 +28,9 @@ #if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 -#include <stdatomic.h> #include "host/hcd.h" #include "host/usbh.h" +#include "host/usbh_pvt.h" //--------------------------------------------------------------------+ // @@ -233,7 +233,7 @@ typedef struct { uint8_t hxfr; }sndfifo_owner; - atomic_flag busy; // busy transferring + bool busy_lock; // busy transferring #if OSAL_MUTEX_REQUIRED OSAL_MUTEX_DEF(spi_mutexdef); @@ -327,7 +327,9 @@ TU_ATTR_ALWAYS_INLINE static inline void mode_write(uint8_t rhport, uint8_t data } TU_ATTR_ALWAYS_INLINE static inline void peraddr_write(uint8_t rhport, uint8_t data, bool in_isr) { - if ( _hcd_data.peraddr == data ) return; // no need to change address + if (_hcd_data.peraddr == data) { + return; // no need to change address + } _hcd_data.peraddr = data; reg_write(rhport, PERADDR_ADDR, data, in_isr); @@ -373,7 +375,7 @@ TU_ATTR_ALWAYS_INLINE static inline void hwfifo_setup(uint8_t rhport, const uint static void hwfifo_receive(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) { uint8_t hirq; - uint8_t const reg = RCVVFIFO_ADDR; + const uint8_t reg = RCVVFIFO_ADDR; max3421_spi_lock(rhport, in_isr); @@ -389,7 +391,7 @@ static void hwfifo_receive(uint8_t rhport, uint8_t * buffer, uint16_t len, bool //--------------------------------------------------------------------+ static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) { - uint8_t const is_out = 1-ep_dir; + const uint8_t is_out = 1-ep_dir; for(size_t i=1; i<CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) { max3421_ep_t* ep = &_hcd_data.ep[i]; // control endpoint is bi-direction (skip check) @@ -727,8 +729,8 @@ static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool // Submit a transfer, when complete hcd_event_xfer_complete() must be invoked bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { - uint8_t const ep_num = tu_edpt_number(ep_addr); - uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr); + const uint8_t ep_num = tu_edpt_number(ep_addr); + const uint8_t ep_dir = (uint8_t) tu_edpt_dir(ep_addr); max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir); TU_VERIFY(ep); @@ -744,8 +746,17 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf ep->xferred_len = 0; ep->state = EP_STATE_ATTEMPT_1; + bool has_xfer = false; + + usbh_spin_lock(false); + if (!_hcd_data.busy_lock) { + _hcd_data.busy_lock = true; + has_xfer = true; + } + usbh_spin_unlock(false); + // carry out transfer if not busy - if (!atomic_flag_test_and_set(&_hcd_data.busy)) { + if (has_xfer) { xact_generic(rhport, ep, true, false); } @@ -781,8 +792,17 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8] ep->xferred_len = 0; ep->state = EP_STATE_ATTEMPT_1; + bool has_xfer = false; + + usbh_spin_lock(false); + if (!_hcd_data.busy_lock) { + _hcd_data.busy_lock = true; + has_xfer = true; + } + usbh_spin_unlock(false); + // carry out transfer if not busy - if (!atomic_flag_test_and_set(&_hcd_data.busy)) { + if (has_xfer) { xact_setup(rhport, ep, false); } @@ -848,8 +868,8 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) { } static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl, bool in_isr) { - uint8_t const ep_dir = 1-ep->hxfr_bm.is_out; - uint8_t const ep_addr = tu_edpt_addr(ep->hxfr_bm.ep_num, ep_dir); + const uint8_t ep_dir = 1 - ep->hxfr_bm.is_out; + const uint8_t ep_addr = tu_edpt_addr(ep->hxfr_bm.ep_num, ep_dir); // save data toggle if (ep_dir) { @@ -867,7 +887,9 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re xact_generic(rhport, next_ep, true, in_isr); }else { // no more pending - atomic_flag_clear(&_hcd_data.busy); + usbh_spin_lock(in_isr); + _hcd_data.busy_lock = false; + usbh_spin_unlock(in_isr); } } @@ -906,7 +928,9 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { xact_generic(rhport, next_ep, true, in_isr); } else { // no more pending in this frame -> clear busy - atomic_flag_clear(&_hcd_data.busy); + usbh_spin_lock(in_isr); + _hcd_data.busy_lock = false; + usbh_spin_unlock(in_isr); } return; @@ -997,8 +1021,8 @@ void print_hirq(uint8_t hirq) { // Interrupt handler void hcd_int_handler(uint8_t rhport, bool in_isr) { uint8_t hirq = reg_read(rhport, HIRQ_ADDR, in_isr) & _hcd_data.hien; - if (!hirq) return; -// print_hirq(hirq); + if (!hirq) { return; } + // print_hirq(hirq); if (hirq & HIRQ_FRAME_IRQ) { _hcd_data.frame_count++; @@ -1017,8 +1041,19 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { } // start usb transfer if not busy - if (ep_retry != NULL && !atomic_flag_test_and_set(&_hcd_data.busy)) { - xact_generic(rhport, ep_retry, true, in_isr); + if (ep_retry != NULL) { + bool has_xfer = false; + + usbh_spin_lock(in_isr); + if (!_hcd_data.busy_lock) { + _hcd_data.busy_lock = true; + has_xfer = true; + } + usbh_spin_unlock(in_isr); + + if (has_xfer) { + xact_generic(rhport, ep_retry, true, in_isr); + } } } diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c index a716dc24c..244f5a2d4 100644 --- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c @@ -239,7 +239,11 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { usbmode |= USBMODE_CM_DEVICE; dcd_reg->USBMODE = usbmode; +#ifdef CFG_TUD_CI_HS_VBUS_CHARGE + dcd_reg->OTGSC = OTGSC_VBUS_CHARGE | OTGSC_OTG_TERMINATION; +#else dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION; +#endif #if !TUD_OPT_HIGH_SPEED dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED; diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 52d675611..865c51894 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -39,6 +39,7 @@ #define DWC2_DEBUG 2 #include "device/dcd.h" +#include "device/usbd_pvt.h" #include "dwc2_common.h" //--------------------------------------------------------------------+ @@ -52,6 +53,7 @@ typedef struct { uint8_t interval; } xfer_ctl_t; +// This variable is modified from ISR context, so it must be protected by critical section static xfer_ctl_t xfer_status[DWC2_EP_MAX][2]; #define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir]) @@ -321,6 +323,9 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { } } +// Since this function returns void, it is not possible to return a boolean success message +// We must make sure that this function is not called when the EP is disabled +// Must be called from critical section static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uint8_t dir) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir); @@ -531,6 +536,8 @@ void dcd_edpt_close_all(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + usbd_spin_lock(false); + _dcd_data.allocated_epin_count = 0; // Disable non-control interrupt @@ -548,8 +555,9 @@ void dcd_edpt_close_all(uint8_t rhport) { dfifo_flush_tx(dwc2, 0x10); // all tx fifo dfifo_flush_rx(dwc2); - dfifo_device_init(rhport); // re-init dfifo + + usbd_spin_unlock(false); } bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { @@ -567,21 +575,31 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpo bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = buffer; - xfer->ff = NULL; - xfer->total_len = total_bytes; + bool ret; - // EP0 can only handle one packet - if (epnum == 0) { - _dcd_data.ep0_pending[dir] = total_bytes; + usbd_spin_lock(false); + + if (xfer->max_size == 0) { + ret = false; // Endpoint is closed + } else { + xfer->buffer = buffer; + xfer->ff = NULL; + xfer->total_len = total_bytes; + + // EP0 can only handle one packet + if (epnum == 0) { + _dcd_data.ep0_pending[dir] = total_bytes; + } + + // Schedule packets to be sent within interrupt + edpt_schedule_packets(rhport, epnum, dir); + ret = true; } - // Schedule packets to be sent within interrupt - edpt_schedule_packets(rhport, epnum, dir); + usbd_spin_unlock(false); - return true; + return ret; } // The number of bytes has to be given explicitly to allow more flexible control of how many @@ -594,17 +612,27 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = NULL; - xfer->ff = ff; - xfer->total_len = total_bytes; + bool ret; - // Schedule packets to be sent within interrupt - // TODO xfer fifo may only available for slave mode - edpt_schedule_packets(rhport, epnum, dir); + usbd_spin_lock(false); - return true; + if (xfer->max_size == 0) { + ret = false; // Endpoint is closed + } else { + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; + + // Schedule packets to be sent within interrupt + // TODO xfer fifo may only available for slave mode + edpt_schedule_packets(rhport, epnum, dir); + ret = true; + } + + usbd_spin_unlock(false); + + return ret; } void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { @@ -631,6 +659,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { //-------------------------------------------------------------------- // 7.4.1 Initialization on USB Reset +// Must be called from critical section static void handle_bus_reset(uint8_t rhport) { dwc2_regs_t *dwc2 = DWC2_REG(rhport); const uint8_t ep_count = dwc2_ep_count(dwc2); @@ -983,14 +1012,16 @@ static void handle_ep_irq(uint8_t rhport, uint8_t dir) { */ void dcd_int_handler(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); - const uint32_t gintmask = dwc2->gintmsk; const uint32_t gintsts = dwc2->gintsts & gintmask; if (gintsts & GINTSTS_USBRST) { // USBRST is start of reset. dwc2->gintsts = GINTSTS_USBRST; + + usbd_spin_lock(true); handle_bus_reset(rhport); + usbd_spin_unlock(true); } if (gintsts & GINTSTS_ENUMDNE) { diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h index 3309760ff..49b8c54cb 100644 --- a/src/portable/synopsys/dwc2/dwc2_esp32.h +++ b/src/portable/synopsys/dwc2/dwc2_esp32.h @@ -55,8 +55,8 @@ static const dwc2_controller_t _dwc2_controller[] = { // On ESP32 for consistency we associate // - Port0 to OTG_FS, and Port1 to OTG_HS static const dwc2_controller_t _dwc2_controller[] = { -{ .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_CH0_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 }, -{ .reg_base = DWC2_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .ep_fifo_size = 4096 } + { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_CH0_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 }, + { .reg_base = DWC2_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .ep_fifo_size = 4096 } }; #endif diff --git a/src/tusb_option.h b/src/tusb_option.h index 98f1a91b5..104f669c9 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -195,6 +195,7 @@ // Analog Devices #define OPT_MCU_MAX32690 2400 ///< ADI MAX32690 +#define OPT_MCU_MAX32665 2401 ///< ADI MAX32666/5 #define OPT_MCU_MAX32666 2401 ///< ADI MAX32666/5 #define OPT_MCU_MAX32650 2402 ///< ADI MAX32650/1/2 #define OPT_MCU_MAX78002 2403 ///< ADI MAX78002 @@ -267,6 +268,15 @@ #define CFG_TUD_DWC2_DMA_ENABLE CFG_TUD_DWC2_DMA_ENABLE_DEFAULT #endif +// Enable CI_HS VBUS Charge. Set this to 1 if the USB_VBUS pin is not connected to 5V VBUS (note: 3.3V is insufficient). +#ifndef CFG_TUD_CI_HS_VBUS_CHARGE + #ifndef CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT + #define CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT 0 + #endif + + #define CFG_TUD_CI_HS_VBUS_CHARGE CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT +#endif + // Enable DWC2 Slave mode for host #ifndef CFG_TUH_DWC2_SLAVE_ENABLE #ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT |
