Merge pull request #528 from adafruit/fix-esp32-max3421e
fix compiling hcd max3421e with arduino-esp32 and arduino-pico due to missing atomic_flag function
This commit is contained in:
commit
9496740134
22 changed files with 414 additions and 196 deletions
52
.github/workflows/githubci.yml
vendored
52
.github/workflows/githubci.yml
vendored
|
|
@ -38,7 +38,7 @@ jobs:
|
|||
run: bash ci/doxy_gen_and_deploy.sh
|
||||
|
||||
# ---------------------------------------
|
||||
# Main
|
||||
# build
|
||||
# ---------------------------------------
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -83,53 +83,3 @@ jobs:
|
|||
|
||||
- name: test platforms
|
||||
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
|
||||
|
||||
# ---------------------------------------
|
||||
# Build ESP32 v2
|
||||
# ---------------------------------------
|
||||
build-esp32-v2:
|
||||
if: false
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-commit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arduino-platform:
|
||||
- 'feather_esp32s2'
|
||||
- 'feather_esp32s3'
|
||||
esp32-version:
|
||||
- '2.0.17'
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Checkout adafruit/ci-arduino
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: adafruit/ci-arduino
|
||||
path: ci
|
||||
|
||||
- name: pre-install
|
||||
run: bash ci/actions_install.sh
|
||||
|
||||
- name: Install arduino-esp32 v2 and Libraries
|
||||
env:
|
||||
BSP_URLS: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
|
||||
run: |
|
||||
arduino-cli core install esp32:esp32@${{ matrix.esp32-version }} --additional-urls $BSP_URLS
|
||||
arduino-cli lib install ${{ env.ARDUINO_LIBS }}
|
||||
arduino-cli core list
|
||||
arduino-cli lib list
|
||||
|
||||
- name: Create custom build script
|
||||
working-directory: ${{ github.workspace }}/ci
|
||||
run: |
|
||||
echo 'import build_platform' > build_esp32_v2.py
|
||||
echo 'build_platform.test_examples_in_folder("'${{ matrix.arduino-platform }}'", build_platform.BUILD_DIR)' >> build_esp32_v2.py
|
||||
echo 'exit(build_platform.success)' >> build_esp32_v2.py
|
||||
cat build_esp32_v2.py
|
||||
|
||||
- name: test platforms
|
||||
run: |
|
||||
python3 ci/build_esp32_v2.py
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
40
src/class/vendor/vendor_device.c
vendored
40
src/class/vendor/vendor_device.c
vendored
|
|
@ -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;
|
||||
}
|
||||
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));
|
||||
|
||||
const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
|
||||
TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
|
||||
found_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);
|
||||
|
|
|
|||
|
|
@ -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")))
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -342,15 +342,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
|
||||
|
|
@ -468,7 +469,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));
|
||||
|
|
@ -477,6 +478,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);
|
||||
|
|
@ -1248,17 +1251,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -547,7 +552,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 +567,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 &&
|
||||
|
|
@ -579,7 +584,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 +624,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 {
|
||||
|
|
@ -894,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;
|
||||
|
|
@ -1463,7 +1477,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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -101,10 +99,71 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
|||
vTaskDelay(pdMS_TO_TICKS(msec));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,32 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
|||
os_time_delay( os_time_ms_to_ticks32(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
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -40,6 +40,33 @@ extern "C" {
|
|||
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
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -43,6 +43,27 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
|||
sleep_ms(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
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -42,6 +42,32 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
|||
rt_thread_mdelay(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
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -56,6 +56,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
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -35,6 +35,35 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
|||
k_msleep(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
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -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,13 +233,7 @@ typedef struct {
|
|||
uint8_t hxfr;
|
||||
}sndfifo_owner;
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_RP2040
|
||||
// currently has undefined reference to `__atomic_test_and_set' with rp2040 on Arduino with gcc 14.2
|
||||
// temporarily use native semaphore instead. TODO rework osal semaphore/mutex later on
|
||||
semaphore_t busy; // busy transferring
|
||||
#else
|
||||
atomic_flag busy; // busy transferring
|
||||
#endif
|
||||
bool busy_lock; // busy transferring
|
||||
|
||||
#if OSAL_MUTEX_REQUIRED
|
||||
OSAL_MUTEX_DEF(spi_mutexdef);
|
||||
|
|
@ -258,25 +252,6 @@ static tuh_configure_max3421_t _tuh_cfg = {
|
|||
.pinctl = 0, // default: negative edge interrupt
|
||||
};
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_RP2040
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool usb_xfer_test_and_set(void) {
|
||||
return !sem_try_acquire(&_hcd_data.busy);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void usb_xfer_clear(void) {
|
||||
sem_release(&_hcd_data.busy);
|
||||
}
|
||||
|
||||
#else
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool usb_xfer_test_and_set(void) {
|
||||
return atomic_flag_test_and_set(&_hcd_data.busy);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void usb_xfer_clear(void) {
|
||||
atomic_flag_clear(&_hcd_data.busy);
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SPI Commands and Helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -352,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);
|
||||
|
|
@ -398,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);
|
||||
|
||||
|
|
@ -414,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)
|
||||
|
|
@ -509,10 +486,6 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
|||
tu_memclr(&_hcd_data, sizeof(_hcd_data));
|
||||
_hcd_data.peraddr = 0xff; // invalid
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_RP2040
|
||||
sem_init(&_hcd_data.busy, 1, 1);
|
||||
#endif
|
||||
|
||||
#if OSAL_MUTEX_REQUIRED
|
||||
_hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef);
|
||||
#endif
|
||||
|
|
@ -570,10 +543,6 @@ bool hcd_deinit(uint8_t rhport) {
|
|||
_hcd_data.spi_mutex = NULL;
|
||||
#endif
|
||||
|
||||
#if CFG_TUSB_MCU == OPT_MCU_RP2040
|
||||
sem_reset(&_hcd_data.busy, 1);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -760,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);
|
||||
|
||||
|
|
@ -777,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 (!usb_xfer_test_and_set()) {
|
||||
if (has_xfer) {
|
||||
xact_generic(rhport, ep, true, false);
|
||||
}
|
||||
|
||||
|
|
@ -814,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 (!usb_xfer_test_and_set()) {
|
||||
if (has_xfer) {
|
||||
xact_setup(rhport, ep, false);
|
||||
}
|
||||
|
||||
|
|
@ -881,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) {
|
||||
|
|
@ -900,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
|
||||
usb_xfer_clear();
|
||||
usbh_spin_lock(in_isr);
|
||||
_hcd_data.busy_lock = false;
|
||||
usbh_spin_unlock(in_isr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -939,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
|
||||
usb_xfer_clear();
|
||||
usbh_spin_lock(in_isr);
|
||||
_hcd_data.busy_lock = false;
|
||||
usbh_spin_unlock(in_isr);
|
||||
}
|
||||
return;
|
||||
|
||||
|
|
@ -1030,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++;
|
||||
|
|
@ -1050,8 +1041,19 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
|||
}
|
||||
|
||||
// start usb transfer if not busy
|
||||
if (ep_retry != NULL && !usb_xfer_test_and_set()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue