summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorValentin Milea <[email protected]>2022-01-07 15:12:07 +0200
committerValentin Milea <[email protected]>2022-01-07 15:12:07 +0200
commitc2533a45bd932d672458cf54d37ac5207a734e41 (patch)
treea8d886bdccaed451053262b0d875612338389474 /src
parenta284e438f1952315631f354dee2b30b264afb324 (diff)
parent3b09b82123a50bef6b18cf90c2734ae7581da4a3 (diff)
Merge branch 'master' into feature/feedback_format
Diffstat (limited to 'src')
-rw-r--r--src/class/usbtmc/usbtmc_device.c18
-rw-r--r--src/common/tusb_verify.h14
-rw-r--r--src/device/dcd_attr.h2
-rw-r--r--src/portable/mentor/musb/dcd_musb.c7
-rw-r--r--src/portable/mentor/musb/hcd_musb.c876
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c8
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c38
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c2
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c5
-rw-r--r--src/portable/synopsys/dwc2/dwc2_bcm.h3
-rw-r--r--src/portable/valentyusb/eptri/dcd_eptri.c8
-rw-r--r--src/tusb_option.h2
12 files changed, 943 insertions, 40 deletions
diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c
index 4bd1edf12..26be987cf 100644
--- a/src/class/usbtmc/usbtmc_device.c
+++ b/src/class/usbtmc/usbtmc_device.c
@@ -235,17 +235,19 @@ void usbtmcd_init_cb(void)
usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb();
#ifndef NDEBUG
# if CFG_TUD_USBTMC_ENABLE_488
- if(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger)
- TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL,);
- // Per USB488 spec: table 8
- TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly,);
- TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly,);
+ if (usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger) {
+ TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL,);
+ }
+ // Per USB488 spec: table 8
+ TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly,);
+ TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly,);
# endif
- if(usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse)
- TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL,);
+ if (usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse) {
+ TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL,);
+ }
#endif
- usbtmcLock = osal_mutex_create(&usbtmcLockBuffer);
+ usbtmcLock = osal_mutex_create(&usbtmcLockBuffer);
}
uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index 56ba8bcd1..8fef11dc7 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -37,31 +37,31 @@
* manipulation that you are told to stay away.
*
* This contains macros for both VERIFY and ASSERT:
- *
+ *
* VERIFY: Used when there is an error condition which is not the
* fault of the MCU. For example, bounds checking on data
* sent to the micro over USB should use this function.
* Another example is checking for buffer overflows, where
* returning from the active function causes a NAK.
- *
+ *
* ASSERT: Used for error conditions that are caused by MCU firmware
* bugs. This is used to discover bugs in the code more
* quickly. One example would be adding assertions in library
* function calls to confirm a function's (untainted)
* parameters are valid.
- *
+ *
* The difference in behavior is that ASSERT triggers a breakpoint while
* verify does not.
*
* #define TU_VERIFY(cond) if(cond) return false;
* #define TU_VERIFY(cond,ret) if(cond) return ret;
- *
+ *
* #define TU_VERIFY_HDLR(cond,handler) if(cond) {handler; return false;}
* #define TU_VERIFY_HDLR(cond,ret,handler) if(cond) {handler; return ret;}
*
* #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;}
* #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
- *
+ *
*------------------------------------------------------------------*/
#ifdef __cplusplus
@@ -81,8 +81,8 @@
#define _MESS_FAILED() do {} while (0)
#endif
-// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
-#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
+// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33
+#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)
#define TU_BREAKPOINT() do \
{ \
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
diff --git a/src/device/dcd_attr.h b/src/device/dcd_attr.h
index 3c5dadaf4..feba82ea9 100644
--- a/src/device/dcd_attr.h
+++ b/src/device/dcd_attr.h
@@ -190,7 +190,7 @@
#define DCD_ATTR_ENDPOINT_MAX 4
//------------- Broadcom -------------//
-#elif TU_CHECK_MCU(OPT_MCU_BCM2711)
+#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
#define DCD_ATTR_ENDPOINT_MAX 8
//------------- Broadcom -------------//
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
index 4b4c2f9b2..f6e05e134 100644
--- a/src/portable/mentor/musb/dcd_musb.c
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -26,7 +26,8 @@
#include "tusb_option.h"
-#if TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+#if TUSB_OPT_DEVICE_ENABLED && \
+ TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
/* GCC warns that an address may be unaligned, even though
@@ -250,12 +251,12 @@ static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
len -= 4;
}
if (len >= 2) {
- *(uint32_t *)addr = reg->u16;
+ *(uint16_t *)addr = reg->u16;
addr += 2;
len -= 2;
}
if (len) {
- *(uint32_t *)addr = reg->u8;
+ *(uint8_t *)addr = reg->u8;
}
}
diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c
new file mode 100644
index 000000000..acccb7674
--- /dev/null
+++ b/src/portable/mentor/musb/hcd_musb.c
@@ -0,0 +1,876 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_HOST_ENABLED && \
+ TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+
+#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
+/* GCC warns that an address may be unaligned, even though
+ * the target CPU has the capability for unaligned memory access. */
+_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
+#endif
+
+#include "host/hcd.h"
+
+#if TU_CHECK_MCU(OPT_MCU_MSP432E4)
+ #include "musb_msp432e.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #include "musb_tm4c.h"
+
+ // HACK generalize later
+ #include "musb_type.h"
+ #define FIFO0_WORD FIFO0
+
+#else
+ #error "Unsupported MCUs"
+#endif
+
+#ifndef HCD_ATTR_ENDPOINT_MAX
+# define HCD_ATTR_ENDPOINT_MAX 8
+#endif
+
+/*------------------------------------------------------------------
+ * MACRO TYPEDEF CONSTANT ENUM DECLARATION
+ *------------------------------------------------------------------*/
+#define REQUEST_TYPE_INVALID (0xFFu)
+
+typedef struct {
+ uint_fast16_t beg; /* offset of including first element */
+ uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t TXFUNCADDR;
+ uint8_t RESERVED0;
+ uint8_t TXHUBADDR;
+ uint8_t TXHUBPORT;
+ uint8_t RXFUNCADDR;
+ uint8_t RESERVED1;
+ uint8_t RXHUBADDR;
+ uint8_t RXHUBPORT;
+} hw_addr_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t TXMAXP;
+ uint8_t TXCSRL;
+ uint8_t TXCSRH;
+ uint16_t RXMAXP;
+ uint8_t RXCSRL;
+ uint8_t RXCSRH;
+ uint16_t RXCOUNT;
+ uint8_t TXTYPE;
+ uint8_t TXINTERVAL;
+ uint8_t RXTYPE;
+ uint8_t RXINTERVAL;
+ uint16_t RESERVED;
+} hw_endpoint_t;
+
+typedef union {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+} hw_fifo_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+} pipe_state_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ uint8_t dev;
+ uint8_t ep;
+} pipe_addr_t;
+
+typedef struct
+{
+ bool need_reset; /* The device has not been reset after connection. */
+ uint8_t bmRequestType;
+ uint8_t ctl_mps[7]; /* EP0 max packet size for each device */
+ pipe_state_t pipe0;
+ pipe_state_t pipe[7][2]; /* pipe[pipe number - 1][direction 0:RX 1:TX] */
+ pipe_addr_t addr[7][2]; /* addr[pipe number - 1][direction 0:RX 1:TX] */
+} hcd_data_t;
+
+/*------------------------------------------------------------------
+ * INTERNAL OBJECT & FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+static hcd_data_t _hcd;
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+ free_block_t *cur = beg;
+ for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+ return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+ free_block_t *p = find_containing_block(blks, blks + num, addr);
+ TU_ASSERT(p != blks + num, -2);
+ if (p->beg == addr) {
+ /* Shrink block */
+ p->beg = addr + size;
+ if (p->beg != p->end) return 0;
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ } else {
+ /* Split into 2 blocks */
+ free_block_t tmp = {
+ .beg = addr + size,
+ .end = p->end
+ };
+ p->end = addr;
+ if (p->beg == p->end) {
+ if (tmp.beg != tmp.end) {
+ *p = tmp;
+ return 0;
+ }
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ }
+ if (tmp.beg == tmp.end) return 0;
+ blks[num] = tmp;
+ return 1;
+ }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+ return blk->end - blk->beg;
+}
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+ free_block_t free_blocks[2 * (HCD_ATTR_ENDPOINT_MAX - 1)];
+ unsigned num_blocks = 1;
+
+ /* Initialize free memory block list */
+ free_blocks[0].beg = 64 / 8;
+ free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */
+ for (int i = 1; i < HCD_ATTR_ENDPOINT_MAX; ++i) {
+ uint_fast16_t addr;
+ int num;
+ USB0->EPIDX = i;
+ addr = USB0->TXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->TXFIFOSZ;
+ unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ }
+ addr = USB0->RXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->RXFIFOSZ;
+ unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ }
+ }
+
+ /* Find the best fit memory block */
+ uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+ free_block_t const *min = NULL;
+ uint_fast16_t min_sz = 0xFFFFu;
+ free_block_t const *end = &free_blocks[num_blocks];
+ for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+ uint_fast16_t sz = free_block_size(cur);
+ if (sz < size_in_8byte_unit) continue;
+ if (size_in_8byte_unit == sz) return cur->beg;
+ if (sz < min_sz) min = cur;
+ }
+ TU_ASSERT(min, 0);
+ return min->beg;
+}
+
+static inline volatile hw_endpoint_t* edpt_regs(unsigned epnum_minus1)
+{
+ volatile hw_endpoint_t *regs = (volatile hw_endpoint_t*)((uintptr_t)&USB0->TXMAXP1);
+ return regs + epnum_minus1;
+}
+
+static unsigned find_pipe(uint_fast8_t dev_addr, uint_fast8_t ep_addr)
+{
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ pipe_addr_t const *p = &_hcd.addr[0][dir_tx];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i, p += 2) {
+ if ((dev_addr == p->dev) && (ep_addr == p->ep))
+ return i + 1;
+ }
+ return 0;
+}
+
+static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ reg->u32 = *(uint32_t const *)addr;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ reg->u16 = *(uint16_t const *)addr;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ reg->u8 = *(uint8_t const *)addr;
+ }
+}
+
+static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ *(uint32_t *)addr = reg->u32;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ *(uint16_t *)addr = reg->u16;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ *(uint8_t *)addr = reg->u8;
+ }
+}
+
+static bool edpt0_xfer_out(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe0;
+ unsigned const rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const mps = _hcd.ctl_mps[dev_addr];
+ unsigned const len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, &USB0->FIFO0_WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ USB0->CSRL0 = USB_CSRL0_TXRDY;
+ return false;
+}
+
+static bool edpt0_xfer_in(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe0;
+ unsigned const rem = pipe->remaining;
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const mps = _hcd.ctl_mps[dev_addr];
+ unsigned const vld = USB0->COUNT0;
+ unsigned const len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, &USB0->FIFO0_WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return true;
+ }
+ USB0->CSRL0 = USB_CSRL0_REQPKT;
+ return false;
+}
+
+static bool edpt0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+
+ unsigned const req = _hcd.bmRequestType;
+ TU_ASSERT(req != REQUEST_TYPE_INVALID);
+ TU_ASSERT(dev_addr < sizeof(_hcd.ctl_mps));
+
+ USB0->TXFUNCADDR0 = dev_addr;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
+ TU_ASSERT(buffer);
+ _hcd.pipe0.buf = buffer;
+ _hcd.pipe0.length = buflen;
+ _hcd.pipe0.remaining = buflen;
+ if (dir_in)
+ USB0->CSRL0 = USB_CSRL0_REQPKT;
+ else
+ edpt0_xfer_out();
+ } else { /* STATUS stage */
+ _hcd.pipe0.buf = NULL;
+ _hcd.pipe0.length = 0;
+ _hcd.pipe0.remaining = 0;
+ USB0->CSRL0 = USB_CSRL0_STATUS | (dir_in ? USB_CSRL0_REQPKT: USB_CSRL0_TXRDY);
+ }
+ return true;
+}
+
+static bool pipe_xfer_out(uint_fast8_t pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][1];
+ unsigned const rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ unsigned const mps = regs->TXMAXP;
+ unsigned const len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, &USB0->FIFO0_WORD + pipenum, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ regs->TXCSRL = USB_TXCSRL1_TXRDY;
+ return false;
+}
+
+static bool pipe_xfer_in(uint_fast8_t pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][0];
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+
+ TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY);
+
+ const unsigned mps = regs->RXMAXP;
+ const unsigned rem = pipe->remaining;
+ const unsigned vld = regs->RXCOUNT;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, &USB0->FIFO0_WORD + pipenum, len);
+ pipe->buf = buf + len;
+ pipe->remaining = rem - len;
+ }
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ regs->RXCSRL = USB_RXCSRL1_REQPKT;
+ return false;
+}
+
+static bool edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+ unsigned const pipenum = find_pipe(dev_addr, ep_addr);
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][dir_tx];
+ pipe->buf = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (dir_tx) {
+ pipe_xfer_out(pipenum);
+ } else {
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ regs->RXCSRL = USB_RXCSRL1_REQPKT;
+ }
+ return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+ (void)rhport;
+
+ uint_fast8_t csrl = USB0->CSRL0;
+ // TU_LOG1(" EP0 CSRL = %x\n", csrl);
+
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const req = _hcd.bmRequestType;
+ if (csrl & (USB_CSRL0_ERROR | USB_CSRL0_NAKTO | USB_CSRL0_STALLED)) {
+ /* No response / NAK timed out / Stall received */
+ if (csrl & (USB_CSRL0_RXRDY | USB_CSRL0_TXRDY))
+ USB0->CSRH0 = USB_CSRH0_FLUSH;
+ USB0->CSRL0 = 0;
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ uint8_t result = (csrl & USB_CSRL0_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ if (REQUEST_TYPE_INVALID == req) { /* SETUP */
+ uint8_t const ep_addr = tu_edpt_addr(0, TUSB_DIR_OUT);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ } else if (csrl & USB_CSRL0_STATUS) { /* STATUS */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_OUT): tu_edpt_addr(0, TUSB_DIR_IN);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ } else { /* DATA */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_IN): tu_edpt_addr(0, TUSB_DIR_OUT);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ }
+ return;
+ }
+ if (csrl & USB_CSRL0_STATUS) {
+ /* STATUS IN */
+ TU_ASSERT(USB_CSRL0_RXRDY == (csrl & USB_CSRL0_RXRDY),);
+ TU_ASSERT(0 == USB0->COUNT0,);
+ USB0->CSRH0 = USB_CSRH0_FLUSH;
+ USB0->CSRL0 = 0;
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_IN),
+ 0, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (csrl & USB_CSRL0_RXRDY) {
+ /* DATA IN */
+ TU_ASSERT(REQUEST_TYPE_INVALID != req,);
+ TU_ASSERT(_hcd.pipe0.buf,);
+ if (edpt0_xfer_in()) {
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_IN),
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ return;
+ }
+
+ /* When CSRL0 is zero, it means that completion of sending a any length packet. */
+ if (!_hcd.pipe0.buf) {
+ /* STATUS OUT */
+ TU_ASSERT(REQUEST_TYPE_INVALID != req,);
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ /* EP address is the reverse direction of DATA stage */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_OUT): tu_edpt_addr(0, TUSB_DIR_IN);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (REQUEST_TYPE_INVALID == req) {
+ /* SETUP */
+ _hcd.bmRequestType = *(uint8_t*)_hcd.pipe0.buf;
+ _hcd.pipe0.buf = NULL;
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_OUT),
+ 8, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+
+ /* DATA OUT */
+ if (edpt0_xfer_out()) {
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_pipe_tx(uint8_t rhport, uint_fast8_t pipenum)
+{
+ (void)rhport;
+ bool completed;
+ uint8_t result;
+
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ unsigned const csrl = regs->TXCSRL;
+ // TU_LOG1(" TXCSRL%d = %x\n", pipenum, csrl);
+ if (csrl & (USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) {
+ if (csrl & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = (csrl & ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = csrl & ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR);
+ completed = true;
+ result = (csrl & USB_TXCSRL1_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ } else {
+ completed = pipe_xfer_out(pipenum);
+ result = XFER_RESULT_SUCCESS;
+ }
+ if (completed) {
+ pipe_addr_t *addr = &_hcd.addr[pipenum - 1][1];
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][1];
+ hcd_event_xfer_complete(addr->dev, addr->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+ }
+}
+
+static void process_pipe_rx(uint8_t rhport, uint_fast8_t pipenum)
+{
+ (void)rhport;
+ bool completed;
+ uint8_t result;
+
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ unsigned const csrl = regs->RXCSRL;
+ // TU_LOG1(" RXCSRL%d = %x\n", pipenum, csrl);
+ if (csrl & (USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) {
+ if (csrl & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = (csrl & ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = csrl & ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR);
+ completed = true;
+ result = (csrl & USB_RXCSRL1_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ } else {
+ completed = pipe_xfer_in(pipenum);
+ result = XFER_RESULT_SUCCESS;
+ }
+ if (completed) {
+ pipe_addr_t *addr = &_hcd.addr[pipenum - 1][0];
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][0];
+ hcd_event_xfer_complete(addr->dev, addr->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+ }
+}
+
+/*------------------------------------------------------------------
+ * Host API
+ *------------------------------------------------------------------*/
+
+bool hcd_init(uint8_t rhport)
+{
+ (void)rhport;
+
+ NVIC_ClearPendingIRQ(USB0_IRQn);
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ USB0->DEVCTL |= USB_DEVCTL_SESSION;
+ USB0->IE = USB_IE_DISCON | USB_IE_CONN | USB_IE_BABBLE | USB_IE_RESUME;
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void)rhport;
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ return USB0->FRAME;
+}
+
+//--------------------------------------------------------------------+
+// Port API
+//--------------------------------------------------------------------+
+
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ (void)rhport;
+ unsigned devctl = USB0->DEVCTL;
+ if (!(devctl & USB_DEVCTL_HOST)) return false;
+ if (devctl & (USB_DEVCTL_LSDEV | USB_DEVCTL_FSDEV)) return true;
+ return false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ (void)rhport;
+ USB0->POWER |= USB_POWER_HSENAB | USB_POWER_RESET;
+ unsigned cnt = SystemCoreClock / 1000 * 20;
+ while (cnt--) __NOP();
+ USB0->POWER &= ~USB_POWER_RESET;
+ _hcd.need_reset = false;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ (void)rhport;
+ unsigned devctl = USB0->DEVCTL;
+ if (devctl & USB_DEVCTL_LSDEV) return TUSB_SPEED_LOW;
+ if (!(devctl & USB_DEVCTL_FSDEV)) return TUSB_SPEED_INVALID;
+ if (USB0->POWER & USB_POWER_HSMODE) return TUSB_SPEED_HIGH;
+ return TUSB_SPEED_FULL;
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ if (sizeof(_hcd.ctl_mps) <= dev_addr) return;
+
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ _hcd.ctl_mps[dev_addr] = 0;
+ if (!dev_addr) return;
+
+ pipe_addr_t *p = &_hcd.addr[0][0];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i) {
+ for (unsigned j = 0; j < 2; ++j, ++p) {
+ if (dev_addr != p->dev) continue;
+ hw_addr_t volatile *fadr = (hw_addr_t volatile*)&USB0->TXFUNCADDR0 + i + 1;
+ hw_endpoint_t volatile *regs = edpt_regs(i);
+ USB0->EPIDX = i + 1;
+ if (j) {
+ USB0->TXIE &= ~TU_BIT(i + 1);
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ regs->TXMAXP = 0;
+ regs->TXTYPE = 0;
+ regs->TXINTERVAL = 0;
+ fadr->TXFUNCADDR = 0;
+ fadr->TXHUBADDR = 0;
+ fadr->TXHUBPORT = 0;
+ USB0->TXFIFOADD = 0;
+ USB0->TXFIFOSZ = 0;
+ } else {
+ USB0->RXIE &= ~TU_BIT(i + 1);
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ regs->RXMAXP = 0;
+ regs->RXTYPE = 0;
+ regs->RXINTERVAL = 0;
+ fadr->RXFUNCADDR = 0;
+ fadr->RXHUBADDR = 0;
+ fadr->RXHUBPORT = 0;
+ USB0->RXFIFOADD = 0;
+ USB0->RXFIFOSZ = 0;
+ }
+ p->dev = 0;
+ p->ep = 0;
+ pipe_state_t *pipe = &_hcd.pipe[i][j];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+ }
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ (void)rhport;
+ pipe_write_packet((void*)(uintptr_t)setup_packet, &USB0->FIFO0_WORD, 8);
+ _hcd.pipe0.buf = (void*)(uintptr_t)setup_packet;
+ _hcd.pipe0.length = 8;
+ _hcd.pipe0.remaining = 0;
+
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ switch (devtree.speed) {
+ default: return false;
+ case TUSB_SPEED_LOW: USB0->TYPE0 = USB_TYPE0_SPEED_LOW; break;
+ case TUSB_SPEED_FULL: USB0->TYPE0 = USB_TYPE0_SPEED_FULL; break;
+ case TUSB_SPEED_HIGH: USB0->TYPE0 = USB_TYPE0_SPEED_HIGH; break;
+ }
+ USB0->TXHUBADDR0 = devtree.hub_addr;
+ USB0->TXHUBPORT0 = devtree.hub_port;
+ USB0->TXFUNCADDR0 = dev_addr;
+ USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_SETUP;
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+ if (sizeof(_hcd.ctl_mps) <= dev_addr) return false;
+ unsigned const ep_addr = ep_desc->bEndpointAddress;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ if (0 == epn) {
+ _hcd.ctl_mps[dev_addr] = ep_desc->wMaxPacketSize;
+ return true;
+ }
+
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ /* Find a free pipe */
+ unsigned pipenum = 0;
+ pipe_addr_t *p = &_hcd.addr[0][dir_tx];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i, p += 2) {
+ if (0 == p->ep) {
+ p->dev = dev_addr;
+ p->ep = ep_addr;
+ pipenum = i + 1;
+ break;
+ }
+ }
+ if (!pipenum) return false;
+
+ unsigned const xfer = ep_desc->bmAttributes.xfer;
+ unsigned const mps = tu_edpt_packet_size(ep_desc);
+
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][dir_tx];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+
+ uint8_t pipe_type = 0;
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ switch (devtree.speed) {
+ default: return false;
+ case TUSB_SPEED_LOW: pipe_type |= USB_TXTYPE1_SPEED_LOW; break;
+ case TUSB_SPEED_FULL: pipe_type |= USB_TXTYPE1_SPEED_FULL; break;
+ case TUSB_SPEED_HIGH: pipe_type |= USB_TXTYPE1_SPEED_HIGH; break;
+ }
+ switch (xfer) {
+ default: return false;
+ case TUSB_XFER_BULK: pipe_type |= USB_TXTYPE1_PROTO_BULK; break;
+ case TUSB_XFER_INTERRUPT: pipe_type |= USB_TXTYPE1_PROTO_INT; break;
+ case TUSB_XFER_ISOCHRONOUS: pipe_type |= USB_TXTYPE1_PROTO_ISOC; break;
+ }
+
+ hw_addr_t volatile *fadr = (hw_addr_t volatile*)&USB0->TXFUNCADDR0 + pipenum;
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ if (dir_tx) {
+ fadr->TXFUNCADDR = dev_addr;
+ fadr->TXHUBADDR = devtree.hub_addr;
+ fadr->TXHUBPORT = devtree.hub_port;
+ regs->TXMAXP = mps;
+ regs->TXTYPE = pipe_type | epn;
+ regs->TXINTERVAL = ep_desc->bInterval;
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ USB0->TXIE |= TU_BIT(pipenum);
+ } else {
+ fadr->RXFUNCADDR = dev_addr;
+ fadr->RXHUBADDR = devtree.hub_addr;
+ fadr->RXHUBPORT = devtree.hub_port;
+ regs->RXMAXP = mps;
+ regs->RXTYPE = pipe_type | epn;
+ regs->RXINTERVAL = ep_desc->bInterval;
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ USB0->RXIE |= TU_BIT(pipenum);
+ }
+
+ /* Setup FIFO */
+ int size_in_log2_minus3 = 28 - TU_MIN(28, __CLZ((uint32_t)mps));
+ if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+ unsigned addr = find_free_memory(size_in_log2_minus3);
+ TU_ASSERT(addr);
+
+ USB0->EPIDX = pipenum;
+ if (dir_tx) {
+ USB0->TXFIFOADD = addr;
+ USB0->TXFIFOSZ = size_in_log2_minus3;
+ } else {
+ USB0->RXFIFOADD = addr;
+ USB0->RXFIFOSZ = size_in_log2_minus3;
+ }
+ return true;
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+ bool ret = false;
+ if (0 == tu_edpt_number(ep_addr)) {
+ ret = edpt0_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ } else {
+ ret = edpt_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ }
+ return ret;
+}
+
+// clear stall, data toggle is also reset to DATA0
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ unsigned const pipenum = find_pipe(dev_addr, ep_addr);
+ if (!pipenum) return false;
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ if (dir_tx)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ return true;
+}
+
+/*-------------------------------------------------------------------
+ * ISR
+ *-------------------------------------------------------------------*/
+void hcd_int_handler(uint8_t rhport)
+{
+ uint_fast8_t is, txis, rxis;
+
+ is = USB0->IS; /* read and clear interrupt status */
+ txis = USB0->TXIS; /* read and clear interrupt status */
+ rxis = USB0->RXIS; /* read and clear interrupt status */
+ // TU_LOG1("D%2x T%2x R%2x\n", is, txis, rxis);
+
+ is &= USB0->IE; /* Clear disabled interrupts */
+ if (is & USB_IS_RESUME) {
+ }
+ if (is & USB_IS_CONN) {
+ _hcd.need_reset = true;
+ hcd_event_device_attach(rhport, true);
+ }
+ if (is & USB_IS_DISCON) {
+ hcd_event_device_remove(rhport, true);
+ }
+ if (is & USB_IS_BABBLE) {
+ }
+ txis &= USB0->TXIE; /* Clear disabled interrupts */
+ if (txis & USB_TXIE_EP0) {
+ process_ep0(rhport);
+ txis &= ~TU_BIT(0);
+ }
+ while (txis) {
+ unsigned const num = __builtin_ctz(txis);
+ process_pipe_tx(rhport, num);
+ txis &= ~TU_BIT(num);
+ }
+ rxis &= USB0->RXIE; /* Clear disabled interrupts */
+ while (rxis) {
+ unsigned const num = __builtin_ctz(rxis);
+ process_pipe_rx(rhport, num);
+ rxis &= ~TU_BIT(num);
+ }
+}
+
+#endif
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 2bcd56b8a..ed597a34f 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -1059,7 +1059,13 @@ void tusb_hal_nrf_power_event (uint32_t event)
// Enable interrupt, priorities should be set by application
NVIC_ClearPendingIRQ(USBD_IRQn);
- NVIC_EnableIRQ(USBD_IRQn);
+ // Don't enable USBD interrupt yet, if dcd_init() did not finish yet
+ // Interrupt will be enabled by tud_init(), when USB stack is ready
+ // to handle interrupts.
+ if (tud_inited())
+ {
+ NVIC_EnableIRQ(USBD_IRQn);
+ }
// Wait for HFCLK
while ( !hfclk_running() ) { }
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index e084478e0..42add3167 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -83,7 +83,7 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
- assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
+ hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
pico_info(" Alloced %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
@@ -93,7 +93,6 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
*ep->endpoint_control = reg;
}
-#if 0 // todo unused
static void _hw_endpoint_close(struct hw_endpoint *ep)
{
// Clear hardware registers and then zero the struct
@@ -103,6 +102,21 @@ static void _hw_endpoint_close(struct hw_endpoint *ep)
*ep->buffer_control = 0;
// Clear any endpoint state
memset(ep, 0, sizeof(struct hw_endpoint));
+
+ // Reclaim buffer space if all endpoints are closed
+ bool reclaim_buffers = true;
+ for ( uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++ )
+ {
+ if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL || hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL)
+ {
+ reclaim_buffers = false;
+ break;
+ }
+ }
+ if (reclaim_buffers)
+ {
+ next_buffer_ptr = &usb_dpram->epx_data[0];
+ }
}
static void hw_endpoint_close(uint8_t ep_addr)
@@ -110,7 +124,6 @@ static void hw_endpoint_close(uint8_t ep_addr)
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_close(ep);
}
-#endif
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
{
@@ -224,6 +237,8 @@ static void reset_non_control_endpoints(void)
// clear non-control hw endpoints
tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2*sizeof(hw_endpoint_t));
+
+ // reclaim buffer space
next_buffer_ptr = &usb_dpram->epx_data[0];
}
@@ -232,6 +247,14 @@ static void dcd_rp2040_irq(void)
uint32_t const status = usb_hw->ints;
uint32_t handled = 0;
+ // xfer events are handled before setup req. So if a transfer completes immediately
+ // before closing the EP, the events will be delivered in same order.
+ if (status & USB_INTS_BUFF_STATUS_BITS)
+ {
+ handled |= USB_INTS_BUFF_STATUS_BITS;
+ hw_handle_buff_status();
+ }
+
if (status & USB_INTS_SETUP_REQ_BITS)
{
handled |= USB_INTS_SETUP_REQ_BITS;
@@ -245,12 +268,6 @@ static void dcd_rp2040_irq(void)
usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
}
- if (status & USB_INTS_BUFF_STATUS_BITS)
- {
- handled |= USB_INTS_BUFF_STATUS_BITS;
- hw_handle_buff_status();
- }
-
#if FORCE_VBUS_DETECT == 0
// Since we force VBUS detect On, device will always think it is connected and
// couldn't distinguish between disconnect and suspend
@@ -479,10 +496,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
- (void) ep_addr;
- // usbd.c says: In progress transfers on this EP may be delivered after this call
pico_trace("dcd_edpt_close %02x\n", ep_addr);
+ hw_endpoint_close(ep_addr);
}
void dcd_int_handler(uint8_t rhport)
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index c9e2f6b26..9d833e65f 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -294,7 +294,7 @@ bool hw_endpoint_xfer_continue(struct hw_endpoint *ep)
// Part way through a transfer
if (!ep->active)
{
- panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
+ panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
}
// Update EP struct from hardware state
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index bb21b3dcd..188611743 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -33,7 +33,8 @@
#if TUSB_OPT_DEVICE_ENABLED && \
( defined(DCD_ATTR_DWC2_STM32) || \
TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_GD32VF103) || \
- TU_CHECK_MCU(OPT_MCU_EFM32GG, OPT_MCU_BCM2711, OPT_MCU_XMC4000) )
+ TU_CHECK_MCU(OPT_MCU_EFM32GG, OPT_MCU_BCM2711, OPT_MCU_BCM2835) || \
+ TU_CHECK_MCU(OPT_MCU_BCM2837, OPT_MCU_XMC4000) )
#include "device/dcd.h"
#include "dwc2_type.h"
@@ -44,7 +45,7 @@
#include "dwc2_esp32.h"
#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
#include "dwc2_gd32.h"
-#elif TU_CHECK_MCU(OPT_MCU_BCM2711)
+#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
#include "dwc2_bcm.h"
#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
#include "dwc2_efm32.h"
diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h
index 353bc21ee..14194e754 100644
--- a/src/portable/synopsys/dwc2/dwc2_bcm.h
+++ b/src/portable/synopsys/dwc2/dwc2_bcm.h
@@ -31,6 +31,7 @@
extern "C" {
#endif
+#include "broadcom/defines.h"
#include "broadcom/interrupts.h"
#include "broadcom/caches.h"
@@ -47,7 +48,6 @@ static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
(void) rhport;
BP_EnableIRQ(USB_IRQn);
- __asm__ volatile("isb"); // needed if TIMER1 IRQ is not enabled !?
}
TU_ATTR_ALWAYS_INLINE
@@ -55,7 +55,6 @@ static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
(void) rhport;
BP_DisableIRQ(USB_IRQn);
- __asm__ volatile("isb"); // needed if TIMER1 IRQ is not enabled !?
}
static inline void dwc2_remote_wakeup_delay(void)
diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c
index 837d0c0ce..51fb8b401 100644
--- a/src/portable/valentyusb/eptri/dcd_eptri.c
+++ b/src/portable/valentyusb/eptri/dcd_eptri.c
@@ -24,6 +24,10 @@
* This file is part of the TinyUSB stack.
*/
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
+
#ifndef DEBUG
#define DEBUG 0
#endif
@@ -32,10 +36,6 @@
#define LOG_USB 0
#endif
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
-
#include "device/dcd.h"
#include "dcd_eptri.h"
#include "csr.h"
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 2edd310fa..c7c7b2454 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -132,6 +132,8 @@
// Broadcom
#define OPT_MCU_BCM2711 1700 ///< Broadcom BCM2711
+#define OPT_MCU_BCM2835 1701 ///< Broadcom BCM2835
+#define OPT_MCU_BCM2837 1702 ///< Broadcom BCM2837
// Infineon
#define OPT_MCU_XMC4000 1800 ///< Infineon XMC4000