summaryrefslogtreecommitdiff
path: root/src/portable
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2024-05-13 21:08:11 +0200
committerHiFiPhile <[email protected]>2024-05-13 21:08:11 +0200
commit0fce7d1f54f5fc405bee3ac20ad6bbdb966abcd0 (patch)
tree1c3c32588f98b69f4fdca963d937ec5289ffc078 /src/portable
parentd0373f4749e320c7cb3fac9cce068b4398e60f2f (diff)
parentd707ea56b47e2fbbe5eaa4854a427a3a7873dea3 (diff)
Merge branch 'master' into test-mode-support
Diffstat (limited to 'src/portable')
-rw-r--r--src/portable/analog/max3421/hcd_max3421.c288
-rw-r--r--src/portable/chipidea/ci_fs/ci_fs_kinetis.h6
-rw-r--r--src/portable/chipidea/ci_fs/ci_fs_mcx.h25
-rw-r--r--src/portable/chipidea/ci_fs/dcd_ci_fs.c14
-rw-r--r--src/portable/ehci/ehci.c2
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c12
-rw-r--r--src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c11
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c609
-rw-r--r--src/portable/nxp/khci/dcd_khci.c12
-rw-r--r--src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c13
-rw-r--r--src/portable/ohci/ohci.h2
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c356
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c20
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c172
-rw-r--r--src/portable/renesas/rusb2/dcd_rusb2.c141
-rw-r--r--src/portable/renesas/rusb2/hcd_rusb2.c89
-rw-r--r--src/portable/sony/cxd56/dcd_cxd56.c30
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c1028
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h (renamed from src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h)194
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c14
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c415
-rw-r--r--src/portable/ti/msp430x5xx/dcd_msp430x5xx.c131
-rw-r--r--src/portable/wch/dcd_ch32_usbhs.c15
23 files changed, 1749 insertions, 1850 deletions
diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c
index cc4799dd6..4dc93d2d8 100644
--- a/src/portable/analog/max3421/hcd_max3421.c
+++ b/src/portable/analog/max3421/hcd_max3421.c
@@ -30,6 +30,7 @@
#include <stdatomic.h>
#include "host/hcd.h"
+#include "host/usbh.h"
//--------------------------------------------------------------------+
//
@@ -166,6 +167,17 @@ enum {
DEFAULT_HIEN = HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ | HIRQ_RCVDAV_IRQ
};
+enum {
+ MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame
+};
+
+enum {
+ EP_STATE_IDLE = 0,
+ EP_STATE_COMPLETE = 1,
+ EP_STATE_ATTEMPT_1 = 2, // pending 1st attempt
+ EP_STATE_ATTEMPT_MAX = 15
+};
+
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@@ -173,18 +185,21 @@ enum {
typedef struct {
uint8_t daddr;
- struct TU_ATTR_PACKED {
- uint8_t ep_dir : 1;
- uint8_t is_iso : 1;
- uint8_t is_setup : 1;
- uint8_t data_toggle : 1;
- uint8_t xfer_pending : 1;
- uint8_t xfer_complete : 1;
+ union { ;
+ struct TU_ATTR_PACKED {
+ uint8_t ep_num : 4;
+ uint8_t is_setup : 1;
+ uint8_t is_out : 1;
+ uint8_t is_iso : 1;
+ }hxfr_bm;
+
+ uint8_t hxfr;
};
struct TU_ATTR_PACKED {
- uint8_t ep_num : 4;
- uint16_t packet_size : 12;
+ uint8_t state : 4;
+ uint8_t data_toggle : 1;
+ uint16_t packet_size : 11;
};
uint16_t total_len;
@@ -195,6 +210,8 @@ typedef struct {
TU_VERIFY_STATIC(sizeof(max3421_ep_t) == 12, "size is not correct");
typedef struct {
+ volatile uint16_t frame_count;
+
// cached register
uint8_t sndbc;
uint8_t hirq;
@@ -204,18 +221,24 @@ typedef struct {
uint8_t hxfr;
atomic_flag busy; // busy transferring
- volatile uint16_t frame_count;
-
- max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0
- OSAL_MUTEX_DEF(spi_mutexdef);
#if OSAL_MUTEX_REQUIRED
+ OSAL_MUTEX_DEF(spi_mutexdef);
osal_mutex_t spi_mutex;
#endif
+
+ max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0
} max3421_data_t;
static max3421_data_t _hcd_data;
+// max NAK before giving up in a frame. 0 means infinite NAKs
+static tuh_configure_max3421_t _tuh_cfg = {
+ .max_nak = MAX_NAK_DEFAULT,
+ .cpuctl = 0, // default: INT pulse width = 10.6 us
+ .pinctl = 0, // default: negative edge interrupt
+};
+
//--------------------------------------------------------------------+
// API: SPI transfer with MAX3421E
// - spi_cs_api(), spi_xfer_api(), int_api(): must be implemented by application
@@ -304,7 +327,6 @@ static void fifo_write(uint8_t rhport, uint8_t reg, uint8_t const * buffer, uint
tuh_max3421_spi_xfer_api(rhport, buffer, NULL, len);
max3421_spi_unlock(rhport, in_isr);
-
}
static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) {
@@ -321,35 +343,35 @@ static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_is
}
//------------- register write helper -------------//
-static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) {
reg_write(rhport, HIRQ_ADDR, data, in_isr);
// HIRQ write 1 is clear
_hcd_data.hirq &= (uint8_t) ~data;
}
-static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) {
_hcd_data.hien = data;
reg_write(rhport, HIEN_ADDR, data, in_isr);
}
-static inline void mode_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void mode_write(uint8_t rhport, uint8_t data, bool in_isr) {
_hcd_data.mode = data;
reg_write(rhport, MODE_ADDR, data, in_isr);
}
-static inline void peraddr_write(uint8_t rhport, uint8_t data, bool in_isr) {
+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
_hcd_data.peraddr = data;
reg_write(rhport, PERADDR_ADDR, data, in_isr);
}
-static inline void hxfr_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void hxfr_write(uint8_t rhport, uint8_t data, bool in_isr) {
_hcd_data.hxfr = data;
reg_write(rhport, HXFR_ADDR, data, in_isr);
}
-static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) {
_hcd_data.sndbc = data;
reg_write(rhport, SNDBC_ADDR, data, in_isr);
}
@@ -359,10 +381,11 @@ static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) {
//--------------------------------------------------------------------+
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;
for(size_t i=1; i<CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
- // for control endpoint, skip direction check
- if (daddr == ep->daddr && ep_num == ep->ep_num && (ep_dir == ep->ep_dir || ep_num == 0)) {
+ // control endpoint is bi-direction (skip check)
+ if (daddr == ep->daddr && ep_num == ep->hxfr_bm.ep_num && (ep_num == 0 || is_out == ep->hxfr_bm.is_out)) {
return ep;
}
}
@@ -393,14 +416,23 @@ static void free_ep(uint8_t daddr) {
}
}
+// Check if endpoint has an queued transfer and not reach max NAK
+TU_ATTR_ALWAYS_INLINE static inline bool is_ep_pending(max3421_ep_t const * ep) {
+ uint8_t const state = ep->state;
+ return ep->packet_size && (state >= EP_STATE_ATTEMPT_1) &&
+ (_tuh_cfg.max_nak == 0 || state < EP_STATE_ATTEMPT_1 + _tuh_cfg.max_nak);
+}
+
+// Find the next pending endpoint using round-robin scheduling, starting from next endpoint.
+// return NULL if not found
+// TODO respect interrupt endpoint's interval
static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
size_t const idx = (size_t) (cur_ep - _hcd_data.ep);
// starting from next endpoint
for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
- if (ep->xfer_pending && ep->packet_size) {
-// TU_LOG3("next pending i = %u\r\n", i);
+ if (is_ep_pending(ep)) {
return ep;
}
}
@@ -408,8 +440,7 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
// wrap around including current endpoint
for (size_t i = 0; i <= idx; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
- if (ep->xfer_pending && ep->packet_size) {
-// TU_LOG3("next pending i = %u\r\n", i);
+ if (is_ep_pending(ep)) {
return ep;
}
}
@@ -424,10 +455,11 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
// optional hcd configuration, called by tuh_configure()
bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
(void) rhport;
- (void) cfg_id;
- (void) cfg_param;
+ TU_VERIFY(cfg_id == TUH_CFGID_MAX3421 && cfg_param != NULL);
- return false;
+ tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param;
+ _tuh_cfg = cfg->max3421;
+ return true;
}
// Initialize controller to host mode
@@ -438,6 +470,7 @@ bool hcd_init(uint8_t rhport) {
TU_LOG2_INT(sizeof(max3421_ep_t));
TU_LOG2_INT(sizeof(max3421_data_t));
+ TU_LOG2_INT(offsetof(max3421_data_t, ep));
tu_memclr(&_hcd_data, sizeof(_hcd_data));
_hcd_data.peraddr = 0xff; // invalid
@@ -446,13 +479,15 @@ bool hcd_init(uint8_t rhport) {
_hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef);
#endif
+ // NOTE: driver does not seem to work without nRST pin signal
+
// full duplex, interrupt negative edge
- reg_write(rhport, PINCTL_ADDR, PINCTL_FDUPSPI, false);
+ reg_write(rhport, PINCTL_ADDR, _tuh_cfg.pinctl | PINCTL_FDUPSPI, false);
- // V1 is 0x01, V2 is 0x12, V3 is 0x13
+ // v1 is 0x01, v2 is 0x12, v3 is 0x13
uint8_t const revision = reg_read(rhport, REVISION_ADDR, false);
- TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false);
TU_LOG2_HEX(revision);
+ TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false);
// reset
reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);
@@ -476,7 +511,25 @@ bool hcd_init(uint8_t rhport) {
tuh_max3421_int_api(rhport, true);
// Enable Interrupt pin
- reg_write(rhport, CPUCTL_ADDR, CPUCTL_IE, false);
+ reg_write(rhport, CPUCTL_ADDR, _tuh_cfg.cpuctl | CPUCTL_IE, false);
+
+ return true;
+}
+
+bool hcd_deinit(uint8_t rhport) {
+ (void) rhport;
+
+ // disable interrupt
+ tuh_max3421_int_api(rhport, false);
+
+ // reset max3421 and power down
+ reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);
+ reg_write(rhport, USBCTL_ADDR, USBCTL_PWRDOWN, false);
+
+ #if OSAL_MUTEX_REQUIRED
+ osal_mutex_delete(_hcd_data.spi_mutex);
+ _hcd_data.spi_mutex = NULL;
+ #endif
return true;
}
@@ -539,7 +592,6 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// Open an endpoint
bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * ep_desc) {
(void) rhport;
- (void) daddr;
uint8_t const ep_num = tu_edpt_number(ep_desc->bEndpointAddress);
tusb_dir_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
@@ -551,12 +603,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
ep = allocate_ep();
TU_ASSERT(ep);
ep->daddr = daddr;
- ep->ep_num = (uint8_t) (ep_num & 0x0f);
- ep->ep_dir = (ep_dir == TUSB_DIR_IN) ? 1 : 0;
- }
-
- if ( TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer ) {
- ep->is_iso = 1;
+ ep->hxfr_bm.ep_num = (uint8_t) (ep_num & 0x0f);
+ ep->hxfr_bm.is_out = (ep_dir == TUSB_DIR_OUT) ? 1 : 0;
+ ep->hxfr_bm.is_iso = (TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer) ? 1 : 0;
}
ep->packet_size = (uint16_t) (tu_edpt_packet_size(ep_desc) & 0x7ff);
@@ -564,7 +613,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
return true;
}
-void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
+static void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
// Page 12: Programming BULK-OUT Transfers
// TODO double buffered
if (switch_ep) {
@@ -580,12 +629,10 @@ void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr);
}
sndbc_write(rhport, xact_len, in_isr);
-
- uint8_t const hxfr = (uint8_t ) (ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0));
- hxfr_write(rhport, hxfr, in_isr);
+ hxfr_write(rhport, ep->hxfr, in_isr);
}
-void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
+static void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
// Page 13: Programming BULK-IN Transfers
if (switch_ep) {
peraddr_write(rhport, ep->daddr, in_isr);
@@ -594,33 +641,36 @@ void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
reg_write(rhport, HCTL_ADDR, hctl, in_isr);
}
- uint8_t const hxfr = (uint8_t) (ep->ep_num | (ep->is_iso ? HXFR_ISO : 0));
- hxfr_write(rhport, hxfr, in_isr);
+ hxfr_write(rhport, ep->hxfr, in_isr);
+}
+
+static void xact_setup(uint8_t rhport, max3421_ep_t *ep, bool in_isr) {
+ peraddr_write(rhport, ep->daddr, in_isr);
+ fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr);
+ hxfr_write(rhport, HXFR_SETUP, in_isr);
}
-TU_ATTR_ALWAYS_INLINE static inline void xact_inout(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
- if (ep->ep_num == 0 ) {
+static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
+ if (ep->hxfr_bm.ep_num == 0 ) {
// setup
- if (ep->is_setup) {
- peraddr_write(rhport, ep->daddr, in_isr);
- fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr);
- hxfr_write(rhport, HXFR_SETUP, in_isr);
+ if (ep->hxfr_bm.is_setup) {
+ xact_setup(rhport, ep, in_isr);
return;
}
// status
if (ep->buf == NULL || ep->total_len == 0) {
- uint8_t const hxfr = HXFR_HS | (ep->ep_dir ? 0 : HXFR_OUT_NIN);
+ uint8_t const hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN));
peraddr_write(rhport, ep->daddr, in_isr);
hxfr_write(rhport, hxfr, in_isr);
return;
}
}
- if (ep->ep_dir) {
- xact_in(rhport, ep, switch_ep, in_isr);
- }else {
+ if (ep->hxfr_bm.is_out) {
xact_out(rhport, ep, switch_ep, in_isr);
+ }else {
+ xact_in(rhport, ep, switch_ep, in_isr);
}
}
@@ -632,25 +682,21 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf
max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir);
TU_VERIFY(ep);
- // control transfer can switch direction
- ep->ep_dir = ep_dir ? 1u : 0u;
+ if (ep_num == 0) {
+ // control transfer can switch direction
+ ep->hxfr_bm.is_out = ep_dir ? 0 : 1;
+ ep->hxfr_bm.is_setup = 0;
+ ep->data_toggle = 1;
+ }
ep->buf = buffer;
ep->total_len = buflen;
ep->xferred_len = 0;
- ep->xfer_complete = 0;
- ep->xfer_pending = 1;
-
- if ( ep_num == 0 ) {
- ep->is_setup = 0;
- ep->data_toggle = 1;
- }
+ ep->state = EP_STATE_ATTEMPT_1;
// carry out transfer if not busy
- if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) {
- xact_inout(rhport, ep, true, false);
- } else {
- return true;
+ if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
+ xact_generic(rhport, ep, true, false);
}
return true;
@@ -673,17 +719,16 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]
max3421_ep_t* ep = find_opened_ep(daddr, 0, 0);
TU_ASSERT(ep);
- ep->ep_dir = 0;
- ep->is_setup = 1;
+ ep->hxfr_bm.is_out = 1;
+ ep->hxfr_bm.is_setup = 1;
ep->buf = (uint8_t*)(uintptr_t) setup_packet;
ep->total_len = 8;
ep->xferred_len = 0;
- ep->xfer_complete = 0;
- ep->xfer_pending = 1;
+ ep->state = EP_STATE_ATTEMPT_1;
// carry out transfer if not busy
- if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) {
- xact_inout(rhport, ep, true, false);
+ if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
+ xact_setup(rhport, ep, false);
}
return true;
@@ -748,22 +793,23 @@ 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_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir);
+ 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);
// save data toggle
- if (ep->ep_dir) {
+ if (ep_dir) {
ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1u : 0u;
}else {
ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1u : 0u;
}
- ep->xfer_pending = 0;
+ ep->state = EP_STATE_IDLE;
hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, in_isr);
// Find next pending endpoint
- max3421_ep_t *next_ep = find_next_pending_ep(ep);
+ max3421_ep_t * next_ep = find_next_pending_ep(ep);
if (next_ep) {
- xact_inout(rhport, next_ep, true, in_isr);
+ xact_generic(rhport, next_ep, true, in_isr);
}else {
// no more pending
atomic_flag_clear(&_hcd_data.busy);
@@ -793,20 +839,23 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
case HRSL_NAK:
if (ep_num == 0) {
- // NAK on control, retry immediately
+ // control endpoint -> retry immediately
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
- }else {
- // NAK on non-control, find next pending to switch
- max3421_ep_t *next_ep = find_next_pending_ep(ep);
+ } else {
+ if (ep->state < EP_STATE_ATTEMPT_MAX) {
+ ep->state++;
+ }
+ max3421_ep_t * next_ep = find_next_pending_ep(ep);
if (ep == next_ep) {
- // this endpoint is only one pending, retry immediately
+ // this endpoint is only one pending -> retry immediately
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
- }else if (next_ep) {
- // switch to next pending TODO could have issue with double buffered if not clear previously out data
- xact_inout(rhport, next_ep, true, in_isr);
- }else {
- TU_ASSERT(false,);
+ } else if (next_ep) {
+ // switch to next pending endpoint TODO could have issue with double buffered if not clear previously out data
+ xact_generic(rhport, next_ep, true, in_isr);
+ } else {
+ // no more pending in this frame -> clear busy
+ atomic_flag_clear(&_hcd_data.busy);
}
}
return;
@@ -828,12 +877,14 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
if (ep_dir) {
// IN transfer: fifo data is already received in RCVDAV IRQ
- if ( hxfr_type & HXFR_HS ) {
- ep->xfer_complete = 1;
+
+ // mark control handshake as complete
+ if (hxfr_type & HXFR_HS) {
+ ep->state = EP_STATE_COMPLETE;
}
// short packet or all bytes transferred
- if ( ep->xfer_complete ) {
+ if (ep->state == EP_STATE_COMPLETE) {
xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
}else {
// more to transfer
@@ -867,13 +918,13 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
void print_hirq(uint8_t hirq) {
TU_LOG3_HEX(hirq);
- if (hirq & HIRQ_HXFRDN_IRQ) TU_LOG3(" HXFRDN");
- if (hirq & HIRQ_FRAME_IRQ) TU_LOG3(" FRAME");
- if (hirq & HIRQ_CONDET_IRQ) TU_LOG3(" CONDET");
- if (hirq & HIRQ_SUSDN_IRQ) TU_LOG3(" SUSDN");
- if (hirq & HIRQ_SNDBAV_IRQ) TU_LOG3(" SNDBAV");
- if (hirq & HIRQ_RCVDAV_IRQ) TU_LOG3(" RCVDAV");
- if (hirq & HIRQ_RWU_IRQ) TU_LOG3(" RWU");
+ if (hirq & HIRQ_HXFRDN_IRQ) TU_LOG3(" HXFRDN");
+ if (hirq & HIRQ_FRAME_IRQ) TU_LOG3(" FRAME");
+ if (hirq & HIRQ_CONDET_IRQ) TU_LOG3(" CONDET");
+ if (hirq & HIRQ_SUSDN_IRQ) TU_LOG3(" SUSDN");
+ if (hirq & HIRQ_SNDBAV_IRQ) TU_LOG3(" SNDBAV");
+ if (hirq & HIRQ_RCVDAV_IRQ) TU_LOG3(" RCVDAV");
+ if (hirq & HIRQ_RWU_IRQ) TU_LOG3(" RWU");
if (hirq & HIRQ_BUSEVENT_IRQ) TU_LOG3(" BUSEVENT");
TU_LOG3("\r\n");
@@ -890,6 +941,25 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (hirq & HIRQ_FRAME_IRQ) {
_hcd_data.frame_count++;
+
+ max3421_ep_t* ep_retry = NULL;
+
+ // reset all endpoints attempt counter
+ for (size_t i = 0; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
+ max3421_ep_t* ep = &_hcd_data.ep[i];
+ if (ep->packet_size && ep->state > EP_STATE_ATTEMPT_1) {
+ ep->state = EP_STATE_ATTEMPT_1;
+
+ if (ep_retry == NULL) {
+ ep_retry = ep;
+ }
+ }
+ }
+
+ // 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 (hirq & HIRQ_CONDET_IRQ) {
@@ -898,17 +968,17 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or
// not call this handler again. So we need to loop until all IRQ are cleared
- while ( hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ) ) {
- if ( hirq & HIRQ_RCVDAV_IRQ ) {
+ while (hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ)) {
+ if (hirq & HIRQ_RCVDAV_IRQ) {
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
- max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
+ max3421_ep_t* ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
uint8_t xact_len = 0;
// RCVDAV_IRQ can trigger 2 times (dual buffered)
- while ( hirq & HIRQ_RCVDAV_IRQ ) {
+ while (hirq & HIRQ_RCVDAV_IRQ) {
uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr);
xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len);
- if ( xact_len ) {
+ if (xact_len) {
fifo_read(rhport, ep->buf, xact_len, in_isr);
ep->buf += xact_len;
ep->xferred_len += xact_len;
@@ -919,12 +989,12 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
hirq = reg_read(rhport, HIRQ_ADDR, in_isr);
}
- if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) {
- ep->xfer_complete = 1;
+ if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) {
+ ep->state = EP_STATE_COMPLETE;
}
}
- if ( hirq & HIRQ_HXFRDN_IRQ ) {
+ if (hirq & HIRQ_HXFRDN_IRQ) {
hirq_write(rhport, HIRQ_HXFRDN_IRQ, in_isr);
handle_xfer_done(rhport, in_isr);
}
diff --git a/src/portable/chipidea/ci_fs/ci_fs_kinetis.h b/src/portable/chipidea/ci_fs/ci_fs_kinetis.h
index cd21af1c7..31e14a546 100644
--- a/src/portable/chipidea/ci_fs/ci_fs_kinetis.h
+++ b/src/portable/chipidea/ci_fs/ci_fs_kinetis.h
@@ -36,14 +36,12 @@
#define CI_FS_REG(_port) ((ci_fs_regs_t*) USB0_BASE)
#define CI_REG CI_FS_REG(0)
-void dcd_int_enable(uint8_t rhport)
-{
+void dcd_int_enable(uint8_t rhport) {
(void) rhport;
NVIC_EnableIRQ(USB0_IRQn);
}
-void dcd_int_disable(uint8_t rhport)
-{
+void dcd_int_disable(uint8_t rhport) {
(void) rhport;
NVIC_DisableIRQ(USB0_IRQn);
}
diff --git a/src/portable/chipidea/ci_fs/ci_fs_mcx.h b/src/portable/chipidea/ci_fs/ci_fs_mcx.h
index 3bfcd398e..4b93a03a7 100644
--- a/src/portable/chipidea/ci_fs/ci_fs_mcx.h
+++ b/src/portable/chipidea/ci_fs/ci_fs_mcx.h
@@ -29,19 +29,28 @@
#include "fsl_device_registers.h"
-#define CI_FS_REG(_port) ((ci_fs_regs_t*) USBFS0_BASE)
-#define CI_REG CI_FS_REG(0)
+#if CFG_TUSB_MCU == OPT_MCU_MCXN9
+ #define CI_FS_REG(_port) ((ci_fs_regs_t*) USBFS0_BASE)
+ #define CIFS_IRQN USB0_FS_IRQn
-void dcd_int_enable(uint8_t rhport)
-{
+#elif CFG_TUSB_MCU == OPT_MCU_MCXA15
+ #define CI_FS_REG(_port) ((ci_fs_regs_t*) USB0_BASE)
+ #define CIFS_IRQN USB0_IRQn
+
+#else
+ #error "MCU is not supported"
+#endif
+
+#define CI_REG CI_FS_REG(0)
+
+void dcd_int_enable(uint8_t rhport) {
(void) rhport;
- NVIC_EnableIRQ(USB0_FS_IRQn);
+ NVIC_EnableIRQ(CIFS_IRQN);
}
-void dcd_int_disable(uint8_t rhport)
-{
+void dcd_int_disable(uint8_t rhport) {
(void) rhport;
- NVIC_DisableIRQ(USB0_FS_IRQn);
+ NVIC_DisableIRQ(CIFS_IRQN);
}
#endif
diff --git a/src/portable/chipidea/ci_fs/dcd_ci_fs.c b/src/portable/chipidea/ci_fs/dcd_ci_fs.c
index 9327e09d8..02f813ab5 100644
--- a/src/portable/chipidea/ci_fs/dcd_ci_fs.c
+++ b/src/portable/chipidea/ci_fs/dcd_ci_fs.c
@@ -271,9 +271,21 @@ void dcd_init(uint8_t rhport)
{
(void) rhport;
+ // save crystal-less setting (if available)
+ #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1
+ uint32_t clk_recover_irc_en = CI_REG->CLK_RECOVER_IRC_EN;
+ uint32_t clk_recover_ctrl = CI_REG->CLK_RECOVER_CTRL;
+ #endif
+
CI_REG->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
while (CI_REG->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+ // restore crystal-less setting (if available)
+ #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1
+ CI_REG->CLK_RECOVER_IRC_EN = clk_recover_irc_en;
+ CI_REG->CLK_RECOVER_CTRL |= clk_recover_ctrl;
+ #endif
+
tu_memclr(&_dcd, sizeof(_dcd));
CI_REG->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
CI_REG->BDT_PAGE1 = (uint8_t)((uintptr_t)_dcd.bdt >> 8);
@@ -283,7 +295,7 @@ void dcd_init(uint8_t rhport)
CI_REG->INT_EN = USB_INTEN_USBRSTEN_MASK;
dcd_connect(rhport);
- // NVIC_ClearPendingIRQ(USB0_IRQn);
+ // NVIC_ClearPendingIRQ(CIFS_IRQN);
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index e145cbb1b..01bbf62bf 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -92,7 +92,7 @@ CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
//--------------------------------------------------------------------+
// Debug
//--------------------------------------------------------------------+
-#if CFG_TUSB_DEBUG >= (EHCI_DBG + 1)
+#if 0 && CFG_TUSB_DEBUG >= (EHCI_DBG + 1)
static inline void print_portsc(ehci_registers_t* regs) {
TU_LOG_HEX(EHCI_DBG, regs->portsc);
TU_LOG(EHCI_DBG, " Connect Status : %u\r\n", regs->portsc_bm.current_connect_status);
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
index 1fcfb6241..bfc0baa56 100644
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -31,16 +31,26 @@
#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED)
// Espressif
-#include "freertos/xtensa_api.h"
+#include "xtensa_api.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "soc/dport_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/usb_periph.h"
+#include "soc/usb_reg.h"
+#include "soc/usb_struct.h"
#include "soc/periph_defs.h" // for interrupt source
#include "device/dcd.h"
+#ifndef USB_OUT_EP_NUM
+#define USB_OUT_EP_NUM ((int) (sizeof(USB0.out_ep_reg) / sizeof(USB0.out_ep_reg[0])))
+#endif
+
+#ifndef USB_IN_EP_NUM
+#define USB_IN_EP_NUM ((int) (sizeof(USB0.in_ep_reg) / sizeof(USB0.in_ep_reg[0])))
+#endif
+
// Max number of bi-directional endpoints including EP0
// Note: ESP32S2 specs say there are only up to 5 IN active endpoints include EP0
// We should probably prohibit enabling Endpoint IN > 4 (not done yet)
diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
index c3d0c7297..d5c0daaeb 100644
--- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
+++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
@@ -283,7 +283,18 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
/* Response with status first before changing device address */
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
}
+
+#ifdef __GNUC__ // caused by extra declaration of SystemCoreClock in freeRTOSConfig.h
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
extern u32 SystemCoreClock;
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
void dcd_remote_wakeup(uint8_t rhport)
{
(void) rhport;
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 4e702aed4..2fe721d6b 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -40,7 +40,6 @@
#include "nrf.h"
#include "nrf_clock.h"
-#include "nrf_power.h"
#include "nrfx_usbd_errata.h"
#ifdef __GNUC__
@@ -57,28 +56,46 @@
#include "mcu/mcu.h"
#endif
+/* Try to detect nrfx version if not configured with CFG_TUD_NRF_NRFX_VERSION
+ * nrfx v1 and v2 are concurrently developed. There is no NRFX_VERSION only MDK VERSION which is as follows:
+ * - v3.0.0: 8.53.1 (conflict with v2.11.0), v3.1.0: 8.55.0 ...
+ * - v2.11.0: 8.53.1, v2.6.0: 8.44.1, v2.5.0: 8.40.2, v2.4.0: 8.37.0, v2.3.0: 8.35.0, v2.2.0: 8.32.1, v2.1.0: 8.30.2, v2.0.0: 8.29.0
+ * - v1.9.0: 8.40.3, v1.8.6: 8.35.0 (conflict with v2.3.0), v1.8.5: 8.32.3, v1.8.4: 8.32.1 (conflict with v2.2.0),
+ * v1.8.2: 8.32.1 (conflict with v2.2.0), v1.8.1: 8.27.1
+ * Therefore the check for v1 would be:
+ * - MDK < 8.29.0 (v2.0), MDK == 8.32.3, 8.40.3
+ * - in case of conflict User of those version must upgrade to other 1.x version or set CFG_TUD_NRF_NRFX_VERSION
+*/
+#ifndef CFG_TUD_NRF_NRFX_VERSION
+ #define _MDK_VERSION (10000*MDK_MAJOR_VERSION + 100*MDK_MINOR_VERSION + MDK_MICRO_VERSION)
+
+ #if _MDK_VERSION < 82900 || _MDK_VERSION == 83203 || _MDK_VERSION == 84003
+ // nrfx <= 1.8.1, or 1.8.5 or 1.9.0
+ #define CFG_TUD_NRF_NRFX_VERSION 1
+ #else
+ #define CFG_TUD_NRF_NRFX_VERSION 2
+ #endif
+#endif
+
/*------------------------------------------------------------------*/
/* MACRO TYPEDEF CONSTANT ENUM
*------------------------------------------------------------------*/
-enum
-{
+enum {
// Max allowed by USB specs
- MAX_PACKET_SIZE = 64,
+ MAX_PACKET_SIZE = 64,
// Mask of all END event (IN & OUT) for all endpoints. ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
EDPT_END_ALL_MASK = (0xff << USBD_INTEN_ENDEPIN0_Pos) | (0xff << USBD_INTEN_ENDEPOUT0_Pos) |
USBD_INTENCLR_ENDISOIN_Msk | USBD_INTEN_ENDISOOUT_Msk
};
-enum
-{
- EP_ISO_NUM = 8, // Endpoint number is fixed (8) for ISOOUT and ISOIN
+enum {
+ EP_ISO_NUM = 8, // Endpoint number is fixed (8) for ISOOUT and ISOIN
EP_CBI_COUNT = 8 // Control Bulk Interrupt endpoints count
};
// Transfer Descriptor
-typedef struct
-{
+typedef struct {
uint8_t* buffer;
uint16_t total_len;
volatile uint16_t actual_len;
@@ -96,113 +113,82 @@ typedef struct
} xfer_td_t;
// Data for managing dcd
-static struct
-{
+static struct {
// All 8 endpoints including control IN & OUT (offset 1)
// +1 for ISO endpoints
xfer_td_t xfer[EP_CBI_COUNT + 1][2];
// nRF can only carry one DMA at a time, this is used to guard the access to EasyDMA
- atomic_bool dma_running;
-}_dcd;
+ atomic_flag dma_running;
+} _dcd;
/*------------------------------------------------------------------*/
/* Control / Bulk / Interrupt (CBI) Transfer
*------------------------------------------------------------------*/
-// NVIC_GetEnableIRQ is only available in CMSIS v5
-#ifndef NVIC_GetEnableIRQ
-static inline uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn)
-{
- if ((int32_t)(IRQn) >= 0)
- {
- return((uint32_t)(((NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
- }
- else
- {
- return(0U);
- }
-}
-#endif
-
// check if we are in ISR
-TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void) {
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false;
}
// helper to start DMA
-static void start_dma(volatile uint32_t* reg_startep)
-{
+static void start_dma(volatile uint32_t* reg_startep) {
(*reg_startep) = 1;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
// TASKS_EP0STATUS, TASKS_EP0RCVOUT seem to need EasyDMA to be available
// However these don't trigger any DMA transfer and got ENDED event subsequently
// Therefore dma_pending is corrected right away
- if ( (reg_startep == &NRF_USBD->TASKS_EP0STATUS) || (reg_startep == &NRF_USBD->TASKS_EP0RCVOUT) )
- {
+ if ((reg_startep == &NRF_USBD->TASKS_EP0STATUS) || (reg_startep == &NRF_USBD->TASKS_EP0RCVOUT)) {
atomic_flag_clear(&_dcd.dma_running);
}
}
-static void edpt_dma_start(volatile uint32_t* reg_startep)
-{
- if ( atomic_flag_test_and_set(&_dcd.dma_running) )
- {
- usbd_defer_func((osal_task_func_t) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
- }else
- {
+static void edpt_dma_start(volatile uint32_t* reg_startep) {
+ if (atomic_flag_test_and_set(&_dcd.dma_running)) {
+ usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
+ } else {
start_dma(reg_startep);
}
}
// DMA is complete
-static void edpt_dma_end(void)
-{
- TU_ASSERT(_dcd.dma_running, );
+static void edpt_dma_end(void) {
atomic_flag_clear(&_dcd.dma_running);
}
// helper getting td
-static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir)
-{
+static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir) {
return &_dcd.xfer[epnum][dir];
}
static void xact_out_dma(uint8_t epnum);
+
// Function wraps xact_out_dma which wants uint8_t while usbd_defer_func wants void (*)(void *)
-static void xact_out_dma_wrapper(void *epnum)
-{
- xact_out_dma((uint8_t)((uintptr_t)epnum));
+static void xact_out_dma_wrapper(void* epnum) {
+ xact_out_dma((uint8_t) ((uintptr_t) epnum));
}
// Start DMA to move data from Endpoint -> RAM
-static void xact_out_dma(uint8_t epnum)
-{
+static void xact_out_dma(uint8_t epnum) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
uint32_t xact_len;
// DMA can't be active during read of SIZE.EPOUT or SIZE.ISOOUT, so try to lock,
// If already running defer call regardless if it was called from ISR or task,
- if ( atomic_flag_test_and_set(&_dcd.dma_running) )
- {
- usbd_defer_func((osal_task_func_t)xact_out_dma_wrapper, (void *)(uint32_t)epnum, is_in_isr());
+ if (atomic_flag_test_and_set(&_dcd.dma_running)) {
+ usbd_defer_func((osal_task_func_t) xact_out_dma_wrapper, (void*) (uint32_t) epnum, is_in_isr());
return;
}
- if (epnum == EP_ISO_NUM)
- {
+ if (epnum == EP_ISO_NUM) {
xact_len = NRF_USBD->SIZE.ISOOUT;
// If ZERO bit is set, ignore ISOOUT length
- if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk)
- {
+ if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk) {
xact_len = 0;
atomic_flag_clear(&_dcd.dma_running);
- }
- else
- {
- if (xfer->started)
- {
+ } else {
+ if (xfer->started) {
// Trigger DMA move data from Endpoint -> SRAM
NRF_USBD->ISOOUT.PTR = (uint32_t) xfer->buffer;
NRF_USBD->ISOOUT.MAXCNT = xact_len;
@@ -212,9 +198,7 @@ static void xact_out_dma(uint8_t epnum)
atomic_flag_clear(&_dcd.dma_running);
}
}
- }
- else
- {
+ } else {
// limit xact len to remaining length
xact_len = tu_min16((uint16_t) NRF_USBD->SIZE.EPOUT[epnum], xfer->total_len - xfer->actual_len);
@@ -228,14 +212,13 @@ static void xact_out_dma(uint8_t epnum)
// Prepare for a CBI transaction IN, call at the start
// it start DMA to transfer data from RAM -> Endpoint
-static void xact_in_dma(uint8_t epnum)
-{
+static void xact_in_dma(uint8_t epnum) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
// Each transaction is up to Max Packet Size
uint16_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps);
- NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
+ NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
@@ -244,26 +227,22 @@ static void xact_in_dma(uint8_t epnum)
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
-void dcd_init (uint8_t rhport)
-{
- TU_LOG1("dcd init\r\n");
+void dcd_init(uint8_t rhport) {
+ TU_LOG2("dcd init\r\n");
(void) rhport;
}
-void dcd_int_enable(uint8_t rhport)
-{
+void dcd_int_enable(uint8_t rhport) {
(void) rhport;
NVIC_EnableIRQ(USBD_IRQn);
}
-void dcd_int_disable(uint8_t rhport)
-{
+void dcd_int_disable(uint8_t rhport) {
(void) rhport;
NVIC_DisableIRQ(USBD_IRQn);
}
-void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
-{
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
(void) rhport;
(void) dev_addr;
// Set Address is automatically update by hw controller, nothing to do
@@ -278,8 +257,7 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk;
}
-void dcd_remote_wakeup(uint8_t rhport)
-{
+void dcd_remote_wakeup(uint8_t rhport) {
(void) rhport;
// Bring controller out of low power mode
@@ -288,8 +266,7 @@ void dcd_remote_wakeup(uint8_t rhport)
}
// disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport)
-{
+void dcd_disconnect(uint8_t rhport) {
(void) rhport;
NRF_USBD->USBPULLUP = 0;
@@ -299,14 +276,12 @@ void dcd_disconnect(uint8_t rhport)
}
// connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(uint8_t rhport)
-{
+void dcd_connect(uint8_t rhport) {
(void) rhport;
NRF_USBD->USBPULLUP = 1;
}
-void dcd_sof_enable(uint8_t rhport, bool en)
-{
+void dcd_sof_enable(uint8_t rhport, bool en) {
(void) rhport;
(void) en;
@@ -316,39 +291,32 @@ void dcd_sof_enable(uint8_t rhport, bool en)
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
-{
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
(void) rhport;
uint8_t const ep_addr = desc_edpt->bEndpointAddress;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
_dcd.xfer[epnum][dir].mps = tu_edpt_packet_size(desc_edpt);
- if (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS)
- {
- if (dir == TUSB_DIR_OUT)
- {
+ if (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) {
+ if (dir == TUSB_DIR_OUT) {
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
NRF_USBD->EPOUTEN |= TU_BIT(epnum);
// Write any value to SIZE register will allow nRF to ACK/accept data
NRF_USBD->SIZE.EPOUT[epnum] = 0;
- }else
- {
+ } else {
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
- NRF_USBD->EPINEN |= TU_BIT(epnum);
+ NRF_USBD->EPINEN |= TU_BIT(epnum);
}
// clear stall and reset DataToggle
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
- }
- else
- {
+ } else {
TU_ASSERT(epnum == EP_ISO_NUM);
- if (dir == TUSB_DIR_OUT)
- {
+ if (dir == TUSB_DIR_OUT) {
// SPLIT ISO buffer when ISO IN endpoint is already opened.
if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
@@ -361,9 +329,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
// Enable SOF and ISOOUT interrupts, and ISOOUT endpoint.
NRF_USBD->INTENSET = USBD_INTENSET_ENDISOOUT_Msk | USBD_INTENSET_SOF_Msk;
NRF_USBD->EPOUTEN |= USBD_EPOUTEN_ISOOUT_Msk;
- }
- else
- {
+ } else {
NRF_USBD->EVENTS_ENDISOIN = 0;
// SPLIT ISO buffer when ISO OUT endpoint is already opened.
@@ -374,39 +340,38 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
// Enable SOF and ISOIN interrupts, and ISOIN endpoint.
NRF_USBD->INTENSET = USBD_INTENSET_ENDISOIN_Msk | USBD_INTENSET_SOF_Msk;
- NRF_USBD->EPINEN |= USBD_EPINEN_ISOIN_Msk;
+ NRF_USBD->EPINEN |= USBD_EPINEN_ISOIN_Msk;
}
}
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
return true;
}
-void dcd_edpt_close_all (uint8_t rhport)
-{
+void dcd_edpt_close_all(uint8_t rhport) {
// disable interrupt to prevent race condition
dcd_int_disable(rhport);
// disable all non-control (bulk + interrupt) endpoints
- for ( uint8_t ep = 1; ep < EP_CBI_COUNT; ep++ )
- {
+ for (uint8_t ep = 1; ep < EP_CBI_COUNT; ep++) {
NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + ep) | TU_BIT(USBD_INTEN_ENDEPIN0_Pos + ep);
NRF_USBD->TASKS_STARTEPIN[ep] = 0;
NRF_USBD->TASKS_STARTEPOUT[ep] = 0;
- tu_memclr(_dcd.xfer[ep], 2*sizeof(xfer_td_t));
+ tu_memclr(_dcd.xfer[ep], 2 * sizeof(xfer_td_t));
}
// disable both ISO
NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk | USBD_INTENCLR_ENDISOOUT_Msk | USBD_INTENCLR_ENDISOIN_Msk;
NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
- NRF_USBD->TASKS_STARTISOIN = 0;
+ NRF_USBD->TASKS_STARTISOIN = 0;
NRF_USBD->TASKS_STARTISOOUT = 0;
- tu_memclr(_dcd.xfer[EP_ISO_NUM], 2*sizeof(xfer_td_t));
+ tu_memclr(_dcd.xfer[EP_ISO_NUM], 2 * sizeof(xfer_td_t));
// de-activate all non-control
NRF_USBD->EPOUTEN = 1UL;
@@ -415,107 +380,89 @@ void dcd_edpt_close_all (uint8_t rhport)
dcd_int_enable(rhport);
}
-void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- if (epnum != EP_ISO_NUM)
- {
+ if (epnum != EP_ISO_NUM) {
// CBI
- if (dir == TUSB_DIR_OUT)
- {
+ if (dir == TUSB_DIR_OUT) {
NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
NRF_USBD->EPOUTEN &= ~TU_BIT(epnum);
- }
- else
- {
+ } else {
NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
NRF_USBD->EPINEN &= ~TU_BIT(epnum);
}
- }
- else
- {
+ } else {
_dcd.xfer[EP_ISO_NUM][dir].mps = 0;
// ISO
- if (dir == TUSB_DIR_OUT)
- {
+ if (dir == TUSB_DIR_OUT) {
NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOOUT_Msk;
NRF_USBD->EPOUTEN &= ~USBD_EPOUTEN_ISOOUT_Msk;
NRF_USBD->EVENTS_ENDISOOUT = 0;
- }
- else
- {
+ } else {
NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOIN_Msk;
NRF_USBD->EPINEN &= ~USBD_EPINEN_ISOIN_Msk;
}
// One of the ISO endpoints closed, no need to split buffers any more.
NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
// When both ISO endpoint are close there is no need for SOF any more.
- if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0) NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
+ if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0)
+ NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
}
_dcd.xfer[epnum][dir].started = false;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
}
-bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_td_t* xfer = get_td(epnum, dir);
TU_ASSERT(!xfer->started);
- xfer->buffer = buffer;
- xfer->total_len = total_bytes;
+ xfer->buffer = buffer;
+ xfer->total_len = total_bytes;
xfer->actual_len = 0;
// Control endpoint with zero-length packet and opposite direction to 1st request byte --> status stage
bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE));
- if ( control_status )
- {
+ if (control_status) {
// Status Phase also requires EasyDMA has to be available as well !!!!
edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
// The nRF doesn't interrupt on status transmit so we queue up a success response.
dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, is_in_isr());
- }
- else if ( dir == TUSB_DIR_OUT )
- {
+ } else if (dir == TUSB_DIR_OUT) {
xfer->started = true;
- if ( epnum == 0 )
- {
+ if (epnum == 0) {
// Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
- }else
- {
+ } else {
// started just set, it could start DMA transfer if interrupt was trigger after this line
// code only needs to start transfer (from Endpoint to RAM) when data_received was set
// before started was set. If started is NOT set but data_received is, it means that
// current transfer was already finished and next data is already present in endpoint and
// can be consumed by future transfer
- __ISB(); __DSB();
- if ( xfer->data_received && xfer->started )
- {
+ __ISB();
+ __DSB();
+ if (xfer->data_received && xfer->started) {
// Data is already received previously
// start DMA to copy to SRAM
xfer->data_received = false;
xact_out_dma(epnum);
- }
- else
- {
+ } else {
// nRF auto accept next Bulk/Interrupt OUT packet
// nothing to do
}
}
- }
- else
- {
+ } else {
// Start DMA to copy data from RAM -> Endpoint
xact_in_dma(epnum);
}
@@ -523,42 +470,37 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
return true;
}
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_td_t* xfer = get_td(epnum, dir);
- if ( epnum == 0 )
- {
+ if (epnum == 0) {
NRF_USBD->TASKS_EP0STALL = 1;
- }else if (epnum != EP_ISO_NUM)
- {
+ } else if (epnum != EP_ISO_NUM) {
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep_addr;
// Note: nRF can auto ACK packet OUT before get stalled.
// There maybe data in endpoint fifo already, we need to pull it out
- if ( (dir == TUSB_DIR_OUT) && xfer->data_received )
- {
+ if ((dir == TUSB_DIR_OUT) && xfer->data_received) {
xfer->data_received = false;
xact_out_dma(epnum);
}
}
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
}
-void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- if ( epnum != 0 && epnum != EP_ISO_NUM )
- {
+ if (epnum != 0 && epnum != EP_ISO_NUM) {
// reset data toggle to DATA0
// First write this register with VALUE=Nop to select the endpoint, then either read it to get the status from
// VALUE, or write it again with VALUE=Data0 or Data1
@@ -571,26 +513,25 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
// Write any value to SIZE register will allow nRF to ACK/accept data
if (dir == TUSB_DIR_OUT) NRF_USBD->SIZE.EPOUT[epnum] = 0;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
}
}
/*------------------------------------------------------------------*/
/* Interrupt Handler
*------------------------------------------------------------------*/
-void bus_reset(void)
-{
+void bus_reset(void) {
// 6.35.6 USB controller automatically disabled all endpoints (except control)
NRF_USBD->EPOUTEN = 1UL;
NRF_USBD->EPINEN = 1UL;
- for(int i=0; i<8; i++)
- {
+ for (int i = 0; i < 8; i++) {
NRF_USBD->TASKS_STARTEPIN[i] = 0;
NRF_USBD->TASKS_STARTEPOUT[i] = 0;
}
- NRF_USBD->TASKS_STARTISOIN = 0;
+ NRF_USBD->TASKS_STARTISOIN = 0;
NRF_USBD->TASKS_STARTISOOUT = 0;
// Clear USB Event Interrupt
@@ -600,43 +541,40 @@ void bus_reset(void)
// Reset interrupt
NRF_USBD->INTENCLR = NRF_USBD->INTEN;
NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_EPDATA_Msk |
- USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk;
+ USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk |
+ USBD_INTEN_ENDEPOUT0_Msk;
tu_varclr(&_dcd);
_dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE;
_dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE;
}
-void dcd_int_handler(uint8_t rhport)
-{
+void dcd_int_handler(uint8_t rhport) {
(void) rhport;
- uint32_t const inten = NRF_USBD->INTEN;
+ uint32_t const inten = NRF_USBD->INTEN;
uint32_t int_status = 0;
volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET;
- for(uint8_t i=0; i<USBD_INTEN_EPDATA_Pos+1; i++)
- {
- if ( tu_bit_test(inten, i) && regevt[i] )
- {
+ for (uint8_t i = 0; i < USBD_INTEN_EPDATA_Pos + 1; i++) {
+ if (tu_bit_test(inten, i) && regevt[i]) {
int_status |= TU_BIT(i);
// event clear
regevt[i] = 0;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
}
}
- if ( int_status & USBD_INTEN_USBRESET_Msk )
- {
+ if (int_status & USBD_INTEN_USBRESET_Msk) {
bus_reset();
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
}
// ISOIN: Data was moved to endpoint buffer, client will be notified in SOF
- if ( int_status & USBD_INTEN_ENDISOIN_Msk )
- {
+ if (int_status & USBD_INTEN_ENDISOIN_Msk) {
xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN);
xfer->actual_len = NRF_USBD->ISOIN.AMOUNT;
@@ -645,32 +583,31 @@ void dcd_int_handler(uint8_t rhport)
xfer->iso_in_transfer_ready = true;
}
- if ( int_status & USBD_INTEN_SOF_Msk )
- {
+ if (int_status & USBD_INTEN_SOF_Msk) {
bool iso_enabled = false;
// ISOOUT: Transfer data gathered in previous frame from buffer to RAM
- if (NRF_USBD->EPOUTEN & USBD_EPOUTEN_ISOOUT_Msk)
- {
+ if (NRF_USBD->EPOUTEN & USBD_EPOUTEN_ISOOUT_Msk) {
iso_enabled = true;
- xact_out_dma(EP_ISO_NUM);
+ // Transfer from endpoint to RAM only if data is not corrupted
+ if ((int_status & USBD_INTEN_USBEVENT_Msk) == 0 ||
+ (NRF_USBD->EVENTCAUSE & USBD_EVENTCAUSE_ISOOUTCRC_Msk) == 0) {
+ xact_out_dma(EP_ISO_NUM);
+ }
}
// ISOIN: Notify client that data was transferred
- if (NRF_USBD->EPINEN & USBD_EPINEN_ISOIN_Msk)
- {
+ if (NRF_USBD->EPINEN & USBD_EPINEN_ISOIN_Msk) {
iso_enabled = true;
xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN);
- if ( xfer->iso_in_transfer_ready )
- {
+ if (xfer->iso_in_transfer_ready) {
xfer->iso_in_transfer_ready = false;
dcd_event_xfer_complete(0, EP_ISO_NUM | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
}
}
- if ( !iso_enabled )
- {
+ if (!iso_enabled) {
// ISO endpoint is not used, SOF is only enabled one-time for remote wakeup
// so we disable it now
NRF_USBD->INTENCLR = USBD_INTENSET_SOF_Msk;
@@ -679,16 +616,17 @@ void dcd_int_handler(uint8_t rhport)
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
- if ( int_status & USBD_INTEN_USBEVENT_Msk )
- {
- TU_LOG(2, "EVENTCAUSE = 0x%04lX\r\n", NRF_USBD->EVENTCAUSE);
+ if (int_status & USBD_INTEN_USBEVENT_Msk) {
+ TU_LOG(3, "EVENTCAUSE = 0x%04" PRIX32 "\r\n", NRF_USBD->EVENTCAUSE);
- enum { EVT_CAUSE_MASK = USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk | USBD_EVENTCAUSE_USBWUALLOWED_Msk };
+ enum {
+ EVT_CAUSE_MASK = USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk | USBD_EVENTCAUSE_USBWUALLOWED_Msk |
+ USBD_EVENTCAUSE_ISOOUTCRC_Msk
+ };
uint32_t const evt_cause = NRF_USBD->EVENTCAUSE & EVT_CAUSE_MASK;
NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt
- if ( evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk )
- {
+ if (evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk) {
// Put controller into low power mode
// Leave HFXO disable to application, since it may be used by other peripherals
NRF_USBD->LOWPOWER = 1;
@@ -696,8 +634,7 @@ void dcd_int_handler(uint8_t rhport)
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
}
- if ( evt_cause & USBD_EVENTCAUSE_USBWUALLOWED_Msk )
- {
+ if (evt_cause & USBD_EVENTCAUSE_USBWUALLOWED_Msk) {
// USB is out of low power mode, and wakeup is allowed
// Initiate RESUME signal
NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume;
@@ -709,34 +646,29 @@ void dcd_int_handler(uint8_t rhport)
NRF_USBD->INTENSET = USBD_INTENSET_SOF_Msk;
}
- if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk )
- {
+ if (evt_cause & USBD_EVENTCAUSE_RESUME_Msk) {
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
}
// Setup tokens are specific to the Control endpoint.
- if ( int_status & USBD_INTEN_EP0SETUP_Msk )
- {
- uint8_t const setup[8] =
- {
- NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH,
- NRF_USBD->WINDEXL , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
+ if (int_status & USBD_INTEN_EP0SETUP_Msk) {
+ uint8_t const setup[8] = {
+ NRF_USBD->BMREQUESTTYPE, NRF_USBD->BREQUEST, NRF_USBD->WVALUEL, NRF_USBD->WVALUEH,
+ NRF_USBD->WINDEXL, NRF_USBD->WINDEXH, NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
};
// nrf5x hw auto handle set address, there is no need to inform usb stack
- tusb_control_request_t const * request = (tusb_control_request_t const *) setup;
+ tusb_control_request_t const* request = (tusb_control_request_t const*) setup;
- if ( !(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient &&
- TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type &&
- TUSB_REQ_SET_ADDRESS == request->bRequest) )
- {
+ if (!(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient &&
+ TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type &&
+ TUSB_REQ_SET_ADDRESS == request->bRequest)) {
dcd_event_setup_received(0, setup, true);
}
}
- if ( int_status & EDPT_END_ALL_MASK )
- {
+ if (int_status & EDPT_END_ALL_MASK) {
// DMA complete move data from SRAM <-> Endpoint
// Must before endpoint transfer handling
edpt_dma_end();
@@ -778,30 +710,24 @@ void dcd_int_handler(uint8_t rhport)
* len if Host decides to sent fewer bytes, it this case transaction is also
* complete and next transfer is not initiated here like for CBI.
*/
- for(uint8_t epnum=0; epnum<EP_CBI_COUNT+1; epnum++)
- {
- if ( tu_bit_test(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum))
- {
+ for (uint8_t epnum = 0; epnum < EP_CBI_COUNT + 1; epnum++) {
+ if (tu_bit_test(int_status, USBD_INTEN_ENDEPOUT0_Pos + epnum)) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
uint16_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
- xfer->buffer += xact_len;
+ xfer->buffer += xact_len;
xfer->actual_len += xact_len;
// Transfer complete if transaction len < Max Packet Size or total len is transferred
- if ( (epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
- {
- if ( epnum == 0 )
- {
+ if ((epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len)) {
+ if (epnum == 0) {
// Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
- }else
- {
+ } else {
// nRF auto accept next Bulk/Interrupt OUT packet
// nothing to do
}
- }else
- {
+ } else {
TU_ASSERT(xfer->started,);
xfer->total_len = xfer->actual_len;
xfer->started = false;
@@ -815,11 +741,11 @@ void dcd_int_handler(uint8_t rhport)
}
// Endpoint <-> Host ( In & OUT )
- if ( int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk) )
- {
+ if (int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk)) {
uint32_t data_status = NRF_USBD->EPDATASTATUS;
NRF_USBD->EPDATASTATUS = data_status;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
// EP0DATADONE is set with either Control Out on IN Data
// Since EPDATASTATUS cannot be used to determine whether it is control OUT or IN.
@@ -828,22 +754,18 @@ void dcd_int_handler(uint8_t rhport)
bool const is_control_out = (int_status & USBD_INTEN_EP0DATADONE_Msk) && !(NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK);
// CBI In: Endpoint -> Host (transaction complete)
- for(uint8_t epnum=0; epnum<EP_CBI_COUNT; epnum++)
- {
- if ( tu_bit_test(data_status, epnum) || (epnum == 0 && is_control_in) )
- {
+ for (uint8_t epnum = 0; epnum < EP_CBI_COUNT; epnum++) {
+ if (tu_bit_test(data_status, epnum) || (epnum == 0 && is_control_in)) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
uint8_t const xact_len = NRF_USBD->EPIN[epnum].AMOUNT;
- xfer->buffer += xact_len;
+ xfer->buffer += xact_len;
xfer->actual_len += xact_len;
- if ( xfer->actual_len < xfer->total_len )
- {
+ if (xfer->actual_len < xfer->total_len) {
// Start DMA to copy next data packet
xact_in_dma(epnum);
- } else
- {
+ } else {
// CBI IN complete
dcd_event_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
}
@@ -851,17 +773,13 @@ void dcd_int_handler(uint8_t rhport)
}
// CBI OUT: Host -> Endpoint
- for(uint8_t epnum=0; epnum<EP_CBI_COUNT; epnum++)
- {
- if ( tu_bit_test(data_status, 16+epnum) || (epnum == 0 && is_control_out) )
- {
+ for (uint8_t epnum = 0; epnum < EP_CBI_COUNT; epnum++) {
+ if (tu_bit_test(data_status, 16 + epnum) || (epnum == 0 && is_control_out)) {
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
- if ( xfer->started && xfer->actual_len < xfer->total_len )
- {
+ if (xfer->started && xfer->actual_len < xfer->total_len) {
xact_out_dma(epnum);
- }else
- {
+ } else {
// Data overflow !!! Nah, nRF will auto accept next Bulk/Interrupt OUT packet
// Mark this endpoint with data received
xfer->data_received = true;
@@ -885,76 +803,80 @@ void dcd_int_handler(uint8_t rhport)
#define SD_MAGIC_NUMBER 0x51B1E5DB
#endif
-static inline bool is_sd_existed(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool is_sd_existed(void) {
return *((uint32_t*)(SOFTDEVICE_INFO_STRUCT_ADDRESS+4)) == SD_MAGIC_NUMBER;
}
// check if SD is existed and enabled
-static inline bool is_sd_enabled(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool is_sd_enabled(void) {
if ( !is_sd_existed() ) return false;
-
uint8_t sd_en = false;
(void) sd_softdevice_is_enabled(&sd_en);
return sd_en;
}
#endif
-static bool hfclk_running(void)
-{
+static bool hfclk_running(void) {
#ifdef SOFTDEVICE_PRESENT
- if ( is_sd_enabled() )
- {
+ if ( is_sd_enabled() ) {
uint32_t is_running = 0;
(void) sd_clock_hfclk_is_running(&is_running);
return (is_running ? true : false);
}
#endif
+#if CFG_TUD_NRF_NRFX_VERSION == 1
+ return nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY);
+#else
return nrf_clock_hf_is_running(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY);
+#endif
}
-static void hfclk_enable(void)
-{
+static void hfclk_enable(void) {
#if CFG_TUSB_OS == OPT_OS_MYNEWT
usb_clock_request();
return;
#else
// already running, nothing to do
- if ( hfclk_running() ) return;
+ if (hfclk_running()) return;
#ifdef SOFTDEVICE_PRESENT
- if ( is_sd_enabled() )
- {
+ if ( is_sd_enabled() ) {
(void)sd_clock_hfclk_request();
return;
}
#endif
+#if CFG_TUD_NRF_NRFX_VERSION == 1
+ nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
+ nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART);
+#else
nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
#endif
+#endif
}
-static void hfclk_disable(void)
-{
+static void hfclk_disable(void) {
#if CFG_TUSB_OS == OPT_OS_MYNEWT
usb_clock_release();
return;
#else
#ifdef SOFTDEVICE_PRESENT
- if ( is_sd_enabled() )
- {
+ if ( is_sd_enabled() ) {
(void)sd_clock_hfclk_release();
return;
}
#endif
+#if CFG_TUD_NRF_NRFX_VERSION == 1
+ nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP);
+#else
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
#endif
+#endif
}
// Power & Clock Peripheral on nRF5x to manage USB
@@ -967,8 +889,7 @@ static void hfclk_disable(void)
// Therefore this function must be called to handle USB power event by
// - nrfx_power_usbevt_init() : if Softdevice is not used or enabled
// - SoftDevice SOC event : if SD is used and enabled
-void tusb_hal_nrf_power_event (uint32_t event)
-{
+void tusb_hal_nrf_power_event(uint32_t event) {
// Value is chosen to be as same as NRFX_POWER_USB_EVT_* in nrfx_power.h
enum {
USB_EVT_DETECTED = 0,
@@ -977,50 +898,41 @@ void tusb_hal_nrf_power_event (uint32_t event)
};
#if CFG_TUSB_DEBUG >= 2
- const char* const power_evt_str[] = { "Detected", "Removed", "Ready" };
+ const char* const power_evt_str[] = {"Detected", "Removed", "Ready"};
TU_LOG(2, "Power USB event: %s\r\n", power_evt_str[event]);
#endif
- switch ( event )
- {
+ switch (event) {
case USB_EVT_DETECTED:
- if ( !NRF_USBD->ENABLE )
- {
+ if (!NRF_USBD->ENABLE) {
// Prepare for receiving READY event: disable interrupt since we will blocking wait
NRF_USBD->INTENCLR = USBD_INTEN_USBEVENT_Msk;
NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
#ifdef NRF52_SERIES // NRF53 does not need this errata
// ERRATA 171, 187, 166
- if ( nrfx_usbd_errata_187() )
- {
+ if (nrfx_usbd_errata_187()) {
// CRITICAL_REGION_ENTER();
- if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
- {
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- *((volatile uint32_t *) (0x4006ED14)) = 0x00000003;
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- }
- else
- {
- *((volatile uint32_t *) (0x4006ED14)) = 0x00000003;
+ if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ *((volatile uint32_t*) (0x4006ED14)) = 0x00000003;
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ } else {
+ *((volatile uint32_t*) (0x4006ED14)) = 0x00000003;
}
// CRITICAL_REGION_EXIT();
}
- if ( nrfx_usbd_errata_171() )
- {
+ if (nrfx_usbd_errata_171()) {
// CRITICAL_REGION_ENTER();
- if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
- {
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- *((volatile uint32_t *) (0x4006EC14)) = 0x000000C0;
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- }
- else
- {
- *((volatile uint32_t *) (0x4006EC14)) = 0x000000C0;
+ if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ *((volatile uint32_t*) (0x4006EC14)) = 0x000000C0;
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ } else {
+ *((volatile uint32_t*) (0x4006EC14)) = 0x000000C0;
}
// CRITICAL_REGION_EXIT();
}
@@ -1028,64 +940,58 @@ void tusb_hal_nrf_power_event (uint32_t event)
// Enable the peripheral (will cause Ready event)
NRF_USBD->ENABLE = 1;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
// Enable HFCLK
hfclk_enable();
}
- break;
+ break;
case USB_EVT_READY:
// Skip if pull-up is enabled and HCLK is already running.
// Application probably call this more than necessary.
- if ( NRF_USBD->USBPULLUP && hfclk_running() ) break;
+ if (NRF_USBD->USBPULLUP && hfclk_running()) break;
// Waiting for USBD peripheral enabled
- while ( !(USBD_EVENTCAUSE_READY_Msk & NRF_USBD->EVENTCAUSE) ) { }
+ while (!(USBD_EVENTCAUSE_READY_Msk & NRF_USBD->EVENTCAUSE)) {}
NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
#ifdef NRF52_SERIES
- if ( nrfx_usbd_errata_171() )
- {
+ if (nrfx_usbd_errata_171()) {
// CRITICAL_REGION_ENTER();
- if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
- {
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- *((volatile uint32_t *) (0x4006EC14)) = 0x00000000;
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- }
- else
- {
- *((volatile uint32_t *) (0x4006EC14)) = 0x00000000;
+ if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ *((volatile uint32_t*) (0x4006EC14)) = 0x00000000;
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ } else {
+ *((volatile uint32_t*) (0x4006EC14)) = 0x00000000;
}
// CRITICAL_REGION_EXIT();
}
- if ( nrfx_usbd_errata_187() )
- {
+ if (nrfx_usbd_errata_187()) {
// CRITICAL_REGION_ENTER();
- if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
- {
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- *((volatile uint32_t *) (0x4006ED14)) = 0x00000000;
- *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
- }
- else
- {
- *((volatile uint32_t *) (0x4006ED14)) = 0x00000000;
+ if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ *((volatile uint32_t*) (0x4006ED14)) = 0x00000000;
+ *((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
+ } else {
+ *((volatile uint32_t*) (0x4006ED14)) = 0x00000000;
}
// CRITICAL_REGION_EXIT();
}
- if ( nrfx_usbd_errata_166() )
- {
- *((volatile uint32_t *) (NRF_USBD_BASE + 0x800)) = 0x7E3;
- *((volatile uint32_t *) (NRF_USBD_BASE + 0x804)) = 0x40;
+ if (nrfx_usbd_errata_166()) {
+ *((volatile uint32_t*) (NRF_USBD_BASE + 0x800)) = 0x7E3;
+ *((volatile uint32_t*) (NRF_USBD_BASE + 0x804)) = 0x40;
- __ISB(); __DSB();
+ __ISB();
+ __DSB();
}
#endif
@@ -1097,30 +1003,31 @@ void tusb_hal_nrf_power_event (uint32_t event)
// Enable interrupt, priorities should be set by application
NVIC_ClearPendingIRQ(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())
- {
+ if (tud_inited()) {
NVIC_EnableIRQ(USBD_IRQn);
}
// Wait for HFCLK
- while ( !hfclk_running() ) { }
+ while (!hfclk_running()) {}
// Enable pull up
NRF_USBD->USBPULLUP = 1;
- __ISB(); __DSB(); // for sync
- break;
+ __ISB();
+ __DSB(); // for sync
+ break;
case USB_EVT_REMOVED:
- if ( NRF_USBD->ENABLE )
- {
+ if (NRF_USBD->ENABLE) {
// Abort all transfers
// Disable pull up
NRF_USBD->USBPULLUP = 0;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
// Disable Interrupt
NVIC_DisableIRQ(USBD_IRQn);
@@ -1129,15 +1036,17 @@ void tusb_hal_nrf_power_event (uint32_t event)
NRF_USBD->INTENCLR = NRF_USBD->INTEN;
NRF_USBD->ENABLE = 0;
- __ISB(); __DSB(); // for sync
+ __ISB();
+ __DSB(); // for sync
hfclk_disable();
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr());
}
- break;
+ break;
- default: break;
+ default:
+ break;
}
}
diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c
index 5c65ea33d..dc71117b3 100644
--- a/src/portable/nxp/khci/dcd_khci.c
+++ b/src/portable/nxp/khci/dcd_khci.c
@@ -269,9 +269,21 @@ void dcd_init(uint8_t rhport)
{
(void) rhport;
+ // save crystal-less setting (if available)
+ #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1
+ uint32_t clk_recover_irc_en = KHCI->CLK_RECOVER_IRC_EN;
+ uint32_t clk_recover_ctrl = KHCI->CLK_RECOVER_CTRL;
+ #endif
+
KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+ // restore crystal-less setting (if available)
+ #if defined(FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED == 1
+ KHCI->CLK_RECOVER_IRC_EN = clk_recover_irc_en;
+ KHCI->CLK_RECOVER_CTRL |= clk_recover_ctrl;
+ #endif
+
tu_memclr(&_dcd, sizeof(_dcd));
KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_dcd.bdt >> 8);
diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
index f4ed09d83..cc18cf59b 100644
--- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -42,7 +42,18 @@
#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
// LPCOpen
+ #ifdef __GNUC__
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
+ #pragma GCC diagnostic ignored "-Wstrict-prototypes"
+ #endif
+
#include "chip.h"
+
+ #ifdef __GNUC__
+ #pragma GCC diagnostic pop
+ #endif
+
#else
// SDK
#include "fsl_device_registers.h"
@@ -239,7 +250,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(ep_cmd_sts_t* ep_cs, bool is_
return is_highspeed ? (ep_cs[0].cmd_sts.type && !ep_cs[0].cmd_sts.rf_tv) : ep_cs->cmd_sts.type;
}
-TU_ATTR_ALWAYS_INLINE static inline bool ep_is_bulk(ep_cmd_sts_t* ep_cs) {
+TU_ATTR_ALWAYS_INLINE TU_ATTR_UNUSED static inline bool ep_is_bulk(ep_cmd_sts_t* ep_cs) {
return (ep_cs[0].cmd_sts.type == 0) && (ep_cs[0].cmd_sts.rf_tv == 0);
}
diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h
index 4feefd771..94bad5df7 100644
--- a/src/portable/ohci/ohci.h
+++ b/src/portable/ohci/ohci.h
@@ -83,7 +83,7 @@ typedef struct TU_ATTR_ALIGNED(16)
volatile uint32_t condition_code : 4;
// Word 1
- volatile uint8_t* current_buffer_pointer;
+ uint8_t* volatile current_buffer_pointer;
// Word 2 : next TD
volatile uint32_t next;
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index e8cee73fd..bc0deee32 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -48,7 +48,7 @@
*------------------------------------------------------------------*/
// Init these in dcd_init
-static uint8_t *next_buffer_ptr;
+static uint8_t* next_buffer_ptr;
// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
@@ -56,79 +56,70 @@ static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
// SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd
static bool _sof_enable = false;
-TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
-{
+TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir) {
return &hw_endpoints[num][dir];
}
-static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
-{
+TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_addr(uint8_t ep_addr) {
uint8_t num = tu_edpt_number(ep_addr);
tusb_dir_t dir = tu_edpt_dir(ep_addr);
return hw_endpoint_get_by_num(num, dir);
}
-static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
-{
+static void _hw_endpoint_alloc(struct hw_endpoint* ep, uint8_t transfer_type) {
// size must be multiple of 64
uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
// double buffered Bulk endpoint
- if ( transfer_type == TUSB_XFER_BULK )
- {
+ if (transfer_type == TUSB_XFER_BULK) {
size *= 2u;
}
ep->hw_data_buf = next_buffer_ptr;
next_buffer_ptr += size;
- assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0);
+ assert(((uintptr_t) next_buffer_ptr & 0b111111u) == 0);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
// Fill in endpoint control register with buffer offset
- uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
+ uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
*ep->endpoint_control = reg;
}
-static void _hw_endpoint_close(struct hw_endpoint *ep)
-{
- // Clear hardware registers and then zero the struct
- // Clears endpoint enable
- *ep->endpoint_control = 0;
- // Clears buffer available, etc
- *ep->buffer_control = 0;
- // Clear any endpoint state
- memset(ep, 0, sizeof(struct hw_endpoint));
+static void _hw_endpoint_close(struct hw_endpoint* ep) {
+ // Clear hardware registers and then zero the struct
+ // Clears endpoint enable
+ *ep->endpoint_control = 0;
+ // Clears buffer available, etc
+ *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];
+ // 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)
-{
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
- _hw_endpoint_close(ep);
+static void hw_endpoint_close(uint8_t ep_addr) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
+ _hw_endpoint_close(ep);
}
-static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
-{
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
const uint8_t num = tu_edpt_number(ep_addr);
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
@@ -143,35 +134,26 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
ep->transfer_type = transfer_type;
// Every endpoint has a buffer control register in dpram
- if ( dir == TUSB_DIR_IN )
- {
+ if (dir == TUSB_DIR_IN) {
ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
- }
- else
- {
+ } else {
ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
}
// Clear existing buffer control state
*ep->buffer_control = 0;
- if ( num == 0 )
- {
+ if (num == 0) {
// EP0 has no endpoint control register because the buffer offsets are fixed
ep->endpoint_control = NULL;
// Buffer offset is fixed (also double buffered)
ep->hw_data_buf = (uint8_t*) &usb_dpram->ep0_buf_a[0];
- }
- else
- {
+ } else {
// Set the endpoint control register (starts at EP1, hence num-1)
- if ( dir == TUSB_DIR_IN )
- {
+ if (dir == TUSB_DIR_IN) {
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].in;
- }
- else
- {
+ } else {
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
}
@@ -180,76 +162,82 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
}
}
-static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
-{
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
- hw_endpoint_xfer_start(ep, buffer, total_bytes);
+static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
+ hw_endpoint_xfer_start(ep, buffer, total_bytes);
}
-static void __tusb_irq_path_func(hw_handle_buff_status)(void)
-{
- uint32_t remaining_buffers = usb_hw->buf_status;
- pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers);
- uint bit = 1u;
- for (uint8_t i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++)
- {
- if (remaining_buffers & bit)
- {
- // clear this in advance
- usb_hw_clear->buf_status = bit;
+static void __tusb_irq_path_func(hw_handle_buff_status)(void) {
+ uint32_t remaining_buffers = usb_hw->buf_status;
+ pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers);
+ uint bit = 1u;
+ for (uint8_t i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++) {
+ if (remaining_buffers & bit) {
+ // clear this in advance
+ usb_hw_clear->buf_status = bit;
- // IN transfer for even i, OUT transfer for odd i
- struct hw_endpoint *ep = hw_endpoint_get_by_num(i >> 1u, (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN);
+ // IN transfer for even i, OUT transfer for odd i
+ struct hw_endpoint* ep = hw_endpoint_get_by_num(i >> 1u, (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN);
- // Continue xfer
- bool done = hw_endpoint_xfer_continue(ep);
- if (done)
- {
- // Notify
- dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true);
- hw_endpoint_reset_transfer(ep);
- }
- remaining_buffers &= ~bit;
- }
- bit <<= 1u;
+ // Continue xfer
+ bool done = hw_endpoint_xfer_continue(ep);
+ if (done) {
+ // Notify
+ dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true);
+ hw_endpoint_reset_transfer(ep);
+ }
+ remaining_buffers &= ~bit;
}
+ bit <<= 1u;
+ }
}
-TU_ATTR_ALWAYS_INLINE static inline void reset_ep0_pid(void)
-{
- // If we have finished this transfer on EP0 set pid back to 1 for next
- // setup transfer. Also clear a stall in case
- uint8_t addrs[] = {0x0, 0x80};
- for (uint i = 0 ; i < TU_ARRAY_SIZE(addrs); i++)
- {
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(addrs[i]);
- ep->next_pid = 1u;
+TU_ATTR_ALWAYS_INLINE static inline void reset_ep0(void) {
+ // If we have finished this transfer on EP0 set pid back to 1 for next
+ // setup transfer. Also clear a stall in case
+ for (uint8_t dir = 0; dir < 2; dir++) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_num(0, dir);
+ if (ep->active) {
+ // Abort any pending transfer from a prior control transfer per USB specs
+ // Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1).
+ // Which means we are not guaranteed to safely abort pending transfer on B0 and B1.
+ uint32_t const abort_mask = (dir ? USB_EP_ABORT_EP0_IN_BITS : USB_EP_ABORT_EP0_OUT_BITS);
+ if (rp2040_chip_version() >= 2) {
+ usb_hw_set->abort = abort_mask;
+ while ((usb_hw->abort_done & abort_mask) != abort_mask) {}
+ }
+
+ _hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_DATA1_PID | USB_BUF_CTRL_SEL);
+ hw_endpoint_reset_transfer(ep);
+
+ if (rp2040_chip_version() >= 2) {
+ usb_hw_clear->abort_done = abort_mask;
+ usb_hw_clear->abort = abort_mask;
+ }
}
+ ep->next_pid = 1u;
+ }
}
-static void __tusb_irq_path_func(reset_non_control_endpoints)(void)
-{
+static void __tusb_irq_path_func(reset_non_control_endpoints)(void) {
// Disable all non-control
- for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS-1; i++ )
- {
+ for (uint8_t i = 0; i < USB_MAX_ENDPOINTS - 1; i++) {
usb_dpram->ep_ctrl[i].in = 0;
usb_dpram->ep_ctrl[i].out = 0;
}
// clear non-control hw endpoints
- tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2*sizeof(hw_endpoint_t));
+ tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2 * sizeof(hw_endpoint_t));
// reclaim buffer space
next_buffer_ptr = &usb_dpram->epx_data[0];
}
-static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
-{
+static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
uint32_t const status = usb_hw->ints;
uint32_t handled = 0;
- if ( status & USB_INTF_DEV_SOF_BITS )
- {
+ if (status & USB_INTF_DEV_SOF_BITS) {
bool keep_sof_alive = false;
handled |= USB_INTF_DEV_SOF_BITS;
@@ -258,20 +246,17 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
// Errata 15 workaround for Device Bulk-In endpoint
e15_last_sof = time_us_32();
- for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++ )
- {
- struct hw_endpoint * ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
+ for (uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
// Active Bulk IN endpoint requires SOF
- if ( (ep->transfer_type == TUSB_XFER_BULK) && ep->active )
- {
+ if ((ep->transfer_type == TUSB_XFER_BULK) && ep->active) {
keep_sof_alive = true;
hw_endpoint_lock_update(ep, 1);
// Deferred enable?
- if ( ep->pending )
- {
+ if (ep->pending) {
ep->pending = 0;
hw_endpoint_start_next_buffer(ep);
}
@@ -282,26 +267,24 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
#endif
// disable SOF interrupt if it is used for RESUME in remote wakeup
- if ( !keep_sof_alive && !_sof_enable ) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+ if (!keep_sof_alive && !_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
}
// 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 )
- {
+ if (status & USB_INTS_BUFF_STATUS_BITS) {
handled |= USB_INTS_BUFF_STATUS_BITS;
hw_handle_buff_status();
}
- if ( status & USB_INTS_SETUP_REQ_BITS )
- {
+ if (status & USB_INTS_SETUP_REQ_BITS) {
handled |= USB_INTS_SETUP_REQ_BITS;
- uint8_t const * setup = remove_volatile_cast(uint8_t const*, &usb_dpram->setup_packet);
+ uint8_t const* setup = remove_volatile_cast(uint8_t const*, &usb_dpram->setup_packet);
// reset pid to both 1 (data and ack)
- reset_ep0_pid();
+ reset_ep0();
// Pass setup packet to tiny usb
dcd_event_setup_received(0, setup, true);
@@ -329,8 +312,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
#endif
// SE0 for 2.5 us or more (will last at least 10ms)
- if ( status & USB_INTS_BUS_RESET_BITS )
- {
+ if (status & USB_INTS_BUS_RESET_BITS) {
pico_trace("BUS RESET\r\n");
handled |= USB_INTS_BUS_RESET_BITS;
@@ -342,7 +324,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
// Only run enumeration workaround if pull up is enabled
- if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix();
+ if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) rp2040_usb_device_enumeration_fix();
#endif
}
@@ -354,22 +336,19 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
* because without VBUS detection, it is impossible to tell the difference between
* being disconnected and suspended.
*/
- if ( status & USB_INTS_DEV_SUSPEND_BITS )
- {
+ if (status & USB_INTS_DEV_SUSPEND_BITS) {
handled |= USB_INTS_DEV_SUSPEND_BITS;
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
}
- if ( status & USB_INTS_DEV_RESUME_FROM_HOST_BITS )
- {
+ if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS) {
handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
}
- if ( status ^ handled )
- {
+ if (status ^ handled) {
panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
}
}
@@ -390,10 +369,11 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
#define PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY 0xff
#endif
-void dcd_init (uint8_t rhport)
-{
+void dcd_init(uint8_t rhport) {
assert(rhport == 0);
+ TU_LOG(2, "Chip Version B%u\r\n", rp2040_chip_version());
+
// Reset hardware to default state
rp2040_usb_init();
@@ -405,7 +385,7 @@ void dcd_init (uint8_t rhport)
irq_add_shared_handler(USBCTRL_IRQ, dcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
// Init control endpoints
- tu_memclr(hw_endpoints[0], 2*sizeof(hw_endpoint_t));
+ tu_memclr(hw_endpoints[0], 2 * sizeof(hw_endpoint_t));
hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
@@ -420,27 +400,37 @@ void dcd_init (uint8_t rhport)
// for the global interrupt enable...
// Note: Force VBUS detect cause disconnection not detectable
usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS;
- usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
- USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS |
- (FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS);
+ usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
+ USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS |
+ (FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS);
dcd_connect(rhport);
}
-void dcd_int_enable(__unused uint8_t rhport)
-{
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, true);
+bool dcd_deinit(uint8_t rhport) {
+ (void) rhport;
+
+ reset_non_control_endpoints();
+ irq_remove_handler(USBCTRL_IRQ, dcd_rp2040_irq);
+
+ // reset usb hardware into initial state
+ reset_block(RESETS_RESET_USBCTRL_BITS);
+ unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
+
+ return true;
+}
+
+void dcd_int_enable(__unused uint8_t rhport) {
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, true);
}
-void dcd_int_disable(__unused uint8_t rhport)
-{
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, false);
+void dcd_int_disable(__unused uint8_t rhport) {
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, false);
}
-void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr)
-{
+void dcd_set_address(__unused uint8_t rhport, __unused uint8_t dev_addr) {
assert(rhport == 0);
// Can't set device address in hardware until status xfer has complete
@@ -448,8 +438,7 @@ void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr)
hw_endpoint_xfer(0x80, NULL, 0);
}
-void dcd_remote_wakeup(__unused uint8_t rhport)
-{
+void dcd_remote_wakeup(__unused uint8_t rhport) {
pico_info("dcd_remote_wakeup %d\n", rhport);
assert(rhport == 0);
@@ -460,100 +449,88 @@ void dcd_remote_wakeup(__unused uint8_t rhport)
}
// disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(__unused uint8_t rhport)
-{
+void dcd_disconnect(__unused uint8_t rhport) {
(void) rhport;
usb_hw_clear->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
}
// connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(__unused uint8_t rhport)
-{
+void dcd_connect(__unused uint8_t rhport) {
(void) rhport;
usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
}
-void dcd_sof_enable(uint8_t rhport, bool en)
-{
+void dcd_sof_enable(uint8_t rhport, bool en) {
(void) rhport;
_sof_enable = en;
- if (en)
- {
+ if (en) {
usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
- }else
- {
+ }
+#if !TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+ else {
// Don't clear immediately if the SOF workaround is in use.
// The SOF handler will conditionally disable the interrupt.
-#if !TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
-#endif
}
+#endif
}
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
-{
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
(void) rhport;
- if ( request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
- request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
- request->bRequest == TUSB_REQ_SET_ADDRESS )
- {
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
usb_hw->dev_addr_ctrl = (uint8_t) request->wValue;
}
}
-bool dcd_edpt_open (__unused uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
-{
- assert(rhport == 0);
- hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
- return true;
+bool dcd_edpt_open(__unused uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
+ assert(rhport == 0);
+ hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
+ return true;
}
-void dcd_edpt_close_all (uint8_t rhport)
-{
+void dcd_edpt_close_all(uint8_t rhport) {
(void) rhport;
// may need to use EP Abort
reset_non_control_endpoints();
}
-bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
- assert(rhport == 0);
- hw_endpoint_xfer(ep_addr, buffer, total_bytes);
- return true;
+bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
+ assert(rhport == 0);
+ hw_endpoint_xfer(ep_addr, buffer, total_bytes);
+ return true;
}
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
- if ( tu_edpt_number(ep_addr) == 0 )
- {
+ if (tu_edpt_number(ep_addr) == 0) {
// A stall on EP0 has to be armed so it can be cleared on the next setup packet
- usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
+ usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS
+ : USB_EP_STALL_ARM_EP0_OUT_BITS;
}
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
// stall and clear current pending buffer
// may need to use EP_ABORT
_hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_STALL);
}
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
-{
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
- if (tu_edpt_number(ep_addr))
- {
- struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+ if (tu_edpt_number(ep_addr)) {
+ struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
// clear stall also reset toggle to DATA0, ready for next transfer
ep->next_pid = 0;
@@ -561,16 +538,13 @@ 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;
-
- pico_trace("dcd_edpt_close %02x\r\n", ep_addr);
- hw_endpoint_close(ep_addr);
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ pico_trace("dcd_edpt_close %02x\r\n", ep_addr);
+ hw_endpoint_close(ep_addr);
}
-void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport)
-{
+void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport) {
(void) rhport;
dcd_rp2040_irq();
}
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 08aef9314..222dbbbf0 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -113,7 +113,7 @@ static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_en
static void __tusb_irq_path_func(hw_handle_buff_status)(void)
{
uint32_t remaining_buffers = usb_hw->buf_status;
- pico_trace("buf_status 0x%08x\n", remaining_buffers);
+ pico_trace("buf_status 0x%08lx\n", remaining_buffers);
// Check EPX first
uint bit = 0b1;
@@ -325,10 +325,8 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;
- pico_trace("hw_endpoint_init dev %d ep %d %s xfer %d\n", ep->dev_addr, tu_edpt_number(ep->ep_addr),
- ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->transfer_type);
- pico_trace("dev %d ep %d %s setup buffer @ 0x%p\n", ep->dev_addr, tu_edpt_number(ep->ep_addr),
- ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->hw_data_buf);
+ pico_trace("hw_endpoint_init dev %d ep %02X xfer %d\n", ep->dev_addr, ep->ep_addr, ep->transfer_type);
+ pico_trace("dev %d ep %02X setup buffer @ 0x%p\n", ep->dev_addr, ep->ep_addr, ep->hw_data_buf);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
// Bits 0-5 should be 0
assert(!(dpram_offset & 0b111111));
@@ -343,7 +341,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
}
*ep->endpoint_control = ep_reg;
- pico_trace("endpoint control (0x%p) <- 0x%x\n", ep->endpoint_control, ep_reg);
+ pico_trace("endpoint control (0x%p) <- 0x%lx\n", ep->endpoint_control, ep_reg);
ep->configured = true;
if ( ep != &epx )
@@ -411,6 +409,16 @@ bool hcd_init(uint8_t rhport)
return true;
}
+bool hcd_deinit(uint8_t rhport) {
+ (void) rhport;
+
+ irq_remove_handler(USBCTRL_IRQ, hcd_rp2040_irq);
+ reset_block(RESETS_RESET_USBCTRL_BITS);
+ unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
+
+ return true;
+}
+
void hcd_port_reset(uint8_t rhport)
{
(void) rhport;
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index a512dc34f..1ca711c77 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -35,26 +35,18 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTOTYPE
//--------------------------------------------------------------------+
-
-// Direction strings for debug
-const char *ep_dir_string[] = {
- "out",
- "in",
-};
-
-static void _hw_endpoint_xfer_sync(struct hw_endpoint *ep);
+static void _hw_endpoint_xfer_sync(struct hw_endpoint* ep);
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
- static bool e15_is_bulkin_ep(struct hw_endpoint *ep);
- static bool e15_is_critical_frame_period(struct hw_endpoint *ep);
+ static bool e15_is_bulkin_ep(struct hw_endpoint* ep);
+ static bool e15_is_critical_frame_period(struct hw_endpoint* ep);
#else
#define e15_is_bulkin_ep(x) (false)
#define e15_is_critical_frame_period(x) (false)
#endif
// if usb hardware is in host mode
-TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void) {
return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false;
}
@@ -62,8 +54,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void)
// Implementation
//--------------------------------------------------------------------+
-void rp2040_usb_init(void)
-{
+void rp2040_usb_init(void) {
// Reset usb controller
reset_block(RESETS_RESET_USBCTRL_BITS);
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
@@ -88,46 +79,33 @@ void rp2040_usb_init(void)
TU_LOG2_INT(sizeof(hw_endpoint_t));
}
-void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint *ep)
-{
+void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint* ep) {
ep->active = false;
ep->remaining_len = 0;
ep->xferred_len = 0;
ep->user_buf = 0;
}
-void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask)
-{
+void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoint* ep, uint32_t and_mask,
+ uint32_t or_mask) {
uint32_t value = 0;
- if ( and_mask )
- {
+ if (and_mask) {
value = *ep->buffer_control & and_mask;
}
- if ( or_mask )
- {
+ if (or_mask) {
value |= or_mask;
- if ( or_mask & USB_BUF_CTRL_AVAIL )
- {
- if ( *ep->buffer_control & USB_BUF_CTRL_AVAIL )
- {
- panic("ep %d %s was already available", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
+ if (or_mask & USB_BUF_CTRL_AVAIL) {
+ if (*ep->buffer_control & USB_BUF_CTRL_AVAIL) {
+ panic("ep %02X was already available", ep->ep_addr);
}
*ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
- // 12 cycle delay.. (should be good for 48*12Mhz = 576Mhz)
+ // 4.1.2.5.1 Con-current access: 12 cycles (should be good for 48*12Mhz = 576Mhz) after write to buffer control
// Don't need delay in host mode as host is in charge
-#if !CFG_TUH_ENABLED
- __asm volatile (
- "b 1f\n"
- "1: b 1f\n"
- "1: b 1f\n"
- "1: b 1f\n"
- "1: b 1f\n"
- "1: b 1f\n"
- "1:\n"
- : : : "memory");
-#endif
+ if ( !is_host_mode()) {
+ busy_wait_at_least_cycles(12);
+ }
}
}
@@ -135,10 +113,9 @@ void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoi
}
// prepare buffer, return buffer control
-static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id)
-{
+static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep, uint8_t buf_id) {
uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
- ep->remaining_len = (uint16_t)(ep->remaining_len - buflen);
+ ep->remaining_len = (uint16_t) (ep->remaining_len - buflen);
uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL;
@@ -146,10 +123,9 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep,
buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
ep->next_pid ^= 1u;
- if ( !ep->rx )
- {
+ if (!ep->rx) {
// Copy data from user buffer to hw buffer
- memcpy(ep->hw_data_buf + buf_id*64, ep->user_buf, buflen);
+ memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen);
ep->user_buf += buflen;
// Mark as full
@@ -159,8 +135,7 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep,
// Is this the last buffer? Only really matters for host mode. Will trigger
// the trans complete irq but also stop it polling. We only really care about
// trans complete for setup packets being sent
- if (ep->remaining_len == 0)
- {
+ if (ep->remaining_len == 0) {
buf_ctrl |= USB_BUF_CTRL_LAST;
}
@@ -170,8 +145,7 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep,
}
// Prepare buffer control register value
-void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint *ep)
-{
+void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep) {
uint32_t ep_ctrl = *ep->endpoint_control;
// always compute and start with buffer 0
@@ -186,8 +160,7 @@ void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint *ep)
bool const force_single = (!is_host && !tu_edpt_dir(ep->ep_addr)) ||
(is_host && tu_edpt_number(ep->ep_addr) != 0);
- if(ep->remaining_len && !force_single)
- {
+ if (ep->remaining_len && !force_single) {
// Use buffer 1 (double buffered) if there is still data
// TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
@@ -196,8 +169,7 @@ void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint *ep)
// Set endpoint control double buffered bit if needed
ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER;
- }else
- {
+ } else {
// Single buffered since 1 is enough
ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
@@ -212,35 +184,28 @@ void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint *ep)
_hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
}
-void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
-{
+void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t total_len) {
hw_endpoint_lock_update(ep, 1);
- if ( ep->active )
- {
+ if (ep->active) {
// TODO: Is this acceptable for interrupt packets?
- TU_LOG(1, "WARN: starting new transfer on already active ep %d %s\r\n", tu_edpt_number(ep->ep_addr),
- ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
-
+ TU_LOG(1, "WARN: starting new transfer on already active ep %02X\r\n", ep->ep_addr);
hw_endpoint_reset_transfer(ep);
}
// Fill in info now that we're kicking off the hw
ep->remaining_len = total_len;
- ep->xferred_len = 0;
- ep->active = true;
- ep->user_buf = buffer;
+ ep->xferred_len = 0;
+ ep->active = true;
+ ep->user_buf = buffer;
- if ( e15_is_bulkin_ep(ep) )
- {
+ if (e15_is_bulkin_ep(ep)) {
usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
}
- if ( e15_is_critical_frame_period(ep) )
- {
+ if (e15_is_critical_frame_period(ep)) {
ep->pending = 1;
- } else
- {
+ } else {
hw_endpoint_start_next_buffer(ep);
}
@@ -248,34 +213,30 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to
}
// sync endpoint buffer and return transferred bytes
-static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id)
-{
+static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uint8_t buf_id) {
uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
- if (buf_id) buf_ctrl = buf_ctrl >> 16;
+ if (buf_id) buf_ctrl = buf_ctrl >> 16;
uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
- if ( !ep->rx )
- {
+ if (!ep->rx) {
// We are continuing a transfer here. If we are TX, we have successfully
// sent some data can increase the length we have sent
assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
- ep->xferred_len = (uint16_t)(ep->xferred_len + xferred_bytes);
- }else
- {
+ ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
+ } else {
// If we have received some data, so can increase the length
// we have received AFTER we have copied it to the user buffer at the appropriate offset
assert(buf_ctrl & USB_BUF_CTRL_FULL);
- memcpy(ep->user_buf, ep->hw_data_buf + buf_id*64, xferred_bytes);
- ep->xferred_len = (uint16_t)(ep->xferred_len + xferred_bytes);
+ memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes);
+ ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
ep->user_buf += xferred_bytes;
}
// Short packet
- if (xferred_bytes < ep->wMaxPacketSize)
- {
+ if (xferred_bytes < ep->wMaxPacketSize) {
pico_trace(" Short packet on buffer %d with %u bytes\r\n", buf_id, xferred_bytes);
// Reduce total length as this is last packet
ep->remaining_len = 0;
@@ -284,8 +245,7 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint *ep, uin
return xferred_bytes;
}
-static void __tusb_irq_path_func(_hw_endpoint_xfer_sync) (struct hw_endpoint *ep)
-{
+static void __tusb_irq_path_func(_hw_endpoint_xfer_sync)(struct hw_endpoint* ep) {
// Update hw endpoint struct with info from hardware
// after a buff status interrupt
@@ -296,14 +256,11 @@ static void __tusb_irq_path_func(_hw_endpoint_xfer_sync) (struct hw_endpoint *ep
uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
// sync buffer 1 if double buffered
- if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS )
- {
- if (buf0_bytes == ep->wMaxPacketSize)
- {
+ if ((*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS) {
+ if (buf0_bytes == ep->wMaxPacketSize) {
// sync buffer 1 if not short packet
sync_ep_buffer(ep, 1);
- }else
- {
+ } else {
// short packet on buffer 0
// TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example
// At this time (currently trigger per 2 buffer), the buffer1 is probably filled with data from
@@ -335,14 +292,12 @@ static void __tusb_irq_path_func(_hw_endpoint_xfer_sync) (struct hw_endpoint *ep
}
// Returns true if transfer is complete
-bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
-{
+bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
hw_endpoint_lock_update(ep, 1);
// 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[tu_edpt_dir(ep->ep_addr)]);
+ if (!ep->active) {
+ panic("Can't continue xfer on inactive ep %02X", ep->ep_addr);
}
// Update EP struct from hardware state
@@ -350,21 +305,15 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
// Now we have synced our state with the hardware. Is there more data to transfer?
// If we are done then notify tinyusb
- if (ep->remaining_len == 0)
- {
- pico_trace("Completed transfer of %d bytes on ep %d %s\r\n",
- ep->xferred_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
+ if (ep->remaining_len == 0) {
+ pico_trace("Completed transfer of %d bytes on ep %02X\r\n", ep->xferred_len, ep->ep_addr);
// Notify caller we are done so it can notify the tinyusb stack
hw_endpoint_lock_update(ep, -1);
return true;
- }
- else
- {
- if ( e15_is_critical_frame_period(ep) )
- {
+ } else {
+ if (e15_is_critical_frame_period(ep)) {
ep->pending = 1;
- } else
- {
+ } else {
hw_endpoint_start_next_buffer(ep);
}
}
@@ -399,16 +348,14 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
volatile uint32_t e15_last_sof = 0;
// check if Errata 15 is needed for this endpoint i.e device bulk-in
-static bool __tusb_irq_path_func(e15_is_bulkin_ep) (struct hw_endpoint *ep)
-{
+static bool __tusb_irq_path_func(e15_is_bulkin_ep)(struct hw_endpoint* ep) {
return (!is_host_mode() && tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN &&
ep->transfer_type == TUSB_XFER_BULK);
}
// check if we need to apply Errata 15 workaround : i.e
// Endpoint is BULK IN and is currently in critical frame period i.e 20% of last usb frame
-static bool __tusb_irq_path_func(e15_is_critical_frame_period) (struct hw_endpoint *ep)
-{
+static bool __tusb_irq_path_func(e15_is_critical_frame_period)(struct hw_endpoint* ep) {
TU_VERIFY(e15_is_bulkin_ep(ep));
/* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point.
@@ -419,11 +366,10 @@ static bool __tusb_irq_path_func(e15_is_critical_frame_period) (struct hw_endpoi
if (delta < 800 || delta > 998) {
return false;
}
- TU_LOG(3, "Avoiding sof %lu now %lu last %lu\r\n", (usb_hw->sof_rd + 1) & USB_SOF_RD_BITS, time_us_32(), e15_last_sof);
+ TU_LOG(3, "Avoiding sof %lu now %lu last %lu\r\n", (usb_hw->sof_rd + 1) & USB_SOF_RD_BITS, time_us_32(),
+ e15_last_sof);
return true;
}
-#endif
-
-
+#endif // TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
#endif
diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c
index 24edc30e7..50400d1f5 100644
--- a/src/portable/renesas/rusb2/dcd_rusb2.c
+++ b/src/portable/renesas/rusb2/dcd_rusb2.c
@@ -57,29 +57,22 @@
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM
//--------------------------------------------------------------------+
+enum {
+ PIPE_COUNT = 10,
+};
-/* Start of definition of packed structs (used by the CCRX toolchain) */
-TU_ATTR_PACKED_BEGIN
-TU_ATTR_BIT_FIELD_ORDER_BEGIN
-
-typedef struct TU_ATTR_PACKED
-{
+typedef struct {
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 */
- struct {
- uint32_t ep : 8; /* an assigned endpoint address */
- uint32_t ff : 1; /* `buf` is TU_FUFO or POD */
- uint32_t : 0;
- };
-} pipe_state_t;
-TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain)
-TU_ATTR_BIT_FIELD_ORDER_END
+ uint8_t ep; /* an assigned endpoint address */
+ uint8_t ff; /* `buf` is TU_FUFO or POD */
+} pipe_state_t;
typedef struct
{
- pipe_state_t pipe[10];
+ pipe_state_t pipe[PIPE_COUNT];
uint8_t ep[2][16]; /* a lookup table for a pipe index from an endpoint address */
} dcd_data_t;
@@ -89,52 +82,44 @@ static dcd_data_t _dcd;
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-// Transfer conditions specifiable for each pipe:
-// - Pipe 0: Control transfer with 64-byte single buffer
-// - Pipes 1 and 2: Bulk isochronous transfer continuous transfer mode with programmable buffer size up
-// to 2 KB and optional double buffer
-// - Pipes 3 to 5: Bulk transfer continuous transfer mode with programmable buffer size up to 2 KB and
-// optional double buffer
-// - Pipes 6 to 9: Interrupt transfer with 64-byte single buffer
-enum {
- PIPE_1ST_BULK = 3,
- PIPE_1ST_INTERRUPT = 6,
- PIPE_COUNT = 10,
-};
-static unsigned find_pipe(unsigned xfer)
-{
- switch (xfer) {
- case TUSB_XFER_ISOCHRONOUS:
- for (int i = 1; i < PIPE_1ST_BULK; ++i) {
- if (0 == _dcd.pipe[i].ep) return i;
- }
- break;
-
- case TUSB_XFER_BULK:
- for (int i = PIPE_1ST_BULK; i < PIPE_1ST_INTERRUPT; ++i) {
- if (0 == _dcd.pipe[i].ep) return i;
- }
- for (int i = 1; i < PIPE_1ST_BULK; ++i) {
- if (0 == _dcd.pipe[i].ep) return i;
- }
- break;
+// Transfer conditions specifiable for each pipe for most MCUs
+// - Pipe 0: Control transfer with 64-byte single buffer
+// - Pipes 1 and 2: Bulk or ISO
+// - Pipes 3 to 5: Bulk
+// - Pipes 6 to 9: Interrupt
+//
+// Note: for small mcu such as
+// - RA2A1: only pipe 4-7 are available, and no support for ISO
+static unsigned find_pipe(unsigned xfer_type) {
+ #if defined(BSP_MCU_GROUP_RA2A1)
+ const uint8_t pipe_idx_arr[4][2] = {
+ { 0, 0 }, // Control
+ { 0, 0 }, // Isochronous not supported
+ { 4, 5 }, // Bulk
+ { 6, 7 }, // Interrupt
+ };
+ #else
+ const uint8_t pipe_idx_arr[4][2] = {
+ { 0, 0 }, // Control
+ { 1, 2 }, // Isochronous
+ { 1, 5 }, // Bulk
+ { 6, 9 }, // Interrupt
+ };
+ #endif
- case TUSB_XFER_INTERRUPT:
- for (int i = PIPE_1ST_INTERRUPT; i < PIPE_COUNT; ++i) {
- if (0 == _dcd.pipe[i].ep) return i;
- }
- break;
+ // find backward since only pipe 1, 2 support ISO
+ const uint8_t idx_first = pipe_idx_arr[xfer_type][0];
+ const uint8_t idx_last = pipe_idx_arr[xfer_type][1];
- default:
- /* No support for control transfer */
- break;
+ for (int i = idx_last; i >= idx_first; i--) {
+ if (0 == _dcd.pipe[i].ep) return i;
}
+
return 0;
}
-static volatile uint16_t* get_pipectr(rusb2_reg_t *rusb, unsigned num)
-{
+static volatile uint16_t* get_pipectr(rusb2_reg_t *rusb, unsigned num) {
if (num) {
return (volatile uint16_t*)&(rusb->PIPE_CTR[num - 1]);
} else {
@@ -142,8 +127,7 @@ static volatile uint16_t* get_pipectr(rusb2_reg_t *rusb, unsigned num)
}
}
-static volatile reg_pipetre_t* get_pipetre(rusb2_reg_t *rusb, unsigned num)
-{
+static volatile reg_pipetre_t* get_pipetre(rusb2_reg_t *rusb, unsigned num) {
volatile reg_pipetre_t* tre = NULL;
if ((1 <= num) && (num <= 5)) {
tre = (volatile reg_pipetre_t*)&(rusb->PIPE_TR[num - 1].E);
@@ -151,8 +135,7 @@ static volatile reg_pipetre_t* get_pipetre(rusb2_reg_t *rusb, unsigned num)
return tre;
}
-static volatile uint16_t* ep_addr_to_pipectr(uint8_t rhport, unsigned ep_addr)
-{
+static volatile uint16_t* ep_addr_to_pipectr(uint8_t rhport, unsigned ep_addr) {
rusb2_reg_t *rusb = RUSB2_REG(rhport);
const unsigned epn = tu_edpt_number(ep_addr);
@@ -165,19 +148,16 @@ static volatile uint16_t* ep_addr_to_pipectr(uint8_t rhport, unsigned ep_addr)
}
}
-static uint16_t edpt0_max_packet_size(rusb2_reg_t* rusb)
-{
+static uint16_t edpt0_max_packet_size(rusb2_reg_t* rusb) {
return rusb->DCPMAXP_b.MXPS;
}
-static uint16_t edpt_max_packet_size(rusb2_reg_t *rusb, unsigned num)
-{
+static uint16_t edpt_max_packet_size(rusb2_reg_t *rusb, unsigned num) {
rusb->PIPESEL = num;
return rusb->PIPEMAXP;
}
-static inline void pipe_wait_for_ready(rusb2_reg_t * rusb, unsigned num)
-{
+static inline void pipe_wait_for_ready(rusb2_reg_t * rusb, unsigned num) {
while ( rusb->D0FIFOSEL_b.CURPIPE != num ) {}
while ( !rusb->D0FIFOCTR_b.FRDY ) {}
}
@@ -266,14 +246,6 @@ static void pipe_read_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void
tu_fifo_advance_write_pointer(f, count);
}
-
-static bool wait_pipe_fifo_empty(rusb2_reg_t* rusb, uint8_t num) {
- TU_ASSERT(num);
- while( (rusb->PIPE_CTR[num-1] & RUSB2_PIPE_CTR_INBUFM_Msk) > 0 ) {}
- return true;
-}
-
-
//--------------------------------------------------------------------+
// Pipe Transfer
//--------------------------------------------------------------------+
@@ -347,7 +319,6 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
const unsigned rem = pipe->remaining;
if (!rem) {
- wait_pipe_fifo_empty(rusb, num);
pipe->buf = NULL;
return true;
}
@@ -844,7 +815,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
}
rusb->PIPECFG = cfg;
- rusb->BRDYSTS = 0x1FFu ^ TU_BIT(num);
+ rusb->BRDYSTS = 0x3FFu ^ TU_BIT(num);
rusb->BRDYENB |= TU_BIT(num);
if (dir || (xfer != TUSB_XFER_BULK)) {
@@ -944,6 +915,18 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
//--------------------------------------------------------------------+
// ISR
//--------------------------------------------------------------------+
+
+#if defined(__CCRX__)
+TU_ATTR_ALWAYS_INLINE static inline unsigned __builtin_ctz(unsigned int value) {
+ unsigned int count = 0;
+ while ((value & 1) == 0) {
+ value >>= 1;
+ count++;
+ }
+ return count;
+}
+#endif
+
void dcd_int_handler(uint8_t rhport)
{
rusb2_reg_t* rusb = RUSB2_REG(rhport);
@@ -1035,17 +1018,7 @@ void dcd_int_handler(uint8_t rhport)
/* clear active bits (don't write 0 to already cleared bits according to the HW manual) */
rusb->BRDYSTS = ~s;
while (s) {
-#if defined(__CCRX__)
- static const int Mod37BitPosition[] = {
- -1, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
- 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5,
- 20, 8, 19, 18
- };
-
- const unsigned num = Mod37BitPosition[(-s & s) % 37];
-#else
const unsigned num = __builtin_ctz(s);
-#endif
process_pipe_brdy(rhport, num);
s &= ~TU_BIT(num);
}
diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c
index bf95be707..f140da690 100644
--- a/src/portable/renesas/rusb2/hcd_rusb2.c
+++ b/src/portable/renesas/rusb2/hcd_rusb2.c
@@ -45,6 +45,9 @@
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
+enum {
+ PIPE_COUNT = 10,
+};
TU_ATTR_PACKED_BEGIN
TU_ATTR_BIT_FIELD_ORDER_BEGIN
@@ -75,7 +78,7 @@ TU_ATTR_BIT_FIELD_ORDER_END
typedef struct
{
bool need_reset; /* The device has not been reset after connection. */
- pipe_state_t pipe[10];
+ pipe_state_t pipe[PIPE_COUNT];
uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
} hcd_data_t;
@@ -86,46 +89,30 @@ typedef struct
static hcd_data_t _hcd;
// TODO merged with DCD
-// Transfer conditions specifiable for each pipe:
+// Transfer conditions specifiable for each pipe for most MCUs
// - Pipe 0: Control transfer with 64-byte single buffer
-// - Pipes 1 and 2: Bulk isochronous transfer continuous transfer mode with programmable buffer size up
-// to 2 KB and optional double buffer
-// - Pipes 3 to 5: Bulk transfer continuous transfer mode with programmable buffer size up to 2 KB and
-// optional double buffer
-// - Pipes 6 to 9: Interrupt transfer with 64-byte single buffer
-enum {
- PIPE_1ST_BULK = 3,
- PIPE_1ST_INTERRUPT = 6,
- PIPE_COUNT = 10,
-};
-
-static unsigned find_pipe(unsigned xfer) {
- switch ( xfer ) {
- case TUSB_XFER_ISOCHRONOUS:
- for (int i = 1; i < PIPE_1ST_BULK; ++i) {
- if ( 0 == _hcd.pipe[i].ep ) return i;
- }
- break;
-
- case TUSB_XFER_BULK:
- for (int i = PIPE_1ST_BULK; i < PIPE_1ST_INTERRUPT; ++i) {
- if ( 0 == _hcd.pipe[i].ep ) return i;
- }
- for (int i = 1; i < PIPE_1ST_BULK; ++i) {
- if ( 0 == _hcd.pipe[i].ep ) return i;
- }
- break;
+// - Pipes 1 and 2: Bulk or ISO
+// - Pipes 3 to 5: Bulk
+// - Pipes 6 to 9: Interrupt
+//
+// Note: for small mcu such as
+// - RA2A1: only pipe 4-7 are available, and no support for ISO
+static unsigned find_pipe(unsigned xfer_type) {
+ const uint8_t pipe_idx_arr[4][2] = {
+ { 0, 0 }, // Control
+ { 1, 2 }, // Isochronous
+ { 1, 5 }, // Bulk
+ { 6, 9 }, // Interrupt
+ };
- case TUSB_XFER_INTERRUPT:
- for (int i = PIPE_1ST_INTERRUPT; i < PIPE_COUNT; ++i) {
- if ( 0 == _hcd.pipe[i].ep ) return i;
- }
- break;
+ // find backward since only pipe 1, 2 support ISO
+ const uint8_t idx_first = pipe_idx_arr[xfer_type][0];
+ const uint8_t idx_last = pipe_idx_arr[xfer_type][1];
- default:
- /* No support for control transfer */
- break;
+ for (int i = idx_last; i >= idx_first; i--) {
+ if (0 == _hcd.pipe[i].ep) return i;
}
+
return 0;
}
@@ -718,7 +705,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
}
rusb->PIPECFG = cfg;
- rusb->BRDYSTS = 0x1FFu ^ TU_BIT(num);
+ rusb->BRDYSTS = 0x3FFu ^ TU_BIT(num);
rusb->NRDYENB |= TU_BIT(num);
rusb->BRDYENB |= TU_BIT(num);
@@ -771,6 +758,17 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
//--------------------------------------------------------------------+
// ISR
//--------------------------------------------------------------------+
+#if defined(__CCRX__)
+TU_ATTR_ALWAYS_INLINE static inline unsigned __builtin_ctz(unsigned int value) {
+ unsigned int count = 0;
+ while ((value & 1) == 0) {
+ value >>= 1;
+ count++;
+ }
+ return count;
+}
+#endif
+
void hcd_int_handler(uint8_t rhport, bool in_isr) {
(void) in_isr;
@@ -820,23 +818,12 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
}
}
-#if defined(__CCRX__)
- static const int Mod37BitPosition[] = {
- -1, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
- 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5,
- 20, 8, 19, 18};
-#endif
-
if (is0 & RUSB2_INTSTS0_NRDY_Msk) {
const unsigned m = rusb->NRDYENB;
unsigned s = rusb->NRDYSTS & m;
rusb->NRDYSTS = ~s;
while (s) {
-#if defined(__CCRX__)
- const unsigned num = Mod37BitPosition[(-s & s) % 37];
-#else
const unsigned num = __builtin_ctz(s);
-#endif
process_pipe_nrdy(rhport, num);
s &= ~TU_BIT(num);
}
@@ -847,11 +834,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
/* clear active bits (don't write 0 to already cleared bits according to the HW manual) */
rusb->BRDYSTS = ~s;
while (s) {
-#if defined(__CCRX__)
- const unsigned num = Mod37BitPosition[(-s & s) % 37];
-#else
const unsigned num = __builtin_ctz(s);
-#endif
process_pipe_brdy(rhport, num);
s &= ~TU_BIT(num);
}
diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c
index 6677891a5..41814370e 100644
--- a/src/portable/sony/cxd56/dcd_cxd56.c
+++ b/src/portable/sony/cxd56/dcd_cxd56.c
@@ -102,17 +102,25 @@ static int _dcd_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_
usbdev = dev;
usbdcd_driver.ep[0] = dev->ep0;
+ #ifdef EP_ALLOCREQ
+ // SDK v2
usbdcd_driver.req[0] = EP_ALLOCREQ(usbdcd_driver.ep[0]);
- if (usbdcd_driver.req[0] != NULL)
- {
+ if (usbdcd_driver.req[0] != NULL) {
usbdcd_driver.req[0]->len = 64;
usbdcd_driver.req[0]->buf = EP_ALLOCBUFFER(usbdcd_driver.ep[0], 64);
- if (!usbdcd_driver.req[0]->buf)
- {
+ if (!usbdcd_driver.req[0]->buf) {
EP_FREEREQ(usbdcd_driver.ep[0], usbdcd_driver.req[0]);
usbdcd_driver.req[0] = NULL;
+ return ENOMEM;
}
}
+ #else
+ // SDK v3
+ usbdcd_driver.req[0] = usbdev_allocreq(usbdcd_driver.ep[0], 64);
+ if (usbdcd_driver.req[0] == NULL) {
+ return ENOMEM;
+ }
+ #endif
usbdcd_driver.req[0]->callback = usbdcd_ep0incomplete;
@@ -295,13 +303,19 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
}
usbdcd_driver.req[epnum] = NULL;
+
+ #ifdef EP_ALLOCREQ
+ // sdk v2
usbdcd_driver.req[epnum] = EP_ALLOCREQ(usbdcd_driver.ep[epnum]);
- if (usbdcd_driver.req[epnum] != NULL)
- {
+ if (usbdcd_driver.req[epnum] != NULL) {
usbdcd_driver.req[epnum]->len = ep_mps;
}
- else
- {
+ #else
+ // sdk v3
+ usbdcd_driver.req[epnum] = usbdev_allocreq(usbdcd_driver.ep[epnum], ep_mps);
+ #endif
+
+ if(usbdcd_driver.req[epnum] == NULL) {
return false;
}
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 9c37f1f98..a26c66892 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -107,9 +107,9 @@
#include "device/dcd.h"
#ifdef TUP_USBIP_FSDEV_STM32
- // Undefine to reduce the dependence on HAL
- #undef USE_HAL_DRIVER
- #include "portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h"
+// Undefine to reduce the dependence on HAL
+#undef USE_HAL_DRIVER
+#include "portable/st/stm32_fsdev/dcd_stm32_fsdev.h"
#endif
/*****************************************************
@@ -119,17 +119,17 @@
// HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM
// (8u here would mean 8 IN and 8 OUT)
#ifndef MAX_EP_COUNT
-# define MAX_EP_COUNT 8U
+#define MAX_EP_COUNT 8U
#endif
// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it
// Both of these MUST be a multiple of 2, and are in byte units.
#ifndef DCD_STM32_BTABLE_BASE
-# define DCD_STM32_BTABLE_BASE 0U
+#define DCD_STM32_BTABLE_BASE 0U
#endif
#ifndef DCD_STM32_BTABLE_SIZE
-# define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE)
+#define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE)
#endif
/***************************************************
@@ -145,21 +145,18 @@ TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligne
//--------------------------------------------------------------------+
// One of these for every EP IN & OUT, uses a bit of RAM....
-typedef struct
-{
- uint8_t * buffer;
- tu_fifo_t * ff;
+typedef struct {
+ uint8_t *buffer;
+ tu_fifo_t *ff;
uint16_t total_len;
uint16_t queued_len;
- uint16_t pma_ptr;
uint16_t max_packet_size;
- uint16_t pma_alloc_size;
- uint8_t ep_idx; // index for USB_EPnR register
+ uint8_t ep_idx; // index for USB_EPnR register
+ bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask
} xfer_ctl_t;
// EP allocator
-typedef struct
-{
+typedef struct {
uint8_t ep_num;
uint8_t ep_type;
bool allocated[2];
@@ -179,28 +176,25 @@ static uint8_t remoteWakeCountdown; // When wake is requested
// into the stack.
static void dcd_handle_bus_reset(void);
-static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix);
+static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix);
+static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr);
static void dcd_ep_ctr_handler(void);
// PMA allocation/access
-static uint8_t open_ep_count;
static uint16_t ep_buf_ptr; ///< Points to first free memory location
-static void dcd_pma_alloc_reset(void);
-static uint16_t dcd_pma_alloc(uint8_t ep_addr, uint16_t length);
-static void dcd_pma_free(uint8_t ep_addr);
-static void dcd_ep_free(uint8_t ep_addr);
+static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf);
static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type);
static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes);
static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes);
-static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes);
-static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes);
+static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes);
+static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes);
//--------------------------------------------------------------------+
// Inline helper
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr)
+TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint32_t ep_addr)
{
uint8_t epnum = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr);
@@ -214,7 +208,7 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr)
// Controller API
//--------------------------------------------------------------------+
-void dcd_init (uint8_t rhport)
+void dcd_init(uint8_t rhport)
{
/* Clocks should already be enabled */
/* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */
@@ -222,43 +216,41 @@ void dcd_init (uint8_t rhport)
/* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL.
* Here, the RM is followed. */
- for(uint32_t i = 0; i<200; i++) // should be a few us
- {
+ for (uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
// Perform USB peripheral reset
USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
- for(uint32_t i = 0; i<200; i++) // should be a few us
- {
+ for (uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
USB->CNTR &= ~USB_CNTR_PDWN;
// Wait startup time, for F042 and F070, this is <= 1 us.
- for(uint32_t i = 0; i<200; i++) // should be a few us
- {
+ for (uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
USB->CNTR = 0; // Enable USB
-#if !defined(STM32G0) && !defined(STM32H5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address
+#if !defined(STM32G0) && !defined(STM32H5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address
USB->BTABLE = DCD_STM32_BTABLE_BASE;
#endif
USB->ISTR = 0; // Clear pending interrupts
// Reset endpoints to disabled
- for(uint32_t i=0; i<STFSDEV_EP_COUNT; i++)
- {
+ for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) {
// This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED.
- pcd_set_endpoint(USB,i,0u);
+ pcd_set_endpoint(USB, i, 0u);
}
USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
dcd_handle_bus_reset();
// Enable pull-up if supported
- if ( dcd_connect ) dcd_connect(rhport);
+ if (dcd_connect) {
+ dcd_connect(rhport);
+ }
}
// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU.
@@ -267,14 +259,14 @@ void dcd_init (uint8_t rhport)
// Disable internal D+ PU
void dcd_disconnect(uint8_t rhport)
{
- (void) rhport;
+ (void)rhport;
USB->BCDR &= ~(USB_BCDR_DPPU);
}
// Enable internal D+ PU
void dcd_connect(uint8_t rhport)
{
- (void) rhport;
+ (void)rhport;
USB->BCDR |= USB_BCDR_DPPU;
}
@@ -282,60 +274,54 @@ void dcd_connect(uint8_t rhport)
// Disable internal D+ PU
void dcd_disconnect(uint8_t rhport)
{
- (void) rhport;
+ (void)rhport;
SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU);
}
// Enable internal D+ PU
void dcd_connect(uint8_t rhport)
{
- (void) rhport;
+ (void)rhport;
SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
}
#endif
void dcd_sof_enable(uint8_t rhport, bool en)
{
- (void) rhport;
- (void) en;
+ (void)rhport;
+ (void)en;
- if (en)
- {
+ if (en) {
USB->CNTR |= USB_CNTR_SOFM;
- }
- else
- {
+ } else {
USB->CNTR &= ~USB_CNTR_SOFM;
}
}
// Enable device interrupt
-void dcd_int_enable (uint8_t rhport)
+void dcd_int_enable(uint8_t rhport)
{
(void)rhport;
// Member here forces write to RAM before allowing ISR to execute
__DSB();
__ISB();
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \
- CFG_TUSB_MCU == OPT_MCU_STM32L4
+#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4
NVIC_EnableIRQ(USB_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
NVIC_EnableIRQ(USB_LP_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
- // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
- // shared USB/CAN IRQs to separate CAN and USB IRQs.
- // This dynamically checks if this remap is active to enable the right IRQs.
- #ifdef SYSCFG_CFGR1_USB_IT_RMP
- if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP)
- {
+// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+// shared USB/CAN IRQs to separate CAN and USB IRQs.
+// This dynamically checks if this remap is active to enable the right IRQs.
+#ifdef SYSCFG_CFGR1_USB_IT_RMP
+ if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
NVIC_EnableIRQ(USB_HP_IRQn);
NVIC_EnableIRQ(USB_LP_IRQn);
NVIC_EnableIRQ(USBWakeUp_RMP_IRQn);
- }
- else
- #endif
+ } else
+#endif
{
NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn);
NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn);
@@ -352,14 +338,14 @@ void dcd_int_enable (uint8_t rhport)
NVIC_EnableIRQ(USBWakeUp_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
- #ifdef STM32G0B0xx
- NVIC_EnableIRQ(USB_IRQn);
- #else
- NVIC_EnableIRQ(USB_UCPD1_2_IRQn);
- #endif
+#ifdef STM32G0B0xx
+ NVIC_EnableIRQ(USB_IRQn);
+#else
+ NVIC_EnableIRQ(USB_UCPD1_2_IRQn);
+#endif
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
- NVIC_EnableIRQ(USB_DRD_FS_IRQn);
+ NVIC_EnableIRQ(USB_DRD_FS_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
NVIC_EnableIRQ(USB_HP_IRQn);
@@ -369,7 +355,7 @@ void dcd_int_enable (uint8_t rhport)
NVIC_EnableIRQ(USB_FS_IRQn);
#else
- #error Unknown arch in USB driver
+#error Unknown arch in USB driver
#endif
}
@@ -378,24 +364,21 @@ void dcd_int_disable(uint8_t rhport)
{
(void)rhport;
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || \
- CFG_TUSB_MCU == OPT_MCU_STM32L4
+#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4
NVIC_DisableIRQ(USB_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
NVIC_DisableIRQ(USB_LP_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
- // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
- // shared USB/CAN IRQs to separate CAN and USB IRQs.
- // This dynamically checks if this remap is active to disable the right IRQs.
- #ifdef SYSCFG_CFGR1_USB_IT_RMP
- if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP)
- {
+// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+// shared USB/CAN IRQs to separate CAN and USB IRQs.
+// This dynamically checks if this remap is active to disable the right IRQs.
+#ifdef SYSCFG_CFGR1_USB_IT_RMP
+ if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
NVIC_DisableIRQ(USB_HP_IRQn);
NVIC_DisableIRQ(USB_LP_IRQn);
NVIC_DisableIRQ(USBWakeUp_RMP_IRQn);
- }
- else
- #endif
+ } else
+#endif
{
NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn);
NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
@@ -412,14 +395,14 @@ void dcd_int_disable(uint8_t rhport)
NVIC_DisableIRQ(USBWakeUp_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
- #ifdef STM32G0B0xx
- NVIC_DisableIRQ(USB_IRQn);
- #else
- NVIC_DisableIRQ(USB_UCPD1_2_IRQn);
- #endif
+#ifdef STM32G0B0xx
+ NVIC_DisableIRQ(USB_IRQn);
+#else
+ NVIC_DisableIRQ(USB_UCPD1_2_IRQn);
+#endif
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
- NVIC_DisableIRQ(USB_DRD_FS_IRQn);
+ NVIC_DisableIRQ(USB_DRD_FS_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
NVIC_DisableIRQ(USB_HP_IRQn);
@@ -429,7 +412,7 @@ void dcd_int_disable(uint8_t rhport)
NVIC_DisableIRQ(USB_FS_IRQn);
#else
- #error Unknown arch in USB driver
+#error Unknown arch in USB driver
#endif
// CMSIS has a membar after disabling interrupts
@@ -438,8 +421,8 @@ void dcd_int_disable(uint8_t rhport)
// Receive Set Address request, mcu port must also include status IN response
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
- (void) rhport;
- (void) dev_addr;
+ (void)rhport;
+ (void)dev_addr;
// Respond with status
dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK | 0x00, NULL, 0);
@@ -450,44 +433,35 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
void dcd_remote_wakeup(uint8_t rhport)
{
- (void) rhport;
+ (void)rhport;
USB->CNTR |= USB_CNTR_RESUME;
remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms.
}
-static const tusb_desc_endpoint_t ep0OUT_desc =
-{
- .bLength = sizeof(tusb_desc_endpoint_t),
- .bDescriptorType = TUSB_DESC_ENDPOINT,
-
- .bEndpointAddress = 0x00,
- .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
- .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
- .bInterval = 0
+static const tusb_desc_endpoint_t ep0OUT_desc = {
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+ .bEndpointAddress = 0x00,
+ .bmAttributes = {.xfer = TUSB_XFER_CONTROL},
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
};
-static const tusb_desc_endpoint_t ep0IN_desc =
-{
- .bLength = sizeof(tusb_desc_endpoint_t),
- .bDescriptorType = TUSB_DESC_ENDPOINT,
-
- .bEndpointAddress = 0x80,
- .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
- .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
- .bInterval = 0
+static const tusb_desc_endpoint_t ep0IN_desc = {
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+ .bEndpointAddress = 0x80,
+ .bmAttributes = {.xfer = TUSB_XFER_CONTROL},
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
};
static void dcd_handle_bus_reset(void)
{
- //__IO uint16_t * const epreg = &(EPREG(0));
USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag
- for(uint32_t i=0; i<STFSDEV_EP_COUNT; i++)
- {
- // Clear all EPREG (or maybe this is automatic? I'm not sure)
- pcd_set_endpoint(USB,i,0u);
-
+ for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) {
// Clear EP allocation status
ep_alloc_status[i].ep_num = 0xFF;
ep_alloc_status[i].ep_type = 0xFF;
@@ -495,9 +469,11 @@ static void dcd_handle_bus_reset(void)
ep_alloc_status[i].allocated[1] = false;
}
- dcd_pma_alloc_reset();
- dcd_edpt_open (0, &ep0OUT_desc);
- dcd_edpt_open (0, &ep0IN_desc);
+ // Reset PMA allocation
+ ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT;
+
+ dcd_edpt_open(0, &ep0OUT_desc);
+ dcd_edpt_open(0, &ep0IN_desc);
USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero.
}
@@ -513,30 +489,63 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
// Verify the CTR_TX bit is set. This was in the ST Micro code,
// but I'm not sure it's actually necessary?
- if((wEPRegVal & USB_EP_CTR_TX) == 0U)
- {
+ if ((wEPRegVal & USB_EP_CTR_TX) == 0U) {
return;
}
/* clear int flag */
pcd_clear_tx_ep_ctr(USB, EPindex);
- xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr);
- if((xfer->total_len != xfer->queued_len)) /* TX not complete */
- {
- dcd_transmit_packet(xfer, EPindex);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
+
+ if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) {
+ // Ignore spurious interrupts that we don't schedule
+ // host can send IN token while there is no data to send, since ISO does not have NAK
+ // this will result to zero length packet --> trigger interrupt (which cannot be masked)
+ if (!xfer->iso_in_sending) {
+ return;
+ }
+ xfer->iso_in_sending = false;
+
+ if (wEPRegVal & USB_EP_DTOG_TX) {
+ pcd_set_ep_tx_dbuf0_cnt(USB, EPindex, 0);
+ } else {
+ pcd_set_ep_tx_dbuf1_cnt(USB, EPindex, 0);
+ }
}
- else /* TX Complete */
- {
+
+ if ((xfer->total_len != xfer->queued_len)) {
+ dcd_transmit_packet(xfer, EPindex);
+ } else {
dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
}
// Handle CTR interrupt for the RX/OUT direction
-//
// Upon call, (wIstr & USB_ISTR_DIR) == 0U
static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
{
+#ifdef FSDEV_BUS_32BIT
+ /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
+ * From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers
+ * Description:
+ * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
+ * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
+ * Workaround:
+ * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
+ * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
+ * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
+ * also takes time, so we'll wait 60 cycles (count = 20).
+ * - Since Low Speed mode is not supported/popular, we will ignore it for now.
+ *
+ * Note: this errata also seems to apply to G0, U5, H5 etc.
+ */
+ volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
+ while (cycle_count > 0U) {
+ cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
+ }
+#endif
+
uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD;
@@ -545,96 +554,83 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
// Verify the CTR_RX bit is set. This was in the ST Micro code,
// but I'm not sure it's actually necessary?
- if((wEPRegVal & USB_EP_CTR_RX) == 0U)
- {
+ if ((wEPRegVal & USB_EP_CTR_RX) == 0U) {
return;
}
- if((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */
- {
+ if ((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) {
+ /* Setup packet */
uint32_t count = pcd_get_ep_rx_cnt(USB, EPindex);
- /* Get SETUP Packet*/
- if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again.
- {
+ // Setup packet should always be 8 bytes. If not, ignore it, and try again.
+ if (count == 8) {
// Must reset EP to NAK (in case it had been stalling) (though, maybe too late here)
- pcd_set_ep_rx_status(USB,0u,USB_EP_RX_NAK);
- pcd_set_ep_tx_status(USB,0u,USB_EP_TX_NAK);
+ pcd_set_ep_rx_status(USB, 0u, USB_EP_RX_NAK);
+ pcd_set_ep_tx_status(USB, 0u, USB_EP_TX_NAK);
#ifdef FSDEV_BUS_32BIT
- dcd_event_setup_received(0, (uint8_t*)(USB_PMAADDR + pcd_get_ep_rx_address(USB, EPindex)), true);
+ dcd_event_setup_received(0, (uint8_t *)(USB_PMAADDR + pcd_get_ep_rx_address(USB, EPindex)), true);
#else
// The setup_received function uses memcpy, so this must first copy the setup data into
// user memory, to allow for the 32-bit access that memcpy performs.
uint8_t userMemBuf[8];
- dcd_read_packet_memory(userMemBuf, pcd_get_ep_rx_address(USB,EPindex), 8);
- dcd_event_setup_received(0, (uint8_t*)userMemBuf, true);
+ dcd_read_packet_memory(userMemBuf, pcd_get_ep_rx_address(USB, EPindex), 8);
+ dcd_event_setup_received(0, (uint8_t *)userMemBuf, true);
#endif
}
- }
- else
- {
+ } else {
+ // Clear RX CTR interrupt flag
+ if (ep_addr != 0u) {
+ pcd_clear_rx_ep_ctr(USB, EPindex);
+ }
+
uint32_t count;
+ uint16_t addr;
/* Read from correct register when ISOCHRONOUS (double buffered) */
- if ( (wEPRegVal & USB_EP_DTOG_RX) && ( (wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) {
- count = pcd_get_ep_tx_cnt(USB, EPindex);
+ if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) {
+ if (wEPRegVal & USB_EP_DTOG_RX) {
+ count = pcd_get_ep_dbuf0_cnt(USB, EPindex);
+ addr = pcd_get_ep_dbuf0_address(USB, EPindex);
+ } else {
+ count = pcd_get_ep_dbuf1_cnt(USB, EPindex);
+ addr = pcd_get_ep_dbuf1_address(USB, EPindex);
+ }
} else {
count = pcd_get_ep_rx_cnt(USB, EPindex);
+ addr = pcd_get_ep_rx_address(USB, EPindex);
}
TU_ASSERT(count <= xfer->max_packet_size, /**/);
- // Clear RX CTR interrupt flag
- if(ep_addr != 0u)
- {
- pcd_clear_rx_ep_ctr(USB, EPindex);
- }
-
- if (count != 0U)
- {
- uint16_t addr = pcd_get_ep_rx_address(USB, EPindex);
-
- if (xfer->ff)
- {
+ if (count != 0U) {
+ if (xfer->ff) {
dcd_read_packet_memory_ff(xfer->ff, addr, count);
- }
- else
- {
+ } else {
dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), addr, count);
}
xfer->queued_len = (uint16_t)(xfer->queued_len + count);
}
- if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
- {
- /* RX COMPLETE */
+ if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) {
+ // all bytes received or short packet
dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- // Though the host could still send, we don't know.
- // Does the bulk pipe need to be reset to valid to allow for a ZLP?
- }
- else
- {
- uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len;
- if(remaining >= xfer->max_packet_size) {
- pcd_set_ep_rx_bufsize(USB, EPindex,xfer->max_packet_size);
- } else {
- pcd_set_ep_rx_bufsize(USB, EPindex,remaining);
- }
-
- if (!((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS)) {
- /* Set endpoint active again for receiving more data.
- * Note that isochronous endpoints stay active always */
- pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID);
+ } else {
+ /* Set endpoint active again for receiving more data.
+ * Note that isochronous endpoints stay active always */
+ if ((wEPRegVal & USB_EP_TYPE_MASK) != USB_EP_ISOCHRONOUS) {
+ uint16_t remaining = xfer->total_len - xfer->queued_len;
+ uint16_t cnt = tu_min16(remaining, xfer->max_packet_size);
+ pcd_set_ep_rx_cnt(USB, EPindex, cnt);
}
+ pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID);
}
}
// For EP0, prepare to receive another SETUP packet.
// Clear CTR last so that a new packet does not overwrite the packing being read.
// (Based on the docs, it seems SETUP will always be accepted after CTR is cleared)
- if(ep_addr == 0u)
- {
- // Always be prepared for a status packet...
- pcd_set_ep_rx_bufsize(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
+ if (ep_addr == 0u) {
+ // Always be prepared for a status packet...
+ pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
pcd_clear_rx_ep_ctr(USB, EPindex);
}
}
@@ -644,40 +640,38 @@ static void dcd_ep_ctr_handler(void)
uint32_t wIstr;
/* stay in loop while pending interrupts */
- while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U)
- {
-
- if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */
- {
+ while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) {
+ if ((wIstr & USB_ISTR_DIR) == 0U) {
+ /* TX/IN */
dcd_ep_ctr_tx_handler(wIstr);
- }
- else /* RX/OUT*/
- {
+ } else {
+ /* RX/OUT*/
dcd_ep_ctr_rx_handler(wIstr);
}
}
}
-void dcd_int_handler(uint8_t rhport) {
+void dcd_int_handler(uint8_t rhport)
+{
- (void) rhport;
+ (void)rhport;
uint32_t int_status = USB->ISTR;
- //const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP
- // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF;
- // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ )
+ // const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP
+ // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF;
+ // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ )
// The ST driver loops here on the CTR bit, but that loop has been moved into the
// dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't
// be triggered repeatedly.
/* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */
- if(int_status & USB_ISTR_SOF) {
+ if (int_status & USB_ISTR_SOF) {
USB->ISTR = (fsdev_bus_t)~USB_ISTR_SOF;
dcd_event_sof(0, USB->FNR & USB_FNR_FN, true);
}
- if(int_status & USB_ISTR_RESET) {
+ if (int_status & USB_ISTR_RESET) {
// USBRST is start of reset.
USB->ISTR = (fsdev_bus_t)~USB_ISTR_RESET;
dcd_handle_bus_reset();
@@ -685,15 +679,13 @@ void dcd_int_handler(uint8_t rhport) {
return; // Don't do the rest of the things here; perhaps they've been cleared?
}
- if (int_status & USB_ISTR_CTR)
- {
+ if (int_status & USB_ISTR_CTR) {
/* servicing of the endpoint correct transfer interrupt */
/* clear of the CTR flag into the sub */
dcd_ep_ctr_handler();
}
- if (int_status & USB_ISTR_WKUP)
- {
+ if (int_status & USB_ISTR_WKUP) {
USB->CNTR &= ~USB_CNTR_LPMODE;
USB->CNTR &= ~USB_CNTR_FSUSP;
@@ -701,8 +693,7 @@ void dcd_int_handler(uint8_t rhport) {
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
- if (int_status & USB_ISTR_SUSP)
- {
+ if (int_status & USB_ISTR_SUSP) {
/* Suspend is asserted for both suspend and unplug events. without Vbus monitoring,
* these events cannot be differentiated, so we only trigger suspend. */
@@ -715,13 +706,11 @@ void dcd_int_handler(uint8_t rhport) {
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
}
- if(int_status & USB_ISTR_ESOF) {
- if(remoteWakeCountdown == 1u)
- {
+ if (int_status & USB_ISTR_ESOF) {
+ if (remoteWakeCountdown == 1u) {
USB->CNTR &= ~USB_CNTR_RESUME;
}
- if(remoteWakeCountdown > 0u)
- {
+ if (remoteWakeCountdown > 0u) {
remoteWakeCountdown--;
}
USB->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF;
@@ -734,15 +723,14 @@ void dcd_int_handler(uint8_t rhport) {
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request)
{
- (void) rhport;
+ (void)rhport;
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
- request->bRequest == TUSB_REQ_SET_ADDRESS )
- {
- uint8_t const dev_addr = (uint8_t) request->wValue;
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ uint8_t const dev_addr = (uint8_t)request->wValue;
// Setting new address after the whole request is complete
USB->DADDR &= ~USB_DADDR_ADD;
@@ -750,41 +738,13 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re
}
}
-static void dcd_pma_alloc_reset(void)
-{
- open_ep_count = 0;
- ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each)
- //TU_LOG2("dcd_pma_alloc_reset()\r\n");
- for(uint32_t i=0; i<MAX_EP_COUNT; i++)
- {
- xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_alloc_size = 0U;
- xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U;
- xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U;
- xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U;
- }
-}
-
/***
* Allocate a section of PMA
- *
- * If the EP number has already been allocated, and the new allocation
- * is larger than the old allocation, then this will fail with a TU_ASSERT.
- * (This is done to simplify the code. More complicated algorithms could be used)
- *
+ * In case of double buffering, high 16bit is the address of 2nd buffer
* During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually.
*/
-static uint16_t dcd_pma_alloc(uint8_t ep_addr, uint16_t length)
+static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf)
{
- xfer_ctl_t* epXferCtl = xfer_ctl_ptr(ep_addr);
-
- if(epXferCtl->pma_alloc_size != 0U)
- {
- //TU_LOG2("dcd_pma_alloc(%x,%x)=%x (cached)\r\n",ep_addr,length,epXferCtl->pma_ptr);
- // Previously allocated
- TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF); // Verify no larger than previous alloc
- return epXferCtl->pma_ptr;
- }
-
// Ensure allocated buffer is aligned
#ifdef FSDEV_BUS_32BIT
length = (length + 3) & ~0x03;
@@ -792,79 +752,44 @@ static uint16_t dcd_pma_alloc(uint8_t ep_addr, uint16_t length)
length = (length + 1) & ~0x01;
#endif
- open_ep_count++;
-
- uint16_t addr = ep_buf_ptr;
+ uint32_t addr = ep_buf_ptr;
ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer
- // Verify no overflow
- TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF);
+ if (dbuf) {
+ addr |= ((uint32_t)ep_buf_ptr) << 16;
+ ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer
+ }
- epXferCtl->pma_ptr = addr;
- epXferCtl->pma_alloc_size = length;
- //TU_LOG1("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr);
+ // Verify packet buffer is not overflowed
+ TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF);
return addr;
}
/***
- * Free a block of PMA space
- */
-static void dcd_pma_free(uint8_t ep_addr)
-{
- // Presently, this should never be called for EP0 IN/OUT
- TU_ASSERT(open_ep_count > 2, /**/);
- TU_ASSERT(xfer_ctl_ptr(ep_addr)->max_packet_size != 0, /**/);
- open_ep_count--;
-
- // If count is 2, only EP0 should be open, so allocations can be mostly reset.
-
- if(open_ep_count == 2)
- {
- ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT + 2*CFG_TUD_ENDPOINT0_SIZE; // 8 bytes per endpoint (two TX and two RX words, each), and EP0
-
- // Skip EP0
- for(uint32_t i=1; i<MAX_EP_COUNT; i++)
- {
- xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_alloc_size = 0U;
- xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_alloc_size = 0U;
- xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_OUT))->pma_ptr = 0U;
- xfer_ctl_ptr(tu_edpt_addr(i,TUSB_DIR_IN))->pma_ptr = 0U;
- }
- }
-}
-
-/***
* Allocate hardware endpoint
*/
static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++)
- {
+ for (uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) {
// Check if already allocated
- if(ep_alloc_status[i].allocated[dir] &&
- ep_alloc_status[i].ep_type == ep_type &&
- ep_alloc_status[i].ep_num == epnum)
- {
+ if (ep_alloc_status[i].allocated[dir] &&
+ ep_alloc_status[i].ep_type == ep_type &&
+ ep_alloc_status[i].ep_num == epnum) {
return i;
}
// If EP of current direction is not allocated
// Except for ISO endpoint, both direction should be free
- if(!ep_alloc_status[i].allocated[dir] &&
- (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1]))
- {
+ if (!ep_alloc_status[i].allocated[dir] &&
+ (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) {
// Check if EP number is the same
- if(ep_alloc_status[i].ep_num == 0xFF ||
- ep_alloc_status[i].ep_num == epnum)
- {
+ if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) {
// One EP pair has to be the same type
- if(ep_alloc_status[i].ep_type == 0xFF ||
- ep_alloc_status[i].ep_type == ep_type)
- {
+ if (ep_alloc_status[i].ep_type == 0xFF || ep_alloc_status[i].ep_type == ep_type) {
ep_alloc_status[i].ep_num = epnum;
ep_alloc_status[i].ep_type = ep_type;
ep_alloc_status[i].allocated[dir] = true;
@@ -879,121 +804,79 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
TU_ASSERT(0);
}
-/***
- * Free hardware endpoint
- */
-static void dcd_ep_free(uint8_t ep_addr)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- for(uint8_t i = 0; i < STFSDEV_EP_COUNT; i++)
- {
- // Check if EP number & dir are the same
- if(ep_alloc_status[i].ep_num == epnum &&
- ep_alloc_status[i].allocated[dir] == dir)
- {
- ep_alloc_status[i].allocated[dir] = false;
- // Reset entry if ISO endpoint or both direction are free
- if(ep_alloc_status[i].ep_type == TUSB_XFER_ISOCHRONOUS ||
- !ep_alloc_status[i].allocated[dir ^ 1])
- {
- ep_alloc_status[i].ep_num = 0xFF;
- ep_alloc_status[i].ep_type = 0xFF;
-
- return;
- }
- }
- }
-}
-
// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers,
// so I'm using the #define from HAL here, instead.
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
{
(void)rhport;
- uint8_t const ep_idx = dcd_ep_alloc(p_endpoint_desc->bEndpointAddress, p_endpoint_desc->bmAttributes.xfer);
- uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+ uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress;
+ uint8_t const ep_idx = dcd_ep_alloc(ep_addr, p_endpoint_desc->bmAttributes.xfer);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc);
const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size);
uint16_t pma_addr;
uint32_t wType;
TU_ASSERT(ep_idx < STFSDEV_EP_COUNT);
- TU_ASSERT(buffer_size <= 1024);
+ TU_ASSERT(buffer_size <= 64);
// Set type
- switch(p_endpoint_desc->bmAttributes.xfer) {
- case TUSB_XFER_CONTROL:
- wType = USB_EP_CONTROL;
- break;
- case TUSB_XFER_ISOCHRONOUS:
- wType = USB_EP_ISOCHRONOUS;
- break;
- case TUSB_XFER_BULK:
- wType = USB_EP_CONTROL;
- break;
+ switch (p_endpoint_desc->bmAttributes.xfer) {
+ case TUSB_XFER_CONTROL:
+ wType = USB_EP_CONTROL;
+ break;
+ case TUSB_XFER_BULK:
+ wType = USB_EP_CONTROL;
+ break;
- case TUSB_XFER_INTERRUPT:
- wType = USB_EP_INTERRUPT;
- break;
+ case TUSB_XFER_INTERRUPT:
+ wType = USB_EP_INTERRUPT;
+ break;
- default:
- TU_ASSERT(false);
+ default:
+ // Note: ISO endpoint should use alloc / active functions
+ TU_ASSERT(false);
}
pcd_set_eptype(USB, ep_idx, wType);
- pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress));
- // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint)
- // or being double-buffered (bulk endpoints)
- pcd_clear_ep_kind(USB,0);
+ pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr));
- /* Create a packet memory buffer area. For isochronous endpoints,
- * use the same buffer as the double buffer, essentially disabling double buffering */
- pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, buffer_size);
+ /* Create a packet memory buffer area. */
+ pma_addr = dcd_pma_alloc(buffer_size, false);
- if( (dir == TUSB_DIR_IN) || (wType == USB_EP_ISOCHRONOUS) )
- {
+ if (dir == TUSB_DIR_IN) {
pcd_set_ep_tx_address(USB, ep_idx, pma_addr);
- pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size);
+ pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK);
pcd_clear_tx_dtog(USB, ep_idx);
- }
-
- if( (dir == TUSB_DIR_OUT) || (wType == USB_EP_ISOCHRONOUS) )
- {
+ } else {
pcd_set_ep_rx_address(USB, ep_idx, pma_addr);
- pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size);
+ pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK);
pcd_clear_rx_dtog(USB, ep_idx);
}
- /* Enable endpoint */
- if (dir == TUSB_DIR_IN)
- {
- if(wType == USB_EP_ISOCHRONOUS) {
- pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS);
- } else {
- pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK);
- }
- } else
- {
- if(wType == USB_EP_ISOCHRONOUS) {
- pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS);
- } else {
- pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK);
- }
- }
-
- xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size;
- xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx = ep_idx;
+ xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size;
+ xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx;
return true;
}
-void dcd_edpt_close_all (uint8_t rhport)
+void dcd_edpt_close_all(uint8_t rhport)
{
- (void) rhport;
- // TODO implement dcd_edpt_close_all()
+ (void)rhport;
+
+ for (uint32_t i = 1; i < STFSDEV_EP_COUNT; i++) {
+ // Reset endpoint
+ pcd_set_endpoint(USB, i, 0);
+ // Clear EP allocation status
+ ep_alloc_status[i].ep_num = 0xFF;
+ ep_alloc_status[i].ep_type = 0xFF;
+ ep_alloc_status[i].allocated[0] = false;
+ ep_alloc_status[i].allocated[1] = false;
+ }
+
+ // Reset PMA allocation
+ ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT + 2 * CFG_TUD_ENDPOINT0_SIZE;
}
/**
@@ -1003,223 +886,203 @@ void dcd_edpt_close_all (uint8_t rhport)
*
* This also clears transfers in progress, should there be any.
*/
-void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
- xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
uint8_t const ep_idx = xfer->ep_idx;
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- if(dir == TUSB_DIR_IN)
- {
+ if (dir == TUSB_DIR_IN) {
pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS);
- }
- else
- {
+ } else {
pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS);
}
-
- dcd_ep_free(ep_addr);
-
- dcd_pma_free(ep_addr);
}
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size)
{
(void)rhport;
- TU_ASSERT(largest_packet_size <= 1024);
-
uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
const uint16_t buffer_size = pcd_aligned_buffer_size(largest_packet_size);
- /* Create a packet memory buffer area. For isochronous endpoints,
- * use the same buffer as the double buffer, essentially disabling double buffering */
- uint16_t pma_addr = dcd_pma_alloc(ep_addr, buffer_size);
-
- xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx;
+ /* Create a packet memory buffer area. Enable double buffering for devices with 2048 bytes PMA,
+ for smaller devices double buffering occupy too much space. */
+#if FSDEV_PMA_SIZE > 1024u
+ uint32_t pma_addr = dcd_pma_alloc(buffer_size, true);
+ uint16_t pma_addr2 = pma_addr >> 16;
+#else
+ uint32_t pma_addr = dcd_pma_alloc(buffer_size, true);
+ uint16_t pma_addr2 = pma_addr;
+#endif
+ pcd_set_ep_tx_address(USB, ep_idx, pma_addr);
+ pcd_set_ep_rx_address(USB, ep_idx, pma_addr2);
pcd_set_eptype(USB, ep_idx, USB_EP_ISOCHRONOUS);
- pcd_set_ep_tx_address(USB, ep_idx, pma_addr);
- pcd_set_ep_rx_address(USB, ep_idx, pma_addr);
+ xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx;
return true;
}
-bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
{
(void)rhport;
- uint8_t const ep_idx = xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->ep_idx;
- uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+ uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress;
+ uint8_t const ep_idx = xfer_ctl_ptr(ep_addr)->ep_idx;
+ uint8_t const dir = tu_edpt_dir(ep_addr);
const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc);
- const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size);
- /* Disable endpoint */
- if(dir == TUSB_DIR_IN)
- {
- pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS);
- }
- else
- {
- pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS);
- }
+ pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS);
+ pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS);
- pcd_set_ep_address(USB, ep_idx, tu_edpt_number(p_endpoint_desc->bEndpointAddress));
- // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint)
- // or being double-buffered (bulk endpoints)
- pcd_clear_ep_kind(USB,0);
+ pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr));
- pcd_set_ep_tx_bufsize(USB, ep_idx, buffer_size);
- pcd_set_ep_rx_bufsize(USB, ep_idx, buffer_size);
pcd_clear_tx_dtog(USB, ep_idx);
pcd_clear_rx_dtog(USB, ep_idx);
- xfer_ctl_ptr(p_endpoint_desc->bEndpointAddress)->max_packet_size = packet_size;
+ if (dir == TUSB_DIR_IN) {
+ pcd_rx_dtog(USB, ep_idx);
+ } else {
+ pcd_tx_dtog(USB, ep_idx);
+ }
+
+ xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size;
return true;
}
// Currently, single-buffered, and only 64 bytes at a time (max)
-static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix)
+static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix)
{
uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len);
-
- if(len > xfer->max_packet_size) // max packet size for FS transfer
- {
+ if (len > xfer->max_packet_size) {
len = xfer->max_packet_size;
}
uint16_t ep_reg = pcd_get_endpoint(USB, ep_ix);
- uint16_t addr_ptr = pcd_get_ep_tx_address(USB, ep_ix);
+ bool const is_iso = (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS;
+ uint16_t addr_ptr;
- if (xfer->ff)
- {
- dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len);
- }
- else
- {
- dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len);
+ if (is_iso) {
+ if (ep_reg & USB_EP_DTOG_TX) {
+ addr_ptr = pcd_get_ep_dbuf1_address(USB, ep_ix);
+ pcd_set_ep_tx_dbuf1_cnt(USB, ep_ix, len);
+ } else {
+ addr_ptr = pcd_get_ep_dbuf0_address(USB, ep_ix);
+ pcd_set_ep_tx_dbuf0_cnt(USB, ep_ix, len);
+ }
+ } else {
+ addr_ptr = pcd_get_ep_tx_address(USB, ep_ix);
+ pcd_set_ep_tx_cnt(USB, ep_ix, len);
}
- xfer->queued_len = (uint16_t)(xfer->queued_len + len);
- /* Write into correct register when ISOCHRONOUS (double buffered) */
- if ( (ep_reg & USB_EP_DTOG_TX) && ( (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) ) {
- pcd_set_ep_rx_cnt(USB, ep_ix, len);
+ if (xfer->ff) {
+ dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len);
} else {
- pcd_set_ep_tx_cnt(USB, ep_ix, len);
+ dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len);
}
+ xfer->queued_len = (uint16_t)(xfer->queued_len + len);
+ dcd_int_disable(0);
pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID);
+ if (is_iso) {
+ xfer->iso_in_sending = true;
+ }
+ dcd_int_enable(0);
}
-bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr)
{
- (void) rhport;
+ (void)rhport;
- xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
uint8_t const ep_idx = xfer->ep_idx;
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- xfer->buffer = buffer;
- xfer->ff = NULL;
- xfer->total_len = total_bytes;
- xfer->queued_len = 0;
-
- if ( dir == TUSB_DIR_OUT )
- {
+ if (dir == TUSB_DIR_IN) {
+ dcd_transmit_packet(xfer, ep_idx);
+ } else {
// A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid
// buffer for the control endpoint.
- if (ep_idx == 0 && buffer == NULL)
- {
- xfer->buffer = (uint8_t*)_setup_packet;
+ if (ep_idx == 0 && xfer->buffer == NULL) {
+ xfer->buffer = (uint8_t *)_setup_packet;
}
- if(total_bytes > xfer->max_packet_size)
- {
- pcd_set_ep_rx_bufsize(USB,ep_idx,xfer->max_packet_size);
+ uint32_t cnt = (uint32_t ) tu_min16(xfer->total_len, xfer->max_packet_size);
+ uint16_t ep_reg = pcd_get_endpoint(USB, ep_idx);
+
+ if ((ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) {
+ pcd_set_ep_rx_dbuf0_cnt(USB, ep_idx, cnt);
+ pcd_set_ep_rx_dbuf1_cnt(USB, ep_idx, cnt);
} else {
- pcd_set_ep_rx_bufsize(USB,ep_idx,total_bytes);
+ pcd_set_ep_rx_cnt(USB, ep_idx, cnt);
}
+
pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_VALID);
}
- else // IN
- {
- dcd_transmit_packet(xfer,ep_idx);
- }
+
return true;
}
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
- (void) rhport;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
- xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr);
- uint8_t const epnum = xfer->ep_idx;
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ xfer->buffer = buffer;
+ xfer->ff = NULL;
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
+ return edpt_xfer(rhport, ep_addr);
+}
+
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
+{
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
xfer->buffer = NULL;
- xfer->ff = ff;
+ xfer->ff = ff;
xfer->total_len = total_bytes;
xfer->queued_len = 0;
- if ( dir == TUSB_DIR_OUT )
- {
- if(total_bytes > xfer->max_packet_size)
- {
- pcd_set_ep_rx_bufsize(USB,epnum,xfer->max_packet_size);
- } else {
- pcd_set_ep_rx_bufsize(USB,epnum,total_bytes);
- }
- pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID);
- }
- else // IN
- {
- dcd_transmit_packet(xfer,epnum);
- }
- return true;
+ return edpt_xfer(rhport, ep_addr);
}
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
- xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
uint8_t const ep_idx = xfer->ep_idx;
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- if (dir == TUSB_DIR_IN)
- { // IN
+ if (dir == TUSB_DIR_IN) {
pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_STALL);
- }
- else
- { // OUT
+ } else {
pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_STALL);
}
}
-void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
- xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr);
uint8_t const ep_idx = xfer->ep_idx;
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- if (dir == TUSB_DIR_IN)
- { // IN
- if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) {
+ if (dir == TUSB_DIR_IN) { // IN
+ if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) {
pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK);
}
/* Reset to DATA0 if clearing stall condition. */
pcd_clear_tx_dtog(USB, ep_idx);
- }
- else
- { // OUT
- if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) {
+ } else { // OUT
+ if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) {
pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK);
}
/* Reset to DATA0 if clearing stall condition. */
@@ -1230,8 +1093,8 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
#ifdef FSDEV_BUS_32BIT
static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes)
{
- const uint8_t* srcVal = src;
- volatile uint32_t* dst32 = (volatile uint32_t*)(USB_PMAADDR + dst);
+ const uint8_t *srcVal = src;
+ volatile uint32_t *dst32 = (volatile uint32_t *)(USB_PMAADDR + dst);
for (uint32_t n = wNBytes / 4; n > 0; --n) {
*dst32++ = tu_unaligned_read32(srcVal);
@@ -1239,18 +1102,15 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, ui
}
wNBytes = wNBytes & 0x03;
- if (wNBytes)
- {
+ if (wNBytes) {
uint32_t wrVal = *srcVal;
wNBytes--;
- if (wNBytes)
- {
+ if (wNBytes) {
wrVal |= *++srcVal << 8;
wNBytes--;
- if (wNBytes)
- {
+ if (wNBytes) {
wrVal |= *++srcVal << 16;
}
}
@@ -1263,20 +1123,20 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, ui
#else
// Packet buffer access can only be 8- or 16-bit.
/**
- * @brief Copy a buffer from user memory area to packet memory area (PMA).
- * This uses byte-access for user memory (so support non-aligned buffers)
- * and 16-bit access for packet memory.
- * @param dst, byte address in PMA; must be 16-bit aligned
- * @param src pointer to user memory area.
- * @param wPMABufAddr address into PMA.
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
+ * @brief Copy a buffer from user memory area to packet memory area (PMA).
+ * This uses byte-access for user memory (so support non-aligned buffers)
+ * and 16-bit access for packet memory.
+ * @param dst, byte address in PMA; must be 16-bit aligned
+ * @param src pointer to user memory area.
+ * @param wPMABufAddr address into PMA.
+ * @param wNBytes no. of bytes to be copied.
+ * @retval None
+ */
static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes)
{
uint32_t n = (uint32_t)wNBytes >> 1U;
uint16_t temp1, temp2;
- const uint8_t * srcVal;
+ const uint8_t *srcVal;
// The GCC optimizer will combine access to 32-bit sizes if we let it. Force
// it volatile so that it won't do that.
@@ -1285,18 +1145,16 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, ui
srcVal = src;
pdwVal = &pma[FSDEV_PMA_STRIDE * (dst >> 1)];
- while (n--)
- {
+ while (n--) {
temp1 = (uint16_t)*srcVal;
srcVal++;
- temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)) ;
+ temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U));
*pdwVal = temp2;
pdwVal += FSDEV_PMA_STRIDE;
srcVal++;
}
- if (wNBytes)
- {
+ if (wNBytes) {
temp1 = *srcVal;
*pdwVal = temp1;
}
@@ -1306,42 +1164,39 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, ui
#endif
/**
- * @brief Copy from FIFO to packet memory area (PMA).
- * Uses byte-access of system memory and 16-bit access of packet memory
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes)
+ * @brief Copy from FIFO to packet memory area (PMA).
+ * Uses byte-access of system memory and 16-bit access of packet memory
+ * @param wNBytes no. of bytes to be copied.
+ * @retval None
+ */
+static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes)
{
// Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
tu_fifo_buffer_info_t info;
tu_fifo_get_read_info(ff, &info);
- uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin);
+ uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin);
uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap);
// We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part,
// last lin byte will be combined with wrapped part
// To ensure PMA is always access aligned (dst aligned to 16 or 32 bit)
#ifdef FSDEV_BUS_32BIT
- if((cnt_lin & 0x03) && cnt_wrap)
- {
+ if ((cnt_lin & 0x03) && cnt_wrap) {
// Copy first linear part
- dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin &~0x03);
- dst += cnt_lin &~0x03;
+ dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x03);
+ dst += cnt_lin & ~0x03;
// Copy last linear bytes & first wrapped bytes to buffer
uint32_t i;
uint8_t tmp[4];
- for (i = 0; i < (cnt_lin & 0x03); i++)
- {
- tmp[i] = ((uint8_t*)info.ptr_lin)[(cnt_lin &~0x03) + i];
+ for (i = 0; i < (cnt_lin & 0x03); i++) {
+ tmp[i] = ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i];
}
uint32_t wCnt = cnt_wrap;
- for (; i < 4 && wCnt > 0; i++, wCnt--)
- {
- tmp[i] = *(uint8_t*)info.ptr_wrap;
- info.ptr_wrap = (uint8_t*)info.ptr_wrap + 1;
+ for (; i < 4 && wCnt > 0; i++, wCnt--) {
+ tmp[i] = *(uint8_t *)info.ptr_wrap;
+ info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1;
}
// Write unaligned buffer
@@ -1350,32 +1205,29 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN
// Copy rest of wrapped byte
if (wCnt)
- dcd_write_packet_memory(dst, info.ptr_wrap, wCnt);
+ dcd_write_packet_memory(dst, info.ptr_wrap, wCnt);
}
#else
- if((cnt_lin & 0x01) && cnt_wrap)
- {
+ if ((cnt_lin & 0x01) && cnt_wrap) {
// Copy first linear part
- dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin &~0x01);
- dst += cnt_lin &~0x01;
+ dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x01);
+ dst += cnt_lin & ~0x01;
// Copy last linear byte & first wrapped byte
- uint16_t tmp = ((uint8_t*)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t*)info.ptr_wrap)[0]) << 8U);
+ uint16_t tmp = ((uint8_t *)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t *)info.ptr_wrap)[0]) << 8U);
dcd_write_packet_memory(dst, &tmp, 2);
dst += 2;
// Copy rest of wrapped byte
- dcd_write_packet_memory(dst, ((uint8_t*)info.ptr_wrap) + 1, cnt_wrap - 1);
+ dcd_write_packet_memory(dst, ((uint8_t *)info.ptr_wrap) + 1, cnt_wrap - 1);
}
#endif
- else
- {
+ else {
// Copy linear part
dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin);
dst += info.len_lin;
- if(info.len_wrap)
- {
+ if (info.len_wrap) {
// Copy wrapped byte
dcd_write_packet_memory(dst, info.ptr_wrap, cnt_wrap);
}
@@ -1389,8 +1241,8 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN
#ifdef FSDEV_BUS_32BIT
static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes)
{
- uint8_t* dstVal = dst;
- volatile uint32_t* src32 = (volatile uint32_t*)(USB_PMAADDR + src);
+ uint8_t *dstVal = dst;
+ volatile uint32_t *src32 = (volatile uint32_t *)(USB_PMAADDR + src);
for (uint32_t n = wNBytes / 4; n > 0; --n) {
tu_unaligned_write32(dstVal, *src32++);
@@ -1398,20 +1250,17 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t
}
wNBytes = wNBytes & 0x03;
- if (wNBytes)
- {
+ if (wNBytes) {
uint32_t rdVal = *src32;
*dstVal = tu_u32_byte0(rdVal);
wNBytes--;
- if (wNBytes)
- {
+ if (wNBytes) {
*++dstVal = tu_u32_byte1(rdVal);
wNBytes--;
- if (wNBytes)
- {
+ if (wNBytes) {
*++dstVal = tu_u32_byte2(rdVal);
}
}
@@ -1421,11 +1270,11 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t
}
#else
/**
- * @brief Copy a buffer from packet memory area (PMA) to user memory area.
- * Uses byte-access of system memory and 16-bit access of packet memory
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
+ * @brief Copy a buffer from packet memory area (PMA) to user memory area.
+ * Uses byte-access of system memory and 16-bit access of packet memory
+ * @param wNBytes no. of bytes to be copied.
+ * @retval None
+ */
static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes)
{
uint32_t n = (uint32_t)wNBytes >> 1U;
@@ -1435,18 +1284,16 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t
uint32_t temp;
pdwVal = &pma[FSDEV_PMA_STRIDE * (src >> 1)];
- uint8_t *dstVal = (uint8_t*)dst;
+ uint8_t *dstVal = (uint8_t *)dst;
- while (n--)
- {
+ while (n--) {
temp = *pdwVal;
pdwVal += FSDEV_PMA_STRIDE;
*dstVal++ = ((temp >> 0) & 0xFF);
*dstVal++ = ((temp >> 8) & 0xFF);
}
- if (wNBytes & 0x01)
- {
+ if (wNBytes & 0x01) {
temp = *pdwVal;
pdwVal += FSDEV_PMA_STRIDE;
*dstVal++ = ((temp >> 0) & 0xFF);
@@ -1456,31 +1303,29 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t
#endif
/**
- * @brief Copy a buffer from user packet memory area (PMA) to FIFO.
- * Uses byte-access of system memory and 16-bit access of packet memory
- * @param wNBytes no. of bytes to be copied.
- * @retval None
- */
-static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes)
+ * @brief Copy a buffer from user packet memory area (PMA) to FIFO.
+ * Uses byte-access of system memory and 16-bit access of packet memory
+ * @param wNBytes no. of bytes to be copied.
+ * @retval None
+ */
+static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes)
{
// Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
// Check for first linear part
tu_fifo_buffer_info_t info;
- tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO
+ tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO
- uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin);
+ uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin);
uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap);
-
// We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part,
// last lin byte will be combined with wrapped part
// To ensure PMA is always access aligned (src aligned to 16 or 32 bit)
#ifdef FSDEV_BUS_32BIT
- if((cnt_lin & 0x03) && cnt_wrap)
- {
+ if ((cnt_lin & 0x03) && cnt_wrap) {
// Copy first linear part
- dcd_read_packet_memory(info.ptr_lin, src, cnt_lin &~0x03);
- src += cnt_lin &~0x03;
+ dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x03);
+ src += cnt_lin & ~0x03;
// Copy last linear bytes & first wrapped bytes
uint8_t tmp[4];
@@ -1488,15 +1333,13 @@ static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNB
src += 4;
uint32_t i;
- for (i = 0; i < (cnt_lin & 0x03); i++)
- {
- ((uint8_t*)info.ptr_lin)[(cnt_lin &~0x03) + i] = tmp[i];
+ for (i = 0; i < (cnt_lin & 0x03); i++) {
+ ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i] = tmp[i];
}
uint32_t wCnt = cnt_wrap;
- for (; i < 4 && wCnt > 0; i++, wCnt--)
- {
- *(uint8_t*)info.ptr_wrap = tmp[i];
- info.ptr_wrap = (uint8_t*)info.ptr_wrap + 1;
+ for (; i < 4 && wCnt > 0; i++, wCnt--) {
+ *(uint8_t *)info.ptr_wrap = tmp[i];
+ info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1;
}
// Copy rest of wrapped byte
@@ -1504,32 +1347,29 @@ static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNB
dcd_read_packet_memory(info.ptr_wrap, src, wCnt);
}
#else
- if((cnt_lin & 0x01) && cnt_wrap)
- {
+ if ((cnt_lin & 0x01) && cnt_wrap) {
// Copy first linear part
- dcd_read_packet_memory(info.ptr_lin, src, cnt_lin &~0x01);
- src += cnt_lin &~0x01;
+ dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x01);
+ src += cnt_lin & ~0x01;
// Copy last linear byte & first wrapped byte
uint8_t tmp[2];
dcd_read_packet_memory(tmp, src, 2);
src += 2;
- ((uint8_t*)info.ptr_lin)[cnt_lin - 1] = tmp[0];
- ((uint8_t*)info.ptr_wrap)[0] = tmp[1];
+ ((uint8_t *)info.ptr_lin)[cnt_lin - 1] = tmp[0];
+ ((uint8_t *)info.ptr_wrap)[0] = tmp[1];
// Copy rest of wrapped byte
- dcd_read_packet_memory(((uint8_t*)info.ptr_wrap) + 1, src, cnt_wrap - 1);
+ dcd_read_packet_memory(((uint8_t *)info.ptr_wrap) + 1, src, cnt_wrap - 1);
}
#endif
- else
- {
+ else {
// Copy linear part
dcd_read_packet_memory(info.ptr_lin, src, cnt_lin);
src += cnt_lin;
- if(info.len_wrap)
- {
+ if (info.len_wrap) {
// Copy wrapped byte
dcd_read_packet_memory(info.ptr_wrap, src, cnt_wrap);
}
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h
index 3f4db985d..7992f34a1 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h
@@ -1,30 +1,32 @@
-/**
- * Copyright(c) 2016 STMicroelectronics
- * Copyright(c) N Conrad
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
+/*
+ * Copyright(c) 2016 STMicroelectronics
+ * Copyright(c) N Conrad
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
// This file contains source copied from ST's HAL, and thus should have their copyright statement.
@@ -113,6 +115,11 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
#include "stm32h5xx.h"
#define FSDEV_BUS_32BIT
+
+ #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE)
+ #define USB_DRD_BASE USB_DRD_FS_BASE
+ #endif
+
#define FSDEV_PMA_SIZE (2048u)
#undef USB_PMAADDR
#define USB_PMAADDR USB_DRD_PMAADDR
@@ -138,7 +145,6 @@
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
#include "stm32wbxx.h"
#define FSDEV_PMA_SIZE (1024u)
@@ -182,27 +188,23 @@ typedef uint16_t fsdev_bus_t;
// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden)
static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR;
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x)
-{
+TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) {
size_t total_word_offset = (((USBx)->BTABLE)>>1) + x;
total_word_offset *= FSDEV_PMA_STRIDE;
return &(pma[total_word_offset]);
}
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u);
}
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u);
}
#endif
/* Aligned buffer size according to hardware */
-TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) {
/* The STM32 full speed USB peripheral supports only a limited set of
* buffer sizes given by the RX buffer entry format in the USB_BTABLE. */
uint16_t blocksize = (size > 62) ? 32 : 2;
@@ -213,9 +215,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t si
return numblocks * blocksize;
}
-/* SetENDPOINT */
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
__O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4);
@@ -226,7 +226,6 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, ui
#endif
}
-/* GetENDPOINT */
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
@@ -237,8 +236,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx
return *reg;
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= (uint32_t)USB_EP_T_MASK;
regVal |= wType;
@@ -246,20 +244,19 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EP_T_FIELD;
return regVal;
}
+
/**
* @brief Clears bit CTR_RX / CTR_TX in the endpoint register.
* @param USBx USB peripheral instance register address.
* @param bEpIdx Endpoint Number.
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal &= ~USB_EP_CTR_RX;
@@ -267,22 +264,21 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx,
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal &= ~USB_EP_CTR_TX;
regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0)
pcd_set_endpoint(USBx, bEpIdx,regVal);
}
+
/**
* @brief gets counter of the tx buffer.
* @param USBx USB peripheral instance register address.
* @param bEpIdx Endpoint Number.
* @retval Counter value
*/
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
return (pma32[2*bEpIdx] & 0x03FF0000) >> 16;
@@ -292,8 +288,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USB
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16;
@@ -303,6 +298,9 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USB
#endif
}
+#define pcd_get_ep_dbuf0_cnt pcd_get_ep_tx_cnt
+#define pcd_get_ep_dbuf1_cnt pcd_get_ep_rx_cnt
+
/**
* @brief Sets address in an endpoint register.
* @param USBx USB peripheral instance register address.
@@ -310,8 +308,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USB
* @param bAddr Address.
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal |= bAddr;
@@ -319,8 +316,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx,
pcd_set_endpoint(USBx, bEpIdx,regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
return pma32[2*bEpIdx] & 0x0000FFFFu ;
@@ -329,8 +325,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef *
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
return pma32[2*bEpIdx + 1] & 0x0000FFFFu;
@@ -339,8 +334,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef *
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr)
-{
+#define pcd_get_ep_dbuf0_address pcd_get_ep_tx_address
+#define pcd_get_ep_dbuf1_address pcd_get_ep_rx_address
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
@@ -349,8 +346,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USB
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
@@ -359,8 +355,10 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USB
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount)
-{
+#define pcd_set_ep_dbuf0_address pcd_set_ep_tx_address
+#define pcd_set_ep_dbuf1_address pcd_set_ep_rx_address
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
@@ -370,8 +368,9 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, u
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount)
-{
+#define pcd_set_ep_tx_dbuf0_cnt pcd_set_ep_tx_cnt
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_dbuf1_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
@@ -381,8 +380,8 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, u
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t blocksize, uint32_t numblocks)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx,
+ uint32_t blocksize, uint32_t numblocks) {
/* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
#ifdef FSDEV_BUS_32BIT
(void) USBx;
@@ -393,8 +392,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDe
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) {
wCount = pcd_aligned_buffer_size(wCount);
/* We assume that the buffer size is already aligned to hardware requirements. */
@@ -408,16 +406,16 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx,
pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_dbuf0_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount);
}
+#define pcd_set_ep_rx_dbuf1_cnt pcd_set_ep_rx_cnt
+
/**
* @brief sets the status for tx transfer (bits STAT_TX[1:0]).
* @param USBx USB peripheral instance register address.
@@ -425,8 +423,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USB
* @param wState new state
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPTX_DTOGMASK;
@@ -443,7 +440,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
-} /* pcd_set_ep_tx_status */
+}
/**
* @brief sets the status for rx transfer (bits STAT_TX[1:0])
@@ -453,31 +450,27 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPRX_DTOGMASK;
/* toggle first bit ? */
- if((USB_EPRX_DTOG1 & wState)!= 0U)
- {
+ if((USB_EPRX_DTOG1 & wState)!= 0U) {
regVal ^= USB_EPRX_DTOG1;
}
/* toggle second bit ? */
- if((USB_EPRX_DTOG2 & wState)!= 0U)
- {
+ if((USB_EPRX_DTOG2 & wState)!= 0U) {
regVal ^= USB_EPRX_DTOG2;
}
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
-} /* pcd_set_ep_rx_status */
+}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
return (regVal & USB_EPRX_STAT) >> (12u);
-} /* pcd_get_ep_rx_status */
+}
/**
@@ -486,16 +479,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef *
* @param bEpIdx Endpoint Number.
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX;
@@ -508,21 +499,16 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32
* @param bEpIdx Endpoint Number.
* @retval None
*/
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- if((regVal & USB_EP_DTOG_RX) != 0)
- {
+ if((regVal & USB_EP_DTOG_RX) != 0) {
pcd_rx_dtog(USBx,bEpIdx);
}
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- if((regVal & USB_EP_DTOG_TX) != 0)
- {
+ if((regVal & USB_EP_DTOG_TX) != 0) {
pcd_tx_dtog(USBx,bEpIdx);
}
}
@@ -533,17 +519,15 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx,
* @param bEpIdx Endpoint Number.
* @retval None
*/
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal |= USB_EP_KIND;
regVal &= USB_EPREG_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPKIND_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c
index 6cc1975a8..6f36ad441 100644
--- a/src/portable/sunxi/dcd_sunxi_musb.c
+++ b/src/portable/sunxi/dcd_sunxi_musb.c
@@ -35,7 +35,9 @@
#include <f1c100s-irq.h>
#include <device/dcd.h>
#include "musb_def.h"
-#include "bsp/board.h"
+
+//#include "bsp/board_api.h"
+extern uint32_t board_millis(void); // TODO remove
typedef uint32_t u32;
typedef uint16_t u16;
@@ -58,7 +60,7 @@ typedef struct TU_ATTR_PACKED
typedef struct
{
- tusb_control_request_t setup_packet;
+ CFG_TUD_MEM_ALIGN tusb_control_request_t setup_packet;
uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
int8_t status_out;
pipe_state_t pipe0;
@@ -350,7 +352,7 @@ static void USBC_INT_DisableRxEp(u8 ep_index)
* INTERNAL FUNCTION DECLARATION
*------------------------------------------------------------------*/
-static dcd_data_t _dcd;
+CFG_TUD_MEM_ALIGN static dcd_data_t _dcd;
static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
{
@@ -560,7 +562,7 @@ static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigne
static void process_setup_packet(uint8_t rhport)
{
- uint32_t *p = (uint32_t*)&_dcd.setup_packet;
+ uint32_t *p = (uint32_t*)(uintptr_t) &_dcd.setup_packet;
p[0] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
p[1] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
@@ -594,7 +596,7 @@ static bool handle_xfer_in(uint_fast8_t ep_addr)
if (len) {
volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_IN);
+ pipe_read_write_packet_ff((tu_fifo_t *)(uintptr_t) buf, addr, len, TUSB_DIR_IN);
} else {
pipe_write_packet(buf, addr, len);
pipe->buf = buf + len;
@@ -622,7 +624,7 @@ static bool handle_xfer_out(uint_fast8_t ep_addr)
if (len) {
volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_OUT);
+ pipe_read_write_packet_ff((tu_fifo_t *)(uintptr_t )buf, addr, len, TUSB_DIR_OUT);
} else {
pipe_read_packet(buf, addr, len);
pipe->buf = buf + len;
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index 8163ba8e1..c9580655f 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -97,28 +97,170 @@ static uint16_t ep0_pending[2]; // Index determines direction as t
// TX FIFO RAM allocation so far in words - RX FIFO size is readily available from dwc2->grxfsiz
static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs)
-static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size)
// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
static bool _sof_en;
-// Calculate the RX FIFO size according to recommendations from reference manual
+// Calculate the RX FIFO size according to minimum recommendations from reference manual
+// RxFIFO = (5 * number of control endpoints + 8) +
+// ((largest USB packet used / 4) + 1 for status information) +
+// (2 * number of OUT endpoints) + 1 for Global NAK
+// with number of control endpoints = 1 we have
+// RxFIFO = 15 + (largest USB packet used / 4) + 2 * number of OUT endpoints
+// we double the largest USB packet size to be able to hold up to 2 packets
static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) {
return 15 + 2 * (max_ep_size / 4) + 2 * ep_count;
}
-static void update_grxfsiz(uint8_t rhport) {
+TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_tx(dwc2_regs_t* dwc2, uint8_t epnum) {
+ // flush TX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_TXFFLSH | (epnum << GRSTCTL_TXFNUM_Pos);
+ while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {}
+}
+TU_ATTR_ALWAYS_INLINE static inline void fifo_flush_rx(dwc2_regs_t* dwc2) {
+ // flush RX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_RXFFLSH;
+ while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {}
+}
+
+static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- // Determine largest EP size for RX FIFO
- uint16_t max_epsize = 0;
- for (uint8_t epnum = 0; epnum < ep_count; epnum++) {
- max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size);
+ TU_ASSERT(epnum < ep_count);
+
+ uint16_t fifo_size = tu_div_ceil(packet_size, 4);
+
+ // "USB Data FIFOs" section in reference manual
+ // Peripheral FIFO architecture
+ //
+ // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+ // | IN FIFO 0 |
+ // --------------- (320 or 1024) - 16
+ // | IN FIFO 1 |
+ // --------------- (320 or 1024) - 16 - x
+ // | . . . . |
+ // --------------- (320 or 1024) - 16 - x - y - ... - z
+ // | IN FIFO MAX |
+ // ---------------
+ // | FREE |
+ // --------------- GRXFSIZ
+ // | OUT FIFO |
+ // | ( Shared ) |
+ // --------------- 0
+ //
+ // In FIFO is allocated by following rules:
+ // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
+ if (dir == TUSB_DIR_OUT) {
+ // Calculate required size of RX FIFO
+ uint16_t const sz = calc_grxfsiz(4 * fifo_size, ep_count);
+
+ // If size_rx needs to be extended check if possible and if so enlarge it
+ if (dwc2->grxfsiz < sz) {
+ TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size / 4);
+
+ // Enlarge RX FIFO
+ dwc2->grxfsiz = sz;
+ }
+ } else {
+ // Note if The TXFELVL is configured as half empty. In order
+ // to be able to write a packet at that point, the fifo must be twice the max_size.
+ if ((dwc2->gahbcfg & GAHBCFG_TXFELVL) == 0) {
+ fifo_size *= 2;
+ }
+
+ // Check if free space is available
+ TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size / 4);
+ _allocated_fifo_words_tx += fifo_size;
+ TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %" PRIu32, fifo_size * 4,
+ _dwc2_controller[rhport].ep_fifo_size - _allocated_fifo_words_tx * 4);
+
+ // DIEPTXF starts at FIFO #1.
+ // Both TXFD and TXSA are in unit of 32-bit words.
+ dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) |
+ (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx);
+ }
+
+ return true;
+}
+
+static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->max_size = tu_edpt_packet_size(p_endpoint_desc);
+ xfer->interval = p_endpoint_desc->bInterval;
+
+ // USBAEP, EPTYP, SD0PID_SEVNFRM, MPSIZ are the same for IN and OUT endpoints.
+ uint32_t const dxepctl = (1 << DOEPCTL_USBAEP_Pos) |
+ (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) |
+ (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
+ (xfer->max_size << DOEPCTL_MPSIZ_Pos);
+
+ if (dir == TUSB_DIR_OUT) {
+ dwc2->epout[epnum].doepctl = dxepctl;
+ dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum);
+ } else {
+ dwc2->epin[epnum].diepctl = dxepctl | (epnum << DIEPCTL_TXFNUM_Pos);
+ dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum));
}
+}
+
+static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- // Update size of RX FIFO
- dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count);
+ if (dir == TUSB_DIR_IN) {
+ dwc2_epin_t* epin = dwc2->epin;
+
+ // Only disable currently enabled non-control endpoint
+ if ((epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA)) {
+ epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0);
+ } else {
+ // Stop transmitting packets and NAK IN xfers.
+ epin[epnum].diepctl |= DIEPCTL_SNAK;
+ while ((epin[epnum].diepint & DIEPINT_INEPNE) == 0) {}
+
+ // Disable the endpoint.
+ epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0);
+ while ((epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0) {}
+
+ epin[epnum].diepint = DIEPINT_EPDISD;
+ }
+
+ // Flush the FIFO, and wait until we have confirmed it cleared.
+ fifo_flush_tx(dwc2, epnum);
+ } else {
+ dwc2_epout_t* epout = dwc2->epout;
+
+ // Only disable currently enabled non-control endpoint
+ if ((epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA)) {
+ epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0;
+ } else {
+ // Asserting GONAK is required to STALL an OUT endpoint.
+ // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
+ // anyway, and it can't be cleared by user code. If this while loop never
+ // finishes, we have bigger problems than just the stack.
+ dwc2->dctl |= DCTL_SGONAK;
+ while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {}
+
+ // Ditto here- disable the endpoint.
+ epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0);
+ while ((epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0) {}
+
+ epout[epnum].doepint = DOEPINT_EPDISD;
+
+ // Allow other OUT endpoints to keep receiving.
+ dwc2->dctl |= DCTL_CGONAK;
+ }
+ }
}
// Start of Bus Reset
@@ -127,7 +269,6 @@ static void bus_reset(uint8_t rhport) {
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
tu_memclr(xfer_status, sizeof(xfer_status));
- _out_ep_closed = false;
_sof_en = false;
@@ -139,7 +280,17 @@ static void bus_reset(uint8_t rhport) {
dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
}
- // 2. Set up interrupt mask
+ // 2. Disable all IN endpoints
+ for (uint8_t n = 0; n < ep_count; n++) {
+ if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) {
+ dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS;
+ }
+ }
+
+ fifo_flush_tx(dwc2, 0x10); // all tx fifo
+ fifo_flush_rx(dwc2);
+
+ // 3. Set up interrupt mask
dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos);
dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM;
dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM;
@@ -269,18 +420,16 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c
/* Controller API
*------------------------------------------------------------------*/
#if CFG_TUSB_DEBUG >= DWC2_DEBUG
-
void print_dwc2_info(dwc2_regs_t* dwc2) {
// print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4
// use dwc2_info.py/md for bit-field value and comparison with other ports
volatile uint32_t const* p = (volatile uint32_t const*) &dwc2->guid;
TU_LOG(DWC2_DEBUG, "guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4\r\n");
for (size_t i = 0; i < 5; i++) {
- TU_LOG(DWC2_DEBUG, "0x%08lX, ", p[i]);
+ TU_LOG(DWC2_DEBUG, "0x%08" PRIX32 ", ", p[i]);
}
- TU_LOG(DWC2_DEBUG, "0x%08lX\r\n", p[5]);
+ TU_LOG(DWC2_DEBUG, "0x%08" PRIX32 "\r\n", p[5]);
}
-
#endif
static void reset_core(dwc2_regs_t* dwc2) {
@@ -298,11 +447,15 @@ static void reset_core(dwc2_regs_t* dwc2) {
}
static bool phy_hs_supported(dwc2_regs_t* dwc2) {
- // note: esp32 incorrect report its hs_phy_type as utmi
+ (void) dwc2;
+
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ // note: esp32 incorrect report its hs_phy_type as utmi
+ return false;
+#elif !TUD_OPT_HIGH_SPEED
return false;
#else
- return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE;
+ return dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE;
#endif
}
@@ -447,13 +600,8 @@ void dcd_init(uint8_t rhport) {
// (non zero-length packet), send STALL back and discard.
dwc2->dcfg |= DCFG_NZLSOHSK;
- // flush all TX fifo and wait for it cleared
- dwc2->grstctl = GRSTCTL_TXFFLSH | (0x10u << GRSTCTL_TXFNUM_Pos);
- while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {}
-
- // flush RX fifo and wait for it cleared
- dwc2->grstctl = GRSTCTL_RXFFLSH;
- while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {}
+ fifo_flush_tx(dwc2, 0x10); // all tx fifo
+ fifo_flush_rx(dwc2);
// Clear all interrupts
uint32_t int_mask = dwc2->gintsts;
@@ -462,11 +610,12 @@ void dcd_init(uint8_t rhport) {
dwc2->gotgint |= int_mask;
// Required as part of core initialization.
- // TODO: How should mode mismatch be handled? It will cause
- // the core to stop working/require reset.
- dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_MMISM | GINTMSK_RXFLVLM |
+ dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_RXFLVLM |
GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
+ // Configure TX FIFO empty level for interrupt. Default is complete empty
+ dwc2->gahbcfg |= GAHBCFG_TXFELVL;
+
// Enable global interrupt
dwc2->gahbcfg |= GAHBCFG_GINT;
@@ -547,84 +696,8 @@ void dcd_sof_enable(uint8_t rhport, bool en) {
*------------------------------------------------------------------*/
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
- (void) rhport;
-
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
-
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
-
- TU_ASSERT(epnum < ep_count);
-
- xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = tu_edpt_packet_size(desc_edpt);
- xfer->interval = desc_edpt->bInterval;
-
- uint16_t const fifo_size = tu_div_ceil(xfer->max_size, 4);
-
- if (dir == TUSB_DIR_OUT) {
- // Calculate required size of RX FIFO
- uint16_t const sz = calc_grxfsiz(4 * fifo_size, ep_count);
-
- // If size_rx needs to be extended check if possible and if so enlarge it
- if (dwc2->grxfsiz < sz) {
- TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size / 4);
-
- // Enlarge RX FIFO
- dwc2->grxfsiz = sz;
- }
-
- dwc2->epout[epnum].doepctl |= (1 << DOEPCTL_USBAEP_Pos) |
- (desc_edpt->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
- (xfer->max_size << DOEPCTL_MPSIZ_Pos);
-
- dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum);
- } else {
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO 0 |
- // --------------- (320 or 1024) - 16
- // | IN FIFO 1 |
- // --------------- (320 or 1024) - 16 - x
- // | . . . . |
- // --------------- (320 or 1024) - 16 - x - y - ... - z
- // | IN FIFO MAX |
- // ---------------
- // | FREE |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // In FIFO is allocated by following rules:
- // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
-
- // Check if free space is available
- TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size / 4);
-
- _allocated_fifo_words_tx += fifo_size;
-
- TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size * 4,
- _dwc2_controller[rhport].ep_fifo_size - _allocated_fifo_words_tx * 4);
-
- // DIEPTXF starts at FIFO #1.
- // Both TXFD and TXSA are in unit of 32-bit words.
- dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) |
- (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx);
-
- dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) |
- (epnum << DIEPCTL_TXFNUM_Pos) |
- (desc_edpt->bmAttributes.xfer << DIEPCTL_EPTYP_Pos) |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DIEPCTL_SD0PID_SEVNFRM : 0) |
- (xfer->max_size << DIEPCTL_MPSIZ_Pos);
-
- dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum));
- }
-
+ TU_ASSERT(fifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt)));
+ edpt_activate(rhport, desc_edpt);
return true;
}
@@ -638,16 +711,39 @@ void dcd_edpt_close_all(uint8_t rhport) {
for (uint8_t n = 1; n < ep_count; n++) {
// disable OUT endpoint
- dwc2->epout[n].doepctl = 0;
+ if (dwc2->epout[n].doepctl & DOEPCTL_EPENA) {
+ dwc2->epout[n].doepctl |= DOEPCTL_SNAK | DOEPCTL_EPDIS;
+ }
xfer_status[n][TUSB_DIR_OUT].max_size = 0;
// disable IN endpoint
- dwc2->epin[n].diepctl = 0;
+ if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) {
+ dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS;
+ }
xfer_status[n][TUSB_DIR_IN].max_size = 0;
}
+ // reset allocated fifo OUT
+ dwc2->grxfsiz = calc_grxfsiz(64, ep_count);
// reset allocated fifo IN
_allocated_fifo_words_tx = 16;
+
+ fifo_flush_tx(dwc2, 0x10); // all tx fifo
+ fifo_flush_rx(dwc2);
+}
+
+bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
+ TU_ASSERT(fifo_alloc(rhport, ep_addr, largest_packet_size));
+ return true;
+}
+
+bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
+ // Disable EP to clear potential incomplete transfers
+ edpt_disable(rhport, p_endpoint_desc->bEndpointAddress, false);
+
+ edpt_activate(rhport, p_endpoint_desc);
+
+ return true;
}
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
@@ -707,89 +803,12 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
return true;
}
-static void dcd_edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
- (void) rhport;
-
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if (dir == TUSB_DIR_IN) {
- dwc2_epin_t* epin = dwc2->epin;
-
- // Only disable currently enabled non-control endpoint
- if ((epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA)) {
- epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0);
- } else {
- // Stop transmitting packets and NAK IN xfers.
- epin[epnum].diepctl |= DIEPCTL_SNAK;
- while ((epin[epnum].diepint & DIEPINT_INEPNE) == 0) {}
-
- // Disable the endpoint.
- epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0);
- while ((epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0) {}
-
- epin[epnum].diepint = DIEPINT_EPDISD;
- }
-
- // Flush the FIFO, and wait until we have confirmed it cleared.
- dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH);
- while ((dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0) {}
- } else {
- dwc2_epout_t* epout = dwc2->epout;
-
- // Only disable currently enabled non-control endpoint
- if ((epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA)) {
- epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0;
- } else {
- // Asserting GONAK is required to STALL an OUT endpoint.
- // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
- // anyway, and it can't be cleared by user code. If this while loop never
- // finishes, we have bigger problems than just the stack.
- dwc2->dctl |= DCTL_SGONAK;
- while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {}
-
- // Ditto here- disable the endpoint.
- epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0);
- while ((epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0) {}
-
- epout[epnum].doepint = DOEPINT_EPDISD;
-
- // Allow other OUT endpoints to keep receiving.
- dwc2->dctl |= DCTL_CGONAK;
- }
- }
-}
-
-/**
- * Close an endpoint.
- */
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_edpt_disable(rhport, ep_addr, false);
-
- // Update max_size
- xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation
-
- if (dir == TUSB_DIR_IN) {
- uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos;
- uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos;
-
- // For now only the last opened endpoint can be closed without fuss.
- TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx,);
- _allocated_fifo_words_tx -= fifo_size;
- } else {
- _out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty
- }
+ edpt_disable(rhport, ep_addr, false);
}
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
- dcd_edpt_disable(rhport, ep_addr, true);
+ edpt_disable(rhport, ep_addr, true);
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
@@ -1130,18 +1149,16 @@ void dcd_int_handler(uint8_t rhport) {
dwc2->gotgint = otg_int;
}
- if (int_status & GINTSTS_SOF) {
- dwc2->gotgint = GINTSTS_SOF;
+ if(int_status & GINTSTS_SOF) {
+ dwc2->gintsts = GINTSTS_SOF;
+ const uint32_t frame = (dwc2->dsts & DSTS_FNSOF) >> DSTS_FNSOF_Pos;
- if (_sof_en) {
- uint32_t frame = (dwc2->dsts & (DSTS_FNSOF)) >> 8;
- dcd_event_sof(rhport, frame, true);
- } else {
- // Disable SOF interrupt if SOF was not explicitly enabled. SOF was used for remote wakeup detection
+ // Disable SOF interrupt if SOF was not explicitly enabled since SOF was used for remote wakeup detection
+ if (!_sof_en) {
dwc2->gintmsk &= ~GINTMSK_SOFM;
}
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ dcd_event_sof(rhport, frame, true);
}
// RxFIFO non-empty interrupt handling.
@@ -1154,15 +1171,7 @@ void dcd_int_handler(uint8_t rhport) {
// Loop until all available packets were handled
do {
handle_rxflvl_irq(rhport);
- } while (dwc2->gotgint & GINTSTS_RXFLVL);
-
- // Manage RX FIFO size
- if (_out_ep_closed) {
- update_grxfsiz(rhport);
-
- // Disable flag
- _out_ep_closed = false;
- }
+ } while(dwc2->gintsts & GINTSTS_RXFLVL);
dwc2->gintmsk |= GINTMSK_RXFLVLM;
}
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
index b4dfda575..8005f5f7b 100644
--- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -94,7 +94,8 @@ static void bus_reset(void)
USBOEPCNT_0 &= ~NAK;
USBIEPCNT_0 &= ~NAK;
- USBCTL |= FEN; // Enable responding to packets.
+ // Enable responding to packets.
+ USBCTL |= FEN;
// Dedicated buffers in hardware for SETUP and EP0, no setup needed.
// Now safe to respond to SETUP packets.
@@ -103,6 +104,28 @@ static void bus_reset(void)
USBKEYPID = 0;
}
+// Controls reset behavior of the USB module on receipt of a bus reset event.
+// - enable: When true, bus reset events will cause a reset the USB module.
+static void enable_functional_reset(const bool enable)
+{
+ // Check whether or not the USB configuration registers were
+ // locked prior to this function being called so that, if
+ // necessary, the lock state can be restored on exit.
+ bool unlocked = (USBKEYPID == 0xA528) ? true : false;
+
+ if(!unlocked) USBKEYPID = USBKEY;
+
+ if(enable)
+ {
+ USBCTL |= FRSTE;
+ }
+ else
+ {
+ USBCTL &= ~FRSTE;
+ }
+
+ if(!unlocked) USBKEYPID = 0;
+}
/*------------------------------------------------------------------*/
/* Controller API
@@ -131,11 +154,14 @@ void dcd_init (uint8_t rhport)
USBVECINT = 0;
- // Enable reset and wait for it before continuing.
- USBIE |= RSTRIE;
-
- // Enable pullup.
- USBCNF |= PUR_EN;
+ if(USBPWRCTL & USBBGVBV) {// Bus power detected?
+ USBPWRCTL |= VBOFFIE; // Enable bus-power-removed interrupt.
+ USBIE |= RSTRIE; // Enable reset and wait for it before continuing.
+ USBCNF |= PUR_EN; // Enable pullup.
+ } else {
+ USBPWRCTL |= VBONIE; // Enable bus-power-applied interrupt.
+ USBCNF &= ~USB_EN; // Disable USB module until bus power is detected.
+ }
USBKEYPID = 0;
}
@@ -610,14 +636,76 @@ static void handle_setup_packet(void)
_setup_packet[i] = setup_buf[i];
}
- // Clearing SETUPIFG by reading USBVECINT does not set NAK, so now that we
- // have a SETUP packet, force NAKs until tinyusb can handle the SETUP
- // packet and prepare for a new xfer.
+ // Force NAKs until tinyusb can handle the SETUP packet and prepare for a new xfer.
USBIEPCNT_0 |= NAK;
USBOEPCNT_0 |= NAK;
+
+ // Clear SETUPIFG to avoid handling in the USBVECINT switch statement.
+ // When handled there the NAKs applied to the endpoints above are
+ // cleared by hardware and the host will receive stale/duplicate data.
+ //
+ // Excerpt from MSP430x5xx and MSP430x6xx Family User's Guide:
+ //
+ // "...the SETUPIFG is cleared upon reading USBIV. In addition, the NAK on
+ // input endpoint 0 and output endpoint 0 is also cleared."
+ USBIEPCNF_0 &= ~UBME; // Errata USB10 workaround.
+ USBOEPCNF_0 &= ~UBME; // Errata USB10 workaround.
+ USBIFG &= ~SETUPIFG;
+ USBIEPCNF_0 |= UBME; // Errata USB10 workaround.
+ USBOEPCNF_0 |= UBME; // Errata USB10 workaround.
dcd_event_setup_received(0, (uint8_t*) &_setup_packet[0], true);
}
+#if CFG_TUSB_OS == OPT_OS_NONE
+TU_ATTR_ALWAYS_INLINE static inline void tu_delay(uint32_t ms) {
+ // msp430 can run up to 25Mhz -> 40ns per cycle. 1 ms = 25000 cycles
+ // each loop need 4 cycle: 1 sub, 1 cmp, 1 jump, 1 nop
+ volatile uint32_t cycles = (25000 * ms) >> 2;
+ while (cycles > 0) {
+ cycles--;
+ asm("nop");
+ }
+}
+#else
+#define tu_delay(ms) osal_task_delay(ms)
+#endif
+
+static void handle_bus_power_event(void *param) {
+ (void) param;
+
+ tu_delay(5); // Bus power settling delay.
+
+ USBKEYPID = USBKEY;
+
+ if(USBPWRCTL & USBBGVBV) { // Event caused by application of bus power.
+ USBPWRCTL |= VBOFFIE; // Enable bus-power-removed interrupt.
+ USBPLLDIVB = USBPLLDIVB; // For some reason the PLL will *NOT* lock unless the divider
+ // register is re-written. The assumption here is that this
+ // register was already properly configured during board-level
+ // initialization.
+ USBPLLCTL |= (UPLLEN | UPFDEN); // Enable the PLL.
+
+ uint16_t attempts = 0;
+ do { // Poll the PLL, checking for a successful lock.
+ USBPLLIR = 0;
+ tu_delay(1);
+ attempts++;
+ } while ((attempts < 10) && (USBPLLIR != 0));
+
+ // A successful lock is indicated by all PLL-related interrupt flags being cleared.
+ if(!USBPLLIR) {
+ dcd_init(0); // Re-initialize the USB module.
+ }
+ } else { // Event caused by removal of bus power.
+ USBPWRCTL |= VBONIE; // Enable bus-power-applied interrupt.
+ USBPLLCTL &= ~(UPLLEN | UPFDEN); // Disable the PLL.
+ USBCNF = 0; // Disable the USB module.
+ dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, false);
+ }
+
+ USBKEYPID = 0;
+}
+
void dcd_int_handler(uint8_t rhport)
{
(void) rhport;
@@ -628,6 +716,7 @@ void dcd_int_handler(uint8_t rhport)
if(setup_status)
{
+ enable_functional_reset(true);
handle_setup_packet();
}
@@ -646,11 +735,32 @@ void dcd_int_handler(uint8_t rhport)
switch(curr_vector)
{
+ case USBVECINT_NONE:
+ break;
+
case USBVECINT_RSTR:
+ enable_functional_reset(false); // Errata USB4 workaround.
bus_reset();
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
break;
+ case USBVECINT_PWR_VBUSOn:
+ case USBVECINT_PWR_VBUSOff: {
+ USBKEYPID = USBKEY;
+ // Prevent (possibly) unstable power from generating spurious interrupts.
+ USBPWRCTL &= ~(VBONIE | VBOFFIE);
+ USBKEYPID = 0;
+
+ dcd_event_t event;
+
+ event.rhport = 0;
+ event.event_id = USBD_EVENT_FUNC_CALL;
+ event.func_call.func = handle_bus_power_event;
+
+ dcd_event_handler(&event, true);
+ }
+ break;
+
// Clear the (hardware-enforced) NAK on EP 0 after a SETUP packet
// is received. At this point, even though the hardware is no longer
// forcing NAKs, the EP0 NAK bits should still be set to avoid
@@ -675,10 +785,12 @@ void dcd_int_handler(uint8_t rhport)
break;
case USBVECINT_INPUT_ENDPOINT0:
+ enable_functional_reset(true);
transmit_packet(0);
break;
case USBVECINT_OUTPUT_ENDPOINT0:
+ enable_functional_reset(true);
receive_packet(0);
break;
@@ -710,7 +822,6 @@ void dcd_int_handler(uint8_t rhport)
default:
while(true);
- break;
}
}
diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c
index 1f1c0b876..68e2179e9 100644
--- a/src/portable/wch/dcd_ch32_usbhs.c
+++ b/src/portable/wch/dcd_ch32_usbhs.c
@@ -135,6 +135,16 @@ void dcd_remote_wakeup(uint8_t rhport)
(void) rhport;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ if (en) {
+ USBHSD->INT_EN |= USBHS_SOF_ACT_EN;
+ } else {
+ USBHSD->INT_EN &= ~(USBHS_SOF_ACT_EN);
+ }
+}
+
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
(void)rhport;
@@ -332,7 +342,10 @@ void dcd_int_handler(uint8_t rhport) {
xfer_ctl_t *xfer = XFER_CTL_BASE(end_num, tu_edpt_dir(endp));
- if (rx_token == PID_OUT) {
+ if (rx_token == PID_SOF) {
+ dcd_event_sof(rhport, USBHSD->FRAME_NO, true);
+
+ } else if (rx_token == PID_OUT) {
uint16_t rx_len = USBHSD->RX_LEN;
receive_packet(xfer, rx_len);