mirror of
https://github.com/hathach/tinyusb.git
synced 2026-02-05 04:45:39 +00:00
3
.idea/cmake.xml
generated
3
.idea/cmake.xml
generated
@ -103,6 +103,8 @@
|
||||
<configuration PROFILE_NAME="metro m7 1011 sd" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011_sd -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
|
||||
<configuration PROFILE_NAME="metro_m7_1011" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011 -DLOG=1 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="rt1010 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1010_evk -DLOG=1 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="rt1024 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1024_evk -DLOG=1 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="rt1050 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1050_evkb -DLOG=1 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="mimxrt1060_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1060_evk -DLOG=1" />
|
||||
<configuration PROFILE_NAME="mimxrt1064_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1064_evk" />
|
||||
<configuration PROFILE_NAME="rt1170 evkb" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1170_evkb -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
|
||||
@ -126,6 +128,7 @@
|
||||
<configuration PROFILE_NAME="stm32h743eval_host1" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32h743eval -DRHPORT_HOST=1 -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
|
||||
<configuration PROFILE_NAME="stm32h743eval IAR" ENABLED="false" CONFIG_NAME="Debug" TOOLCHAIN_NAME="iccarm" GENERATION_OPTIONS="-DBOARD=stm32h743eval -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1 -DIAR_CSTAT=1" />
|
||||
<configuration PROFILE_NAME="stm32h743nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32h743nucleo -DLOG=1" />
|
||||
<configuration PROFILE_NAME="stm32h7s3nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32h7s3nucleo -DLOG=1" />
|
||||
<configuration PROFILE_NAME="stm32l0538disco" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32l0538disco -DLOG=0 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="stm32l476disco" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32l476disco -DLOG=1 -DLOGGER=RTT" />
|
||||
<configuration PROFILE_NAME="stm32u575nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32u575nucleo -DLOG=1 -DLOGGER=RTT" />
|
||||
|
||||
4
.idea/debugServers/ST_LINK.xml
generated
4
.idea/debugServers/ST_LINK.xml
generated
@ -1,10 +1,10 @@
|
||||
<component name="DebugServers">
|
||||
<stlink-debug-target name="ST-LINK" uniqueID="300d1a6f-85c0-4eb3-9753-f033d01e2eff">
|
||||
<stlink-debug-target name="ST-LINK" uniqueID="cf98f5f4-9c5b-4340-ab06-16ddd7f07062">
|
||||
<debugger version="1">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<env />
|
||||
</debugger>
|
||||
<gdbserver exe="$USER_HOME$/st/stm32cubeide_1.16.1/plugins/com.st.stm32cube.ide.mcu.externaltools.stlink-gdb-server.linux64_2.1.400.202404281720/tools/bin/ST-LINK_gdbserver" programmer="$USER_HOME$/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin" />
|
||||
<gdbserver exe="/opt/st/stm32cubeclt_1.20.0/STLink-gdb-server/bin/ST-LINK_gdbserver" programmer="/opt/st/stm32cubeclt_1.20.0/STM32CubeProgrammer/bin" />
|
||||
<st-link />
|
||||
<device interface="SWD" />
|
||||
<connection port="61234" warmup-ms="500" />
|
||||
|
||||
13
.idea/debugServers/mcxa153.xml
generated
Normal file
13
.idea/debugServers/mcxa153.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="DebugServers">
|
||||
<jlink-debug-target name="mcxa153" uniqueID="6a023429-69e6-4f8c-a592-4995cdf255db">
|
||||
<debugger version="1">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<env />
|
||||
</debugger>
|
||||
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
|
||||
<console port="19021" />
|
||||
<target device="MCXA153" reset-before="false" />
|
||||
<connection extended-remote="false" port="4444" warmup-ms="500" />
|
||||
<swo />
|
||||
</jlink-debug-target>
|
||||
</component>
|
||||
13
.idea/debugServers/ra6m1.xml
generated
Normal file
13
.idea/debugServers/ra6m1.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="DebugServers">
|
||||
<jlink-debug-target name="ra6m1" uniqueID="c8cdc79a-939b-4342-92b1-d24da72d12fe">
|
||||
<debugger version="1">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<env />
|
||||
</debugger>
|
||||
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
|
||||
<console port="19021" />
|
||||
<target device="R7FA6M1AD" reset-before="false" frequency="16000" />
|
||||
<connection extended-remote="false" port="4444" warmup-ms="500" />
|
||||
<swo />
|
||||
</jlink-debug-target>
|
||||
</component>
|
||||
13
.idea/debugServers/ra6m5.xml
generated
Normal file
13
.idea/debugServers/ra6m5.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="DebugServers">
|
||||
<jlink-debug-target name="ra6m5" uniqueID="19100d9f-7329-47da-b566-f9faf297f47c">
|
||||
<debugger version="1">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<env />
|
||||
</debugger>
|
||||
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
|
||||
<console port="19021" />
|
||||
<target device="R7FA6M5BH" reset-before="false" frequency="16000" />
|
||||
<connection extended-remote="false" port="4444" warmup-ms="500" />
|
||||
<swo />
|
||||
</jlink-debug-target>
|
||||
</component>
|
||||
13
.idea/debugServers/rt1011.xml
generated
Normal file
13
.idea/debugServers/rt1011.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="DebugServers">
|
||||
<jlink-debug-target name="rt1011" uniqueID="e10c53c4-acf5-4a6f-a05d-32b7b042d70a">
|
||||
<debugger version="1">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<env />
|
||||
</debugger>
|
||||
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
|
||||
<console port="19021" />
|
||||
<target device="MIMXRT1011xxx5A" reset-before="false" />
|
||||
<connection extended-remote="false" port="4444" warmup-ms="500" />
|
||||
<swo />
|
||||
</jlink-debug-target>
|
||||
</component>
|
||||
13
.idea/debugServers/rt1170.xml
generated
Normal file
13
.idea/debugServers/rt1170.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="DebugServers">
|
||||
<jlink-debug-target name="rt1170" uniqueID="cfc772e4-782e-49a3-99fb-b6f726e14f9d">
|
||||
<debugger version="1">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<env />
|
||||
</debugger>
|
||||
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
|
||||
<console port="19021" />
|
||||
<target device="MIMXRT1176xxxA_M7" reset-before="false" frequency="16000" />
|
||||
<connection extended-remote="false" port="4444" warmup-ms="500" />
|
||||
<swo />
|
||||
</jlink-debug-target>
|
||||
</component>
|
||||
13
.idea/debugServers/stm32f072.xml
generated
Normal file
13
.idea/debugServers/stm32f072.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="DebugServers">
|
||||
<jlink-debug-target name="stm32f072" uniqueID="f5c65701-0f8d-4923-a7ea-3ee2547147ae">
|
||||
<debugger version="1">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<env />
|
||||
</debugger>
|
||||
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
|
||||
<console port="19021" />
|
||||
<target device="STM32F072RB" reset-before="false" frequency="12000" />
|
||||
<connection extended-remote="false" port="4444" warmup-ms="500" />
|
||||
<swo />
|
||||
</jlink-debug-target>
|
||||
</component>
|
||||
13
.idea/debugServers/stm32f303.xml
generated
Normal file
13
.idea/debugServers/stm32f303.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="DebugServers">
|
||||
<jlink-debug-target name="stm32f303" uniqueID="1cdd63e5-1736-42be-bff3-4c48e1f169fa">
|
||||
<debugger version="1">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<env />
|
||||
</debugger>
|
||||
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
|
||||
<console port="19021" />
|
||||
<target device="STM32F303VC" reset-before="false" frequency="12000" />
|
||||
<connection extended-remote="false" port="4444" warmup-ms="500" />
|
||||
<swo />
|
||||
</jlink-debug-target>
|
||||
</component>
|
||||
13
.idea/debugServers/stm32l053.xml
generated
Normal file
13
.idea/debugServers/stm32l053.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="DebugServers">
|
||||
<jlink-debug-target name="stm32l053" uniqueID="51d156d7-86a6-4006-814a-ed14981d7b49">
|
||||
<debugger version="1">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<env />
|
||||
</debugger>
|
||||
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
|
||||
<console port="19021" />
|
||||
<target device="STM32L053R8" reset-before="false" frequency="12000" />
|
||||
<connection extended-remote="false" port="4444" warmup-ms="500" />
|
||||
<swo />
|
||||
</jlink-debug-target>
|
||||
</component>
|
||||
@ -246,10 +246,9 @@ static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_devi
|
||||
cdc_printf("Device %u: ID %04x:%04x SN ", daddr, desc_device->idVendor, desc_device->idProduct);
|
||||
uint8_t xfer_result = tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, serial, sizeof(serial));
|
||||
if (XFER_RESULT_SUCCESS != xfer_result) {
|
||||
serial[0] = 'n';
|
||||
serial[1] = '/';
|
||||
serial[2] = 'a';
|
||||
serial[3] = 0;
|
||||
serial[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * 1 + 2));
|
||||
serial[1] = '0';
|
||||
serial[2] = 0;
|
||||
}
|
||||
print_utf16(serial, TU_ARRAY_SIZE(serial));
|
||||
cdc_printf("\r\n");
|
||||
|
||||
@ -130,11 +130,10 @@ void tuh_mount_cb(uint8_t daddr) {
|
||||
}
|
||||
if (XFER_RESULT_SUCCESS != xfer_result) {
|
||||
uint16_t* serial = (uint16_t*)(uintptr_t) desc.serial;
|
||||
serial[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * 3 + 2));
|
||||
serial[1] = 'n';
|
||||
serial[2] = '/';
|
||||
serial[3] = 'a';
|
||||
serial[4] = 0;
|
||||
|
||||
serial[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * 1 + 2));
|
||||
serial[1] = '0'; // simply 0
|
||||
serial[2] = 0;
|
||||
}
|
||||
print_utf16((uint16_t*)(uintptr_t) desc.serial, sizeof(desc.serial)/2);
|
||||
printf("\r\n");
|
||||
|
||||
@ -157,10 +157,12 @@ target_link_libraries(tinyusb_bsp INTERFACE
|
||||
# tinyusb_additions will hold our extra settings for examples
|
||||
add_library(tinyusb_additions INTERFACE)
|
||||
|
||||
if (PICO_PLATFORM STREQUAL rp2040)
|
||||
target_compile_definitions(tinyusb_additions INTERFACE
|
||||
PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1
|
||||
PICO_RP2040_USB_DEVICE_UFRAME_FIX=1
|
||||
)
|
||||
)
|
||||
endif ()
|
||||
|
||||
if(LOGGER STREQUAL "RTT" OR LOGGER STREQUAL "rtt")
|
||||
target_compile_definitions(tinyusb_additions INTERFACE
|
||||
|
||||
@ -39,122 +39,104 @@
|
||||
#include "device/dcd.h"
|
||||
|
||||
// Current implementation force vbus detection as always present, causing device think it is always plugged into host.
|
||||
// Therefore it cannot detect disconnect event, mistaken it as suspend.
|
||||
// Therefore, it cannot detect disconnect event, mistaken it as suspend.
|
||||
// Note: won't work if change to 0 (for now)
|
||||
#define FORCE_VBUS_DETECT 1
|
||||
#define FORCE_VBUS_DETECT 1
|
||||
|
||||
#define USB_INTS_ERROR_BITS \
|
||||
(USB_INTS_ERROR_DATA_SEQ_BITS | USB_INTS_ERROR_BIT_STUFF_BITS | USB_INTS_ERROR_CRC_BITS | \
|
||||
USB_INTS_ERROR_RX_OVERFLOW_BITS | USB_INTS_ERROR_RX_TIMEOUT_BITS)
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Low level controller
|
||||
*------------------------------------------------------------------*/
|
||||
// Init these in dcd_init
|
||||
static uint8_t* next_buffer_ptr;
|
||||
// HW buffer pointer from USB buffer space (max 3840 bytes)
|
||||
static uint8_t *hw_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];
|
||||
|
||||
// SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd
|
||||
// SOF may be used by remote wakeup as RESUME, this indicates 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) {
|
||||
return &hw_endpoints[num][dir];
|
||||
TU_ATTR_ALWAYS_INLINE static inline hw_endpoint_t *hw_endpoint_get(uint8_t epnum, tusb_dir_t dir) {
|
||||
return &hw_endpoints[epnum][dir];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Allocate from the USB buffer space (max 3840 bytes)
|
||||
static void hw_endpoint_alloc(struct hw_endpoint* ep, size_t size) {
|
||||
// round up size to multiple of 64
|
||||
size = tu_round_up(ep->wMaxPacketSize, 64);
|
||||
|
||||
// double buffered Bulk endpoint
|
||||
if (ep->transfer_type == TUSB_XFER_BULK) {
|
||||
size *= 2u;
|
||||
}
|
||||
|
||||
// assign buffer
|
||||
ep->hw_data_buf = next_buffer_ptr;
|
||||
next_buffer_ptr += size;
|
||||
|
||||
hard_assert(next_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data));
|
||||
pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf);
|
||||
}
|
||||
|
||||
// Enable endpoint
|
||||
TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_enable(struct hw_endpoint* ep) {
|
||||
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf);
|
||||
*ep->endpoint_control = reg;
|
||||
TU_ATTR_ALWAYS_INLINE static inline hw_endpoint_t *hw_endpoint_get_by_addr(uint8_t ep_addr) {
|
||||
const uint8_t num = tu_edpt_number(ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
return hw_endpoint_get(num, dir);
|
||||
}
|
||||
|
||||
// main processing for dcd_edpt_iso_activate
|
||||
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);
|
||||
|
||||
ep->ep_addr = ep_addr;
|
||||
|
||||
// For device, IN is a tx transfer and OUT is an rx transfer
|
||||
ep->rx = (dir == TUSB_DIR_OUT);
|
||||
|
||||
ep->next_pid = 0u;
|
||||
static void hw_endpoint_init(hw_endpoint_t *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
|
||||
ep->ep_addr = ep_addr;
|
||||
ep->next_pid = 0u;
|
||||
ep->wMaxPacketSize = wMaxPacketSize;
|
||||
ep->transfer_type = transfer_type;
|
||||
|
||||
// Every endpoint has a buffer control register in dpram
|
||||
if (dir == TUSB_DIR_IN) {
|
||||
ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
|
||||
} else {
|
||||
ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
|
||||
}
|
||||
ep->transfer_type = transfer_type;
|
||||
|
||||
// Clear existing buffer control state
|
||||
*ep->buffer_control = 0;
|
||||
|
||||
if (num == 0) {
|
||||
// EP0 has no endpoint control register because the buffer offsets are fixed
|
||||
ep->endpoint_control = NULL;
|
||||
io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
|
||||
*buf_ctrl_reg = 0;
|
||||
|
||||
// allocated hw buffer
|
||||
const uint8_t epnum = tu_edpt_number(ep_addr);
|
||||
if (epnum == 0) {
|
||||
// Buffer offset is fixed (also double buffered)
|
||||
ep->hw_data_buf = (uint8_t*) &usb_dpram->ep0_buf_a[0];
|
||||
} else {
|
||||
// Set the endpoint control register (starts at EP1, hence num-1)
|
||||
if (dir == TUSB_DIR_IN) {
|
||||
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].in;
|
||||
} else {
|
||||
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
|
||||
// round up size to multiple of 64
|
||||
uint16_t size = (uint16_t)tu_round_up(wMaxPacketSize, 64);
|
||||
|
||||
// double buffered Bulk endpoint
|
||||
if (transfer_type == TUSB_XFER_BULK) {
|
||||
size *= 2u;
|
||||
|
||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
|
||||
ep->e15_bulk_in = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// assign buffer
|
||||
ep->hw_data_buf = hw_buffer_ptr;
|
||||
hw_buffer_ptr += size;
|
||||
|
||||
hard_assert(hw_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data));
|
||||
pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf);
|
||||
}
|
||||
}
|
||||
|
||||
// Init, allocate buffer and enable endpoint
|
||||
static void hw_endpoint_enable(hw_endpoint_t *ep, uint8_t transfer_type) {
|
||||
io_rw_32 *ctrl_reg = hwep_ctrl_reg_device(ep);
|
||||
// Set endpoint control register to enable (EP0 has no endpoint control register)
|
||||
if (ctrl_reg != NULL) {
|
||||
const uint32_t ctrl_value =
|
||||
EP_CTRL_ENABLE_BITS | ((uint32_t)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf);
|
||||
*ctrl_reg = ctrl_value;
|
||||
}
|
||||
}
|
||||
|
||||
// Init and enable endpoint
|
||||
static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
|
||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||
hw_endpoint_init(ep_addr, wMaxPacketSize, transfer_type);
|
||||
const uint8_t num = tu_edpt_number(ep_addr);
|
||||
if (num != 0) {
|
||||
// EP0 is already enabled
|
||||
hw_endpoint_alloc(ep, ep->wMaxPacketSize);
|
||||
hw_endpoint_enable(ep);
|
||||
}
|
||||
}
|
||||
const uint8_t epnum = tu_edpt_number(ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
hw_endpoint_t *ep = hw_endpoint_get(epnum, dir);
|
||||
|
||||
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);
|
||||
hw_endpoint_init(ep, ep_addr, wMaxPacketSize, transfer_type);
|
||||
hw_endpoint_enable(ep, transfer_type);
|
||||
}
|
||||
|
||||
static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
|
||||
// Abort any pending transfer
|
||||
const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr);
|
||||
const uint8_t epnum = tu_edpt_number(ep->ep_addr);
|
||||
const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1));
|
||||
|
||||
// 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.
|
||||
const uint8_t dir = tu_edpt_dir(ep->ep_addr);
|
||||
const uint8_t epnum = tu_edpt_number(ep->ep_addr);
|
||||
const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1));
|
||||
if (rp2040_chip_version() >= 2) {
|
||||
usb_hw_set->abort = abort_mask;
|
||||
while ((usb_hw->abort_done & abort_mask) != abort_mask) {}
|
||||
@ -165,7 +147,8 @@ static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
|
||||
buf_ctrl |= USB_BUF_CTRL_DATA1_PID;
|
||||
}
|
||||
|
||||
_hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
|
||||
io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
|
||||
hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl);
|
||||
hw_endpoint_reset_transfer(ep);
|
||||
|
||||
if (rp2040_chip_version() >= 2) {
|
||||
@ -174,7 +157,7 @@ static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
|
||||
}
|
||||
}
|
||||
|
||||
static void __tusb_irq_path_func(hw_handle_buff_status)(void) {
|
||||
static void __tusb_irq_path_func(handle_hw_buff_status)(void) {
|
||||
uint32_t remaining_buffers = usb_hw->buf_status;
|
||||
pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers);
|
||||
uint bit = 1u;
|
||||
@ -184,12 +167,13 @@ static void __tusb_irq_path_func(hw_handle_buff_status)(void) {
|
||||
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);
|
||||
const uint8_t epnum = i >> 1u;
|
||||
const tusb_dir_t dir = (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN;
|
||||
hw_endpoint_t *ep = hw_endpoint_get(epnum, dir);
|
||||
|
||||
// Continue xfer
|
||||
bool done = hw_endpoint_xfer_continue(ep);
|
||||
const bool done = hw_endpoint_xfer_continue(ep);
|
||||
if (done) {
|
||||
// Notify
|
||||
// Notify usbd
|
||||
const uint16_t xferred_len = ep->xferred_len;
|
||||
hw_endpoint_reset_transfer(ep);
|
||||
dcd_event_xfer_complete(0, ep->ep_addr, xferred_len, XFER_RESULT_SUCCESS, true);
|
||||
@ -204,7 +188,7 @@ 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);
|
||||
struct hw_endpoint *ep = hw_endpoint_get(0, dir);
|
||||
ep->next_pid = 1u;
|
||||
if (ep->active) {
|
||||
hw_endpoint_abort_xfer(ep); // Abort any pending transfer per USB specs
|
||||
@ -223,11 +207,11 @@ static void __tusb_irq_path_func(reset_non_control_endpoints)(void) {
|
||||
tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2 * sizeof(hw_endpoint_t));
|
||||
|
||||
// reclaim buffer space
|
||||
next_buffer_ptr = &usb_dpram->epx_data[0];
|
||||
hw_buffer_ptr = &usb_dpram->epx_data[0];
|
||||
}
|
||||
|
||||
static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
|
||||
uint32_t const status = usb_hw->ints;
|
||||
const uint32_t status = usb_hw->ints;
|
||||
uint32_t handled = 0;
|
||||
|
||||
if (status & USB_INTF_DEV_SOF_BITS) {
|
||||
@ -240,27 +224,26 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
|
||||
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);
|
||||
struct hw_endpoint *ep = hw_endpoint_get(i, TUSB_DIR_IN);
|
||||
|
||||
// Active Bulk IN endpoint requires SOF
|
||||
if ((ep->transfer_type == TUSB_XFER_BULK) && ep->active) {
|
||||
if (ep->e15_bulk_in && ep->active) {
|
||||
keep_sof_alive = true;
|
||||
|
||||
hw_endpoint_lock_update(ep, 1);
|
||||
|
||||
// Deferred enable?
|
||||
if (ep->pending) {
|
||||
ep->pending = 0;
|
||||
hw_endpoint_start_next_buffer(ep);
|
||||
}
|
||||
|
||||
hw_endpoint_lock_update(ep, -1);
|
||||
}
|
||||
}
|
||||
#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);
|
||||
}
|
||||
@ -269,7 +252,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
|
||||
// before closing the EP, the events will be delivered in same order.
|
||||
if (status & USB_INTS_BUFF_STATUS_BITS) {
|
||||
handled |= USB_INTS_BUFF_STATUS_BITS;
|
||||
hw_handle_buff_status();
|
||||
handle_hw_buff_status();
|
||||
}
|
||||
|
||||
if (status & USB_INTS_SETUP_REQ_BITS) {
|
||||
@ -287,15 +270,12 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
|
||||
#if FORCE_VBUS_DETECT == 0
|
||||
// Since we force VBUS detect On, device will always think it is connected and
|
||||
// couldn't distinguish between disconnect and suspend
|
||||
if (status & USB_INTS_DEV_CONN_DIS_BITS)
|
||||
{
|
||||
if (status & USB_INTS_DEV_CONN_DIS_BITS) {
|
||||
handled |= USB_INTS_DEV_CONN_DIS_BITS;
|
||||
|
||||
if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
|
||||
{
|
||||
if (usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS) {
|
||||
// Connected: nothing to do
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
// Disconnected
|
||||
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
|
||||
}
|
||||
@ -315,10 +295,12 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
|
||||
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
|
||||
|
||||
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
|
||||
#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();
|
||||
#endif
|
||||
if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) {
|
||||
rp2040_usb_device_enumeration_fix();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Note from pico datasheet 4.1.2.6.4 (v1.2)
|
||||
@ -346,13 +328,6 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
|
||||
}
|
||||
}
|
||||
|
||||
#define USB_INTS_ERROR_BITS ( \
|
||||
USB_INTS_ERROR_DATA_SEQ_BITS | \
|
||||
USB_INTS_ERROR_BIT_STUFF_BITS | \
|
||||
USB_INTS_ERROR_CRC_BITS | \
|
||||
USB_INTS_ERROR_RX_OVERFLOW_BITS | \
|
||||
USB_INTS_ERROR_RX_TIMEOUT_BITS)
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Controller API
|
||||
*------------------------------------------------------------------*/
|
||||
@ -369,9 +344,9 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
||||
TU_LOG(2, "Chip Version B%u\r\n", rp2040_chip_version());
|
||||
|
||||
// Reset hardware to default state
|
||||
rp2040_usb_init();
|
||||
rp2usb_init();
|
||||
|
||||
#if FORCE_VBUS_DETECT
|
||||
#if FORCE_VBUS_DETECT
|
||||
// Force VBUS detect so the device thinks it is plugged into a host
|
||||
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
|
||||
#endif
|
||||
@ -425,12 +400,11 @@ void dcd_int_disable(__unused uint8_t rhport) {
|
||||
irq_set_enabled(USBCTRL_IRQ, false);
|
||||
}
|
||||
|
||||
void dcd_set_address(__unused uint8_t rhport, __unused uint8_t dev_addr) {
|
||||
assert(rhport == 0);
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
|
||||
(void)dev_addr;
|
||||
// Can't set device address in hardware until status xfer has complete
|
||||
// Send 0len complete response on EP0 IN
|
||||
hw_endpoint_xfer(0x80, NULL, 0);
|
||||
dcd_edpt_xfer(rhport, 0x80, NULL, 0, false);
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(__unused uint8_t rhport) {
|
||||
@ -475,7 +449,6 @@ void dcd_sof_enable(uint8_t rhport, bool en) {
|
||||
/*------------------------------------------------------------------*/
|
||||
/* DCD Endpoint port
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
|
||||
(void) rhport;
|
||||
|
||||
@ -489,7 +462,6 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
|
||||
(void) rhport;
|
||||
const uint8_t xfer_type = desc_edpt->bmAttributes.xfer;
|
||||
TU_VERIFY(xfer_type != TUSB_XFER_ISOCHRONOUS);
|
||||
hw_endpoint_open(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), xfer_type);
|
||||
return true;
|
||||
}
|
||||
@ -497,56 +469,57 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
|
||||
// New API: Allocate packet buffer used by ISO endpoints
|
||||
// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering
|
||||
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
|
||||
(void) rhport;
|
||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||
hw_endpoint_init(ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS);
|
||||
hw_endpoint_alloc(ep, largest_packet_size);
|
||||
(void)rhport;
|
||||
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
|
||||
hw_endpoint_init(ep, ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS);
|
||||
return true;
|
||||
}
|
||||
|
||||
// New API: Configure and enable an ISO endpoint according to descriptor
|
||||
bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
|
||||
(void) rhport;
|
||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_desc->bEndpointAddress);
|
||||
bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *ep_desc) {
|
||||
(void)rhport;
|
||||
const uint8_t epnum = tu_edpt_number(ep_desc->bEndpointAddress);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_desc->bEndpointAddress);
|
||||
struct hw_endpoint *ep = hw_endpoint_get(epnum, dir);
|
||||
TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and allocated previously
|
||||
|
||||
if (ep->active) {
|
||||
hw_endpoint_abort_xfer(ep); // abort any pending transfer
|
||||
}
|
||||
|
||||
ep->wMaxPacketSize = ep_desc->wMaxPacketSize;
|
||||
hw_endpoint_enable(ep);
|
||||
|
||||
hw_endpoint_enable(ep, TUSB_XFER_ISOCHRONOUS);
|
||||
return true;
|
||||
}
|
||||
|
||||
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, bool is_isr) {
|
||||
(void) is_isr;
|
||||
assert(rhport == 0);
|
||||
hw_endpoint_xfer(ep_addr, buffer, total_bytes);
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) {
|
||||
(void)rhport;
|
||||
(void)is_isr;
|
||||
hw_endpoint_t *ep = hw_endpoint_get_by_addr(ep_addr);
|
||||
hw_endpoint_xfer_start(ep, buffer, total_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void)rhport;
|
||||
const uint8_t epnum = tu_edpt_number(ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
|
||||
hw_endpoint_t *ep = hw_endpoint_get(epnum, dir);
|
||||
|
||||
if (tu_edpt_number(ep_addr) == 0) {
|
||||
if (epnum == 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 = (dir == 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);
|
||||
|
||||
// stall and clear current pending buffer
|
||||
// may need to use EP_ABORT
|
||||
_hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_STALL);
|
||||
// stall and clear current pending buffer, may need to use EP_ABORT
|
||||
io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
|
||||
hwbuf_ctrl_set(buf_ctrl_reg, USB_BUF_CTRL_STALL);
|
||||
}
|
||||
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
@ -557,7 +530,8 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
|
||||
// clear stall also reset toggle to DATA0, ready for next transfer
|
||||
ep->next_pid = 0;
|
||||
_hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL);
|
||||
io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
|
||||
hwbuf_ctrl_clear_mask(buf_ctrl_reg, USB_BUF_CTRL_STALL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -62,34 +62,33 @@ enum {
|
||||
USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
|
||||
};
|
||||
|
||||
static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) {
|
||||
uint8_t num = tu_edpt_number(ep_addr);
|
||||
if ( num == 0 ) return &epx;
|
||||
if (num == 0) {
|
||||
return &epx;
|
||||
}
|
||||
|
||||
for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ )
|
||||
{
|
||||
for (uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) {
|
||||
struct hw_endpoint *ep = &ep_pool[i];
|
||||
if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep;
|
||||
if (ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr)) {
|
||||
return ep;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void) {
|
||||
return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool need_pre(uint8_t dev_addr)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool need_pre(uint8_t dev_addr) {
|
||||
// If this device is different to the speed of the root device
|
||||
// (i.e. is a low speed device on a full speed hub) then need pre
|
||||
return hcd_port_speed_get(0) != tuh_speed_get(dev_addr);
|
||||
}
|
||||
|
||||
static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result)
|
||||
{
|
||||
static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result) {
|
||||
// Mark transfer as done before we tell the tinyusb stack
|
||||
uint8_t dev_addr = ep->dev_addr;
|
||||
uint8_t ep_addr = ep->ep_addr;
|
||||
@ -98,47 +97,28 @@ static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_
|
||||
hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true);
|
||||
}
|
||||
|
||||
static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_endpoint *ep)
|
||||
{
|
||||
static void __tusb_irq_path_func(handle_hwbuf_status_bit)(uint bit, struct hw_endpoint *ep) {
|
||||
usb_hw_clear->buf_status = bit;
|
||||
// EP may have been stalled?
|
||||
assert(ep->active);
|
||||
bool done = hw_endpoint_xfer_continue(ep);
|
||||
if ( done )
|
||||
{
|
||||
const bool done = hw_endpoint_xfer_continue(ep);
|
||||
if (done) {
|
||||
hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
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\n", remaining_buffers);
|
||||
static void __tusb_irq_path_func(handle_hwbuf_status)(void) {
|
||||
uint32_t buf_status = usb_hw->buf_status;
|
||||
pico_trace("buf_status 0x%08lx\n", buf_status);
|
||||
|
||||
// Check EPX first
|
||||
uint bit = 0b1;
|
||||
if ( remaining_buffers & bit )
|
||||
{
|
||||
remaining_buffers &= ~bit;
|
||||
uint32_t bit = 1u;
|
||||
if (buf_status & bit) {
|
||||
buf_status &= ~bit;
|
||||
struct hw_endpoint * ep = &epx;
|
||||
|
||||
uint32_t ep_ctrl = *ep->endpoint_control;
|
||||
if ( ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS )
|
||||
{
|
||||
TU_LOG(3, "Double Buffered: ");
|
||||
}
|
||||
else
|
||||
{
|
||||
TU_LOG(3, "Single Buffered: ");
|
||||
}
|
||||
TU_LOG_HEX(3, ep_ctrl);
|
||||
|
||||
_handle_buff_status_bit(bit, ep);
|
||||
handle_hwbuf_status_bit(bit, ep);
|
||||
}
|
||||
|
||||
// Check "interrupt" (asynchronous) endpoints for both IN and OUT
|
||||
for ( uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && remaining_buffers; i++ )
|
||||
{
|
||||
for (uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && buf_status; i++) {
|
||||
// EPX is bit 0 & 1
|
||||
// IEP1 IN is bit 2
|
||||
// IEP1 OUT is bit 3
|
||||
@ -147,20 +127,17 @@ static void __tusb_irq_path_func(hw_handle_buff_status)(void)
|
||||
// IEP3 IN is bit 6
|
||||
// IEP3 OUT is bit 7
|
||||
// etc
|
||||
for ( uint j = 0; j < 2; j++ )
|
||||
{
|
||||
for (uint j = 0; j < 2; j++) {
|
||||
bit = 1 << (i * 2 + j);
|
||||
if ( remaining_buffers & bit )
|
||||
{
|
||||
remaining_buffers &= ~bit;
|
||||
_handle_buff_status_bit(bit, &ep_pool[i]);
|
||||
if (buf_status & bit) {
|
||||
buf_status &= ~bit;
|
||||
handle_hwbuf_status_bit(bit, &ep_pool[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( remaining_buffers )
|
||||
{
|
||||
panic("Unhandled buffer %d\n", remaining_buffers);
|
||||
if (buf_status) {
|
||||
panic("Unhandled buffer %d\n", buf_status);
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,7 +197,7 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void)
|
||||
{
|
||||
handled |= USB_INTS_BUFF_STATUS_BITS;
|
||||
TU_LOG(2, "Buffer complete\r\n");
|
||||
hw_handle_buff_status();
|
||||
handle_hwbuf_status();
|
||||
}
|
||||
|
||||
if ( status & USB_INTS_TRANS_COMPLETE_BITS )
|
||||
@ -240,9 +217,8 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void)
|
||||
if ( status & USB_INTS_ERROR_DATA_SEQ_BITS )
|
||||
{
|
||||
usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS;
|
||||
TU_LOG(3, " Seq Error: [0] = 0x%04u [1] = 0x%04x\r\n",
|
||||
tu_u32_low16(*epx.buffer_control),
|
||||
tu_u32_high16(*epx.buffer_control));
|
||||
TU_LOG(3, " Seq Error: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(*hwbuf_ctrl_reg_host(&epx)),
|
||||
tu_u32_high16(*hwbuf_ctrl_reg_host(&epx)));
|
||||
panic("Data Seq Error \n");
|
||||
}
|
||||
|
||||
@ -266,7 +242,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void)
|
||||
ep = &ep_pool[i];
|
||||
if ( !ep->configured )
|
||||
{
|
||||
// Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
|
||||
// Will be configured by hw_endpoint_init / hw_endpoint_allocate
|
||||
ep->interrupt_num = (uint8_t) (i - 1);
|
||||
return ep;
|
||||
}
|
||||
@ -274,41 +250,31 @@ static struct hw_endpoint *_next_free_interrupt_ep(void)
|
||||
return ep;
|
||||
}
|
||||
|
||||
static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
|
||||
{
|
||||
struct hw_endpoint * ep = NULL;
|
||||
static hw_endpoint_t *hw_endpoint_allocate(uint8_t transfer_type) {
|
||||
hw_endpoint_t *ep = NULL;
|
||||
|
||||
if ( transfer_type != TUSB_XFER_CONTROL )
|
||||
{
|
||||
if (transfer_type == TUSB_XFER_CONTROL) {
|
||||
ep = &epx;
|
||||
ep->hw_data_buf = &usbh_dpram->epx_data[0];
|
||||
} else {
|
||||
// Note: even though datasheet name these "Interrupt" endpoints. These are actually
|
||||
// "Asynchronous" endpoints and can be used for other type such as: Bulk (ISO need confirmation)
|
||||
ep = _next_free_interrupt_ep();
|
||||
pico_info("Allocate %s ep %d\n", tu_edpt_type_str(transfer_type), ep->interrupt_num);
|
||||
assert(ep);
|
||||
ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
|
||||
ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
|
||||
// 0 for epx (double buffered): TODO increase to 1024 for ISO
|
||||
// 2x64 for intep0
|
||||
// 3x64 for intep1
|
||||
// etc
|
||||
ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 2)];
|
||||
}
|
||||
else
|
||||
{
|
||||
ep = &epx;
|
||||
ep->buffer_control = &usbh_dpram->epx_buf_ctrl;
|
||||
ep->endpoint_control = &usbh_dpram->epx_ctrl;
|
||||
ep->hw_data_buf = &usbh_dpram->epx_data[0];
|
||||
}
|
||||
|
||||
return ep;
|
||||
}
|
||||
|
||||
static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
|
||||
{
|
||||
static void hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize,
|
||||
uint8_t transfer_type, uint8_t bmInterval) {
|
||||
// Already has data buffer, endpoint control, and buffer control allocated at this point
|
||||
assert(ep->endpoint_control);
|
||||
assert(ep->buffer_control);
|
||||
assert(ep->hw_data_buf);
|
||||
|
||||
uint8_t const num = tu_edpt_number(ep_addr);
|
||||
@ -317,49 +283,41 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
|
||||
ep->ep_addr = ep_addr;
|
||||
ep->dev_addr = dev_addr;
|
||||
|
||||
// For host, IN to host == RX, anything else rx == false
|
||||
ep->rx = (dir == TUSB_DIR_IN);
|
||||
|
||||
// Response to a setup packet on EP0 starts with pid of 1
|
||||
ep->next_pid = (num == 0 ? 1u : 0u);
|
||||
ep->wMaxPacketSize = wMaxPacketSize;
|
||||
ep->transfer_type = transfer_type;
|
||||
|
||||
pico_trace("hw_endpoint_init dev %d ep %02X xfer %d\n", ep->dev_addr, ep->ep_addr, ep->transfer_type);
|
||||
pico_trace("hw_endpoint_init dev %d ep %02X xfer %d\n", ep->dev_addr, ep->ep_addr, 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));
|
||||
|
||||
// Fill in endpoint control register with buffer offset
|
||||
uint32_t ep_reg = EP_CTRL_ENABLE_BITS
|
||||
| EP_CTRL_INTERRUPT_PER_BUFFER
|
||||
| (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
|
||||
| dpram_offset;
|
||||
if ( bmInterval )
|
||||
{
|
||||
ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
|
||||
uint32_t ctrl_value = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER |
|
||||
((uint32_t)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
|
||||
if (bmInterval) {
|
||||
ctrl_value |= (uint32_t)((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
|
||||
}
|
||||
*ep->endpoint_control = ep_reg;
|
||||
pico_trace("endpoint control (0x%p) <- 0x%lx\n", ep->endpoint_control, ep_reg);
|
||||
|
||||
io_rw_32 *ctrl_reg = hwep_ctrl_reg_host(ep);
|
||||
*ctrl_reg = ctrl_value;
|
||||
pico_trace("endpoint control (0x%p) <- 0x%lx\n", ctrl_reg, ctrl_value);
|
||||
ep->configured = true;
|
||||
|
||||
if ( ep != &epx )
|
||||
{
|
||||
if (ep != &epx) {
|
||||
// Endpoint has its own addr_endp and interrupt bits to be setup!
|
||||
// This is an interrupt/async endpoint. so need to set up ADDR_ENDP register with:
|
||||
// - device address
|
||||
// - endpoint number / direction
|
||||
// - preamble
|
||||
uint32_t reg = (uint32_t) (dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB));
|
||||
uint32_t reg = (uint32_t)(dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB));
|
||||
|
||||
if ( dir == TUSB_DIR_OUT )
|
||||
{
|
||||
if (dir == TUSB_DIR_OUT) {
|
||||
reg |= USB_ADDR_ENDP1_INTEP_DIR_BITS;
|
||||
}
|
||||
|
||||
if ( need_pre(dev_addr) )
|
||||
{
|
||||
if (need_pre(dev_addr)) {
|
||||
reg |= USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS;
|
||||
}
|
||||
usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = reg;
|
||||
@ -367,8 +325,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
|
||||
// Finally, enable interrupt that endpoint
|
||||
usb_hw_set->int_ep_ctrl = 1 << (ep->interrupt_num + 1);
|
||||
|
||||
// If it's an interrupt endpoint we need to set up the buffer control
|
||||
// register
|
||||
// If it's an interrupt endpoint we need to set up the buffer control register
|
||||
}
|
||||
}
|
||||
|
||||
@ -382,7 +339,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
||||
assert(rhport == 0);
|
||||
|
||||
// Reset any previous state
|
||||
rp2040_usb_init();
|
||||
rp2usb_init();
|
||||
|
||||
// Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
|
||||
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
|
||||
@ -466,8 +423,8 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
|
||||
// reset epx if it is currently active with unplugged device
|
||||
if (epx.configured && epx.active && epx.dev_addr == dev_addr) {
|
||||
epx.configured = false;
|
||||
*epx.endpoint_control = 0;
|
||||
*epx.buffer_control = 0;
|
||||
*hwep_ctrl_reg_host(&epx) = 0;
|
||||
*hwbuf_ctrl_reg_host(&epx) = 0;
|
||||
hw_endpoint_reset_transfer(&epx);
|
||||
}
|
||||
|
||||
@ -482,54 +439,41 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
|
||||
|
||||
// unconfigure the endpoint
|
||||
ep->configured = false;
|
||||
*ep->endpoint_control = 0;
|
||||
*ep->buffer_control = 0;
|
||||
*hwep_ctrl_reg_host(ep) = 0;
|
||||
*hwbuf_ctrl_reg_host(ep) = 0;
|
||||
hw_endpoint_reset_transfer(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t hcd_frame_number(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
uint32_t hcd_frame_number(uint8_t rhport) {
|
||||
(void)rhport;
|
||||
return usb_hw->sof_rd;
|
||||
}
|
||||
|
||||
void hcd_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
assert(rhport == 0);
|
||||
void hcd_int_enable(uint8_t rhport) {
|
||||
(void)rhport;
|
||||
irq_set_enabled(USBCTRL_IRQ, true);
|
||||
}
|
||||
|
||||
void hcd_int_disable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
void hcd_int_disable(uint8_t rhport) {
|
||||
(void)rhport;
|
||||
// todo we should check this is disabling from the correct core; note currently this is never called
|
||||
assert(rhport == 0);
|
||||
irq_set_enabled(USBCTRL_IRQ, false);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint API
|
||||
//--------------------------------------------------------------------+
|
||||
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t *ep_desc) {
|
||||
(void)rhport;
|
||||
pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress);
|
||||
|
||||
// Allocated differently based on if it's an interrupt endpoint or not
|
||||
struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
|
||||
hw_endpoint_t *ep = hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
|
||||
TU_ASSERT(ep);
|
||||
|
||||
_hw_endpoint_init(ep,
|
||||
dev_addr,
|
||||
ep_desc->bEndpointAddress,
|
||||
tu_edpt_packet_size(ep_desc),
|
||||
ep_desc->bmAttributes.xfer,
|
||||
ep_desc->bInterval);
|
||||
hw_endpoint_init(ep, dev_addr, ep_desc->bEndpointAddress, tu_edpt_packet_size(ep_desc), ep_desc->bmAttributes.xfer,
|
||||
ep_desc->bInterval);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -539,13 +483,12 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
|
||||
return false; // TODO not implemented yet
|
||||
}
|
||||
|
||||
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
|
||||
{
|
||||
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) {
|
||||
(void) rhport;
|
||||
|
||||
pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen);
|
||||
|
||||
uint8_t const ep_num = tu_edpt_number(ep_addr);
|
||||
const uint8_t ep_num = tu_edpt_number(ep_addr);
|
||||
tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
// Get appropriate ep. Either EPX or interrupt endpoint
|
||||
@ -557,19 +500,17 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
assert(!ep->active);
|
||||
|
||||
// Control endpoint can change direction 0x00 <-> 0x80
|
||||
if ( ep_addr != ep->ep_addr )
|
||||
{
|
||||
if (ep_addr != ep->ep_addr) {
|
||||
assert(ep_num == 0);
|
||||
|
||||
// Direction has flipped on endpoint control so re init it but with same properties
|
||||
_hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0);
|
||||
hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, TUSB_XFER_CONTROL, 0);
|
||||
}
|
||||
|
||||
// If a normal transfer (non-interrupt) then initiate using
|
||||
// sie ctrl registers. Otherwise, interrupt ep registers should
|
||||
// already be configured
|
||||
if ( ep == &epx )
|
||||
{
|
||||
if (ep == &epx) {
|
||||
hw_endpoint_xfer_start(ep, buffer, buflen);
|
||||
|
||||
// That has set up buffer control, endpoint control etc
|
||||
@ -585,8 +526,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
usb_hw->sie_ctrl = flags & ~USB_SIE_CTRL_START_TRANS_BITS;
|
||||
busy_wait_at_least_cycles(12);
|
||||
usb_hw->sie_ctrl = flags;
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
hw_endpoint_xfer_start(ep, buffer, buflen);
|
||||
}
|
||||
|
||||
@ -611,14 +551,14 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
|
||||
}
|
||||
|
||||
// Configure EP0 struct with setup info for the trans complete
|
||||
struct hw_endpoint * ep = _hw_endpoint_allocate( (uint8_t) TUSB_XFER_CONTROL);
|
||||
hw_endpoint_t *ep = hw_endpoint_allocate((uint8_t)TUSB_XFER_CONTROL);
|
||||
TU_ASSERT(ep);
|
||||
|
||||
// EPX should be inactive
|
||||
assert(!ep->active);
|
||||
|
||||
// EP0 out
|
||||
_hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
|
||||
hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
|
||||
assert(ep->configured);
|
||||
|
||||
ep->remaining_len = 8;
|
||||
|
||||
@ -35,20 +35,13 @@
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF PROTOTYPE
|
||||
//--------------------------------------------------------------------+
|
||||
static void _hw_endpoint_xfer_sync(struct hw_endpoint* ep);
|
||||
static void hwep_xfer_sync(hw_endpoint_t *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);
|
||||
#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) {
|
||||
return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false;
|
||||
}
|
||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
static bool e15_is_critical_frame_period(struct hw_endpoint *ep);
|
||||
#else
|
||||
#define e15_is_critical_frame_period(x) (false)
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Implementation
|
||||
@ -62,7 +55,7 @@ static void unaligned_memcpy(void *dst, const void *src, size_t n) {
|
||||
}
|
||||
}
|
||||
|
||||
void rp2040_usb_init(void) {
|
||||
void rp2usb_init(void) {
|
||||
// Reset usb controller
|
||||
reset_block(RESETS_RESET_USBCTRL_BITS);
|
||||
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
|
||||
@ -93,35 +86,38 @@ void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint* ep) {
|
||||
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) {
|
||||
uint32_t value = 0;
|
||||
void __tusb_irq_path_func(hwbuf_ctrl_update)(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask) {
|
||||
const bool is_host = rp2usb_is_host_mode();
|
||||
uint32_t value = 0;
|
||||
uint32_t buf_ctrl = *buf_ctrl_reg;
|
||||
|
||||
if (and_mask) {
|
||||
value = *ep->buffer_control & and_mask;
|
||||
value = buf_ctrl & and_mask;
|
||||
}
|
||||
|
||||
if (or_mask) {
|
||||
value |= or_mask;
|
||||
if (or_mask & USB_BUF_CTRL_AVAIL) {
|
||||
if (*ep->buffer_control & USB_BUF_CTRL_AVAIL) {
|
||||
panic("ep %02X was already available", ep->ep_addr);
|
||||
if (buf_ctrl & USB_BUF_CTRL_AVAIL) {
|
||||
panic("buf_ctrl @ 0x%lX already available", (uintptr_t)buf_ctrl_reg);
|
||||
}
|
||||
*ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
|
||||
// 4.1.2.5.1 Con-current access: 12 cycles (should be good for 48*12Mhz = 576Mhz) after write to buffer control
|
||||
*buf_ctrl_reg = value & ~USB_BUF_CTRL_AVAIL;
|
||||
|
||||
// Section 4.1.2.7.1 (rp2040) / 12.7.3.7.1 (rp2350) Concurrent access: after write to buffer control, we need to
|
||||
// wait at least 1/48 mhz (usb clock), 12 cycles should be good for 48*12Mhz = 576Mhz.
|
||||
// Don't need delay in host mode as host is in charge
|
||||
if (!is_host_mode()) {
|
||||
if (!is_host) {
|
||||
busy_wait_at_least_cycles(12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ep->buffer_control = value;
|
||||
*buf_ctrl_reg = value;
|
||||
}
|
||||
|
||||
// prepare buffer, return buffer control
|
||||
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);
|
||||
// prepare buffer, move data if tx, return buffer control
|
||||
static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id, bool is_rx) {
|
||||
const uint16_t buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
|
||||
ep->remaining_len = (uint16_t) (ep->remaining_len - buflen);
|
||||
|
||||
uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL;
|
||||
@ -130,7 +126,7 @@ 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 (!is_rx) {
|
||||
// Copy data from user buffer to hw buffer
|
||||
unaligned_memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen);
|
||||
ep->user_buf += buflen;
|
||||
@ -146,49 +142,73 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep,
|
||||
buf_ctrl |= USB_BUF_CTRL_LAST;
|
||||
}
|
||||
|
||||
if (buf_id) buf_ctrl = buf_ctrl << 16;
|
||||
if (buf_id) {
|
||||
buf_ctrl = buf_ctrl << 16;
|
||||
}
|
||||
|
||||
return buf_ctrl;
|
||||
}
|
||||
|
||||
// Prepare buffer control register value
|
||||
void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep) {
|
||||
uint32_t ep_ctrl = *ep->endpoint_control;
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
|
||||
|
||||
// always compute and start with buffer 0
|
||||
uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL;
|
||||
bool is_rx;
|
||||
bool is_host = false;
|
||||
io_rw_32 *ep_ctrl_reg;
|
||||
io_rw_32 *buf_ctrl_reg;
|
||||
|
||||
// For now: skip double buffered for OUT endpoint in Device mode, since
|
||||
// host could send < 64 bytes and cause short packet on buffer0
|
||||
// NOTE: this could happen to Host mode IN endpoint
|
||||
// Also, Host mode "interrupt" endpoint hardware is only single buffered,
|
||||
// NOTE2: Currently Host bulk is implemented using "interrupt" endpoint
|
||||
bool const is_host = is_host_mode();
|
||||
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) {
|
||||
// Use buffer 1 (double buffered) if there is still data
|
||||
// TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
|
||||
|
||||
buf_ctrl |= prepare_ep_buffer(ep, 1);
|
||||
|
||||
// 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 {
|
||||
// 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;
|
||||
#if CFG_TUH_ENABLED
|
||||
is_host = rp2usb_is_host_mode();
|
||||
if (is_host) {
|
||||
buf_ctrl_reg = hwbuf_ctrl_reg_host(ep);
|
||||
ep_ctrl_reg = hwep_ctrl_reg_host(ep);
|
||||
is_rx = (dir == TUSB_DIR_IN);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
|
||||
ep_ctrl_reg = hwep_ctrl_reg_device(ep);
|
||||
is_rx = (dir == TUSB_DIR_OUT);
|
||||
}
|
||||
|
||||
*ep->endpoint_control = ep_ctrl;
|
||||
// always compute and start with buffer 0
|
||||
uint32_t buf_ctrl = prepare_ep_buffer(ep, 0, is_rx) | USB_BUF_CTRL_SEL;
|
||||
|
||||
// EP0 has no endpoint control register, also usbd only schedule 1 packet at a time (single buffer)
|
||||
if (ep_ctrl_reg != NULL) {
|
||||
uint32_t ep_ctrl = *ep_ctrl_reg;
|
||||
|
||||
// For now: skip double buffered for RX e.g OUT endpoint in Device mode, since host could send < 64 bytes and cause
|
||||
// short packet on buffer0
|
||||
// NOTE: this could happen to Host mode IN endpoint Also, Host mode "interrupt" endpoint hardware is only single
|
||||
// buffered,
|
||||
// NOTE2: Currently Host bulk is implemented using "interrupt" endpoint
|
||||
const bool force_single = (!is_host && is_rx) || (is_host && tu_edpt_number(ep->ep_addr) != 0);
|
||||
|
||||
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)
|
||||
|
||||
buf_ctrl |= prepare_ep_buffer(ep, 1, is_rx);
|
||||
|
||||
// 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 {
|
||||
// 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;
|
||||
}
|
||||
|
||||
*ep_ctrl_reg = ep_ctrl;
|
||||
}
|
||||
|
||||
TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
|
||||
|
||||
// Finally, write to buffer_control which will trigger the transfer
|
||||
// the next time the controller polls this dpram address
|
||||
_hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
|
||||
hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl);
|
||||
}
|
||||
|
||||
void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t total_len) {
|
||||
@ -206,13 +226,16 @@ void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t to
|
||||
ep->active = true;
|
||||
ep->user_buf = buffer;
|
||||
|
||||
if (e15_is_bulkin_ep(ep)) {
|
||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
if (ep->e15_bulk_in) {
|
||||
usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
|
||||
}
|
||||
|
||||
if (e15_is_critical_frame_period(ep)) {
|
||||
ep->pending = 1;
|
||||
} else {
|
||||
ep->pending = 1; // skip transfer if we are in critical frame period
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
hw_endpoint_start_next_buffer(ep);
|
||||
}
|
||||
|
||||
@ -220,13 +243,16 @@ 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) {
|
||||
uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
|
||||
if (buf_id) buf_ctrl = buf_ctrl >> 16;
|
||||
static uint16_t __tusb_irq_path_func(sync_ep_buffer)(hw_endpoint_t *ep, io_rw_32 *buf_ctrl_reg, uint8_t buf_id,
|
||||
bool is_rx) {
|
||||
uint32_t buf_ctrl = *buf_ctrl_reg;
|
||||
if (buf_id) {
|
||||
buf_ctrl = buf_ctrl >> 16;
|
||||
}
|
||||
|
||||
uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
|
||||
const uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
|
||||
|
||||
if (!ep->rx) {
|
||||
if (!is_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));
|
||||
@ -244,7 +270,6 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uin
|
||||
|
||||
// Short packet
|
||||
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;
|
||||
}
|
||||
@ -252,21 +277,38 @@ 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) {
|
||||
// Update hw endpoint struct with info from hardware
|
||||
// after a buff status interrupt
|
||||
// Update hw endpoint struct with info from hardware after a buff status interrupt
|
||||
static void __tusb_irq_path_func(hwep_xfer_sync)(hw_endpoint_t *ep) {
|
||||
// const uint8_t ep_num = tu_edpt_number(ep->ep_addr);
|
||||
const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
|
||||
|
||||
uint32_t __unused buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
|
||||
TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
|
||||
io_rw_32 *buf_ctrl_reg;
|
||||
io_rw_32 *ep_ctrl_reg;
|
||||
bool is_rx;
|
||||
|
||||
// always sync buffer 0
|
||||
uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
|
||||
#if CFG_TUH_ENABLED
|
||||
const bool is_host = rp2usb_is_host_mode();
|
||||
if (is_host) {
|
||||
buf_ctrl_reg = hwbuf_ctrl_reg_host(ep);
|
||||
ep_ctrl_reg = hwep_ctrl_reg_host(ep);
|
||||
is_rx = (dir == TUSB_DIR_IN);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
|
||||
ep_ctrl_reg = hwep_ctrl_reg_device(ep);
|
||||
is_rx = (dir == TUSB_DIR_OUT);
|
||||
}
|
||||
|
||||
TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(*buf_ctrl_reg),
|
||||
tu_u32_high16(*buf_ctrl_reg));
|
||||
uint16_t buf0_bytes = sync_ep_buffer(ep, buf_ctrl_reg, 0, is_rx); // always sync buffer 0
|
||||
|
||||
// sync buffer 1 if double buffered
|
||||
if ((*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS) {
|
||||
if (ep_ctrl_reg != NULL && (*ep_ctrl_reg) & EP_CTRL_DOUBLE_BUFFERED_BITS) {
|
||||
if (buf0_bytes == ep->wMaxPacketSize) {
|
||||
// sync buffer 1 if not short packet
|
||||
sync_ep_buffer(ep, 1);
|
||||
sync_ep_buffer(ep, buf_ctrl_reg, 1, is_rx);
|
||||
} else {
|
||||
// short packet on buffer 0
|
||||
// TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example
|
||||
@ -287,7 +329,8 @@ static void __tusb_irq_path_func(_hw_endpoint_xfer_sync)(struct hw_endpoint* ep)
|
||||
ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
|
||||
ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
|
||||
|
||||
_hw_endpoint_buffer_control_set_value32(ep, 0);
|
||||
io_rw_32 *buf_ctrl_reg = is_host ? hwbuf_ctrl_reg_host(ep) : hwbuf_ctrl_reg_device(ep);
|
||||
hwbuf_ctrl_set(buf_ctrl_reg, 0);
|
||||
|
||||
usb_hw->abort &= ~TU_BIT(ep_id);
|
||||
|
||||
@ -308,7 +351,7 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
|
||||
}
|
||||
|
||||
// Update EP struct from hardware state
|
||||
_hw_endpoint_xfer_sync(ep);
|
||||
hwep_xfer_sync(ep);
|
||||
|
||||
// Now we have synced our state with the hardware. Is there more data to transfer?
|
||||
// If we are done then notify tinyusb
|
||||
@ -318,9 +361,12 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
|
||||
hw_endpoint_lock_update(ep, -1);
|
||||
return true;
|
||||
} else {
|
||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
if (e15_is_critical_frame_period(ep)) {
|
||||
ep->pending = 1;
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
hw_endpoint_start_next_buffer(ep);
|
||||
}
|
||||
}
|
||||
@ -335,6 +381,7 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
// E15 is fixed with RP2350
|
||||
|
||||
/* Don't mark IN buffers as available during the last 200us of a full-speed
|
||||
frame. This avoids a situation seen with the USB2.0 hub on a Raspberry
|
||||
@ -354,16 +401,12 @@ 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) {
|
||||
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) {
|
||||
TU_VERIFY(e15_is_bulkin_ep(ep));
|
||||
if (!ep->e15_bulk_in) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point.
|
||||
* The device state machine cannot recover from receiving an incorrect PID
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
#ifndef RP2040_COMMON_H_
|
||||
#define RP2040_COMMON_H_
|
||||
|
||||
#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE)
|
||||
#error TinyUSB device and host mode not supported at the same time
|
||||
#endif
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#include "pico.h"
|
||||
@ -13,17 +9,34 @@
|
||||
#include "hardware/resets.h"
|
||||
#include "hardware/timer.h"
|
||||
|
||||
#if defined(PICO_RP2040_USB_DEVICE_ENUMERATION_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX)
|
||||
#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
|
||||
#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE)
|
||||
#error TinyUSB device and host mode not supported at the same time
|
||||
#endif
|
||||
|
||||
#if defined(PICO_RP2040_USB_DEVICE_UFRAME_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX)
|
||||
#define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX PICO_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
// E5 and E15 only apply to RP2040
|
||||
#if defined(PICO_RP2040) && PICO_RP2040 == 1
|
||||
// RP2040 E5: USB device fails to exit RESET state on busy USB bus.
|
||||
#if defined(PICO_RP2040_USB_DEVICE_ENUMERATION_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX)
|
||||
#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
|
||||
#endif
|
||||
|
||||
// RP2040 E15: USB Device controller will hang if certain bus errors occur during an IN transfer.
|
||||
#if defined(PICO_RP2040_USB_DEVICE_UFRAME_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX)
|
||||
#define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX PICO_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
|
||||
#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX 0
|
||||
#endif
|
||||
|
||||
#ifndef TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
#define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX 0
|
||||
#endif
|
||||
|
||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
#undef PICO_RP2040_USB_FAST_IRQ
|
||||
#define PICO_RP2040_USB_FAST_IRQ 1
|
||||
#undef PICO_RP2040_USB_FAST_IRQ
|
||||
#define PICO_RP2040_USB_FAST_IRQ 1
|
||||
#endif
|
||||
|
||||
#ifndef PICO_RP2040_USB_FAST_IRQ
|
||||
@ -36,6 +49,9 @@
|
||||
#define __tusb_irq_path_func(x) x
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
#define usb_hw_set ((usb_hw_t *) hw_set_alias_untyped(usb_hw))
|
||||
#define usb_hw_clear ((usb_hw_t *) hw_clear_alias_untyped(usb_hw))
|
||||
|
||||
@ -43,61 +59,48 @@
|
||||
#define pico_trace(...) TU_LOG(3, __VA_ARGS__)
|
||||
|
||||
// Hardware information per endpoint
|
||||
typedef struct hw_endpoint
|
||||
{
|
||||
// Is this a valid struct
|
||||
bool configured;
|
||||
typedef struct hw_endpoint {
|
||||
uint8_t ep_addr;
|
||||
uint8_t next_pid;
|
||||
uint8_t transfer_type;
|
||||
|
||||
// Transfer direction (i.e. IN is rx for host but tx for device)
|
||||
// allows us to common up transfer functions
|
||||
bool rx;
|
||||
bool active; // transferring data
|
||||
|
||||
uint8_t ep_addr;
|
||||
uint8_t next_pid;
|
||||
|
||||
// Endpoint control register
|
||||
io_rw_32 *endpoint_control;
|
||||
|
||||
// Buffer control register
|
||||
io_rw_32 *buffer_control;
|
||||
|
||||
// Buffer pointer in usb dpram
|
||||
uint8_t *hw_data_buf;
|
||||
|
||||
// User buffer in main memory
|
||||
uint8_t *user_buf;
|
||||
|
||||
// Current transfer information
|
||||
uint16_t remaining_len;
|
||||
uint16_t xferred_len;
|
||||
|
||||
// Data needed from EP descriptor
|
||||
uint16_t wMaxPacketSize;
|
||||
|
||||
// Endpoint is in use
|
||||
bool active;
|
||||
|
||||
// Interrupt, bulk, etc
|
||||
uint8_t transfer_type;
|
||||
|
||||
// Transfer scheduled but not active
|
||||
uint8_t pending;
|
||||
|
||||
#if CFG_TUH_ENABLED
|
||||
// Only needed for host
|
||||
uint8_t dev_addr;
|
||||
|
||||
// If interrupt endpoint
|
||||
uint8_t interrupt_num;
|
||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
bool e15_bulk_in; // Errata15 device bulk in
|
||||
uint8_t pending; // Transfer scheduled but not active
|
||||
#endif
|
||||
|
||||
uint16_t wMaxPacketSize;
|
||||
uint8_t *hw_data_buf; // Buffer pointer in usb dpram
|
||||
|
||||
// Current transfer information
|
||||
uint8_t *user_buf; // User buffer in main memory
|
||||
uint16_t remaining_len;
|
||||
uint16_t xferred_len;
|
||||
|
||||
#if CFG_TUH_ENABLED
|
||||
// Is this a valid struct
|
||||
bool configured;
|
||||
|
||||
// Only needed for host
|
||||
uint8_t dev_addr;
|
||||
|
||||
// If interrupt endpoint
|
||||
uint8_t interrupt_num;
|
||||
#endif
|
||||
} hw_endpoint_t;
|
||||
|
||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
extern volatile uint32_t e15_last_sof;
|
||||
#endif
|
||||
|
||||
void rp2040_usb_init(void);
|
||||
void rp2usb_init(void);
|
||||
|
||||
// if usb hardware is in host mode
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool rp2usb_is_host_mode(void) {
|
||||
return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false;
|
||||
}
|
||||
|
||||
void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
|
||||
bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
|
||||
@ -110,34 +113,60 @@ TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_lock_update(__unused struct
|
||||
// sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
|
||||
}
|
||||
|
||||
void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask);
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t _hw_endpoint_buffer_control_get_value32 (struct hw_endpoint *ep)
|
||||
{
|
||||
return *ep->buffer_control;
|
||||
// #if CFG_TUD_ENABLED
|
||||
TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_ctrl_reg_device(struct hw_endpoint *ep) {
|
||||
uint8_t const epnum = tu_edpt_number(ep->ep_addr);
|
||||
const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr);
|
||||
if (epnum == 0) {
|
||||
// EP0 has no endpoint control register because the buffer offsets are fixed and always enabled
|
||||
return NULL;
|
||||
}
|
||||
return (dir == TUSB_DIR_IN) ? &usb_dpram->ep_ctrl[epnum - 1].in : &usb_dpram->ep_ctrl[epnum - 1].out;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_value32 (struct hw_endpoint *ep, uint32_t value)
|
||||
{
|
||||
_hw_endpoint_buffer_control_update32(ep, 0, value);
|
||||
TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwbuf_ctrl_reg_device(struct hw_endpoint *ep) {
|
||||
const uint8_t epnum = tu_edpt_number(ep->ep_addr);
|
||||
const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr);
|
||||
return (dir == TUSB_DIR_IN) ? &usb_dpram->ep_buf_ctrl[epnum].in : &usb_dpram->ep_buf_ctrl[epnum].out;
|
||||
}
|
||||
// #endif
|
||||
|
||||
#if CFG_TUH_ENABLED
|
||||
TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_ctrl_reg_host(struct hw_endpoint *ep) {
|
||||
if (tu_edpt_number(ep->ep_addr) == 0) {
|
||||
return &usbh_dpram->epx_ctrl;
|
||||
}
|
||||
return &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_mask32 (struct hw_endpoint *ep, uint32_t value)
|
||||
{
|
||||
_hw_endpoint_buffer_control_update32(ep, ~value, value);
|
||||
TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwbuf_ctrl_reg_host(struct hw_endpoint *ep) {
|
||||
if (tu_edpt_number(ep->ep_addr) == 0) {
|
||||
return &usbh_dpram->epx_buf_ctrl;
|
||||
}
|
||||
return &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
void hwbuf_ctrl_update(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask);
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set(io_rw_32 *buf_ctrl_reg, uint32_t value) {
|
||||
hwbuf_ctrl_update(buf_ctrl_reg, 0, value);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_clear_mask32 (struct hw_endpoint *ep, uint32_t value)
|
||||
{
|
||||
_hw_endpoint_buffer_control_update32(ep, ~value, 0);
|
||||
TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) {
|
||||
hwbuf_ctrl_update(buf_ctrl_reg, ~value, value);
|
||||
}
|
||||
|
||||
static inline uintptr_t hw_data_offset (uint8_t *buf)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_clear_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) {
|
||||
hwbuf_ctrl_update(buf_ctrl_reg, ~value, 0);
|
||||
}
|
||||
|
||||
static inline uintptr_t hw_data_offset(uint8_t *buf) {
|
||||
// Remove usb base from buffer pointer
|
||||
return (uintptr_t) buf ^ (uintptr_t) usb_dpram;
|
||||
return (uintptr_t)buf ^ (uintptr_t)usb_dpram;
|
||||
}
|
||||
|
||||
extern const char *ep_dir_string[];
|
||||
|
||||
#endif
|
||||
|
||||
@ -336,7 +336,7 @@
|
||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||
#endif
|
||||
|
||||
//------------- pio-usb -------------//
|
||||
//------------- Raspberry Pi -------------//
|
||||
// Enable PIO-USB software host controller
|
||||
#ifndef CFG_TUH_RPI_PIO_USB
|
||||
#define CFG_TUH_RPI_PIO_USB 0
|
||||
|
||||
@ -107,7 +107,6 @@
|
||||
"host": false,
|
||||
"dual": false
|
||||
},
|
||||
"comment": "MSC is slow to enumerated #2602",
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "000831174392",
|
||||
|
||||
Reference in New Issue
Block a user