summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZixun LI <[email protected]>2026-05-23 21:12:30 +0200
committerGitHub <[email protected]>2026-05-23 21:12:30 +0200
commit65fb8dfbadbb0b5970a1e984c290b5d6a5bcb315 (patch)
tree070990b12b8bf13b27873dad44515a04653aae70 /src
parent4c87db341e4af7d53ce9cbbdf693593a520dc538 (diff)
parent311fb46eb2f963254af6ab206b74828a0ba0273c (diff)
Merge pull request #3622 from mickabrig7/master
fix(dcd_ch32_usbfs): fix dropped bulk OUT packets by properly re-arming EP_RX_CTRL state
Diffstat (limited to 'src')
-rw-r--r--src/common/tusb_mcu.h10
-rw-r--r--src/portable/wch/dcd_ch32_usbfs.c199
-rw-r--r--src/portable/wch/dcd_ch32_usbhs.c434
3 files changed, 348 insertions, 295 deletions
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index c85ade4d0..413ac4850 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -616,10 +616,6 @@
#define CFG_TUH_WCH_USBIP_USBFS 1
#endif
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_CH32
- #define CFG_TUSB_FSDEV_PMA_SIZE 512u
-
// default to FSDEV for device
#if !defined(CFG_TUD_WCH_USBIP_USBFS)
#define CFG_TUD_WCH_USBIP_USBFS 0
@@ -629,6 +625,12 @@
#define CFG_TUD_WCH_USBIP_FSDEV (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
#endif
+ #if CFG_TUD_WCH_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_CH32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
+ #endif
+
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_CH32V307)
diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c
index 5cd25e33e..af0f17785 100644
--- a/src/portable/wch/dcd_ch32_usbfs.c
+++ b/src/portable/wch/dcd_ch32_usbfs.c
@@ -29,29 +29,29 @@
#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUD_WCH_USBIP_USBFS
-#include "device/dcd.h"
-#include "ch32_usbfs_reg.h"
+ #include "device/dcd.h"
+ #include "ch32_usbfs_reg.h"
-/* private defines */
-#define EP_MAX (8)
+ /* private defines */
+ #define EP_MAX (8)
-#define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep])
-#define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep])
-#define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep])
-#define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep])
+ #define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep])
+ #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep])
+ #define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep])
+ #define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep])
/* private data */
struct usb_xfer {
- bool valid;
- uint8_t* buffer;
- size_t len;
- size_t processed_len;
- size_t max_size;
+ bool valid;
+ uint8_t *buffer;
+ size_t len;
+ size_t processed_len;
+ size_t max_size;
};
static struct {
- bool ep0_tog;
- bool isochronous[EP_MAX];
+ bool ep0_tog;
+ bool isochronous[EP_MAX];
struct usb_xfer xfer[EP_MAX][2];
TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64];
TU_ATTR_ALIGNED(4) struct {
@@ -64,7 +64,7 @@ static struct {
/* private helpers */
static void update_in(uint8_t rhport, uint8_t ep, bool force) {
- struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_IN];
+ struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_IN];
if (xfer->valid) {
if (force || xfer->len) {
size_t len = TU_MIN(xfer->max_size, xfer->len);
@@ -82,7 +82,7 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) {
EP_TX_LEN(ep) = len;
if (ep == 0) {
EP_TX_CTRL(0) = USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0);
- data.ep0_tog = !data.ep0_tog;
+ data.ep0_tog = !data.ep0_tog;
} else if (data.isochronous[ep]) {
EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NYET;
} else {
@@ -90,16 +90,18 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) {
}
} else {
xfer->valid = false;
- EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK;
- dcd_event_xfer_complete(
- rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len,
- XFER_RESULT_SUCCESS, true);
+ if (ep == 0) {
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0);
+ } else if (!data.isochronous[ep]) {
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK;
+ }
+ dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, XFER_RESULT_SUCCESS, true);
}
}
}
static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) {
- struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_OUT];
+ struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT];
if (xfer->valid) {
size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len));
if (ep == 3) {
@@ -117,25 +119,39 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) {
}
if (ep == 0) {
- EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_NAK;
+ } else {
+ uint8_t rx_res =
+ data.isochronous[ep] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK);
+ EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res;
}
}
}
+static void reset_ep_ctrls(void) {
+ for (uint8_t ep = 1; ep < EP_MAX; ep++) {
+ EP_DMA(ep) = (uint32_t)&data.buffer[ep][0];
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NYET;
+ EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET;
+ }
+ EP_DMA(3) = (uint32_t)&data.ep3_buffer.out[0];
+}
+
/* public functions */
-bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rh_init;
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) {
+ (void)rh_init;
// init registers
USBOTG_FS->BASE_CTRL = USBFS_CTRL_SYS_CTRL | USBFS_CTRL_INT_BUSY | USBFS_CTRL_DMA_EN;
USBOTG_FS->UDEV_CTRL = USBFS_UDEV_CTRL_PD_DIS | USBFS_UDEV_CTRL_PORT_EN;
- USBOTG_FS->DEV_ADDR = 0x00;
+ USBOTG_FS->DEV_ADDR = 0x00;
USBOTG_FS->INT_FG = 0xFF;
USBOTG_FS->INT_EN = USBFS_INT_EN_BUS_RST | USBFS_INT_EN_TRANSFER | USBFS_INT_EN_SUSPEND;
// setup endpoint 0
- EP_DMA(0) = (uint32_t) &data.buffer[0][0];
- EP_TX_LEN(0) = 0;
+ EP_DMA(0) = (uint32_t)&data.buffer[0][0];
+ EP_TX_LEN(0) = 0;
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
@@ -143,15 +159,9 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
USBOTG_FS->UEP4_1_MOD = 0xCC;
USBOTG_FS->UEP2_3_MOD = 0xCC;
USBOTG_FS->UEP5_6_MOD = 0xCC;
- USBOTG_FS->UEP7_MOD = 0x0C;
+ USBOTG_FS->UEP7_MOD = 0x0C;
- for (uint8_t ep = 1; ep < EP_MAX; ep++) {
- EP_DMA(ep) = (uint32_t) &data.buffer[ep][0];
- EP_TX_LEN(ep) = 0;
- EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
- EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK;
- }
- EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0];
+ reset_ep_ctrls();
dcd_connect(rhport);
@@ -159,15 +169,15 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
}
void dcd_int_handler(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
uint8_t status = USBOTG_FS->INT_FG;
if (status & USBFS_INT_FG_TRANSFER) {
- uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST);
- uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST);
+ uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST);
+ uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST);
+ uint16_t rx_len = USBOTG_FS->RX_LEN;
switch (token) {
case PID_OUT: {
- uint16_t rx_len = USBOTG_FS->RX_LEN;
update_out(rhport, ep, rx_len);
break;
}
@@ -179,24 +189,30 @@ void dcd_int_handler(uint8_t rhport) {
case PID_SETUP:
// setup clears stall
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
- EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+ data.ep0_tog = true;
+
+ const tusb_control_request_t *setup = (const tusb_control_request_t *)&data.buffer[0][TUSB_DIR_OUT][0];
+ EP_RX_CTRL(0) = (setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK;
- data.ep0_tog = true;
dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true);
break;
}
USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER;
} else if (status & USBFS_INT_FG_BUS_RST) {
- data.ep0_tog = true;
+ data.ep0_tog = true;
data.xfer[0][TUSB_DIR_OUT].max_size = 64;
- data.xfer[0][TUSB_DIR_IN].max_size = 64;
+ data.xfer[0][TUSB_DIR_IN].max_size = 64;
- //dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true);
- dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true);
+ // dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL,
+ // true);
+ dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL,
+ true);
USBOTG_FS->DEV_ADDR = 0x00;
- EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+
+ reset_ep_ctrls();
USBOTG_FS->INT_FG = USBFS_INT_FG_BUS_RST;
} else if (status & USBFS_INT_FG_SUSPEND) {
@@ -207,71 +223,62 @@ void dcd_int_handler(uint8_t rhport) {
}
void dcd_int_enable(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
NVIC_EnableIRQ(USBHD_IRQn);
}
void dcd_int_disable(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
NVIC_DisableIRQ(USBHD_IRQn);
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
- (void) dev_addr;
+ (void)dev_addr;
dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); // zlp status response
}
void dcd_remote_wakeup(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
// TODO optional
}
void dcd_connect(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
USBOTG_FS->BASE_CTRL |= USBFS_CTRL_DEV_PUEN;
}
void dcd_disconnect(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
USBOTG_FS->BASE_CTRL &= ~USBFS_CTRL_DEV_PUEN;
}
void dcd_sof_enable(uint8_t rhport, bool en) {
- (void) rhport;
- (void) en;
+ (void)rhport;
+ (void)en;
// TODO implement later
}
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
- (void) rhport;
+void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *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) {
- USBOTG_FS->DEV_ADDR = (uint8_t) request->wValue;
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ USBOTG_FS->DEV_ADDR = (uint8_t)request->wValue;
}
- EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
- EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
}
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
- (void) rhport;
- uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress);
+bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) {
+ (void)rhport;
+ uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress);
uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress);
TU_ASSERT(ep < EP_MAX);
- data.isochronous[ep] = desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS;
data.xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep);
if (ep != 0) {
if (dir == TUSB_DIR_OUT) {
- if (data.isochronous[ep]) {
- EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET;
- } else {
- EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_ACK;
- }
+ EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_T_RES_NAK;
} else {
- EP_TX_LEN(ep) = 0;
EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
}
}
@@ -279,52 +286,60 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
}
void dcd_edpt_close_all(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
// TODO optional
}
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
- (void) rhport;
- (void) ep_addr;
+ (void)rhport;
+ (void)ep_addr;
(void)largest_packet_size;
- return false;
+ uint8_t ep = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+
+ data.isochronous[ep] = true;
+ data.xfer[ep][dir].max_size = largest_packet_size;
+ return true;
}
bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) {
(void)rhport;
(void)desc_ep;
- return false;
+ return true;
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) {
- (void) is_isr;
- (void) rhport;
- uint8_t ep = tu_edpt_number(ep_addr);
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) {
+ (void)is_isr;
+ (void)rhport;
+ uint8_t ep = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr);
- struct usb_xfer* xfer = &data.xfer[ep][dir];
+ struct usb_xfer *xfer = &data.xfer[ep][dir];
dcd_int_disable(rhport);
- xfer->valid = true;
- xfer->buffer = buffer;
- xfer->len = total_bytes;
+ xfer->valid = true;
+ xfer->buffer = buffer;
+ xfer->len = total_bytes;
xfer->processed_len = 0;
dcd_int_enable(rhport);
if (dir == TUSB_DIR_IN) {
update_in(rhport, ep, true);
+ } else {
+ uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : USBFS_EP_R_RES_ACK;
+ EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res;
}
return true;
}
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
- (void) rhport;
- uint8_t ep = tu_edpt_number(ep_addr);
+ (void)rhport;
+ uint8_t ep = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr);
if (ep == 0) {
if (dir == TUSB_DIR_OUT) {
EP_RX_CTRL(0) = USBFS_EP_R_RES_STALL;
} else {
- EP_TX_LEN(0) = 0;
+ EP_TX_LEN(0) = 0;
EP_TX_CTRL(0) = USBFS_EP_T_RES_STALL;
}
} else {
@@ -337,8 +352,8 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
- (void) rhport;
- uint8_t ep = tu_edpt_number(ep_addr);
+ (void)rhport;
+ uint8_t ep = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr);
if (ep == 0) {
if (dir == TUSB_DIR_OUT) {
@@ -346,9 +361,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
}
} else {
if (dir == TUSB_DIR_OUT) {
- EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~(USBFS_EP_R_RES_MASK | USBFS_EP_R_TOG)) | USBFS_EP_R_RES_ACK;
+ EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK;
} else {
- EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK | USBFS_EP_T_TOG)) | USBFS_EP_T_RES_NAK;
+ EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
}
}
}
diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c
index 11734de37..a6dd5bb79 100644
--- a/src/portable/wch/dcd_ch32_usbhs.c
+++ b/src/portable/wch/dcd_ch32_usbhs.c
@@ -24,7 +24,6 @@
*
* This file is part of the TinyUSB stack.
*/
-
#include "tusb_option.h"
#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && defined(CFG_TUD_WCH_USBIP_USBHS) && \
@@ -37,138 +36,182 @@
#define EP_MAX 16
typedef struct {
- uint8_t* buffer;
+ uint8_t *buffer;
uint16_t total_len;
uint16_t queued_len;
uint16_t max_size;
- bool is_last_packet;
- bool is_iso;
+ bool is_iso;
+ bool valid;
} xfer_ctl_t;
-typedef enum {
- EP_RESPONSE_ACK,
- EP_RESPONSE_NAK,
-} ep_response_list_t;
-
-#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
+ #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
static xfer_ctl_t xfer_status[EP_MAX][2];
-#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2)
-#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4)
-#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4)
-#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2)
+ #define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2)
+ #define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4)
+ #define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4)
+ #define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2)
-#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1))
-#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
+ #define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1))
+ #define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
/* Endpoint Buffer */
TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE];
+static bool ep0_tog;
+static bool ep_data_tog[EP_MAX][2];
-static void ep_set_response_and_toggle(uint8_t ep_num, tusb_dir_t ep_dir, ep_response_list_t response_type) {
+static void set_ep_toggle(uint8_t ep_num, tusb_dir_t ep_dir, bool data1) {
if (ep_dir == TUSB_DIR_IN) {
- uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_T_RES_ACK : USBHS_EP_T_RES_NAK;
- if (ep_num == 0) {
- if (response_type == EP_RESPONSE_ACK) {
- if (EP_TX_LEN(ep_num) == 0) {
- EP_TX_CTRL(ep_num) |= USBHS_EP_T_TOG_1;
- } else {
- EP_TX_CTRL(ep_num) ^= USBHS_EP_T_TOG_1;
- }
- }
- }
- if (xfer_status[ep_num][TUSB_DIR_IN].is_iso == true) {
- EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG;
- } else {
- EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | response;
- }
+ EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_TOG_MASK)) |
+ (data1 ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
} else {
- uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK;
- if (ep_num == 0) {
- if (response_type == EP_RESPONSE_ACK) {
- if (xfer_status[ep_num][TUSB_DIR_OUT].queued_len == 0) {
- EP_RX_CTRL(ep_num) |= USBHS_EP_R_TOG_1;
- }
- } else {
- EP_RX_CTRL(ep_num) ^= USBHS_EP_R_TOG_1;
- }
- }
- EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | response;
+ EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_TOG_MASK)) |
+ (data1 ? USBHS_EP_R_TOG_1 : USBHS_EP_R_TOG_0);
}
}
-static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer) {
- if (ep_dir == TUSB_DIR_IN) {
- uint16_t remaining = xfer->total_len - xfer->queued_len;
- uint16_t next_tx_size = TU_MIN(remaining, xfer->max_size);
+static void queue_in_packet(uint8_t ep_num, xfer_ctl_t* xfer) {
+ uint16_t remaining = xfer->total_len - xfer->queued_len;
+ uint16_t tx_len = TU_MIN(remaining, xfer->max_size);
+
+ if (ep_num == 0) {
+ memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], tx_len);
+ } else {
+ EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
+ }
+
+ EP_TX_LEN(ep_num) = tx_len;
+ xfer->queued_len += tx_len;
+
+ if (ep_num == 0) {
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_ACK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
+ ep0_tog = !ep0_tog;
+ } else if (xfer->is_iso) {
+ EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NYET;
+ } else {
+ set_ep_toggle(ep_num, TUSB_DIR_IN, ep_data_tog[ep_num][TUSB_DIR_IN]);
+ EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
+ }
+}
+
+static void queue_out_packet(uint8_t ep_num, xfer_ctl_t* xfer) {
+ uint16_t remaining = xfer->total_len - xfer->queued_len;
+ uint16_t rx_len = TU_MIN(remaining, xfer->max_size);
+ if (ep_num > 0) {
+ EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
+ EP_RX_MAX_LEN(ep_num) = rx_len;
+ }
+
+ if (ep_num == 0) {
+ EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_ACK;
+ } else if (xfer->is_iso) {
+ EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NYET;
+ } else {
+ set_ep_toggle(ep_num, TUSB_DIR_OUT, ep_data_tog[ep_num][TUSB_DIR_OUT]);
+ EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_ACK;
+ }
+}
+
+static void update_in(uint8_t rhport, uint8_t ep_num, bool force) {
+ xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, TUSB_DIR_IN);
+ if (!xfer->valid) {
+ return;
+ }
+
+ if (!force && ep_num != 0 && !xfer->is_iso) {
+ ep_data_tog[ep_num][TUSB_DIR_IN] = !ep_data_tog[ep_num][TUSB_DIR_IN];
+ }
+
+ if (force || (xfer->total_len > xfer->queued_len)) {
+ queue_in_packet(ep_num, xfer);
+ } else {
+ xfer->valid = false;
if (ep_num == 0) {
- memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], next_tx_size);
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
} else {
- EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
+ EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK;
}
+ dcd_event_xfer_complete(rhport, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ }
+}
- EP_TX_LEN(ep_num) = next_tx_size;
- xfer->queued_len += next_tx_size;
- if (xfer->queued_len == xfer->total_len) {
- xfer->is_last_packet = true;
- }
- if (xfer->is_iso == true) {
- /* Enable EP to generate ISA_ACT interrupt */
- USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num);
- }
- } else { /* TUSB_DIR_OUT */
- uint16_t left_to_receive = xfer->total_len - xfer->queued_len;
- uint16_t max_possible_rx_size = TU_MIN(xfer->max_size, left_to_receive);
+static void update_out(uint8_t rhport, uint8_t ep_num, uint16_t rx_len) {
+ xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, TUSB_DIR_OUT);
+ if (!xfer->valid) {
+ return;
+ }
+
+ uint16_t remaining = xfer->total_len - xfer->queued_len;
+ uint16_t len = TU_MIN(rx_len, TU_MIN(remaining, xfer->max_size));
+
+ if (ep_num == 0) {
+ memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, len);
+ }
+
+ xfer->queued_len += len;
+
+ if (ep_num != 0 && !xfer->is_iso) {
+ ep_data_tog[ep_num][TUSB_DIR_OUT] = !ep_data_tog[ep_num][TUSB_DIR_OUT];
+ }
- if (max_possible_rx_size == left_to_receive) {
- xfer->is_last_packet = true;
+ if ((xfer->queued_len == xfer->total_len) || (len < xfer->max_size)) {
+ xfer->valid = false;
+ if (ep_num == 0) {
+ EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK;
}
+ dcd_event_xfer_complete(rhport, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ }
- if (ep_num > 0) {
- EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
- EP_RX_MAX_LEN(ep_num) = max_possible_rx_size;
+ if (ep_num != 0) {
+ if (xfer->valid) {
+ queue_out_packet(ep_num, xfer);
+ } else {
+ uint8_t rx_res = xfer->is_iso ? USBHS_EP_R_RES_NYET : USBHS_EP_R_RES_NAK;
+ EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | rx_res;
}
}
- ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK);
}
-bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rhport;
- (void) rh_init;
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) {
+ (void)rhport;
+ (void)rh_init;
memset(&xfer_status, 0, sizeof(xfer_status));
+ memset(ep_data_tog, 0, sizeof(ep_data_tog));
+ ep0_tog = true;
USBHSD->HOST_CTRL = 0x00;
USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
USBHSD->CONTROL = 0;
-#if TUD_OPT_HIGH_SPEED
+ #if TUD_OPT_HIGH_SPEED
USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
-#else
- #error OPT_MODE_FULL_SPEED not currently supported on CH32
+ #else
+ #error OPT_MODE_FULL_SPEED not currently supported on CH32
USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
-#endif
+ #endif
USBHSD->INT_EN = 0;
- USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN | USBHS_ISO_ACT_EN;
+ USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN;
USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
- USBHSD->ENDP_TYPE = 0x00;
- USBHSD->BUF_MODE = 0x00;
+ USBHSD->ENDP_TYPE = 0x00;
+ USBHSD->BUF_MODE = 0x00;
for (int ep = 0; ep < EP_MAX; ep++) {
- EP_TX_LEN(ep) = 0;
- EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
- EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ EP_RX_CTRL(ep) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0;
EP_RX_MAX_LEN(ep) = 0;
}
- USBHSD->UEP0_DMA = (uint32_t) ep0_buffer;
- USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE;
+ USBHSD->UEP0_DMA = (uint32_t)ep0_buffer;
+ USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE;
xfer_status[0][TUSB_DIR_OUT].max_size = CFG_TUD_ENDPOINT0_SIZE;
- xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE;
+ xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE;
USBHSD->DEV_AD = 0;
USBHSD->CONTROL |= USBHS_DEV_PU_EN;
@@ -177,22 +220,24 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
}
void dcd_int_enable(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
NVIC_EnableIRQ(USBHS_IRQn);
}
void dcd_int_disable(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
NVIC_DisableIRQ(USBHS_IRQn);
}
void dcd_edpt_close_all(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
+
+ memset(ep_data_tog, 0, sizeof(ep_data_tog));
for (size_t ep = 1; ep < EP_MAX; ep++) {
- EP_TX_LEN(ep) = 0;
- EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
- EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ EP_RX_CTRL(ep) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0;
EP_RX_MAX_LEN(ep) = 0;
}
@@ -201,18 +246,18 @@ void dcd_edpt_close_all(uint8_t rhport) {
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
- (void) dev_addr;
+ (void)dev_addr;
// Response with zlp status
dcd_edpt_xfer(rhport, 0x80, NULL, 0, false);
}
void dcd_remote_wakeup(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
}
void dcd_sof_enable(uint8_t rhport, bool en) {
- (void) rhport;
+ (void)rhport;
if (en) {
USBHSD->INT_EN |= USBHS_SOF_ACT_EN;
} else {
@@ -220,24 +265,19 @@ void dcd_sof_enable(uint8_t rhport, bool en) {
}
}
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
- (void) rhport;
-
+void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *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) {
- USBHSD->DEV_AD = (uint8_t) request->wValue;
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ USBHSD->DEV_AD = (uint8_t)request->wValue;
}
-
- EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
- EP_RX_CTRL(0) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0;
}
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
- (void) rhport;
+bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) {
+ (void)rhport;
- uint8_t const ep_num = tu_edpt_number(desc_edpt->bEndpointAddress);
- tusb_dir_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
+ const uint8_t ep_num = tu_edpt_number(desc_edpt->bEndpointAddress);
+ const tusb_dir_t dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
TU_ASSERT(ep_num < EP_MAX);
@@ -245,13 +285,14 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
return true;
}
- xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir);
- xfer->max_size = tu_edpt_packet_size(desc_edpt);
+ xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, dir);
+ xfer->max_size = tu_edpt_packet_size(desc_edpt);
+ ep_data_tog[ep_num][dir] = false;
xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
if (dir == TUSB_DIR_OUT) {
USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << ep_num);
- EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0;
if (xfer->is_iso == true) {
USBHSD->ENDP_TYPE |= (USBHS_EP0_R_TYP << ep_num);
}
@@ -259,31 +300,31 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
} else {
if (xfer->is_iso == true) {
USBHSD->ENDP_TYPE |= (USBHS_EP0_T_TYP << ep_num);
- } else {
- /* Enable all types except Isochronous to avoid ISO_ACT interrupt generation */
- USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num);
}
- EP_TX_LEN(ep_num) = 0;
- EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num);
+ EP_TX_LEN(ep_num) = 0;
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
}
return true;
}
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
- (void) rhport;
+ (void)rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
if (dir == TUSB_DIR_OUT) {
- EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0;
EP_RX_MAX_LEN(ep_num) = 0;
+ ep_data_tog[ep_num][TUSB_DIR_OUT] = false;
USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num);
USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num);
- } else { // TUSB_DIR_IN
- EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
- EP_TX_LEN(ep_num) = 0;
+ } else { // TUSB_DIR_IN
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ EP_TX_LEN(ep_num) = 0;
+ ep_data_tog[ep_num][TUSB_DIR_IN] = false;
USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num);
USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num);
}
@@ -305,128 +346,120 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
#endif
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
- (void) rhport;
+ (void)rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
if (dir == TUSB_DIR_OUT) {
EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_STALL;
} else {
- EP_TX_LEN(0) = 0;
+ EP_TX_LEN(0) = 0;
EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_STALL;
}
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
- (void) rhport;
+ (void)rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
if (dir == TUSB_DIR_OUT) {
- EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0;
+ ep_data_tog[ep_num][TUSB_DIR_OUT] = false;
} else {
- EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_R_RES_NAK;
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ ep_data_tog[ep_num][TUSB_DIR_IN] = false;
}
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) {
- (void) is_isr;
- (void) rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) {
+ (void)is_isr;
+ (void)rhport;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+
+ xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, dir);
+ xfer->buffer = buffer;
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
+ xfer->valid = true;
- xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir);
- xfer->buffer = buffer;
- xfer->total_len = total_bytes;
- xfer->queued_len = 0;
- xfer->is_last_packet = false;
+ if (ep_num == 0 && dir == TUSB_DIR_OUT) {
+ if (total_bytes == 0) {
+ EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_TOG_MASK)) | USBHS_EP_R_TOG_1;
+ } else {
+ EP_RX_CTRL(0) ^= USBHS_EP_R_TOG_1;
+ }
+ }
- xfer_data_packet(ep_num, dir, xfer);
+ if (dir == TUSB_DIR_IN) {
+ update_in(rhport, ep_num, true);
+ } else {
+ queue_out_packet(ep_num, xfer);
+ }
return true;
}
void dcd_int_handler(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
- uint8_t int_flag = USBHSD->INT_FG;
+ uint8_t int_flag = USBHSD->INT_FG;
uint8_t int_status = USBHSD->INT_ST;
- if (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)) {
- uint8_t const token = int_status & MASK_UIS_TOKEN;
+ if (int_flag & USBHS_TRANSFER_FLAG) {
+ const uint8_t token = int_status & MASK_UIS_TOKEN;
+ const uint8_t ep_num = int_status & MASK_UIS_ENDP;
+ const uint16_t len = USBHSD->RX_LEN;
if (token == USBHS_TOKEN_PID_SOF) {
uint32_t frame_count = USBHSD->FRAME_NO & USBHS_FRAME_NO_NUM_MASK;
dcd_event_sof(rhport, frame_count, true);
- }else {
- uint8_t const ep_num = int_status & MASK_UIS_ENDP;
- tusb_dir_t const ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT;
- uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir);
- xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, ep_dir);
-
- if (token == USBHS_TOKEN_PID_OUT) {
- uint16_t rx_len = USBHSD->RX_LEN;
-
- if (ep_num == 0) {
- memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, rx_len);
- }
-
- xfer->queued_len += rx_len;
- if (rx_len < xfer->max_size) {
- xfer->is_last_packet = true;
- }
- } else if (token == USBHS_TOKEN_PID_IN) {
- if (xfer->is_iso && xfer->is_last_packet) {
- /* Disable EP to avoid ISO_ACT interrupt generation */
- USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num);
- } else {
- // Do nothing, no need to update xfer->is_last_packet, it is already updated in xfer_data_packet
- }
- }
-
- if (xfer->is_last_packet == true) {
- ep_set_response_and_toggle(ep_num, ep_dir, EP_RESPONSE_NAK);
- dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- } else {
- /* prepare next part of packet to xref */
- xfer_data_packet(ep_num, ep_dir, xfer);
- }
+ } else if (token == USBHS_TOKEN_PID_OUT) {
+ update_out(rhport, ep_num, len);
+ } else if (token == USBHS_TOKEN_PID_IN) {
+ update_in(rhport, ep_num, false);
}
-
- USBHSD->INT_FG = (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)); /* Clear flag */
+ USBHSD->INT_FG = (int_flag & USBHS_TRANSFER_FLAG); /* Clear flag */
} else if (int_flag & USBHS_SETUP_FLAG) {
- ep_set_response_and_toggle(0, TUSB_DIR_IN, EP_RESPONSE_NAK);
- ep_set_response_and_toggle(0, TUSB_DIR_OUT, EP_RESPONSE_NAK);
+ tusb_control_request_t const* setup =
+ (tusb_control_request_t const*) ep0_buffer;
+ ep0_tog = true;
+ EP_RX_CTRL(0) = (setup->wLength == 0) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK;
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK;
+
dcd_event_setup_received(0, ep0_buffer, true);
USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
} else if (int_flag & USBHS_BUS_RST_FLAG) {
// TODO CH32 does not detect actual speed at this time (should be known at end of reset)
// This interrupt probably triggered at start of bus reset
-// tusb_speed_t actual_speed;
-// switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){
-// case USBHS_SPEED_TYPE_HIGH:
-// actual_speed = TUSB_SPEED_HIGH;
-// break;
-// case USBHS_SPEED_TYPE_FULL:
-// actual_speed = TUSB_SPEED_FULL;
-// break;
-// case USBHS_SPEED_TYPE_LOW:
-// actual_speed = TUSB_SPEED_LOW;
-// break;
-// default:
-// TU_ASSERT(0,);
-// break;
-// }
-// dcd_event_bus_reset(0, actual_speed, true);
+ // tusb_speed_t actual_speed;
+ // switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){
+ // case USBHS_SPEED_TYPE_HIGH:
+ // actual_speed = TUSB_SPEED_HIGH;
+ // break;
+ // case USBHS_SPEED_TYPE_FULL:
+ // actual_speed = TUSB_SPEED_FULL;
+ // break;
+ // case USBHS_SPEED_TYPE_LOW:
+ // actual_speed = TUSB_SPEED_LOW;
+ // break;
+ // default:
+ // TU_ASSERT(0,);
+ // break;
+ // }
+ // dcd_event_bus_reset(0, actual_speed, true);
dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true);
USBHSD->DEV_AD = 0;
- EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
- EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ memset(ep_data_tog, 0, sizeof(ep_data_tog));
+ ep0_tog = true;
+ EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
USBHSD->INT_FG = USBHS_BUS_RST_FLAG; /* Clear flag */
} else if (int_flag & USBHS_SUSPEND_FLAG) {
@@ -434,6 +467,9 @@ void dcd_int_handler(uint8_t rhport) {
dcd_event_handler(&event, true);
USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
+ } else {
+ // Unhandled interrupt
+ USBHSD->INT_FG = int_flag; /* Clear all flags */
}
}
#endif