summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-03-28 23:27:39 +0700
committerhathach <[email protected]>2026-03-28 23:27:39 +0700
commitdfcd271400c31e15a7d38b319c65173c3e4227c7 (patch)
treefe35d23da973fd7c38efb5b2e4f5d6139fe485f7 /src
parent7d004257d9cb849e90166a50c0f751b162fd6a68 (diff)
rp2 common refactor
Diffstat (limited to 'src')
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c4
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c54
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c179
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h6
4 files changed, 117 insertions, 126 deletions
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index b52c3114f..d4c1bf708 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -180,7 +180,7 @@ static void __tusb_irq_path_func(handle_hw_buff_status)(void) {
usb_hw_clear->buf_status = bit;
buf_status &= ~bit;
- if (rp2usb_xfer_continue(ep, ep_reg, buf_reg, buf_id)) {
+ if (rp2usb_xfer_continue(ep, ep_reg, buf_reg, buf_id, dir == TUSB_DIR_OUT)) {
const uint16_t xferred_len = ep->xferred_len;
rp2usb_reset_transfer(ep);
dcd_event_xfer_complete(0, ep->ep_addr, xferred_len, XFER_RESULT_SUCCESS, true);
@@ -276,7 +276,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);
+ rp2usb_buffer_start(ep, ep_reg, buf_reg32, false, false);
} else if (buf0_idle) {
uint16_t buf0 = bufctrl_prepare16(ep, ep->dpram_buf, false);
bufctrl_write16(buf_reg16, buf0);
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 167a80a7a..31bbfc0be 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -35,8 +35,11 @@
#define HAS_STOP_EPX_ON_NAK
#endif
+// port 0 is native USB port, other is counted as software PIO
+ #define RHPORT_NATIVE 0
+
//--------------------------------------------------------------------+
-// INCLUDE
+ // INCLUDE
//--------------------------------------------------------------------+
#include "rp2040_usb.h"
#include "osal/osal.h"
@@ -44,9 +47,6 @@
#include "host/hcd.h"
#include "host/usbh.h"
- // port 0 is native USB port, other is counted as software PIO
- #define RHPORT_NATIVE 0
-
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@@ -119,12 +119,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool need_pre(uint8_t dev_addr) {
//--------------------------------------------------------------------+
// EPX
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline void sie_start_xfer(bool send_setup, tusb_dir_t ep_dir, bool need_pre) {
+TU_ATTR_ALWAYS_INLINE static inline void sie_start_xfer(bool send_setup, bool is_rx, bool need_pre) {
uint32_t value = usb_hw->sie_ctrl & SIE_CTRL_BASE_MASK; // preserve base bits
if (send_setup) {
value |= USB_SIE_CTRL_SEND_SETUP_BITS;
} else {
- value |= (ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS);
+ value |= (is_rx ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS);
}
if (need_pre) {
value |= USB_SIE_CTRL_PREAMBLE_EN_BITS;
@@ -179,18 +179,18 @@ static void __tusb_irq_path_func(epx_switch_ep)(hw_endpoint_t *ep) {
if (is_setup) {
usb_hw->dev_addr_ctrl = ep->dev_addr;
- sie_start_xfer(true, TUSB_DIR_OUT, ep->need_pre);
+ sie_start_xfer(true, false, ep->need_pre);
} else {
- const uint8_t ep_num = tu_edpt_number(ep->ep_addr);
- const tusb_dir_t ep_dir = tu_edpt_dir(ep->ep_addr);
- io_rw_32 *ep_reg = &usbh_dpram->epx_ctrl;
- io_rw_32 *buf_reg = &usbh_dpram->epx_buf_ctrl;
+ const uint8_t ep_num = tu_edpt_number(ep->ep_addr);
+ 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);
+ rp2usb_buffer_start(ep, ep_reg, buf_reg, is_rx, is_rx || ep->transfer_type == TUSB_XFER_INTERRUPT);
usb_hw->dev_addr_ctrl = (uint32_t)(ep->dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB));
- sie_start_xfer(false, ep_dir, ep->need_pre); // start transfer
+ sie_start_xfer(false, is_rx, ep->need_pre); // start transfer
}
}
@@ -246,13 +246,13 @@ static void __tusb_irq_path_func(handle_buf_status_isr)(void) {
io_rw_32 *ep_reg = &usbh_dpram->epx_ctrl;
io_rw_32 *buf_reg = &usbh_dpram->epx_buf_ctrl;
- if (rp2usb_xfer_continue(epx, ep_reg, buf_reg, buf_id)) {
+ if (rp2usb_xfer_continue(epx, ep_reg, buf_reg, buf_id, tu_edpt_dir(epx->ep_addr) == TUSB_DIR_IN)) {
xfer_complete_isr(epx, XFER_RESULT_SUCCESS);
}
}
// Check "interrupt" (asynchronous) endpoints for both IN and OUT
- uint32_t buf_status = usb_hw->buf_status & ~1u;
+ uint32_t buf_status = usb_hw->buf_status & (uint32_t)~BUF_STATUS_EPX;
while (buf_status) {
// ctz/clz is faster than loop which has only a few bit set in general
const uint8_t idx = (uint8_t) __builtin_ctz(buf_status);
@@ -268,9 +268,9 @@ static void __tusb_irq_path_func(handle_buf_status_isr)(void) {
for (size_t e = 0; e < TU_ARRAY_SIZE(ep_pool); e++) {
hw_endpoint_t *ep = &ep_pool[e];
if (ep->interrupt_num == epnum) {
- io_rw_32 *ep_reg = dpram_int_ep_ctrl(ep->interrupt_num);
- io_rw_32 *buf_reg = dpram_int_ep_buffer_ctrl(ep->interrupt_num);
- const bool done = rp2usb_xfer_continue(ep, ep_reg, buf_reg, 0);
+ io_rw_32 *ep_reg = dpram_int_ep_ctrl(ep->interrupt_num);
+ io_rw_32 *buf_reg = dpram_int_ep_buffer_ctrl(ep->interrupt_num);
+ const bool done = rp2usb_xfer_continue(ep, ep_reg, buf_reg, 0, tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN);
if (done) {
xfer_complete_isr(ep, XFER_RESULT_SUCCESS);
}
@@ -326,21 +326,20 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) {
#ifdef HAS_STOP_EPX_ON_NAK
if (status & USB_INTS_EPX_STOPPED_ON_NAK_BITS) {
usb_hw_clear->nak_poll = USB_NAK_POLL_EPX_STOPPED_ON_NAK_BITS;
-
hw_endpoint_t *next_ep = epx_next_pending(epx);
if (next_ep != NULL) {
epx_save_context();
epx_switch_ep(next_ep);
} else {
- // No switch: disable stop-on-NAK, restart current transfer
+ // No pending endpoint, this is the only active one: disable stop-on-NAK, continue current transfer
usb_hw_clear->nak_poll = USB_NAK_POLL_STOP_EPX_ON_NAK_BITS;
- sie_start_xfer(false, tu_edpt_dir(epx->ep_addr), epx->need_pre);
+ sie_start_xfer(false, TUSB_DIR_IN == tu_edpt_dir(epx->ep_addr), epx->need_pre);
}
}
-#else
+ #else
// RP2040: on SOF, stop and switch if there's a pending ep
if (status & USB_INTS_HOST_SOF_BITS) {
- (void) usb_hw->sof_rd; // clear SOF by reading SOF_RD
+ (void)usb_hw->sof_rd; // clear SOF by reading SOF_RD
if (epx->active && tu_edpt_number(epx->ep_addr) != 0) {
hw_endpoint_t *next_ep = epx_next_pending(epx);
if (next_ep) {
@@ -360,10 +359,10 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) {
} else if (!epx_next_pending(epx)) {
// EPX is on control endpoint or inactive — disable SOF if nothing pending
usb_hw_clear->inte = USB_INTE_HOST_SOF_BITS;
- usb_hw->nak_poll = USB_NAK_POLL_RESET;
+ usb_hw->nak_poll = USB_NAK_POLL_RESET;
}
}
-#endif
+ #endif
if (status & USB_INTS_ERROR_RX_TIMEOUT_BITS) {
usb_hw_clear->sie_status = USB_SIE_STATUS_RX_TIMEOUT_BITS;
@@ -611,6 +610,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
} else {
const uint8_t ep_num = tu_edpt_number(ep->ep_addr);
const tusb_dir_t ep_dir = tu_edpt_dir(ep->ep_addr);
+ const bool is_rx = (ep_dir == TUSB_DIR_IN);
io_rw_32 *ep_reg = &usbh_dpram->epx_ctrl;
io_rw_32 *buf_reg = &usbh_dpram->epx_buf_ctrl;
@@ -620,7 +620,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
rp2usb_xfer_start(ep, ep_reg, buf_reg, buffer, NULL, buflen); // prepare bufctrl
usb_hw->dev_addr_ctrl = (uint32_t)(ep->dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB));
- sie_start_xfer(false, ep_dir, ep->need_pre); // start transfer
+ sie_start_xfer(false, is_rx, ep->need_pre); // start transfer
}
rp2usb_critical_exit();
}
@@ -667,7 +667,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, const uint8_t setup_packet
ep->active = true;
usb_hw->dev_addr_ctrl = dev_addr; // Set device address
- sie_start_xfer(true, TUSB_DIR_OUT, ep->need_pre); // start transfer
+ sie_start_xfer(true, false, ep->need_pre); // start transfer
}
rp2usb_critical_exit();
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index 15d4d723f..49c948af6 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -58,7 +58,7 @@ static void unaligned_memcpy(uint8_t *dst, const uint8_t *src, size_t n) {
}
}
-#if CFG_TUD_EDPT_DEDICATED_HWFIFO
+ #if CFG_TUD_EDPT_DEDICATED_HWFIFO
void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) {
(void)access_mode;
unaligned_memcpy((uint8_t *)(uintptr_t)hwfifo, src, len);
@@ -68,25 +68,25 @@ void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, co
(void)access_mode;
unaligned_memcpy(dest, (const uint8_t *)(uintptr_t)hwfifo, len);
}
-#endif
+ #endif
void rp2usb_init(void) {
// Reset usb controller
reset_block(RESETS_RESET_USBCTRL_BITS);
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
-#ifdef __GNUC__
- // Clear any previous state just in case
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warray-bounds"
-#if __GNUC__ > 6
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-#endif
-#endif
+ #ifdef __GNUC__
+ // Clear any previous state just in case
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Warray-bounds"
+ #if __GNUC__ > 6
+ #pragma GCC diagnostic ignored "-Wstringop-overflow"
+ #endif
+ #endif
memset(usb_dpram, 0, sizeof(*usb_dpram));
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
+ #ifdef __GNUC__
+ #pragma GCC diagnostic pop
+ #endif
// Mux the controller to the onboard usb phy
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
@@ -101,10 +101,10 @@ void rp2usb_init(void) {
}
void __tusb_irq_path_func(rp2usb_reset_transfer)(hw_endpoint_t *ep) {
- ep->active = false;
+ ep->active = false;
ep->remaining_len = 0;
- ep->xferred_len = 0;
- ep->user_buf = 0;
+ ep->xferred_len = 0;
+ ep->user_buf = 0;
ep->is_xfer_fifo = false;
}
@@ -134,9 +134,7 @@ void __tusb_irq_path_func(bufctrl_write16)(io_rw_16 *buf_reg16, uint16_t value)
}
*buf_reg16 = value & (uint16_t)~USB_BUF_CTRL_AVAIL; // write other bits first
- // Section 4.1.2.7.1 (rp2040) / 12.7.3.7.1 (rp2350) Concurrent access: after write to buffer control,
- // wait for USB controller to see the update before setting AVAILABLE.
- // Don't need delay in host mode as host is in charge of when to start the transaction.
+ // Section 4.1.2.7.1 (rp2040) / 12.7.3.7.1 (rp2350) Concurrent access
if (value & USB_BUF_CTRL_AVAIL) {
if (!rp2usb_is_host_mode()) {
busy_wait_at_least_cycles(12);
@@ -146,7 +144,7 @@ void __tusb_irq_path_func(bufctrl_write16)(io_rw_16 *buf_reg16, uint16_t value)
}
// prepare buffer, move data if tx, return buffer control
-uint16_t __tusb_irq_path_func(bufctrl_prepare16)(struct hw_endpoint *ep, uint8_t *dpram_buf, bool is_rx) {
+uint16_t __tusb_irq_path_func(bufctrl_prepare16)(hw_endpoint_t *ep, uint8_t *dpram_buf, bool is_rx) {
const uint16_t buflen = tu_min16(ep->remaining_len, ep->max_packet_size);
ep->remaining_len -= buflen;
@@ -158,13 +156,13 @@ uint16_t __tusb_irq_path_func(bufctrl_prepare16)(struct hw_endpoint *ep, uint8_t
if (!is_rx) {
if (buflen) {
- // Copy data from user buffer/fifo to hw buffer
- #if CFG_TUD_EDPT_DEDICATED_HWFIFO
+ // Copy data from user buffer/fifo to hw buffer
+ #if CFG_TUD_EDPT_DEDICATED_HWFIFO
if (ep->is_xfer_fifo) {
// not in sram, may mess up timing with E15 workaround
tu_hwfifo_write_from_fifo(dpram_buf, ep->user_fifo, buflen, NULL);
} else
- #endif
+ #endif
{
unaligned_memcpy(dpram_buf, ep->user_buf, buflen);
ep->user_buf += buflen;
@@ -185,33 +183,13 @@ uint16_t __tusb_irq_path_func(bufctrl_prepare16)(struct hw_endpoint *ep, uint8_t
}
// 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) {
- const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
- const bool is_host = rp2usb_is_host_mode();
-
- bool is_rx;
- if (is_host) {
- is_rx = (dir == TUSB_DIR_IN);
- } else {
- is_rx = (dir == TUSB_DIR_OUT);
- }
-
+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) {
// 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) {
- #if 1
- const bool force_single = (is_host && tu_edpt_number(ep->ep_addr) != 0);
- #else
- bool force_single = false; // is_rx;
- #if CFG_TUH_ENABLED
- if (is_host && ep->interrupt_num != 0) {
- force_single = true;
- }
- #endif
-#endif
-
uint32_t ep_ctrl = *ep_reg;
if (ep->remaining_len && !force_single) {
// Use buffer 1 (double buffered) if there is still data
@@ -224,13 +202,13 @@ void __tusb_irq_path_func(rp2usb_buffer_start)(hw_endpoint_t *ep, io_rw_32 *ep_r
*ep_reg = ep_ctrl;
}
- // Finally, write to buffer_control which will trigger the transfer the next time the controller polls this endpoint
+ // Finally, write to buffer control which will trigger the transfer the next time the controller polls this endpoint
bufctrl_write32(buf_reg, buf_ctrl);
}
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) {
- (void) ff;
+ (void)ff;
hw_endpoint_lock_update(ep, 1);
if (ep->active) {
@@ -241,20 +219,22 @@ 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->xferred_len = 0;
+ ep->active = true;
-#if CFG_TUD_EDPT_DEDICATED_HWFIFO
+ #if CFG_TUD_EDPT_DEDICATED_HWFIFO
if (ff != NULL) {
ep->user_fifo = ff;
ep->is_xfer_fifo = true;
} else
-#endif
+ #endif
{
ep->user_buf = buffer;
ep->is_xfer_fifo = false;
}
+ const bool is_host = rp2usb_is_host_mode();
+
if (ep->future_len > 0) {
// only on rx endpoint
const uint8_t future_len = ep->future_len;
@@ -272,7 +252,6 @@ void rp2usb_xfer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, u
const uint16_t xferred_len = ep->xferred_len;
rp2usb_reset_transfer(ep);
- const bool is_host = rp2usb_is_host_mode();
#if CFG_TUH_ENABLED
if (is_host) {
hcd_event_xfer_complete(0, ep->ep_addr, xferred_len, XFER_RESULT_SUCCESS, false);
@@ -302,12 +281,20 @@ void rp2usb_xfer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, u
}
#endif
- rp2usb_buffer_start(ep, ep_reg, buf_reg);
+ 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 && (is_rx || 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);
hw_endpoint_lock_update(ep, -1);
}
// sync endpoint buffer and return transferred bytes
-static uint16_t __tusb_irq_path_func(hwbuf_sync)(hw_endpoint_t *ep, bool is_rx, uint16_t buf_ctrl, uint8_t *dpram_buf) {
+static uint16_t __tusb_irq_path_func(bufctrl_sync16)(hw_endpoint_t *ep, bool is_rx, uint16_t buf_ctrl,
+ uint8_t *dpram_buf) {
const uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
if (!is_rx) {
@@ -342,17 +329,10 @@ static uint16_t __tusb_irq_path_func(hwbuf_sync)(hw_endpoint_t *ep, bool is_rx,
// Returns true if transfer is complete.
// buf_id: which buffer completed (from BUFF_CPU_SHOULD_HANDLE, only used for double-buffered).
-bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg,
- uint8_t buf_id) {
+bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t buf_id,
+ bool is_rx) {
hw_endpoint_lock_update(ep, 1);
- const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
- const bool is_host = rp2usb_is_host_mode();
- const bool is_rx = is_host ? (dir == TUSB_DIR_IN) : (dir == TUSB_DIR_OUT);
-
- io_rw_16 *buf_reg16 = (io_rw_16 *)buf_reg;
- uint16_t buf_ctrl16 = *(buf_reg16 + buf_id);
-
if (!ep->active) {
// probably land here due to short packet on rx with double buffered
hw_endpoint_lock_update(ep, -1);
@@ -360,7 +340,7 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_
}
const bool is_double = (ep_reg != NULL && ((*ep_reg) & EP_CTRL_DOUBLE_BUFFERED_BITS));
- (void)is_double;
+ const bool is_host = rp2usb_is_host_mode();
#if CFG_TUSB_RP2_ERRATA_E4
const bool need_e4_fix = (is_host && !is_double);
@@ -372,7 +352,7 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_
// BUF1 half instead of BUF0. The side effect that controller can execute an extra packet after writing to BUF1
// since it leave BUF0 intact, which can be poll before buf_status interrupt is trigger.
// Workaround for the side effect, we will enable double-buffered for rx but only prepare 1 buf at a time.
- uint8_t* dpram_buf = ep->dpram_buf;
+ uint8_t *dpram_buf = ep->dpram_buf;
if (buf_id) {
#if CFG_TUSB_RP2_ERRATA_E4
if (!need_e4_fix) // incorrect buf_id, buffer pointer is still buf0
@@ -382,7 +362,10 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_
}
}
- const uint16_t xact_bytes = hwbuf_sync(ep, is_rx, buf_ctrl16, dpram_buf);
+ io_rw_16 *buf_reg16 = (io_rw_16 *)buf_reg;
+ uint16_t buf_ctrl16 = *(buf_reg16 + buf_id);
+
+ const uint16_t xact_bytes = bufctrl_sync16(ep, is_rx, buf_ctrl16, dpram_buf);
const bool is_last = buf_ctrl16 & USB_BUF_CTRL_LAST;
const bool is_short = xact_bytes < ep->max_packet_size;
const bool is_done = is_short || (buf_ctrl16 & USB_BUF_CTRL_LAST);
@@ -391,40 +374,48 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_
// The other buffer may be: (a) still AVAIL, (b) in-progress (controller receiving), or (c) already completed.
// We must abort to safely reclaim it. If it has valid data (FULL), save as future for the next transfer.
// After abort, zero buf_ctrl.
- // Note: Host mode we cannot save next transfer data due to shared epx -> force single
+ // Note: Host mode we cannot save next transfer data due to shared epx --> force single
if (is_short && is_double && is_rx && !is_last) {
- io_rw_16 *buf_reg16_other = buf_reg16 + (buf_id ^ 1);
- const uint32_t abort_bit = TU_BIT((tu_edpt_number(ep->ep_addr) << 1) | (dir ? 0 : 1));
-
- #if CFG_TUSB_RP2_ERRATA_E2
- if (rp2040_chipversion >= 2)
+ #if CFG_TUH_ENABLED
+ if (is_host) {}
#endif
- {
- usb_hw_set->abort = abort_bit;
- while ((usb_hw->abort_done & abort_bit) != abort_bit) {}
- }
- // After abort, check if the other buffer received valid data
- const uint16_t buf_ctrl16_other = *buf_reg16_other;
- if (buf_ctrl16_other & USB_BUF_CTRL_FULL) {
- // Host already sent data into this buffer (e.g. write payload right after short CBW).
- // Save it for the next transfer.
- ep->future_len = (uint8_t)(buf_ctrl16_other & USB_BUF_CTRL_LEN_MASK);
- ep->future_bufid = buf_id ^ 1;
- // buff_status will be clear by the next run
- } else {
- ep->next_pid ^= 1u; // roll back pid if aborted
- }
+ #if CFG_TUD_ENABLED
+ if (!is_host) {
+ io_rw_16 *buf_reg16_other = buf_reg16 + (buf_id ^ 1);
+ const uint32_t abort_bit = TU_BIT(tu_edpt_number(ep->ep_addr) << 1); // IN endpoint
- *buf_reg = 0; // reset buffer control
+ #if CFG_TUSB_RP2_ERRATA_E2
+ if (rp2040_chipversion >= 2)
+ #endif
+ {
+ usb_hw_set->abort = abort_bit;
+ while ((usb_hw->abort_done & abort_bit) != abort_bit) {}
+ }
- #if CFG_TUSB_RP2_ERRATA_E2
- if (rp2040_chipversion >= 2)
- #endif
- {
- usb_hw_clear->abort_done = abort_bit;
- usb_hw_clear->abort = abort_bit;
+ // After abort, check if the other buffer received valid data
+ const uint16_t buf_ctrl16_other = *buf_reg16_other;
+ if (buf_ctrl16_other & USB_BUF_CTRL_FULL) {
+ // Host already sent data into this buffer (e.g. write payload right after short CBW).
+ // Save it for the next transfer.
+ ep->future_len = (uint8_t)(buf_ctrl16_other & USB_BUF_CTRL_LEN_MASK);
+ ep->future_bufid = buf_id ^ 1;
+ // buff_status will be clear by the next run
+ } else {
+ ep->next_pid ^= 1u; // roll back pid if aborted
+ }
+
+ *buf_reg = 0; // reset buffer control
+
+ #if CFG_TUSB_RP2_ERRATA_E2
+ if (rp2040_chipversion >= 2)
+ #endif
+ {
+ usb_hw_clear->abort_done = abort_bit;
+ usb_hw_clear->abort = abort_bit;
+ }
}
+ #endif
hw_endpoint_lock_update(ep, -1);
return true;
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index 3b45c7c94..c4c7e625e 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -145,8 +145,8 @@ 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);
-void rp2usb_buffer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg);
+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_reset_transfer(hw_endpoint_t *ep);
@@ -161,7 +161,7 @@ TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_lock_update(__unused struct
//--------------------------------------------------------------------+
void bufctrl_write32(io_rw_32 *buf_reg, uint32_t value);
void bufctrl_write16(io_rw_16 *buf_reg16, uint16_t value);
-uint16_t bufctrl_prepare16(struct hw_endpoint *ep, uint8_t *dpram_buf, bool is_rx);
+uint16_t bufctrl_prepare16(hw_endpoint_t *ep, uint8_t *dpram_buf, bool is_rx);
TU_ATTR_ALWAYS_INLINE static inline uintptr_t hw_data_offset(uint8_t *buf) {
// Remove usb base from buffer pointer