summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-04-01 15:51:31 +0700
committerhathach <[email protected]>2026-04-01 17:47:01 +0700
commit78d34d5b6488d7129530461ce1865a33a946e698 (patch)
tree6c81065a6f0624e265bf581c1c7a8f650a72b2b4 /src
parent9ac343a0471b03b1a76166c72347e7fdbf2c4800 (diff)
reduce code size, use state to replace active + pending
Diffstat (limited to 'src')
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c13
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c106
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c78
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h27
4 files changed, 103 insertions, 121 deletions
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index 8814f95d1..ca03ebf8a 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -111,7 +111,6 @@ static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
// double buffered Bulk endpoint
if (transfer_type == TUSB_XFER_BULK) {
size *= 2u;
-
#if CFG_TUSB_RP2_ERRATA_E15
if (dir == TUSB_DIR_IN) {
ep->e15_bulk_in = true;
@@ -195,7 +194,7 @@ TU_ATTR_ALWAYS_INLINE static inline void reset_ep0(void) {
for (uint8_t dir = 0; dir < 2; dir++) {
struct hw_endpoint *ep = hw_endpoint_get(0, dir);
ep->next_pid = 1u;
- if (ep->active) {
+ if (ep->state == EPSTATE_ACTIVE) {
hw_endpoint_abort_xfer(ep); // Abort any pending transfer per USB specs
}
}
@@ -254,12 +253,12 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
struct hw_endpoint *ep = hw_endpoint_get(i, TUSB_DIR_IN);
// Active Bulk IN endpoint requires SOF
- if (ep->e15_bulk_in && ep->active) {
+ if (ep->e15_bulk_in && ep->state == EPSTATE_ACTIVE) {
keep_sof_alive = true;
hw_endpoint_lock_update(ep, 1);
- if (ep->pending) {
- ep->pending = 0;
+ if (ep->state == EPSTATE_PENDING) {
+ ep->state = EPSTATE_ACTIVE;
io_rw_32 *buf_reg32 = get_buf_ctrl(i, TUSB_DIR_IN);
io_rw_16 *buf_reg16 = (io_rw_16 *)buf_reg32;
@@ -276,7 +275,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
if (buf0_idle && buf1_idle) {
// both are idle, start fresh
io_rw_32 *ep_reg = get_ep_ctrl(i, TUSB_DIR_IN);
- rp2usb_buffer_start(ep, ep_reg, buf_reg32, false, false);
+ rp2usb_buffer_start(ep, ep_reg, buf_reg32, false);
} else if (buf0_idle) {
uint16_t buf0 = bufctrl_prepare16(ep, ep->dpram_buf, false);
bufctrl_write16(buf_reg16, buf0);
@@ -501,7 +500,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *ep_desc)
struct hw_endpoint *ep = hw_endpoint_get(epnum, dir);
TU_ASSERT(ep->dpram_buf != NULL); // must be inited and allocated previously
- if (ep->active) {
+ if (ep->state == EPSTATE_ACTIVE) {
hw_endpoint_abort_xfer(ep); // abort any pending transfer
}
ep->max_packet_size = ep_desc->wMaxPacketSize;
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index fb1676f50..02a4e055e 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -66,6 +66,10 @@ enum {
SIE_CTRL_SPEED_FULL = 2,
};
+enum {
+ EPX_CTRL_DEFAULT = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER | offsetof(usb_host_dpram_t, epx_data)
+};
+
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@@ -123,7 +127,7 @@ TU_ATTR_ALWAYS_INLINE static inline void sie_stop_xfer(void) {
while (usb_hw->sie_ctrl & USB_SIE_CTRL_STOP_TRANS_BITS) {}
}
-TU_ATTR_ALWAYS_INLINE static inline void sie_start_xfer(bool send_setup, bool is_rx, bool need_pre) {
+static void __tusb_irq_path_func(sie_start_xfer)(bool send_setup, bool is_rx, bool need_pre) {
uint32_t sie_ctrl = usb_hw->sie_ctrl & SIE_CTRL_BASE_MASK; // preserve base bits
if (send_setup) {
sie_ctrl |= USB_SIE_CTRL_SEND_SETUP_BITS;
@@ -135,31 +139,16 @@ TU_ATTR_ALWAYS_INLINE static inline void sie_start_xfer(bool send_setup, bool is
}
// START_TRANS bit on SIE_CTRL has the same behavior as the AVAILABLE bit
- // described in RP2040 Datasheet, release 2.1, section "4.1.2.5.1. Concurrent access".
+ // described in RP2040 Datasheet, release 2.1, section "4.1.2.5.1. Concurrent access".!
// We write everything except the START_TRANS bit first, then wait some cycles.
usb_hw->sie_ctrl = sie_ctrl;
busy_wait_at_least_cycles(12);
usb_hw->sie_ctrl = sie_ctrl | USB_SIE_CTRL_START_TRANS_BITS;
}
-TU_ATTR_ALWAYS_INLINE static inline void epx_start_xfer(hw_endpoint_t *ep, bool is_setup) {
- usb_hw->dev_addr_ctrl = (uint32_t)(ep->dev_addr | (tu_edpt_number(ep->ep_addr) << USB_ADDR_ENDP_ENDPOINT_LSB));
- sie_start_xfer(is_setup, tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN, ep->need_pre);
-}
-
// prepare epx_ctrl register for new endpoint
-TU_ATTR_ALWAYS_INLINE static inline void epx_ctrl_prepare(hw_endpoint_t *ep) {
- // RP2040-E4: USB host writes status to the upper half of buffer control in single buffered mode.
- // The buffer selector toggles even in single-buffered mode, so the previous transfer's status
- // may have been written to BUF1 half, leaving BUF0 with a stale AVAILABLE bit. Clear it here.
- #if defined(PICO_RP2040) && PICO_RP2040 == 1
- usbh_dpram->epx_buf_ctrl = 0;
- #endif
-
- // ep control
- const uint32_t ep_ctrl = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER |
- ((uint32_t)ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->dpram_buf);
- usbh_dpram->epx_ctrl = ep_ctrl;
+TU_ATTR_ALWAYS_INLINE static inline void epx_ctrl_prepare(uint8_t transfer_type) {
+ usbh_dpram->epx_ctrl = EPX_CTRL_DEFAULT | ((uint32_t)transfer_type << EP_CTRL_BUFFER_TYPE_LSB);
}
// Save buffer context for EPX preemption (called after STOP_TRANS).
@@ -196,31 +185,30 @@ static void __tusb_irq_path_func(epx_save_context)(hw_endpoint_t *ep) {
usbh_dpram->epx_buf_ctrl = 0;
- ep->pending = 1;
- ep->active = false;
+ ep->state = EPSTATE_PENDING;
}
-// All non-interrupt endpoints use shared EPX.
-// Save the current EPX context, mark pending, switch to ep
+// switch epx to new endpoint and start the transfer
static void __tusb_irq_path_func(epx_switch_ep)(hw_endpoint_t *ep) {
- const bool is_setup = (ep->pending == 2);
+ const bool is_setup = (ep->state == EPSTATE_PENDING_SETUP);
- epx = ep; // switch pointer
- ep->pending = 0;
- ep->active = true;
+ epx = ep; // switch pointer
+ ep->state = EPSTATE_ACTIVE;
if (is_setup) {
// panic("new setup \n");
- epx_start_xfer(ep, true);
+ usb_hw->dev_addr_ctrl = ep->dev_addr;
+ sie_start_xfer(true, false, ep->need_pre);
} else {
- io_rw_32 *ep_reg = &usbh_dpram->epx_ctrl;
+ const bool is_rx = (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN);
+ io_rw_32 *ep_reg = &usbh_dpram->epx_ctrl;
io_rw_32 *buf_reg = &usbh_dpram->epx_buf_ctrl;
- epx_ctrl_prepare(ep);
- rp2usb_buffer_start(ep, ep_reg, buf_reg, tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN,
- ep->transfer_type == TUSB_XFER_INTERRUPT);
+ epx_ctrl_prepare(ep->transfer_type);
+ rp2usb_buffer_start(ep, ep_reg, buf_reg, is_rx);
- epx_start_xfer(ep, false);
+ usb_hw->dev_addr_ctrl = (uint32_t)(ep->dev_addr | (tu_edpt_number(ep->ep_addr) << USB_ADDR_ENDP_ENDPOINT_LSB));
+ sie_start_xfer(is_setup, is_rx, ep->need_pre);
}
}
@@ -228,12 +216,12 @@ static void __tusb_irq_path_func(epx_switch_ep)(hw_endpoint_t *ep) {
static hw_endpoint_t *__tusb_irq_path_func(epx_next_pending)(hw_endpoint_t *cur_ep) {
const uint cur_idx = (uint)(cur_ep - &ep_pool[0]);
for (uint i = cur_idx + 1; i < TU_ARRAY_SIZE(ep_pool); i++) {
- if (ep_pool[i].pending) {
+ if (ep_pool[i].state >= EPSTATE_PENDING) {
return &ep_pool[i];
}
}
for (uint i = 0; i < cur_idx; i++) {
- if (ep_pool[i].pending) {
+ if (ep_pool[i].state >= EPSTATE_PENDING) {
return &ep_pool[i];
}
}
@@ -246,7 +234,7 @@ static hw_endpoint_t *__tusb_irq_path_func(epx_next_pending)(hw_endpoint_t *cur_
//--------------------------------------------------------------------+
static void __tusb_irq_path_func(xfer_complete_isr)(hw_endpoint_t *ep, xfer_result_t xfer_result, bool is_more) {
// Mark transfer as done before we tell the tinyusb stack
- uint xferred_len = ep->xferred_len;
+ uint32_t xferred_len = ep->xferred_len;
rp2usb_reset_transfer(ep);
hcd_event_xfer_complete(ep->dev_addr, ep->ep_addr, xferred_len, xfer_result, true);
@@ -345,7 +333,7 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) {
// Even if STOP_TRANS bit is clear, controller maybe in middle of retrying and may re-raise timeout once extra time
// Only handle if epx is active, don't carry more epx transfer since STOP_TRANS is raced and not safe.
- if (epx->active) {
+ if (epx->state == EPSTATE_ACTIVE) {
xfer_complete_isr(epx, XFER_RESULT_FAILED, false);
}
}
@@ -392,7 +380,7 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) {
usb_hw_clear->inte = USB_INTE_HOST_SOF_BITS;
usb_hw->nak_poll = USB_NAK_POLL_RESET;
epx_switch_request = false;
- } else if (epx->active) {
+ } else if (epx->state == EPSTATE_ACTIVE) {
if (epx_switch_request) {
// Second SOF with no transfer completion: endpoint is NAK-retrying, safe to switch.
epx_switch_request = false;
@@ -496,20 +484,14 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
return; // address 0 is for device enumeration
}
- // reset epx if it is currently active with unplugged device
- if (epx->max_packet_size > 0 && epx->dev_addr == dev_addr) {
- // if (epx->active) {
- // // need to abort transfer
- // }
- epx->max_packet_size = 0;
- }
+ rp2usb_critical_enter();
for (size_t i = 0; i < TU_ARRAY_SIZE(ep_pool); i++) {
hw_endpoint_t *ep = &ep_pool[i];
if (ep->dev_addr == dev_addr && ep->max_packet_size > 0) {
- ep->pending = 0; // clear any pending transfer
+ ep->state = EPSTATE_IDLE; // clear any pending transfer
- if (ep->interrupt_num) {
+ if (ep->interrupt_num > 0) {
// disable interrupt endpoint
usb_hw_clear->int_ep_ctrl = TU_BIT(ep->interrupt_num);
usb_hw->int_ep_addr_ctrl[ep->interrupt_num - 1] = 0;
@@ -523,6 +505,8 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
ep->max_packet_size = 0; // mark as unused
}
}
+
+ rp2usb_critical_exit();
}
uint32_t hcd_frame_number(uint8_t rhport) {
@@ -557,16 +541,15 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t
const uint8_t ep_addr = ep_desc->bEndpointAddress;
const uint16_t max_packet_size = tu_edpt_packet_size(ep_desc);
- const uint8_t transfer_type = ep_desc->bmAttributes.xfer;
ep->max_packet_size = max_packet_size;
ep->ep_addr = ep_addr;
ep->dev_addr = dev_addr;
- ep->transfer_type = transfer_type;
+ ep->transfer_type = ep_desc->bmAttributes.xfer;
ep->need_pre = need_pre(dev_addr);
ep->next_pid = 0u;
- if (transfer_type != TUSB_XFER_INTERRUPT) {
+ if (ep->transfer_type != TUSB_XFER_INTERRUPT) {
ep->dpram_buf = usbh_dpram->epx_data;
} else {
// from 15 interrupt endpoints pool
@@ -627,7 +610,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
hw_endpoint_t *ep = edpt_find(dev_addr, ep_addr);
TU_ASSERT(ep);
- if (ep->transfer_type == TUSB_XFER_INTERRUPT) {
+ if (ep->interrupt_num > 0) {
// For interrupt endpoint control and buffer is already configured
// Note: Interrupt is single buffered only
io_rw_32 *ep_reg = dpram_int_ep_ctrl(ep->interrupt_num);
@@ -642,10 +625,10 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
// If EPX is busy with another transfer, mark as pending
rp2usb_critical_enter();
- if (epx->active) {
+ if (epx->state == EPSTATE_ACTIVE) {
ep->user_buf = buffer;
ep->remaining_len = buflen;
- ep->pending = 1;
+ ep->state = EPSTATE_PENDING;
#ifdef HAS_STOP_EPX_ON_NAK
usb_hw_set->nak_poll = USB_NAK_POLL_STOP_EPX_ON_NAK_BITS;
@@ -660,9 +643,10 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
epx = ep;
- epx_ctrl_prepare(ep);
+ epx_ctrl_prepare(ep->transfer_type);
rp2usb_xfer_start(ep, ep_reg, buf_reg, buffer, NULL, buflen); // prepare bufctrl
- epx_start_xfer(ep, false);
+ usb_hw->dev_addr_ctrl = (uint32_t)(ep->dev_addr | (tu_edpt_number(ep->ep_addr) << USB_ADDR_ENDP_ENDPOINT_LSB));
+ sie_start_xfer(false, tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN, ep->need_pre);
}
rp2usb_critical_exit();
}
@@ -688,8 +672,8 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, const uint8_t setup_packet
ep->xferred_len = 0;
// If EPX is busy, mark as pending setup (DPRAM already has the packet)
- if (epx->active) {
- ep->pending = 2; // setup
+ if (epx->state == EPSTATE_ACTIVE) {
+ ep->state = EPSTATE_PENDING_SETUP;
#ifdef HAS_STOP_EPX_ON_NAK
usb_hw_set->nak_poll = USB_NAK_POLL_STOP_EPX_ON_NAK_BITS;
#else
@@ -697,9 +681,11 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, const uint8_t setup_packet
usb_hw_set->inte = USB_INTE_HOST_SOF_BITS;
#endif
} else {
- epx = ep;
- ep->active = true;
- epx_start_xfer(ep, true);
+ epx = ep;
+ ep->state = EPSTATE_ACTIVE;
+
+ usb_hw->dev_addr_ctrl = ep->dev_addr;
+ sie_start_xfer(true, tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN, ep->need_pre);
}
rp2usb_critical_exit();
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index 156be62e4..206da041b 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -101,12 +101,13 @@ void rp2usb_init(void) {
}
void __tusb_irq_path_func(rp2usb_reset_transfer)(hw_endpoint_t *ep) {
- ep->active = false;
- ep->pending = 0;
+ ep->state = EPSTATE_IDLE;
ep->remaining_len = 0;
ep->xferred_len = 0;
ep->user_buf = 0;
+#if CFG_TUD_EDPT_DEDICATED_HWFIFO
ep->is_xfer_fifo = false;
+#endif
}
void __tusb_irq_path_func(bufctrl_write32)(io_rw_32 *buf_reg, uint32_t value) {
@@ -183,14 +184,19 @@ uint16_t __tusb_irq_path_func(bufctrl_prepare16)(hw_endpoint_t *ep, uint8_t *dpr
}
// Start transaction on hw buffer
-void __tusb_irq_path_func(rp2usb_buffer_start)(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, bool is_rx,
- bool force_single) {
+void __tusb_irq_path_func(rp2usb_buffer_start)(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, bool is_rx) {
// always compute and start with buffer 0
uint32_t buf_ctrl = bufctrl_prepare16(ep, ep->dpram_buf, is_rx) | USB_BUF_CTRL_SEL;
// Note: device EP0 does not have an endpoint control register
if (ep_reg != NULL) {
uint32_t ep_ctrl = *ep_reg;
+ #if CFG_TUH_ENABLED
+ const bool force_single = (rp2usb_is_host_mode() && ep->interrupt_num > 0);
+ #else
+ const bool force_single = false;
+ #endif
+
if (ep->remaining_len && !force_single) {
// Use buffer 1 (double buffered) if there is still data
buf_ctrl |= (uint32_t)bufctrl_prepare16(ep, ep->dpram_buf + 64, is_rx) << 16;
@@ -211,8 +217,7 @@ void rp2usb_xfer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, u
(void)ff;
hw_endpoint_lock_update(ep, 1);
- if (ep->active) {
- // TODO: Is this acceptable for interrupt packets?
+ if (ep->state == EPSTATE_ACTIVE) {
TU_LOG(1, "WARN: starting new transfer on already active ep %02X\r\n", ep->ep_addr);
rp2usb_reset_transfer(ep);
}
@@ -220,7 +225,7 @@ void rp2usb_xfer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, u
// Fill in info now that we're kicking off the hw
ep->remaining_len = total_len;
ep->xferred_len = 0;
- ep->active = true;
+ ep->state = EPSTATE_ACTIVE;
#if CFG_TUD_EDPT_DEDICATED_HWFIFO
if (ff != NULL) {
@@ -229,66 +234,50 @@ void rp2usb_xfer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, u
} else
#endif
{
- ep->user_buf = buffer;
+ ep->user_buf = buffer;
+ #if CFG_TUD_EDPT_DEDICATED_HWFIFO
ep->is_xfer_fifo = false;
+ #endif
}
const bool is_host = rp2usb_is_host_mode();
+ const bool is_rx = (is_host == (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN));
- if (ep->future_len > 0) {
- // only on rx endpoint
+ #if CFG_TUD_ENABLED
+ if (!is_host && ep->future_len > 0) {
+ // Device only: previous short-packet abort saved data from the other buffer
const uint8_t future_len = ep->future_len;
memcpy(ep->user_buf, ep->dpram_buf + (ep->future_bufid << 6), future_len);
ep->xferred_len += future_len;
ep->remaining_len -= future_len;
ep->user_buf += future_len;
-
ep->future_len = 0;
ep->future_bufid = 0;
if (ep->remaining_len == 0) {
- // all data has been received, no need to start hw transfer
- ep->active = false;
const uint16_t xferred_len = ep->xferred_len;
rp2usb_reset_transfer(ep);
-
- #if CFG_TUH_ENABLED
- if (is_host) {
- hcd_event_xfer_complete(0, ep->ep_addr, xferred_len, XFER_RESULT_SUCCESS, false);
- }
- #endif
- #if CFG_TUD_ENABLED
- if (!is_host) {
- dcd_event_xfer_complete(0, ep->ep_addr, xferred_len, XFER_RESULT_SUCCESS, false);
- }
- #endif
-
+ dcd_event_xfer_complete(0, ep->ep_addr, xferred_len, XFER_RESULT_SUCCESS, false);
hw_endpoint_lock_update(ep, -1);
return;
}
}
- #if CFG_TUSB_RP2_ERRATA_E15
+ #if CFG_TUSB_RP2_ERRATA_E15
if (ep->e15_bulk_in) {
usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
// skip transfer if we are in critical frame period
if (e15_is_critical_frame_period()) {
- ep->pending = 1;
+ ep->state = EPSTATE_PENDING;
hw_endpoint_lock_update(ep, -1);
return;
}
}
- #endif
+ #endif // CFG_TUSB_RP2_ERRATA_E15
+ #endif // CFG_TUD_ENABLED
- const bool is_rx = (is_host == (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN));
- #if CFG_TUH_ENABLED
- const bool force_single = (is_host && ep->transfer_type == TUSB_XFER_INTERRUPT);
- #else
- const bool force_single = false;
- #endif
-
- rp2usb_buffer_start(ep, ep_reg, buf_reg, is_rx, force_single);
+ rp2usb_buffer_start(ep, ep_reg, buf_reg, is_rx);
hw_endpoint_lock_update(ep, -1);
}
@@ -333,7 +322,7 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_
bool is_rx) {
hw_endpoint_lock_update(ep, 1);
- if (!ep->active) {
+ if (ep->state != EPSTATE_ACTIVE) {
// probably land here due to short packet on rx with double buffered
hw_endpoint_lock_update(ep, -1);
return false;
@@ -394,12 +383,12 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_
if (buf_ctrl16_other & USB_BUF_CTRL_FULL) {
// Data already sent into this buffer. Save it for the next transfer.
// buff_status will be clear by the next run
- if (is_host) {
- // host put future_len pointer at end of epx_data
- } else {
+ #if CFG_TUD_ENABLED
+ if (!is_host) {
ep->future_len = (uint8_t)(buf_ctrl16_other & USB_BUF_CTRL_LEN_MASK);
+ ep->future_bufid = buf_id ^ 1;
}
- ep->future_bufid = buf_id ^ 1;
+ #endif
} else {
ep->next_pid ^= 1u; // roll back pid if aborted
}
@@ -422,10 +411,11 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_
if (!is_done && ep->remaining_len > 0) {
#if CFG_TUSB_RP2_ERRATA_E15
- if (ep->e15_bulk_in && e15_is_critical_frame_period()) {
+ const bool need_e15 = ep->e15_bulk_in;
+ if (need_e15 && e15_is_critical_frame_period()) {
// mark as pending if matches E15 condition
- ep->pending = 1;
- } else if (ep->e15_bulk_in && ep->pending) {
+ ep->state = EPSTATE_PENDING;
+ } else if (need_e15 && ep->state == EPSTATE_PENDING) {
// if already pending, meaning the other buf completes first, don't arm buffer, let SOF handle it
// do nothing
} else
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index 2ba9d018e..8ebc3e3fc 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -32,9 +32,9 @@
// RP2040-E15: USB Device controller will hang if certain bus errors occur during an IN transfer.
#ifndef CFG_TUSB_RP2_ERRATA_E15
#if defined(PICO_RP2040_USB_DEVICE_UFRAME_FIX)
- #define CFG_TUSB_RP2_ERRATA_E15 PICO_RP2040_USB_DEVICE_UFRAME_FIX
+ #define CFG_TUSB_RP2_ERRATA_E15 (CFG_TUD_ENABLED && PICO_RP2040_USB_DEVICE_UFRAME_FIX)
#elif defined(TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX)
- #define CFG_TUSB_RP2_ERRATA_E15 TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+ #define CFG_TUSB_RP2_ERRATA_E15 (CFG_TUD_ENABLED && TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX)
#endif
#endif
#endif
@@ -90,18 +90,23 @@ enum {
EPSTATE_IDLE = 0,
EPSTATE_ACTIVE,
EPSTATE_PENDING,
+ EPSTATE_PENDING_SETUP
};
// Hardware information per endpoint
typedef struct hw_endpoint {
uint8_t ep_addr;
uint8_t next_pid;
- bool active; // transferring data
- uint8_t pending; // Transfer scheduled but not active
- bool is_xfer_fifo; // transfer using fifo
+ uint8_t state;
- uint8_t future_bufid;
- uint8_t future_len;
+#if CFG_TUD_EDPT_DEDICATED_HWFIFO
+ bool is_xfer_fifo; // transfer using fifo
+#endif
+
+#if CFG_TUD_ENABLED
+ uint8_t future_bufid; // which buffer holds next data
+ uint8_t future_len; // next data len
+#endif
#if CFG_TUSB_RP2_ERRATA_E15
bool e15_bulk_in; // Errata15 device bulk in
@@ -110,8 +115,10 @@ typedef struct hw_endpoint {
#if CFG_TUH_ENABLED
uint8_t dev_addr;
uint8_t interrupt_num; // 1-15 for interrupt endpoints
- uint8_t transfer_type;
- bool need_pre; // need preamble for low speed device behind full speed hub
+ struct TU_ATTR_PACKED {
+ uint8_t transfer_type : 2;
+ uint8_t need_pre : 1; // preamble for low-speed device behind full speed hub
+ };
#endif
uint16_t max_packet_size; // max packet size also indicates configured
@@ -153,7 +160,7 @@ TU_ATTR_ALWAYS_INLINE static inline void rp2usb_critical_exit(void) {
void rp2usb_xfer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t *buffer, tu_fifo_t *ff,
uint16_t total_len);
bool rp2usb_xfer_continue(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t buf_id, bool is_rx);
-void rp2usb_buffer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, bool is_rx, bool force_single);
+void rp2usb_buffer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, bool is_rx);
void rp2usb_reset_transfer(hw_endpoint_t *ep);