Merge branch 'master' into renesas_ra_hs_rebased
This commit is contained in:
@@ -64,6 +64,7 @@ function(add_tinyusb TARGET)
|
||||
-Wnull-dereference
|
||||
-Wuninitialized
|
||||
-Wunused
|
||||
-Wunused-function
|
||||
-Wreturn-type
|
||||
-Wredundant-decls
|
||||
)
|
||||
|
||||
@@ -113,21 +113,21 @@
|
||||
// EP IN software buffers and mutexes
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
|
||||
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO
|
||||
#endif
|
||||
#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
|
||||
|
||||
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO
|
||||
#endif
|
||||
#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
|
||||
|
||||
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO
|
||||
#endif
|
||||
@@ -139,36 +139,36 @@
|
||||
// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
|
||||
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
|
||||
#endif
|
||||
#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
|
||||
|
||||
// EP OUT software buffers and mutexes
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
|
||||
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO
|
||||
#endif
|
||||
#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
|
||||
|
||||
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO
|
||||
#endif
|
||||
#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
|
||||
|
||||
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO
|
||||
#endif
|
||||
@@ -180,27 +180,27 @@
|
||||
// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
|
||||
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
|
||||
#endif
|
||||
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
|
||||
|
||||
// Control buffers
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
|
||||
|
||||
#if CFG_TUD_AUDIO > 1
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 2
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
|
||||
#endif
|
||||
|
||||
// Active alternate setting of interfaces
|
||||
@@ -217,7 +217,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
|
||||
// Software encoding/decoding support FIFOs
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
|
||||
#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
|
||||
tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
|
||||
@@ -225,7 +225,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
|
||||
tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
|
||||
@@ -233,7 +233,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
|
||||
tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
|
||||
@@ -243,7 +243,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
|
||||
#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
|
||||
tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
|
||||
@@ -251,7 +251,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
|
||||
tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
|
||||
@@ -259,7 +259,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
|
||||
tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
|
||||
#if CFG_FIFO_MUTEX
|
||||
osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
|
||||
@@ -416,7 +416,7 @@ typedef struct
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
|
||||
CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
|
||||
static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
|
||||
|
||||
@@ -55,7 +55,7 @@ typedef struct
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION btd_interface_t _btd_itf;
|
||||
CFG_TUD_MEM_SECTION btd_interface_t _btd_itf;
|
||||
|
||||
static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
|
||||
{
|
||||
|
||||
@@ -76,7 +76,7 @@ typedef struct
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
|
||||
CFG_TUD_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
|
||||
|
||||
static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
|
||||
{
|
||||
|
||||
@@ -56,7 +56,7 @@ typedef struct
|
||||
} dfu_state_ctx_t;
|
||||
|
||||
// Only a single dfu state is allowed
|
||||
CFG_TUSB_MEM_SECTION tu_static dfu_state_ctx_t _dfu_ctx;
|
||||
CFG_TUD_MEM_SECTION tu_static dfu_state_ctx_t _dfu_ctx;
|
||||
|
||||
static void reset_state(void)
|
||||
{
|
||||
|
||||
@@ -58,7 +58,7 @@ typedef struct
|
||||
tusb_hid_descriptor_hid_t const * hid_descriptor;
|
||||
} hidd_interface_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID];
|
||||
CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID];
|
||||
|
||||
/*------------- Helpers -------------*/
|
||||
static inline uint8_t get_index_by_itfnum(uint8_t itf_num)
|
||||
|
||||
@@ -82,7 +82,7 @@ typedef struct
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI];
|
||||
CFG_TUD_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI];
|
||||
|
||||
bool tud_midi_n_mounted (uint8_t itf)
|
||||
{
|
||||
|
||||
@@ -34,13 +34,16 @@
|
||||
|
||||
#include "msc_device.h"
|
||||
|
||||
// Level where CFG_TUSB_DEBUG must be at least for this driver is logged
|
||||
#ifndef CFG_TUD_MSC_LOG_LEVEL
|
||||
#define CFG_TUD_MSC_LOG_LEVEL 2
|
||||
#endif
|
||||
|
||||
#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_MSC_LOG_LEVEL, __VA_ARGS__)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Can be selectively disabled to reduce logging when troubleshooting other driver
|
||||
#define MSC_DEBUG 2
|
||||
|
||||
enum
|
||||
{
|
||||
MSC_STAGE_CMD = 0,
|
||||
@@ -71,8 +74,8 @@ typedef struct
|
||||
uint8_t add_sense_qualifier;
|
||||
}mscd_interface_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static mscd_interface_t _mscd_itf;
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static mscd_interface_t _mscd_itf;
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
@@ -164,7 +167,7 @@ uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw)
|
||||
{
|
||||
if ( block_count )
|
||||
{
|
||||
TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n");
|
||||
TU_LOG_DRV(" SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n");
|
||||
status = MSC_CSW_STATUS_PHASE_ERROR;
|
||||
}else
|
||||
{
|
||||
@@ -174,22 +177,22 @@ uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw)
|
||||
{
|
||||
if ( SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir) )
|
||||
{
|
||||
TU_LOG(MSC_DEBUG, " SCSI case 10 (Ho <> Di)\r\n");
|
||||
TU_LOG_DRV(" SCSI case 10 (Ho <> Di)\r\n");
|
||||
status = MSC_CSW_STATUS_PHASE_ERROR;
|
||||
}
|
||||
else if ( SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir) )
|
||||
{
|
||||
TU_LOG(MSC_DEBUG, " SCSI case 8 (Hi <> Do)\r\n");
|
||||
TU_LOG_DRV(" SCSI case 8 (Hi <> Do)\r\n");
|
||||
status = MSC_CSW_STATUS_PHASE_ERROR;
|
||||
}
|
||||
else if ( 0 == block_count )
|
||||
{
|
||||
TU_LOG(MSC_DEBUG, " SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n");
|
||||
TU_LOG_DRV(" SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n");
|
||||
status = MSC_CSW_STATUS_FAILED;
|
||||
}
|
||||
else if ( cbw->total_bytes / block_count == 0 )
|
||||
{
|
||||
TU_LOG(MSC_DEBUG, " Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n");
|
||||
TU_LOG_DRV(" Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n");
|
||||
status = MSC_CSW_STATUS_PHASE_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -352,7 +355,7 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
|
||||
switch ( request->bRequest )
|
||||
{
|
||||
case MSC_REQ_RESET:
|
||||
TU_LOG(MSC_DEBUG, " MSC BOT Reset\r\n");
|
||||
TU_LOG_DRV(" MSC BOT Reset\r\n");
|
||||
TU_VERIFY(request->wValue == 0 && request->wLength == 0);
|
||||
|
||||
// driver state reset
|
||||
@@ -363,7 +366,7 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
|
||||
|
||||
case MSC_REQ_GET_MAX_LUN:
|
||||
{
|
||||
TU_LOG(MSC_DEBUG, " MSC Get Max Lun\r\n");
|
||||
TU_LOG_DRV(" MSC Get Max Lun\r\n");
|
||||
TU_VERIFY(request->wValue == 0 && request->wLength == 1);
|
||||
|
||||
uint8_t maxlun = 1;
|
||||
@@ -400,7 +403,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
||||
|
||||
if ( !(xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE) )
|
||||
{
|
||||
TU_LOG(MSC_DEBUG, " SCSI CBW is not valid\r\n");
|
||||
TU_LOG_DRV(" SCSI CBW is not valid\r\n");
|
||||
|
||||
// BOT 6.6.1 If CBW is not valid stall both endpoints until reset recovery
|
||||
p_msc->stage = MSC_STAGE_NEED_RESET;
|
||||
@@ -412,7 +415,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
||||
return false;
|
||||
}
|
||||
|
||||
TU_LOG(MSC_DEBUG, " SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
|
||||
TU_LOG_DRV(" SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
|
||||
//TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2);
|
||||
|
||||
p_csw->signature = MSC_CSW_SIGNATURE;
|
||||
@@ -457,7 +460,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
||||
{
|
||||
if (p_cbw->total_bytes > sizeof(_mscd_buf))
|
||||
{
|
||||
TU_LOG(MSC_DEBUG, " SCSI reject non READ10/WRITE10 with large data\r\n");
|
||||
TU_LOG_DRV(" SCSI reject non READ10/WRITE10 with large data\r\n");
|
||||
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
|
||||
}else
|
||||
{
|
||||
@@ -479,7 +482,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
||||
if ( resplen < 0 )
|
||||
{
|
||||
// unsupported command
|
||||
TU_LOG(MSC_DEBUG, " SCSI unsupported or failed command\r\n");
|
||||
TU_LOG_DRV(" SCSI unsupported or failed command\r\n");
|
||||
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
|
||||
}
|
||||
else if (resplen == 0)
|
||||
@@ -514,7 +517,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
||||
break;
|
||||
|
||||
case MSC_STAGE_DATA:
|
||||
TU_LOG(MSC_DEBUG, " SCSI Data [Lun%u]\r\n", p_cbw->lun);
|
||||
TU_LOG_DRV(" SCSI Data [Lun%u]\r\n", p_cbw->lun);
|
||||
//TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2);
|
||||
|
||||
if (SCSI_CMD_READ_10 == p_cbw->command[0])
|
||||
@@ -546,7 +549,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
||||
if ( cb_result < 0 )
|
||||
{
|
||||
// unsupported command
|
||||
TU_LOG(MSC_DEBUG, " SCSI unsupported command\r\n");
|
||||
TU_LOG_DRV(" SCSI unsupported command\r\n");
|
||||
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
|
||||
}else
|
||||
{
|
||||
@@ -575,7 +578,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
||||
// Wait for the Status phase to complete
|
||||
if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) )
|
||||
{
|
||||
TU_LOG(MSC_DEBUG, " SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status);
|
||||
TU_LOG_DRV(" SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status);
|
||||
// TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2);
|
||||
|
||||
// Invoke complete callback if defined
|
||||
@@ -845,7 +848,7 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
|
||||
if ( nbytes < 0 )
|
||||
{
|
||||
// negative means error -> endpoint is stalled & status in CSW set to failed
|
||||
TU_LOG(MSC_DEBUG, " tud_msc_read10_cb() return -1\r\n");
|
||||
TU_LOG_DRV(" tud_msc_read10_cb() return -1\r\n");
|
||||
|
||||
// set sense
|
||||
set_sense_medium_not_present(p_cbw->lun);
|
||||
@@ -907,7 +910,7 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3
|
||||
if ( nbytes < 0 )
|
||||
{
|
||||
// negative means error -> failed this scsi op
|
||||
TU_LOG(MSC_DEBUG, " tud_msc_write10_cb() return -1\r\n");
|
||||
TU_LOG_DRV(" tud_msc_write10_cb() return -1\r\n");
|
||||
|
||||
// update actual byte before failed
|
||||
p_msc->xferred_len += xferred_bytes;
|
||||
|
||||
@@ -61,10 +61,10 @@ typedef struct
|
||||
#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t)
|
||||
#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0
|
||||
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static
|
||||
uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN];
|
||||
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static
|
||||
uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN];
|
||||
|
||||
struct ecm_notify_struct
|
||||
@@ -94,8 +94,8 @@ tu_static const struct ecm_notify_struct ecm_notify_csc =
|
||||
.uplink = 9728000,
|
||||
};
|
||||
|
||||
// TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static union
|
||||
// TODO remove CFG_TUD_MEM_SECTION, control internal buffer is already in this special section
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static union
|
||||
{
|
||||
uint8_t rndis_buf[120];
|
||||
struct ecm_notify_struct ecm_buf;
|
||||
@@ -104,8 +104,8 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static union
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// TODO remove CFG_TUSB_MEM_SECTION
|
||||
CFG_TUSB_MEM_SECTION tu_static netd_interface_t _netd_itf;
|
||||
// TODO remove CFG_TUD_MEM_SECTION
|
||||
CFG_TUD_MEM_SECTION tu_static netd_interface_t _netd_itf;
|
||||
|
||||
tu_static bool can_xmit;
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ typedef struct
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = {
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = {
|
||||
.wLength = sizeof(ntb_parameters_t),
|
||||
.bmNtbFormatsSupported = 0x01,
|
||||
.dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE,
|
||||
@@ -145,9 +145,9 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_par
|
||||
.wNtbOutMaxDatagrams = 0
|
||||
};
|
||||
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static transmit_ntb_t transmit_ntb[2];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static transmit_ntb_t transmit_ntb[2];
|
||||
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE];
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE];
|
||||
|
||||
tu_static ncm_interface_t ncm_interface;
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ typedef struct
|
||||
usbtmc_capabilities_specific_t const * capabilities;
|
||||
} usbtmc_interface_state_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION tu_static usbtmc_interface_state_t usbtmc_state =
|
||||
CFG_TUD_MEM_SECTION tu_static usbtmc_interface_state_t usbtmc_state =
|
||||
{
|
||||
.itf_id = 0xFF,
|
||||
};
|
||||
|
||||
2
src/class/vendor/vendor_device.c
vendored
2
src/class/vendor/vendor_device.c
vendored
@@ -59,7 +59,7 @@ typedef struct
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE];
|
||||
} vendord_interface_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION tu_static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
|
||||
CFG_TUD_MEM_SECTION tu_static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
|
||||
|
||||
#define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, rx_ff)
|
||||
|
||||
|
||||
@@ -130,8 +130,8 @@ typedef struct TU_ATTR_PACKED {
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUSB_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO];
|
||||
CFG_TUSB_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING];
|
||||
CFG_TUD_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO];
|
||||
CFG_TUD_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING];
|
||||
|
||||
tu_static uint8_t const _cap_get = 0x1u; /* support for GET */
|
||||
tu_static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
#define U32_TO_U8S_LE(_u32) TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32)
|
||||
|
||||
#define TU_BIT(n) (1UL << (n))
|
||||
|
||||
// Generate a mask with bit from high (31) to low (0) set, e.g TU_GENMASK(3, 0) = 0b1111
|
||||
#define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) )
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -99,10 +101,9 @@ TU_ATTR_WEAK extern void* tusb_app_phys_to_virt(void *phys_addr);
|
||||
#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var)))
|
||||
|
||||
// This is a backport of memset_s from c11
|
||||
TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count) {
|
||||
// TODO may check if desst and src is not NULL
|
||||
if (count > destsz) {
|
||||
if ( count > destsz ) {
|
||||
return -1;
|
||||
}
|
||||
memset(dest, ch, count);
|
||||
@@ -110,10 +111,9 @@ TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, i
|
||||
}
|
||||
|
||||
// This is a backport of memcpy_s from c11
|
||||
TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void * src, size_t count )
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void *src, size_t count) {
|
||||
// TODO may check if desst and src is not NULL
|
||||
if (count > destsz) {
|
||||
if ( count > destsz ) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest, src, count);
|
||||
@@ -169,6 +169,9 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align32 (uint32_t value) { retur
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); }
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned32(uint32_t value) { return (value & 0x1FUL) == 0; }
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned64(uint64_t value) { return (value & 0x3FUL) == 0; }
|
||||
|
||||
//------------- Mathematics -------------//
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; }
|
||||
|
||||
|
||||
@@ -43,9 +43,6 @@
|
||||
#define CFG_TUD_TASK_QUEUE_SZ 16
|
||||
#endif
|
||||
|
||||
// Debug level of USBD
|
||||
#define USBD_DBG 2
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Data
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -81,7 +78,7 @@ tu_static usbd_device_t _usbd_dev;
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
#define DRIVER_NAME(_name) .name = _name,
|
||||
#else
|
||||
#define DRIVER_NAME(_name)
|
||||
@@ -308,7 +305,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event,
|
||||
//--------------------------------------------------------------------+
|
||||
// Debug
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] =
|
||||
{
|
||||
"Invalid" ,
|
||||
@@ -330,7 +327,7 @@ void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback)
|
||||
usbd_class_driver_t const * driver = get_driver(i);
|
||||
if ( driver && driver->control_xfer_cb == callback )
|
||||
{
|
||||
TU_LOG(USBD_DBG, " %s control complete\r\n", driver->name);
|
||||
TU_LOG_USBD(" %s control complete\r\n", driver->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -396,10 +393,10 @@ bool tud_init (uint8_t rhport)
|
||||
// skip if already initialized
|
||||
if ( tud_inited() ) return true;
|
||||
|
||||
TU_LOG(USBD_DBG, "USBD init on controller %u\r\n", rhport);
|
||||
TU_LOG_INT(USBD_DBG, sizeof(usbd_device_t));
|
||||
TU_LOG_INT(USBD_DBG, sizeof(tu_fifo_t));
|
||||
TU_LOG_INT(USBD_DBG, sizeof(tu_edpt_stream_t));
|
||||
TU_LOG_USBD("USBD init on controller %u\r\n", rhport);
|
||||
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t));
|
||||
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t));
|
||||
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t));
|
||||
|
||||
tu_varclr(&_usbd_dev);
|
||||
|
||||
@@ -424,7 +421,7 @@ bool tud_init (uint8_t rhport)
|
||||
{
|
||||
usbd_class_driver_t const * driver = get_driver(i);
|
||||
TU_ASSERT(driver);
|
||||
TU_LOG(USBD_DBG, "%s init\r\n", driver->name);
|
||||
TU_LOG_USBD("%s init\r\n", driver->name);
|
||||
driver->init();
|
||||
}
|
||||
|
||||
@@ -496,21 +493,21 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
dcd_event_t event;
|
||||
if ( !osal_queue_receive(_usbd_q, &event, timeout_ms) ) return;
|
||||
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG(USBD_DBG, "\r\n"); // extra line for setup
|
||||
TU_LOG(USBD_DBG, "USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED");
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG_USBD("\r\n"); // extra line for setup
|
||||
TU_LOG_USBD("USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED");
|
||||
#endif
|
||||
|
||||
switch ( event.event_id )
|
||||
{
|
||||
case DCD_EVENT_BUS_RESET:
|
||||
TU_LOG(USBD_DBG, ": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]);
|
||||
TU_LOG_USBD(": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]);
|
||||
usbd_reset(event.rhport);
|
||||
_usbd_dev.speed = event.bus_reset.speed;
|
||||
break;
|
||||
|
||||
case DCD_EVENT_UNPLUGGED:
|
||||
TU_LOG(USBD_DBG, "\r\n");
|
||||
TU_LOG_USBD("\r\n");
|
||||
usbd_reset(event.rhport);
|
||||
|
||||
// invoke callback
|
||||
@@ -518,8 +515,8 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
break;
|
||||
|
||||
case DCD_EVENT_SETUP_RECEIVED:
|
||||
TU_LOG_PTR(USBD_DBG, &event.setup_received);
|
||||
TU_LOG(USBD_DBG, "\r\n");
|
||||
TU_LOG_PTR(CFG_TUD_LOG_LEVEL, &event.setup_received);
|
||||
TU_LOG_USBD("\r\n");
|
||||
|
||||
// Mark as connected after receiving 1st setup packet.
|
||||
// But it is easier to set it every time instead of wasting time to check then set
|
||||
@@ -534,7 +531,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
// Process control request
|
||||
if ( !process_control_request(event.rhport, &event.setup_received) )
|
||||
{
|
||||
TU_LOG(USBD_DBG, " Stall EP0\r\n");
|
||||
TU_LOG_USBD(" Stall EP0\r\n");
|
||||
// Failed -> stall both control endpoint IN and OUT
|
||||
dcd_edpt_stall(event.rhport, 0);
|
||||
dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK);
|
||||
@@ -548,7 +545,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const ep_dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
TU_LOG(USBD_DBG, "on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
|
||||
TU_LOG_USBD("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
|
||||
|
||||
_usbd_dev.ep_status[epnum][ep_dir].busy = 0;
|
||||
_usbd_dev.ep_status[epnum][ep_dir].claimed = 0;
|
||||
@@ -563,7 +560,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
usbd_class_driver_t const * driver = get_driver( _usbd_dev.ep2drv[epnum][ep_dir] );
|
||||
TU_ASSERT(driver, );
|
||||
|
||||
TU_LOG(USBD_DBG, " %s xfer callback\r\n", driver->name);
|
||||
TU_LOG_USBD(" %s xfer callback\r\n", driver->name);
|
||||
driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len);
|
||||
}
|
||||
}
|
||||
@@ -575,27 +572,27 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
// e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected
|
||||
if ( _usbd_dev.connected )
|
||||
{
|
||||
TU_LOG(USBD_DBG, ": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en);
|
||||
TU_LOG_USBD(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en);
|
||||
if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en);
|
||||
}else
|
||||
{
|
||||
TU_LOG(USBD_DBG, " Skipped\r\n");
|
||||
TU_LOG_USBD(" Skipped\r\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case DCD_EVENT_RESUME:
|
||||
if ( _usbd_dev.connected )
|
||||
{
|
||||
TU_LOG(USBD_DBG, "\r\n");
|
||||
TU_LOG_USBD("\r\n");
|
||||
if (tud_resume_cb) tud_resume_cb();
|
||||
}else
|
||||
{
|
||||
TU_LOG(USBD_DBG, " Skipped\r\n");
|
||||
TU_LOG_USBD(" Skipped\r\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case USBD_EVENT_FUNC_CALL:
|
||||
TU_LOG(USBD_DBG, "\r\n");
|
||||
TU_LOG_USBD("\r\n");
|
||||
if ( event.func_call.func ) event.func_call.func(event.func_call.param);
|
||||
break;
|
||||
|
||||
@@ -620,7 +617,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request)
|
||||
{
|
||||
usbd_control_set_complete_callback(driver->control_xfer_cb);
|
||||
TU_LOG(USBD_DBG, " %s control request\r\n", driver->name);
|
||||
TU_LOG_USBD(" %s control request\r\n", driver->name);
|
||||
return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request);
|
||||
}
|
||||
|
||||
@@ -641,11 +638,11 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request);
|
||||
}
|
||||
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME)
|
||||
{
|
||||
TU_LOG(USBD_DBG, " %s", tu_str_std_request[p_request->bRequest]);
|
||||
if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG(USBD_DBG, "\r\n");
|
||||
TU_LOG_USBD(" %s", tu_str_std_request[p_request->bRequest]);
|
||||
if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG_USBD("\r\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -701,7 +698,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
if ( _usbd_dev.cfg_num )
|
||||
{
|
||||
// already configured: need to clear all endpoints and driver first
|
||||
TU_LOG(USBD_DBG, " Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num);
|
||||
TU_LOG_USBD(" Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num);
|
||||
|
||||
// close all non-control endpoints, cancel all pending transfers if any
|
||||
dcd_edpt_close_all(rhport);
|
||||
@@ -730,7 +727,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
// Only support remote wakeup for device feature
|
||||
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
|
||||
|
||||
TU_LOG(USBD_DBG, " Enable Remote Wakeup\r\n");
|
||||
TU_LOG_USBD(" Enable Remote Wakeup\r\n");
|
||||
|
||||
// Host may enable remote wake up before suspending especially HID device
|
||||
_usbd_dev.remote_wakeup_en = true;
|
||||
@@ -741,7 +738,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
// Only support remote wakeup for device feature
|
||||
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
|
||||
|
||||
TU_LOG(USBD_DBG, " Disable Remote Wakeup\r\n");
|
||||
TU_LOG_USBD(" Disable Remote Wakeup\r\n");
|
||||
|
||||
// Host may disable remote wake up after resuming
|
||||
_usbd_dev.remote_wakeup_en = false;
|
||||
@@ -924,7 +921,7 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
|
||||
if ( (sizeof(tusb_desc_interface_t) <= drv_len) && (drv_len <= remaining_len) )
|
||||
{
|
||||
// Open successfully
|
||||
TU_LOG(USBD_DBG, " %s opened\r\n", driver->name);
|
||||
TU_LOG_USBD(" %s opened\r\n", driver->name);
|
||||
|
||||
// Some drivers use 2 or more interfaces but may not have IAD e.g MIDI (always) or
|
||||
// BTH (even CDC) with class in device descriptor (single interface)
|
||||
@@ -983,7 +980,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
|
||||
{
|
||||
case TUSB_DESC_DEVICE:
|
||||
{
|
||||
TU_LOG(USBD_DBG, " Device\r\n");
|
||||
TU_LOG_USBD(" Device\r\n");
|
||||
|
||||
void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb();
|
||||
|
||||
@@ -1007,7 +1004,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
|
||||
|
||||
case TUSB_DESC_BOS:
|
||||
{
|
||||
TU_LOG(USBD_DBG, " BOS\r\n");
|
||||
TU_LOG_USBD(" BOS\r\n");
|
||||
|
||||
// requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
|
||||
if (!tud_descriptor_bos_cb) return false;
|
||||
@@ -1029,12 +1026,12 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
|
||||
|
||||
if ( desc_type == TUSB_DESC_CONFIGURATION )
|
||||
{
|
||||
TU_LOG(USBD_DBG, " Configuration[%u]\r\n", desc_index);
|
||||
TU_LOG_USBD(" Configuration[%u]\r\n", desc_index);
|
||||
desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index);
|
||||
}else
|
||||
{
|
||||
// Host only request this after getting Device Qualifier descriptor
|
||||
TU_LOG(USBD_DBG, " Other Speed Configuration\r\n");
|
||||
TU_LOG_USBD(" Other Speed Configuration\r\n");
|
||||
TU_VERIFY( tud_descriptor_other_speed_configuration_cb );
|
||||
desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
|
||||
}
|
||||
@@ -1050,7 +1047,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
|
||||
|
||||
case TUSB_DESC_STRING:
|
||||
{
|
||||
TU_LOG(USBD_DBG, " String[%u]\r\n", desc_index);
|
||||
TU_LOG_USBD(" String[%u]\r\n", desc_index);
|
||||
|
||||
// String Descriptor always uses the desc set from user
|
||||
uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, tu_le16toh(p_request->wIndex));
|
||||
@@ -1063,7 +1060,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
|
||||
|
||||
case TUSB_DESC_DEVICE_QUALIFIER:
|
||||
{
|
||||
TU_LOG(USBD_DBG, " Device Qualifier\r\n");
|
||||
TU_LOG_USBD(" Device Qualifier\r\n");
|
||||
|
||||
TU_VERIFY( tud_descriptor_device_qualifier_cb );
|
||||
|
||||
@@ -1248,7 +1245,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
|
||||
// TODO skip ready() check for now since enumeration also use this API
|
||||
// TU_VERIFY(tud_ready());
|
||||
|
||||
TU_LOG(USBD_DBG, " Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
|
||||
TU_LOG_USBD(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
|
||||
|
||||
// Attempt to transfer on a busy endpoint, sound like an race condition !
|
||||
TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
|
||||
@@ -1265,7 +1262,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
|
||||
// DCD error, mark endpoint as ready to allow next transfer
|
||||
_usbd_dev.ep_status[epnum][dir].busy = 0;
|
||||
_usbd_dev.ep_status[epnum][dir].claimed = 0;
|
||||
TU_LOG(USBD_DBG, "FAILED\r\n");
|
||||
TU_LOG_USBD("FAILED\r\n");
|
||||
TU_BREAKPOINT();
|
||||
return false;
|
||||
}
|
||||
@@ -1282,7 +1279,7 @@ bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
TU_LOG(USBD_DBG, " Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes);
|
||||
TU_LOG_USBD(" Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes);
|
||||
|
||||
// Attempt to transfer on a busy endpoint, sound like an race condition !
|
||||
TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
|
||||
@@ -1293,14 +1290,14 @@ bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
|
||||
|
||||
if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes))
|
||||
{
|
||||
TU_LOG(USBD_DBG, "OK\r\n");
|
||||
TU_LOG_USBD("OK\r\n");
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
// DCD error, mark endpoint as ready to allow next transfer
|
||||
_usbd_dev.ep_status[epnum][dir].busy = 0;
|
||||
_usbd_dev.ep_status[epnum][dir].claimed = 0;
|
||||
TU_LOG(USBD_DBG, "failed\r\n");
|
||||
TU_LOG_USBD("failed\r\n");
|
||||
TU_BREAKPOINT();
|
||||
return false;
|
||||
}
|
||||
@@ -1326,7 +1323,7 @@ void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
// only stalled if currently cleared
|
||||
if ( !_usbd_dev.ep_status[epnum][dir].stalled )
|
||||
{
|
||||
TU_LOG(USBD_DBG, " Stall EP %02X\r\n", ep_addr);
|
||||
TU_LOG_USBD(" Stall EP %02X\r\n", ep_addr);
|
||||
dcd_edpt_stall(rhport, ep_addr);
|
||||
_usbd_dev.ep_status[epnum][dir].stalled = 1;
|
||||
_usbd_dev.ep_status[epnum][dir].busy = 1;
|
||||
@@ -1343,7 +1340,7 @@ void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
// only clear if currently stalled
|
||||
if ( _usbd_dev.ep_status[epnum][dir].stalled )
|
||||
{
|
||||
TU_LOG(USBD_DBG, " Clear Stall EP %02X\r\n", ep_addr);
|
||||
TU_LOG_USBD(" Clear Stall EP %02X\r\n", ep_addr);
|
||||
dcd_edpt_clear_stall(rhport, ep_addr);
|
||||
_usbd_dev.ep_status[epnum][dir].stalled = 0;
|
||||
_usbd_dev.ep_status[epnum][dir].busy = 0;
|
||||
@@ -1371,7 +1368,7 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
|
||||
rhport = _usbd_rhport;
|
||||
|
||||
TU_ASSERT(dcd_edpt_close, /**/);
|
||||
TU_LOG(USBD_DBG, " CLOSING Endpoint: 0x%02X\r\n", ep_addr);
|
||||
TU_LOG_USBD(" CLOSING Endpoint: 0x%02X\r\n", ep_addr);
|
||||
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
@@ -32,10 +32,7 @@
|
||||
#include "tusb.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
// Debug level of USBD Control
|
||||
#define USBD_CONTROL_DEBUG 2
|
||||
|
||||
#if CFG_TUSB_DEBUG >= USBD_CONTROL_DEBUG
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback);
|
||||
#endif
|
||||
|
||||
@@ -58,7 +55,7 @@ typedef struct
|
||||
|
||||
tu_static usbd_control_xfer_t _ctrl_xfer;
|
||||
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN
|
||||
tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -191,7 +188,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
|
||||
{
|
||||
TU_VERIFY(_ctrl_xfer.buffer);
|
||||
memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes);
|
||||
TU_LOG_MEM(USBD_CONTROL_DEBUG, _usbd_ctrl_buf, xferred_bytes, 2);
|
||||
TU_LOG_MEM(CFG_TUD_LOG_LEVEL, _usbd_ctrl_buf, xferred_bytes, 2);
|
||||
}
|
||||
|
||||
_ctrl_xfer.total_xferred += (uint16_t) xferred_bytes;
|
||||
@@ -208,7 +205,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
|
||||
// callback can still stall control in status phase e.g out data does not make sense
|
||||
if ( _ctrl_xfer.complete_cb )
|
||||
{
|
||||
#if CFG_TUSB_DEBUG >= USBD_CONTROL_DEBUG
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -33,13 +33,20 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Level where CFG_TUSB_DEBUG must be at least for USBD is logged
|
||||
#ifndef CFG_TUD_LOG_LEVEL
|
||||
#define CFG_TUD_LOG_LEVEL 2
|
||||
#endif
|
||||
|
||||
#define TU_LOG_USBD(...) TU_LOG(CFG_TUD_LOG_LEVEL, __VA_ARGS__)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
typedef struct
|
||||
{
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
char const* name;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -110,15 +110,15 @@ typedef struct
|
||||
|
||||
// clean/flush data cache: write cache -> memory.
|
||||
// Required before an DMA TX transfer to make sure data is in memory
|
||||
void hcd_dcache_clean(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
bool hcd_dcache_clean(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
|
||||
// invalidate data cache: mark cache as invalid, next read will read from memory
|
||||
// Required BOTH before and after an DMA RX transfer
|
||||
void hcd_dcache_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
|
||||
// clean and invalidate data cache
|
||||
// Required before an DMA transfer where memory is both read/write by DMA
|
||||
void hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
@@ -171,11 +171,15 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
|
||||
// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked
|
||||
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen);
|
||||
|
||||
// Abort a queued transfer. Note: it can only abort transfer that has not been started
|
||||
// Return true if a queued transfer is aborted, false if there is no transfer to abort
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
||||
// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]);
|
||||
|
||||
// clear stall, data toggle is also reset to DATA0
|
||||
bool hcd_edpt_clear_stall(uint8_t daddr, uint8_t ep_addr);
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH implemented API
|
||||
|
||||
@@ -45,8 +45,8 @@ typedef struct
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t port_count;
|
||||
uint8_t status_change; // data from status change interrupt endpoint
|
||||
|
||||
CFG_TUH_MEM_ALIGN uint8_t status_change;
|
||||
CFG_TUH_MEM_ALIGN hub_port_status_response_t port_status;
|
||||
CFG_TUH_MEM_ALIGN hub_status_response_t hub_status;
|
||||
} hub_interface_t;
|
||||
|
||||
124
src/host/usbh.c
124
src/host/usbh.c
@@ -38,17 +38,19 @@
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#ifndef CFG_TUH_TASK_QUEUE_SZ
|
||||
#define CFG_TUH_TASK_QUEUE_SZ 16
|
||||
#define CFG_TUH_TASK_QUEUE_SZ 16
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_INTERFACE_MAX
|
||||
#define CFG_TUH_INTERFACE_MAX 8
|
||||
#define CFG_TUH_INTERFACE_MAX 8
|
||||
#endif
|
||||
|
||||
// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message
|
||||
#define USBH_DEBUG 2
|
||||
// Level where CFG_TUSB_DEBUG must be at least for USBH is logged
|
||||
#ifndef CFG_TUH_LOG_LEVEL
|
||||
#define CFG_TUH_LOG_LEVEL 2
|
||||
#endif
|
||||
|
||||
#define TU_LOG_USBH(...) TU_LOG(USBH_DEBUG, __VA_ARGS__)
|
||||
#define TU_LOG_USBH(...) TU_LOG(CFG_TUH_LOG_LEVEL, __VA_ARGS__)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-HCD common data structure
|
||||
@@ -322,12 +324,12 @@ bool tuh_init(uint8_t controller_id)
|
||||
if ( tuh_inited() ) return true;
|
||||
|
||||
TU_LOG_USBH("USBH init on controller %u\r\n", controller_id);
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(usbh_device_t));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(hcd_event_t));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(_ctrl_xfer));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(tuh_xfer_t));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(tu_fifo_t));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(tu_edpt_stream_t));
|
||||
TU_LOG_INT(CFG_TUH_LOG_LEVEL, sizeof(usbh_device_t));
|
||||
TU_LOG_INT(CFG_TUH_LOG_LEVEL, sizeof(hcd_event_t));
|
||||
TU_LOG_INT(CFG_TUH_LOG_LEVEL, sizeof(_ctrl_xfer));
|
||||
TU_LOG_INT(CFG_TUH_LOG_LEVEL, sizeof(tuh_xfer_t));
|
||||
TU_LOG_INT(CFG_TUH_LOG_LEVEL, sizeof(tu_fifo_t));
|
||||
TU_LOG_INT(CFG_TUH_LOG_LEVEL, sizeof(tu_edpt_stream_t));
|
||||
|
||||
// Event queue
|
||||
_usbh_q = osal_queue_create( &_usbh_qdef );
|
||||
@@ -450,39 +452,28 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
TU_LOG_USBH("on EP %02X with %u bytes: %s\r\n", ep_addr, (unsigned int) event.xfer_complete.len,
|
||||
tu_str_xfer_result[event.xfer_complete.result]);
|
||||
|
||||
if (event.dev_addr == 0)
|
||||
{
|
||||
if (event.dev_addr == 0) {
|
||||
// device 0 only has control endpoint
|
||||
TU_ASSERT(epnum == 0, );
|
||||
usbh_control_xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
usbh_device_t* dev = get_device(event.dev_addr);
|
||||
TU_VERIFY(dev && dev->connected, );
|
||||
|
||||
dev->ep_status[epnum][ep_dir].busy = 0;
|
||||
dev->ep_status[epnum][ep_dir].claimed = 0;
|
||||
|
||||
if ( 0 == epnum )
|
||||
{
|
||||
usbh_control_xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len);
|
||||
}else
|
||||
{
|
||||
uint8_t drv_id = dev->ep2drv[epnum][ep_dir];
|
||||
if(drv_id < USBH_CLASS_DRIVER_COUNT)
|
||||
{
|
||||
TU_LOG_USBH("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
|
||||
usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CFG_TUH_API_EDPT_XFER
|
||||
tuh_xfer_cb_t complete_cb = dev->ep_callback[epnum][ep_dir].complete_cb;
|
||||
if ( complete_cb )
|
||||
{
|
||||
tuh_xfer_t xfer =
|
||||
{
|
||||
if ( 0 == epnum ) {
|
||||
usbh_control_xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result,
|
||||
event.xfer_complete.len);
|
||||
}else {
|
||||
// Prefer application callback over built-in one if available. This occurs when tuh_edpt_xfer() is used
|
||||
// with enabled driver e.g HID endpoint
|
||||
#if CFG_TUH_API_EDPT_XFER
|
||||
tuh_xfer_cb_t const complete_cb = dev->ep_callback[epnum][ep_dir].complete_cb;
|
||||
if ( complete_cb ) {
|
||||
// re-construct xfer info
|
||||
tuh_xfer_t xfer = {
|
||||
.daddr = event.dev_addr,
|
||||
.ep_addr = ep_addr,
|
||||
.result = event.xfer_complete.result,
|
||||
@@ -491,16 +482,21 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
.buffer = NULL, // not available
|
||||
.complete_cb = complete_cb,
|
||||
.user_data = dev->ep_callback[epnum][ep_dir].user_data
|
||||
};
|
||||
};
|
||||
|
||||
complete_cb(&xfer);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
complete_cb(&xfer);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
uint8_t const drv_id = dev->ep2drv[epnum][ep_dir];
|
||||
if ( drv_id < USBH_CLASS_DRIVER_COUNT ) {
|
||||
TU_LOG_USBH("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
|
||||
usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result,
|
||||
event.xfer_complete.len);
|
||||
} else {
|
||||
// no driver/callback responsible for this transfer
|
||||
TU_ASSERT(false, );
|
||||
TU_ASSERT(false,);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -565,7 +561,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer)
|
||||
TU_LOG_USBH("[%u:%u] %s: ", rhport, daddr,
|
||||
(xfer->setup->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME) ?
|
||||
tu_str_std_request[xfer->setup->bRequest] : "Class Request");
|
||||
TU_LOG_PTR(USBH_DEBUG, xfer->setup);
|
||||
TU_LOG_PTR(CFG_TUH_LOG_LEVEL, xfer->setup);
|
||||
TU_LOG_USBH("\r\n");
|
||||
|
||||
if (xfer->complete_cb)
|
||||
@@ -671,7 +667,7 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result
|
||||
if (request->wLength)
|
||||
{
|
||||
TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, dev_addr);
|
||||
TU_LOG_MEM(USBH_DEBUG, _ctrl_xfer.buffer, xferred_bytes, 2);
|
||||
TU_LOG_MEM(CFG_TUH_LOG_LEVEL, _ctrl_xfer.buffer, xferred_bytes, 2);
|
||||
}
|
||||
|
||||
_ctrl_xfer.actual_len = (uint16_t) xferred_bytes;
|
||||
@@ -714,6 +710,25 @@ bool tuh_edpt_xfer(tuh_xfer_t* xfer)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) {
|
||||
usbh_device_t* dev = get_device(daddr);
|
||||
TU_VERIFY(dev);
|
||||
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
// skip if not busy
|
||||
TU_VERIFY(dev->ep_status[epnum][dir].busy);
|
||||
|
||||
bool const ret = hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr);
|
||||
if (ret) {
|
||||
// mark as ready if transfer is aborted
|
||||
dev->ep_status[epnum][dir].busy = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH API For Class Driver
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -745,7 +760,7 @@ void usbh_int_set(bool enabled)
|
||||
// Endpoint API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
// Claim an endpoint for transfer
|
||||
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
// Note: addr0 only use tuh_control_xfer
|
||||
@@ -761,7 +776,7 @@ bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
// Release an claimed endpoint due to failed transfer attempt
|
||||
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
// Note: addr0 only use tuh_control_xfer
|
||||
@@ -777,7 +792,7 @@ bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
// Submit an transfer
|
||||
bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||
{
|
||||
@@ -844,14 +859,13 @@ bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
|
||||
return hcd_edpt_open(usbh_get_rhport(dev_addr), dev_addr, desc_ep);
|
||||
}
|
||||
|
||||
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) {
|
||||
usbh_device_t* dev = get_device(dev_addr);
|
||||
TU_VERIFY(dev);
|
||||
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
return dev->ep_status[epnum][dir].busy;
|
||||
}
|
||||
|
||||
@@ -1186,7 +1200,7 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu
|
||||
TU_LOG_USBH("Device unplugged address = %u\r\n", daddr);
|
||||
|
||||
if (is_hub_addr(daddr)) {
|
||||
TU_LOG(USBH_DEBUG, " is a HUB device %u\r\n", daddr);
|
||||
TU_LOG(CFG_TUH_LOG_LEVEL, " is a HUB device %u\r\n", daddr);
|
||||
|
||||
// Submit removed event If the device itself is a hub (un-rolled recursive)
|
||||
// TODO a better to unroll recursrive is using array of removing_hubs and mark it here
|
||||
@@ -1657,7 +1671,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
|
||||
|
||||
if( drv_id >= USBH_CLASS_DRIVER_COUNT )
|
||||
{
|
||||
TU_LOG(USBH_DEBUG, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n",
|
||||
TU_LOG(CFG_TUH_LOG_LEVEL, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n",
|
||||
desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol);
|
||||
}
|
||||
}
|
||||
@@ -1695,7 +1709,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
||||
|
||||
if (is_hub_addr(dev_addr))
|
||||
{
|
||||
TU_LOG(USBH_DEBUG, "HUB address = %u is mounted\r\n", dev_addr);
|
||||
TU_LOG(CFG_TUH_LOG_LEVEL, "HUB address = %u is mounted\r\n", dev_addr);
|
||||
}else
|
||||
{
|
||||
// Invoke callback if available
|
||||
|
||||
@@ -172,8 +172,12 @@ bool tuh_control_xfer(tuh_xfer_t* xfer);
|
||||
// - sync : blocking if complete callback is NULL.
|
||||
bool tuh_edpt_xfer(tuh_xfer_t* xfer);
|
||||
|
||||
// Open an non-control endpoint
|
||||
bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep);
|
||||
// Open a non-control endpoint
|
||||
bool tuh_edpt_open(uint8_t daddr, tusb_desc_endpoint_t const * desc_ep);
|
||||
|
||||
// Abort a queued transfer. Note: it can only abort transfer that has not been started
|
||||
// Return true if a queued transfer is aborted, false if there is no transfer to abort
|
||||
bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr);
|
||||
|
||||
// Set Configuration (control transfer)
|
||||
// config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1
|
||||
|
||||
@@ -51,7 +51,7 @@ extern int8_t board_ft9xx_vbus(void);
|
||||
extern int board_uart_write(void const *buf, int len);
|
||||
|
||||
// Static array to store an incoming SETUP request for processing by tinyusb.
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN
|
||||
static uint8_t _ft9xx_setup_packet[8];
|
||||
|
||||
struct ft9xx_xfer_state
|
||||
|
||||
@@ -116,7 +116,7 @@ typedef struct
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// BDT(Buffer Descriptor Table) must be 256-byte aligned
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
|
||||
|
||||
|
||||
@@ -68,25 +68,34 @@ TU_ATTR_ALWAYS_INLINE static inline bool imxrt_is_cache_mem(uintptr_t addr) {
|
||||
return !(0x20000000 <= addr && addr < 0x20100000);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
const uintptr_t addr32 = (uintptr_t) addr;
|
||||
if (imxrt_is_cache_mem(addr32)) {
|
||||
TU_ASSERT(tu_is_aligned32(addr32));
|
||||
SCB_CleanDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
const uintptr_t addr32 = (uintptr_t) addr;
|
||||
if (imxrt_is_cache_mem(addr32)) {
|
||||
// Invalidating does not push cached changes back to RAM so we need to be
|
||||
// *very* careful when we do it. If we're not aligned, then we risk resetting
|
||||
// values back to their RAM state.
|
||||
TU_ASSERT(tu_is_aligned32(addr32));
|
||||
SCB_InvalidateDCache_by_Addr((void*) addr32, (int32_t) data_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
const uintptr_t addr32 = (uintptr_t) addr;
|
||||
if (imxrt_is_cache_mem(addr32)) {
|
||||
TU_ASSERT(tu_is_aligned32(addr32));
|
||||
SCB_CleanInvalidateDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -175,7 +175,7 @@ typedef struct {
|
||||
dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
|
||||
}dcd_data_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(2048)
|
||||
static dcd_data_t _dcd_data;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
@@ -41,16 +41,16 @@
|
||||
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
|
||||
#include "ci_hs_imxrt.h"
|
||||
|
||||
void hcd_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
imxrt_dcache_clean(addr, data_size);
|
||||
bool hcd_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
return imxrt_dcache_clean(addr, data_size);
|
||||
}
|
||||
|
||||
void hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
imxrt_dcache_invalidate(addr, data_size);
|
||||
bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
return imxrt_dcache_invalidate(addr, data_size);
|
||||
}
|
||||
|
||||
void hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
imxrt_dcache_clean_invalidate(addr, data_size);
|
||||
bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
return imxrt_dcache_clean_invalidate(addr, data_size);
|
||||
}
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
#ifdef TUP_USBIP_CHIPIDEA_HS
|
||||
// NXP Transdimension: 8 elements
|
||||
#define FRAMELIST_SIZE_BIT_VALUE 7u
|
||||
#define FRAMELIST_SIZE_USBCMD_VALUE (((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_POS_FRAMELIST_SIZE) | \
|
||||
((FRAMELIST_SIZE_BIT_VALUE >> 2) << EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB))
|
||||
#define FRAMELIST_SIZE_USBCMD_VALUE (((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_FRAMELIST_SIZE_SHIFT) | \
|
||||
((FRAMELIST_SIZE_BIT_VALUE >> 2) << EHCI_USBCMD_CHIPIDEA_FRAMELIST_SIZE_MSB_SHIFT))
|
||||
#else
|
||||
// STD EHCI: 256 elements
|
||||
#define FRAMELIST_SIZE_BIT_VALUE 2u
|
||||
@@ -126,52 +126,50 @@ static inline void print_intr(uint32_t intr) {
|
||||
//--------------------------------------------------------------------+
|
||||
// PROTOTYPE
|
||||
//--------------------------------------------------------------------+
|
||||
static inline ehci_link_t* get_period_head(uint8_t rhport, uint32_t interval_ms)
|
||||
{
|
||||
(void) rhport;
|
||||
return (ehci_link_t*) &ehci_data.period_head_arr[ tu_log2( tu_min32(FRAMELIST_SIZE, interval_ms) ) ];
|
||||
}
|
||||
|
||||
static inline ehci_qhd_t* qhd_control(uint8_t dev_addr)
|
||||
{
|
||||
return &ehci_data.control[dev_addr].qhd;
|
||||
}
|
||||
// weak dcache for non-cacheable MCU
|
||||
TU_ATTR_WEAK bool hcd_dcache_clean(void const* addr, uint32_t data_size) { (void) addr; (void) data_size; return true; }
|
||||
TU_ATTR_WEAK bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) { (void) addr; (void) data_size; return true; }
|
||||
TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) { (void) addr; (void) data_size; return true; }
|
||||
|
||||
static inline ehci_qhd_t* qhd_async_head(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
// control qhd of dev0 is used as async head
|
||||
return qhd_control(0);
|
||||
}
|
||||
|
||||
static inline ehci_qtd_t* qtd_control(uint8_t dev_addr)
|
||||
{
|
||||
return &ehci_data.control[dev_addr].qtd;
|
||||
}
|
||||
|
||||
|
||||
static inline ehci_qhd_t* qhd_next (ehci_qhd_t const * p_qhd);
|
||||
static inline ehci_qhd_t* qhd_find_free (void);
|
||||
static inline ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_control(uint8_t dev_addr);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_next (ehci_qhd_t const * p_qhd);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_find_free (void);
|
||||
static ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
|
||||
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
|
||||
static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd);
|
||||
static void qhd_remove_qtd(ehci_qhd_t *qhd);
|
||||
|
||||
static inline ehci_qtd_t* qtd_find_free (void);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_control(uint8_t dev_addr);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_find_free (void);
|
||||
static void qtd_init (ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes);
|
||||
|
||||
static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
|
||||
static inline ehci_link_t* list_next (ehci_link_t const *p_link);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_get_period_head(uint8_t rhport, uint32_t interval_ms);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* list_get_async_head(uint8_t rhport);
|
||||
TU_ATTR_ALWAYS_INLINE static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_next (ehci_link_t const *p_link);
|
||||
static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr);
|
||||
|
||||
TU_ATTR_WEAK void hcd_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
static void ehci_disable_schedule(ehci_registers_t* regs, bool is_period) {
|
||||
// maybe have a timeout for status
|
||||
if (is_period) {
|
||||
regs->command_bm.periodic_enable = 0;
|
||||
while(regs->status_bm.periodic_status) {}
|
||||
} else {
|
||||
regs->command_bm.async_enable = 0;
|
||||
while(regs->status_bm.async_status) {} // should have a timeout
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_WEAK void hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
}
|
||||
|
||||
TU_ATTR_WEAK void hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
static void ehci_enable_schedule(ehci_registers_t* regs, bool is_period) {
|
||||
// maybe have a timeout for status
|
||||
if (is_period) {
|
||||
regs->command_bm.periodic_enable = 1;
|
||||
while ( 0 == regs->status_bm.periodic_status ) {}
|
||||
} else {
|
||||
regs->command_bm.async_enable = 1;
|
||||
while( 0 == regs->status_bm.async_status ) {}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -228,43 +226,6 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport)
|
||||
return (tusb_speed_t) ehci_data.regs->portsc_bm.nxp_port_speed; // NXP specific port speed
|
||||
}
|
||||
|
||||
static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr) {
|
||||
ehci_link_t* prev = list_head;
|
||||
|
||||
while (prev && !prev->terminate) {
|
||||
ehci_qhd_t* qhd = (ehci_qhd_t*) (uintptr_t) list_next(prev);
|
||||
|
||||
// done if loop back to head
|
||||
if ( (uintptr_t) qhd == (uintptr_t) list_head) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( qhd->dev_addr == dev_addr ) {
|
||||
// TODO deactivate all TD, wait for QHD to inactive before removal
|
||||
prev->address = qhd->next.address;
|
||||
|
||||
// EHCI 4.8.2 link the removed qhd's next to async head (which always reachable by Host Controller)
|
||||
qhd->next.address = ((uint32_t) list_head) | (EHCI_QTYPE_QHD << 1);
|
||||
|
||||
if ( qhd->int_smask )
|
||||
{
|
||||
// period list queue element is guarantee to be free in the next frame (1 ms)
|
||||
qhd->used = 0;
|
||||
}else
|
||||
{
|
||||
// async list use async advance handshake
|
||||
// mark as removing, will completely re-usable when async advance isr occurs
|
||||
qhd->removing = 1;
|
||||
}
|
||||
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
hcd_dcache_clean(prev, sizeof(ehci_qhd_t));
|
||||
}else {
|
||||
prev = list_next(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close all opened endpoint belong to this device
|
||||
void hcd_device_close(uint8_t rhport, uint8_t daddr)
|
||||
{
|
||||
@@ -274,7 +235,7 @@ void hcd_device_close(uint8_t rhport, uint8_t daddr)
|
||||
}
|
||||
|
||||
// Remove from async list
|
||||
list_remove_qhd_by_daddr((ehci_link_t *) qhd_async_head(rhport), daddr);
|
||||
list_remove_qhd_by_daddr((ehci_link_t *) list_get_async_head(rhport), daddr);
|
||||
|
||||
// Remove from all interval period list
|
||||
for(uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++) {
|
||||
@@ -286,37 +247,42 @@ void hcd_device_close(uint8_t rhport, uint8_t daddr)
|
||||
}
|
||||
|
||||
static void init_periodic_list(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
|
||||
// Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only
|
||||
for ( uint32_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++ ) {
|
||||
ehci_data.period_head_arr[i].int_smask = 1; // queue head in period list must have smask non-zero
|
||||
ehci_data.period_head_arr[i].qtd_overlay.halted = 1; // dummy node, always inactive
|
||||
}
|
||||
|
||||
ehci_link_t * const framelist = ehci_data.period_framelist;
|
||||
ehci_link_t * const period_1ms = get_period_head(rhport, 1u);
|
||||
|
||||
// TODO EHCI_FRAMELIST_SIZE with other size than 8
|
||||
// all links --> period_head_arr[0] (1ms)
|
||||
// 0, 2, 4, 6 etc --> period_head_arr[1] (2ms)
|
||||
// 1, 5 --> period_head_arr[2] (4ms)
|
||||
// 3 --> period_head_arr[3] (8ms)
|
||||
|
||||
// TODO EHCI_FRAMELIST_SIZE with other size than 8
|
||||
ehci_link_t * const framelist = ehci_data.period_framelist;
|
||||
ehci_link_t * const head_1ms = (ehci_link_t *) &ehci_data.period_head_arr[0];
|
||||
ehci_link_t * const head_2ms = (ehci_link_t *) &ehci_data.period_head_arr[1];
|
||||
ehci_link_t * const head_4ms = (ehci_link_t *) &ehci_data.period_head_arr[2];
|
||||
ehci_link_t * const head_8ms = (ehci_link_t *) &ehci_data.period_head_arr[3];
|
||||
|
||||
for (uint32_t i = 0; i < FRAMELIST_SIZE; i++) {
|
||||
framelist[i].address = (uint32_t) period_1ms;
|
||||
framelist[i].address = (uint32_t) head_1ms;
|
||||
framelist[i].type = EHCI_QTYPE_QHD;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < FRAMELIST_SIZE; i += 2) {
|
||||
list_insert(framelist + i, get_period_head(rhport, 2u), EHCI_QTYPE_QHD);
|
||||
list_insert(framelist + i, head_2ms, EHCI_QTYPE_QHD);
|
||||
}
|
||||
|
||||
for (uint32_t i = 1; i < FRAMELIST_SIZE; i += 4) {
|
||||
list_insert(framelist + i, get_period_head(rhport, 4u), EHCI_QTYPE_QHD);
|
||||
list_insert(framelist + i, head_4ms, EHCI_QTYPE_QHD);
|
||||
}
|
||||
|
||||
list_insert(framelist + 3, get_period_head(rhport, 8u), EHCI_QTYPE_QHD);
|
||||
list_insert(framelist + 3, head_8ms, EHCI_QTYPE_QHD);
|
||||
|
||||
period_1ms->terminate = 1;
|
||||
head_1ms->terminate = 1;
|
||||
}
|
||||
|
||||
bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
|
||||
@@ -341,18 +307,18 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
|
||||
regs->status = (EHCI_INT_MASK_ALL & ~EHCI_INT_MASK_PORT_CHANGE);
|
||||
|
||||
// Enable interrupts
|
||||
regs->inten = EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE | EHCI_INT_MASK_ASYNC_ADVANCE |
|
||||
EHCI_INT_MASK_NXP_PERIODIC | EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
|
||||
regs->inten = EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
|
||||
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
|
||||
|
||||
//------------- Asynchronous List -------------//
|
||||
ehci_qhd_t * const async_head = qhd_async_head(rhport);
|
||||
ehci_qhd_t * const async_head = list_get_async_head(rhport);
|
||||
tu_memclr(async_head, sizeof(ehci_qhd_t));
|
||||
|
||||
async_head->next.address = (uint32_t) async_head; // circular list, next is itself
|
||||
async_head->next.type = EHCI_QTYPE_QHD;
|
||||
async_head->head_list_flag = 1;
|
||||
async_head->qtd_overlay.halted = 1; // inactive most of time
|
||||
async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified
|
||||
async_head->next.address = (uint32_t) async_head; // circular list, next is itself
|
||||
async_head->next.type = EHCI_QTYPE_QHD;
|
||||
async_head->head_list_flag = 1;
|
||||
async_head->qtd_overlay.halted = 1; // inactive most of time
|
||||
async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified
|
||||
|
||||
regs->async_list_addr = (uint32_t) async_head;
|
||||
|
||||
@@ -366,8 +332,7 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
|
||||
regs->nxp_tt_control = 0;
|
||||
|
||||
//------------- USB CMD Register -------------//
|
||||
regs->command |= TU_BIT(EHCI_USBCMD_POS_RUN_STOP) | TU_BIT(EHCI_USBCMD_POS_ASYNC_ENABLE) |
|
||||
TU_BIT(EHCI_USBCMD_POS_PERIOD_ENABLE) | // TODO enable period list only there is int/iso endpoint
|
||||
regs->command |= EHCI_USBCMD_RUN_STOP | EHCI_USBCMD_PERIOD_SCHEDULE_ENABLE | EHCI_USBCMD_ASYNC_SCHEDULE_ENABLE |
|
||||
FRAMELIST_SIZE_USBCMD_VALUE;
|
||||
|
||||
//------------- ConfigFlag Register (skip) -------------//
|
||||
@@ -377,7 +342,7 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
|
||||
if (ehci_data.cap_regs->hcsparams_bm.port_power_control) {
|
||||
// mask out all change bits since they are Write 1 to clear
|
||||
uint32_t portsc = (regs->portsc & ~EHCI_PORTSC_MASK_W1C);
|
||||
portsc |= ECHI_PORTSC_MASK_PORT_POWER;
|
||||
portsc |= EHCI_PORTSC_MASK_PORT_POWER;
|
||||
|
||||
regs->portsc = portsc;
|
||||
}
|
||||
@@ -426,11 +391,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
|
||||
{
|
||||
case TUSB_XFER_CONTROL:
|
||||
case TUSB_XFER_BULK:
|
||||
list_head = (ehci_link_t*) qhd_async_head(rhport);
|
||||
list_head = (ehci_link_t*) list_get_async_head(rhport);
|
||||
break;
|
||||
|
||||
case TUSB_XFER_INTERRUPT:
|
||||
list_head = get_period_head(rhport, p_qhd->interval_ms);
|
||||
list_head = list_get_period_head(rhport, p_qhd->interval_ms);
|
||||
break;
|
||||
|
||||
case TUSB_XFER_ISOCHRONOUS:
|
||||
@@ -439,10 +404,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
TU_ASSERT(list_head);
|
||||
|
||||
// TODO might need to disable async/period list
|
||||
list_insert(list_head, (ehci_link_t*) p_qhd, EHCI_QTYPE_QHD);
|
||||
|
||||
hcd_dcache_clean(p_qhd, sizeof(ehci_qhd_t));
|
||||
@@ -476,20 +439,25 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
ehci_qhd_t* qhd;
|
||||
ehci_qhd_t* qhd = qhd_get_from_addr(dev_addr, ep_addr);
|
||||
ehci_qtd_t* qtd;
|
||||
|
||||
if (epnum == 0) {
|
||||
qhd = qhd_control(dev_addr);
|
||||
qtd = qtd_control(dev_addr);
|
||||
// Control endpoint never be stalled. Skip reset Data Toggle since it is fixed per stage
|
||||
if (qhd->qtd_overlay.halted) {
|
||||
qhd->qtd_overlay.halted = false;
|
||||
}
|
||||
|
||||
qtd = qtd_control(dev_addr);
|
||||
qtd_init(qtd, buffer, buflen);
|
||||
|
||||
// first data toggle is always 1 (data & setup stage)
|
||||
qtd->data_toggle = 1;
|
||||
qtd->pid = dir ? EHCI_PID_IN : EHCI_PID_OUT;
|
||||
} else {
|
||||
qhd = qhd_get_from_addr(dev_addr, ep_addr);
|
||||
// skip if endpoint is halted
|
||||
TU_VERIFY(!qhd->qtd_overlay.halted);
|
||||
|
||||
qtd = qtd_find_free();
|
||||
TU_ASSERT(qtd);
|
||||
|
||||
@@ -510,12 +478,45 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t daddr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
|
||||
// TODO ISO not supported yet
|
||||
ehci_qhd_t* qhd = qhd_get_from_addr(dev_addr, ep_addr);
|
||||
ehci_qtd_t * volatile qtd = qhd->attached_qtd;
|
||||
TU_VERIFY(qtd != NULL); // no queued transfer
|
||||
|
||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
||||
TU_VERIFY(qtd->active); // transfer is already complete
|
||||
|
||||
// HC is still processing, disable HC list schedule before making changes
|
||||
bool const is_period = (qhd->interval_ms > 0);
|
||||
|
||||
ehci_disable_schedule(ehci_data.regs, is_period);
|
||||
|
||||
// check active bit again just in case HC has just processed the TD
|
||||
bool const still_active = qtd->active;
|
||||
if (still_active) {
|
||||
// remove TD from QH overlay
|
||||
qhd->qtd_overlay.next.terminate = 1;
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
|
||||
// remove TD from QH software list
|
||||
qhd_remove_qtd(qhd);
|
||||
}
|
||||
|
||||
ehci_enable_schedule(ehci_data.regs, is_period);
|
||||
|
||||
return still_active; // true if removed an active transfer
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
ehci_qhd_t *qhd = qhd_get_from_addr(daddr, ep_addr);
|
||||
qhd->qtd_overlay.halted = 0;
|
||||
qhd->qtd_overlay.data_toggle = 0;
|
||||
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
|
||||
// TODO reset data toggle ?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -541,71 +542,77 @@ void async_advance_isr(uint8_t rhport)
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void port_connect_status_change_isr(uint8_t rhport)
|
||||
{
|
||||
void port_connect_status_change_isr(uint8_t rhport) {
|
||||
// NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
|
||||
if (ehci_data.regs->portsc_bm.current_connect_status)
|
||||
{
|
||||
if ( ehci_data.regs->portsc_bm.current_connect_status ) {
|
||||
hcd_port_reset(rhport);
|
||||
hcd_event_device_attach(rhport, true);
|
||||
}else // device unplugged
|
||||
} else // device unplugged
|
||||
{
|
||||
hcd_event_device_remove(rhport, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Check queue head for potential transfer complete (successful or error)
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void qhd_xfer_complete_isr(ehci_qhd_t * qhd) {
|
||||
// examine TD attached to queue head
|
||||
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) qhd->attached_qtd;
|
||||
if (qtd == NULL) return; // no TD attached
|
||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
||||
hcd_dcache_invalidate(qhd, sizeof(ehci_qhd_t)); // HC may have updated the overlay
|
||||
volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
|
||||
|
||||
// TD is still active, no need to process
|
||||
if (qtd->active) {
|
||||
return;
|
||||
}
|
||||
// process non-active (completed) QHD with attached (scheduled) TD
|
||||
if ( !qtd_overlay->active && qhd->attached_qtd != NULL ) {
|
||||
xfer_result_t xfer_result;
|
||||
|
||||
uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
||||
|
||||
// invalidate dcache if IN transfer
|
||||
if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
|
||||
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
||||
}
|
||||
|
||||
// remove and free TD before invoking callback
|
||||
qhd->attached_qtd = NULL;
|
||||
qhd->attached_buffer = 0;
|
||||
qtd->used = 0; // free QTD
|
||||
|
||||
// notify usbh
|
||||
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
||||
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
|
||||
{
|
||||
ehci_qhd_t *p_qhd = async_head;
|
||||
do
|
||||
{
|
||||
hcd_dcache_invalidate(p_qhd, sizeof(ehci_qhd_t));
|
||||
|
||||
// halted or error is processed in error isr
|
||||
if ( !p_qhd->qtd_overlay.halted ) {
|
||||
qhd_xfer_complete_isr(p_qhd);
|
||||
if ( qtd_overlay->halted ) {
|
||||
if (qtd_overlay->xact_err || qtd_overlay->err_count == 0 || qtd_overlay->buffer_err || qtd_overlay->babble_err) {
|
||||
// Error count = 0 often occurs when device disconnected, or other bus-related error
|
||||
xfer_result = XFER_RESULT_FAILED;
|
||||
TU_LOG3(" QHD xfer err count: %d\n", qtd_overlay->err_count);
|
||||
// TU_BREAKPOINT(); // TODO skip unplugged device
|
||||
}else {
|
||||
// no error bits are set, endpoint is halted due to STALL
|
||||
xfer_result = XFER_RESULT_STALLED;
|
||||
}
|
||||
} else {
|
||||
xfer_result = XFER_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
p_qhd = qhd_next(p_qhd);
|
||||
}while(p_qhd != async_head); // async list traversal, stop if loop around
|
||||
ehci_qtd_t * volatile qtd = qhd->attached_qtd;
|
||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t)); // HC may have written back TD
|
||||
|
||||
uint8_t const dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
||||
|
||||
// invalidate dcache if IN transfer with data
|
||||
if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
|
||||
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
||||
}
|
||||
|
||||
// remove and free TD before invoking callback
|
||||
qhd_remove_qtd(qhd);
|
||||
|
||||
// notify usbh
|
||||
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
||||
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
||||
void proccess_async_xfer_isr(ehci_qhd_t * const list_head)
|
||||
{
|
||||
uint32_t const period_1ms_addr = (uint32_t) get_period_head(rhport, 1u);
|
||||
ehci_link_t next_link = * get_period_head(rhport, interval_ms);
|
||||
ehci_qhd_t *qhd = list_head;
|
||||
|
||||
do {
|
||||
qhd_xfer_complete_isr(qhd);
|
||||
qhd = qhd_next(qhd);
|
||||
} while ( qhd != list_head ); // async list traversal, stop if loop around
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms)
|
||||
{
|
||||
uint32_t const period_1ms_addr = (uint32_t) list_get_period_head(rhport, 1u);
|
||||
ehci_link_t next_link = *list_get_period_head(rhport, interval_ms);
|
||||
|
||||
while (!next_link.terminate) {
|
||||
if (interval_ms > 1 && period_1ms_addr == tu_align32(next_link.address)) {
|
||||
@@ -618,22 +625,13 @@ void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
||||
switch (next_link.type) {
|
||||
case EHCI_QTYPE_QHD: {
|
||||
ehci_qhd_t *qhd = (ehci_qhd_t *) entry_addr;
|
||||
hcd_dcache_invalidate(qhd, sizeof(ehci_qhd_t));
|
||||
|
||||
if (!qhd->qtd_overlay.halted) {
|
||||
qhd_xfer_complete_isr(qhd);
|
||||
}
|
||||
qhd_xfer_complete_isr(qhd);
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO support hs/fs ISO
|
||||
case EHCI_QTYPE_ITD:
|
||||
// TODO support hs ISO
|
||||
break;
|
||||
|
||||
case EHCI_QTYPE_SITD:
|
||||
// TODO support split ISO
|
||||
break;
|
||||
|
||||
case EHCI_QTYPE_FSTN:
|
||||
default:
|
||||
break;
|
||||
@@ -643,108 +641,6 @@ void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO merge with qhd_xfer_complete_isr()
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void qhd_xfer_error_isr(ehci_qhd_t * qhd)
|
||||
{
|
||||
volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
|
||||
|
||||
// TD has error
|
||||
if (qtd_overlay->halted) {
|
||||
xfer_result_t xfer_result;
|
||||
|
||||
if (qtd_overlay->xact_err || qtd_overlay->err_count == 0 || qtd_overlay->buffer_err || qtd_overlay->babble_err) {
|
||||
// Error count = 0 often occurs when device disconnected, or other bus-related error
|
||||
xfer_result = XFER_RESULT_FAILED;
|
||||
}else {
|
||||
// no error bits are set, endpoint is halted due to STALL
|
||||
xfer_result = XFER_RESULT_STALLED;
|
||||
}
|
||||
|
||||
// if (XFER_RESULT_FAILED == xfer_result ) {
|
||||
// TU_LOG1(" QHD xfer err count: %d\n", qtd_overlay->err_count);
|
||||
// TU_BREAKPOINT(); // TODO skip unplugged device
|
||||
// }
|
||||
|
||||
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) qhd->attached_qtd;
|
||||
TU_ASSERT(qtd, ); // No TD yet, probably a race condition or cache issue !?
|
||||
|
||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
||||
|
||||
uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
||||
|
||||
// invalidate dcache if IN transfer
|
||||
if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
|
||||
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
||||
}
|
||||
|
||||
// remove and free TD before invoking callback
|
||||
qhd->attached_qtd = NULL;
|
||||
qhd->attached_buffer = 0;
|
||||
qtd->used = 0; // free QTD
|
||||
|
||||
if (0 == qhd->ep_number ) {
|
||||
// control cannot be halted
|
||||
qhd->qtd_overlay.next.terminate = 1;
|
||||
qhd->qtd_overlay.alternate.terminate = 1;
|
||||
qhd->qtd_overlay.halted = 0;
|
||||
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
}
|
||||
|
||||
// notify usbh
|
||||
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
||||
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void xfer_error_isr(uint8_t rhport)
|
||||
{
|
||||
//------------- async list -------------//
|
||||
ehci_qhd_t * const async_head = qhd_async_head(rhport);
|
||||
ehci_qhd_t *p_qhd = async_head;
|
||||
do
|
||||
{
|
||||
hcd_dcache_invalidate(p_qhd, sizeof(ehci_qhd_t));
|
||||
qhd_xfer_error_isr( p_qhd );
|
||||
p_qhd = qhd_next(p_qhd);
|
||||
}while(p_qhd != async_head); // async list traversal, stop if loop around
|
||||
|
||||
//------------- TODO refractor period list -------------//
|
||||
uint32_t const period_1ms_addr = (uint32_t) get_period_head(rhport, 1u);
|
||||
for (uint32_t interval_ms=1; interval_ms <= FRAMELIST_SIZE; interval_ms *= 2)
|
||||
{
|
||||
ehci_link_t next_item = * get_period_head(rhport, interval_ms);
|
||||
|
||||
// TODO abstract max loop guard for period
|
||||
while( !next_item.terminate &&
|
||||
!(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) )
|
||||
{
|
||||
switch ( next_item.type )
|
||||
{
|
||||
case EHCI_QTYPE_QHD:
|
||||
{
|
||||
ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) tu_align32(next_item.address);
|
||||
hcd_dcache_invalidate(p_qhd_int, sizeof(ehci_qhd_t));
|
||||
|
||||
qhd_xfer_error_isr(p_qhd_int);
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO support hs/fs ISO
|
||||
case EHCI_QTYPE_ITD:
|
||||
case EHCI_QTYPE_SITD:
|
||||
case EHCI_QTYPE_FSTN:
|
||||
default: break;
|
||||
}
|
||||
|
||||
next_item = *list_next(&next_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------- Host Controller Driver's Interrupt Handler -------------//
|
||||
void hcd_int_handler(uint8_t rhport)
|
||||
{
|
||||
@@ -776,29 +672,16 @@ void hcd_int_handler(uint8_t rhport)
|
||||
regs->status = EHCI_INT_MASK_PORT_CHANGE; // Acknowledge
|
||||
}
|
||||
|
||||
if (int_status & EHCI_INT_MASK_ERROR) {
|
||||
xfer_error_isr(rhport);
|
||||
regs->status = EHCI_INT_MASK_ERROR; // Acknowledge
|
||||
}
|
||||
// A USB transfer is completed (OK or error)
|
||||
uint32_t const usb_int = int_status & (EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR);
|
||||
if (usb_int) {
|
||||
proccess_async_xfer_isr(list_get_async_head(rhport));
|
||||
|
||||
//------------- some QTD/SITD/ITD with IOC set is completed -------------//
|
||||
if (int_status & EHCI_INT_MASK_NXP_ASYNC) {
|
||||
async_list_xfer_complete_isr(qhd_async_head(rhport));
|
||||
regs->status = EHCI_INT_MASK_NXP_ASYNC; // Acknowledge
|
||||
}
|
||||
|
||||
if (int_status & EHCI_INT_MASK_NXP_PERIODIC)
|
||||
{
|
||||
for (uint32_t i=1; i <= FRAMELIST_SIZE; i *= 2)
|
||||
{
|
||||
period_list_xfer_complete_isr(rhport, i);
|
||||
for ( uint32_t i = 1; i <= FRAMELIST_SIZE; i *= 2 ) {
|
||||
process_period_xfer_isr(rhport, i);
|
||||
}
|
||||
regs->status = EHCI_INT_MASK_NXP_PERIODIC; // Acknowledge
|
||||
}
|
||||
|
||||
if (int_status & EHCI_INT_MASK_USB) {
|
||||
// TODO standard EHCI xfer complete
|
||||
regs->status = EHCI_INT_MASK_USB; // Acknowledge
|
||||
regs->status = usb_int; // Acknowledge
|
||||
}
|
||||
|
||||
//------------- There is some removed async previously -------------//
|
||||
@@ -810,35 +693,103 @@ void hcd_int_handler(uint8_t rhport)
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HELPER
|
||||
// List Managing Helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get head of periodic list
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_get_period_head(uint8_t rhport, uint32_t interval_ms) {
|
||||
(void) rhport;
|
||||
return (ehci_link_t*) &ehci_data.period_head_arr[ tu_log2( tu_min32(FRAMELIST_SIZE, interval_ms) ) ];
|
||||
}
|
||||
|
||||
//------------- queue head helper -------------//
|
||||
static inline ehci_qhd_t* qhd_find_free (void)
|
||||
// Get head of async list
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* list_get_async_head(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
return qhd_control(0); // control qhd of dev0 is used as async head
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_next(ehci_link_t const *p_link) {
|
||||
return (ehci_link_t*) tu_align32(p_link->address);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
|
||||
{
|
||||
for (uint32_t i=0; i<QHD_MAX; i++)
|
||||
{
|
||||
new->address = current->address;
|
||||
current->address = ((uint32_t) new) | (new_type << 1);
|
||||
}
|
||||
|
||||
// Remove all queue head belong to this device address
|
||||
static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr) {
|
||||
ehci_link_t* prev = list_head;
|
||||
|
||||
while (prev && !prev->terminate) {
|
||||
ehci_qhd_t* qhd = (ehci_qhd_t*) (uintptr_t) list_next(prev);
|
||||
|
||||
// done if loop back to head
|
||||
if ( (uintptr_t) qhd == (uintptr_t) list_head) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( qhd->dev_addr == dev_addr ) {
|
||||
// TODO deactivate all TD, wait for QHD to inactive before removal
|
||||
prev->address = qhd->next.address;
|
||||
|
||||
// EHCI 4.8.2 link the removed qhd's next to async head (which always reachable by Host Controller)
|
||||
qhd->next.address = ((uint32_t) list_head) | (EHCI_QTYPE_QHD << 1);
|
||||
|
||||
if ( qhd->int_smask )
|
||||
{
|
||||
// period list queue element is guarantee to be free in the next frame (1 ms)
|
||||
qhd->used = 0;
|
||||
}else
|
||||
{
|
||||
// async list use async advance handshake
|
||||
// mark as removing, will completely re-usable when async advance isr occurs
|
||||
qhd->removing = 1;
|
||||
}
|
||||
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
hcd_dcache_clean(prev, sizeof(ehci_qhd_t));
|
||||
}else {
|
||||
prev = list_next(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Queue Header helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get queue head for control transfer (always available)
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_control(uint8_t dev_addr) {
|
||||
return &ehci_data.control[dev_addr].qhd;
|
||||
}
|
||||
|
||||
// Find a free queue head
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t *qhd_find_free(void) {
|
||||
for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
|
||||
if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd)
|
||||
{
|
||||
return (ehci_qhd_t*) tu_align32(p_qhd->next.address);
|
||||
// Next queue head link
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t *qhd_next(ehci_qhd_t const *p_qhd) {
|
||||
return (ehci_qhd_t *) tu_align32(p_qhd->next.address);
|
||||
}
|
||||
|
||||
static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
|
||||
// Get queue head from device + endpoint address
|
||||
static ehci_qhd_t *qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr) {
|
||||
if ( 0 == tu_edpt_number(ep_addr) ) {
|
||||
return qhd_control(dev_addr);
|
||||
}
|
||||
|
||||
for(uint32_t i=0; i<QHD_MAX; i++)
|
||||
{
|
||||
ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
|
||||
|
||||
for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
|
||||
if ( (qhd_pool[i].dev_addr == dev_addr) &&
|
||||
ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) )
|
||||
{
|
||||
ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) ) {
|
||||
return &qhd_pool[i];
|
||||
}
|
||||
}
|
||||
@@ -846,6 +797,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Init queue head with endpoint descriptor
|
||||
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
|
||||
{
|
||||
// address 0 is used as async head, which always on the list --> cannot be cleared (ehci halted otherwise)
|
||||
@@ -920,6 +872,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
|
||||
}
|
||||
}
|
||||
|
||||
// Attach a TD to queue head
|
||||
static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd) {
|
||||
qhd->attached_qtd = qtd;
|
||||
qhd->attached_buffer = qtd->buffer[0];
|
||||
@@ -931,17 +884,35 @@ static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd) {
|
||||
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
|
||||
}
|
||||
|
||||
// Remove an attached TD from queue head
|
||||
static void qhd_remove_qtd(ehci_qhd_t *qhd) {
|
||||
ehci_qtd_t * volatile qtd = qhd->attached_qtd;
|
||||
|
||||
//------------- TD helper -------------//
|
||||
static inline ehci_qtd_t *qtd_find_free(void) {
|
||||
qhd->attached_qtd = NULL;
|
||||
qhd->attached_buffer = 0;
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
|
||||
qtd->used = 0; // free QTD
|
||||
hcd_dcache_clean(qtd, sizeof(ehci_qtd_t));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Queue TD helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get TD for control transfer (always available)
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_control(uint8_t dev_addr) {
|
||||
return &ehci_data.control[dev_addr].qtd;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t *qtd_find_free(void) {
|
||||
for (uint32_t i = 0; i < QTD_MAX; i++) {
|
||||
if (!ehci_data.qtd_pool[i].used) return &ehci_data.qtd_pool[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
|
||||
{
|
||||
static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes) {
|
||||
tu_memclr(qtd, sizeof(ehci_qtd_t));
|
||||
qtd->used = 1;
|
||||
|
||||
@@ -955,24 +926,9 @@ static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
|
||||
qtd->expected_bytes = total_bytes;
|
||||
|
||||
qtd->buffer[0] = (uint32_t) buffer;
|
||||
for(uint8_t i=1; i<5; i++)
|
||||
{
|
||||
for(uint8_t i=1; i<5; i++) {
|
||||
qtd->buffer[i] |= tu_align4k(qtd->buffer[i - 1] ) + 4096;
|
||||
}
|
||||
}
|
||||
|
||||
//------------- List Managing Helper -------------//
|
||||
|
||||
// insert at head
|
||||
static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
|
||||
{
|
||||
new->address = current->address;
|
||||
current->address = ((uint32_t) new) | (new_type << 1);
|
||||
}
|
||||
|
||||
static inline ehci_link_t* list_next(ehci_link_t const *p_link)
|
||||
{
|
||||
return (ehci_link_t*) tu_align32(p_link->address);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -278,23 +278,24 @@ enum {
|
||||
EHCI_INT_MASK_PERIODIC_SCHED_STATUS = TU_BIT(14),
|
||||
EHCI_INT_MASK_ASYNC_SCHED_STATUS = TU_BIT(15),
|
||||
|
||||
EHCI_INT_MASK_NXP_ASYNC = TU_BIT(18),
|
||||
EHCI_INT_MASK_NXP_PERIODIC = TU_BIT(19),
|
||||
|
||||
EHCI_INT_MASK_ALL =
|
||||
EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
|
||||
EHCI_INT_MASK_FRAMELIST_ROLLOVER | EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR |
|
||||
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF |
|
||||
EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC
|
||||
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF
|
||||
};
|
||||
|
||||
enum {
|
||||
EHCI_USBCMD_POS_RUN_STOP = 0,
|
||||
EHCI_USBCMD_POS_FRAMELIST_SIZE = 2,
|
||||
EHCI_USBCMD_POS_PERIOD_ENABLE = 4,
|
||||
EHCI_USBCMD_POS_ASYNC_ENABLE = 5,
|
||||
EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB = 15,
|
||||
EHCI_USBCMD_POS_INTERRUPT_THRESHOLD = 16
|
||||
EHCI_USBCMD_FRAMELIST_SIZE_SHIFT = 2, // [2..3]
|
||||
EHCI_USBCMD_CHIPIDEA_FRAMELIST_SIZE_MSB_SHIFT = 15,
|
||||
EHCI_USBCMD_INTERRUPT_THRESHOLD_SHIFT = 16
|
||||
};
|
||||
|
||||
enum {
|
||||
EHCI_USBCMD_RUN_STOP = TU_BIT(0), // [0..0] 1 = Run, 0 = Stop
|
||||
EHCI_USBCMD_HCRESET = TU_BIT(1), // [1..1] SW write 1 to reset HC, clear by HC when complete
|
||||
EHCI_USBCMD_PERIOD_SCHEDULE_ENABLE = TU_BIT(4), // [4..4] Enable periodic schedule
|
||||
EHCI_USBCMD_ASYNC_SCHEDULE_ENABLE = TU_BIT(5), // [5..5] Enable async schedule
|
||||
EHCI_USBCMD_INTR_ON_ASYNC_ADVANCE_DOORBELL = TU_BIT(6), // [6..6] Tell HC to interrupt next time it advances async list. Clear by HC
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -306,7 +307,7 @@ enum {
|
||||
EHCI_PORTSC_MASK_FORCE_RESUME = TU_BIT(6),
|
||||
EHCI_PORTSC_MASK_PORT_SUSPEND = TU_BIT(7),
|
||||
EHCI_PORTSC_MASK_PORT_RESET = TU_BIT(8),
|
||||
ECHI_PORTSC_MASK_PORT_POWER = TU_BIT(12),
|
||||
EHCI_PORTSC_MASK_PORT_POWER = TU_BIT(12),
|
||||
|
||||
EHCI_PORTSC_MASK_W1C =
|
||||
EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE |
|
||||
|
||||
@@ -822,9 +822,17 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear stall, data toggle is also reset to DATA0
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
unsigned const pipenum = find_pipe(dev_addr, ep_addr);
|
||||
if (!pipenum) return false;
|
||||
hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
|
||||
|
||||
@@ -189,7 +189,7 @@ typedef struct
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// BDT(Buffer Descriptor Table) must be 256-byte aligned
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) volatile static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) volatile static dcd_data_t _dcd;
|
||||
|
||||
#if TU_PIC_INT_SIZE == 4
|
||||
TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
|
||||
|
||||
@@ -77,7 +77,7 @@ static tusb_speed_t get_speed(void);
|
||||
static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix);
|
||||
|
||||
// DMA descriptors shouldn't be placed in ITCM !
|
||||
CFG_TUSB_MEM_SECTION static dma_desc_t dma_desc[6];
|
||||
CFG_TUD_MEM_SECTION static dma_desc_t dma_desc[6];
|
||||
|
||||
static xfer_ctl_t xfer_status[EP_MAX];
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ typedef struct
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// BDT(Buffer Descriptor Table) must be 256-byte aligned
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ typedef struct
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// BDT(Buffer Descriptor Table) must be 256-byte aligned
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
|
||||
|
||||
|
||||
@@ -562,8 +562,16 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
if (!tu_edpt_number(ep_addr)) return true;
|
||||
int num = find_pipe(dev_addr, ep_addr);
|
||||
if (num < 0) return false;
|
||||
|
||||
@@ -92,7 +92,7 @@ typedef struct
|
||||
|
||||
} dcd_data_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(128) static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(128) static dcd_data_t _dcd;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
@@ -176,11 +176,11 @@ typedef struct
|
||||
// EP list must be 256-byte aligned
|
||||
// Some MCU controller may require this variable to be placed in specific SRAM region.
|
||||
// For example: LPC55s69 port1 Highspeed must be USB_RAM (0x40100000)
|
||||
// Use CFG_TUSB_MEM_SECTION to place it accordingly.
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
|
||||
// Use CFG_TUD_MEM_SECTION to place it accordingly.
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
|
||||
|
||||
// Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug)
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Multiple Controllers
|
||||
|
||||
@@ -341,19 +341,24 @@ static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t
|
||||
p_ed->is_interrupt_xfer = (xfer_type == TUSB_XFER_INTERRUPT ? 1 : 0);
|
||||
}
|
||||
|
||||
static void gtd_init(ohci_gtd_t* p_td, uint8_t* data_ptr, uint16_t total_bytes)
|
||||
{
|
||||
static void gtd_init(ohci_gtd_t *p_td, uint8_t *data_ptr, uint16_t total_bytes) {
|
||||
tu_memclr(p_td, sizeof(ohci_gtd_t));
|
||||
|
||||
p_td->used = 1;
|
||||
p_td->expected_bytes = total_bytes;
|
||||
p_td->used = 1;
|
||||
p_td->expected_bytes = total_bytes;
|
||||
|
||||
p_td->buffer_rounding = 1; // less than queued length is not a error
|
||||
p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO;
|
||||
p_td->condition_code = OHCI_CCODE_NOT_ACCESSED;
|
||||
p_td->buffer_rounding = 1; // less than queued length is not a error
|
||||
p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO;
|
||||
p_td->condition_code = OHCI_CCODE_NOT_ACCESSED;
|
||||
|
||||
p_td->current_buffer_pointer = _phys_addr(data_ptr);
|
||||
p_td->buffer_end = total_bytes ? (_phys_addr(data_ptr + total_bytes - 1)) : (uint8_t *)p_td->current_buffer_pointer;
|
||||
uint8_t *cbp = (uint8_t *) _phys_addr(data_ptr);
|
||||
|
||||
p_td->current_buffer_pointer = cbp;
|
||||
if ( total_bytes ) {
|
||||
p_td->buffer_end = _phys_addr(data_ptr + total_bytes - 1);
|
||||
} else {
|
||||
p_td->buffer_end = cbp;
|
||||
}
|
||||
}
|
||||
|
||||
static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
|
||||
@@ -487,7 +492,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
|
||||
ohci_ed_t* ed = &ohci_data.control[dev_addr].ed;
|
||||
ohci_gtd_t *qtd = &ohci_data.control[dev_addr].gtd;
|
||||
|
||||
gtd_init(qtd, (uint8_t*) setup_packet, 8);
|
||||
gtd_init(qtd, (uint8_t*)(uintptr_t) setup_packet, 8);
|
||||
qtd->index = dev_addr;
|
||||
qtd->pid = PID_SETUP;
|
||||
qtd->data_toggle = GTD_DT_DATA0;
|
||||
@@ -543,8 +548,16 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
ohci_ed_t * const p_ed = ed_from_addr(dev_addr, ep_addr);
|
||||
|
||||
p_ed->is_stalled = 0;
|
||||
|
||||
@@ -138,6 +138,11 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return pio_usb_host_endpoint_transfer(pio_rhport, dev_addr, ep_addr, buffer, buflen);
|
||||
}
|
||||
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
uint8_t const pio_rhport = RHPORT_PIO(rhport);
|
||||
return pio_usb_host_endpoint_abort_transfer(pio_rhport, dev_addr, ep_addr);
|
||||
}
|
||||
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
|
||||
{
|
||||
uint8_t const pio_rhport = RHPORT_PIO(rhport);
|
||||
@@ -158,8 +163,8 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
|
||||
// return busy;
|
||||
//}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
|
||||
|
||||
@@ -576,6 +576,14 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
|
||||
{
|
||||
(void) rhport;
|
||||
@@ -617,8 +625,8 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
|
||||
|
||||
@@ -752,9 +752,15 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
|
||||
return r;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t rhport = 0; // FIXME change API
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
uint16_t volatile *ctr = addr_to_pipectr(rhport, dev_addr, ep_addr);
|
||||
TU_ASSERT(ctr);
|
||||
|
||||
|
||||
@@ -295,15 +295,14 @@
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
||||
// TODO MEM_SECTION can be different for host and device controller
|
||||
// should use CFG_TUD_MEM_SECTION, CFG_TUH_MEM_SECTION
|
||||
// Memory section for placing buffer used for usb transferring. If MEM_SECTION is different for
|
||||
// host and device use: CFG_TUD_MEM_SECTION, CFG_TUH_MEM_SECTION instead
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
// alignment requirement of buffer used for endpoint transferring
|
||||
// TODO MEM_ALIGN can be different for host and device controller
|
||||
// should use CFG_TUD_MEM_ALIGN, CFG_TUH_MEM_ALIGN
|
||||
// Alignment requirement of buffer used for usb transferring. if MEM_ALIGN is different for
|
||||
// host and device controller use: CFG_TUD_MEM_ALIGN, CFG_TUH_MEM_ALIGN instead
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
|
||||
#endif
|
||||
@@ -321,24 +320,14 @@
|
||||
// Device Options (Default)
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// Attribute to place data in accessible RAM for device controller
|
||||
// default to CFG_TUSB_MEM_SECTION for backward-compatible
|
||||
// Attribute to place data in accessible RAM for device controller (default: CFG_TUSB_MEM_SECTION)
|
||||
#ifndef CFG_TUD_MEM_SECTION
|
||||
#ifdef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUD_MEM_SECTION CFG_TUSB_MEM_SECTION
|
||||
#else
|
||||
#define CFG_TUD_MEM_SECTION
|
||||
#endif
|
||||
#define CFG_TUD_MEM_SECTION CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
// Attribute to align memory for device controller
|
||||
// default to CFG_TUSB_MEM_ALIGN for backward-compatible
|
||||
// Attribute to align memory for device controller (default: CFG_TUSB_MEM_ALIGN)
|
||||
#ifndef CFG_TUD_MEM_ALIGN
|
||||
#ifdef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUD_MEM_ALIGN CFG_TUSB_MEM_ALIGN
|
||||
#else
|
||||
#define CFG_TUD_MEM_ALIGN TU_ATTR_ALIGNED(4)
|
||||
#endif
|
||||
#define CFG_TUD_MEM_ALIGN CFG_TUSB_MEM_ALIGN
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
@@ -419,19 +408,14 @@
|
||||
#endif
|
||||
#endif // CFG_TUH_ENABLED
|
||||
|
||||
// Attribute to place data in accessible RAM for host controller
|
||||
// default to CFG_TUSB_MEM_SECTION for backward-compatible
|
||||
// Attribute to place data in accessible RAM for host controller (default: CFG_TUSB_MEM_SECTION)
|
||||
#ifndef CFG_TUH_MEM_SECTION
|
||||
#ifdef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUH_MEM_SECTION CFG_TUSB_MEM_SECTION
|
||||
#else
|
||||
#define CFG_TUH_MEM_SECTION
|
||||
#endif
|
||||
#define CFG_TUH_MEM_SECTION CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
// Attribute to align memory for host controller
|
||||
#ifndef CFG_TUH_MEM_ALIGN
|
||||
#define CFG_TUH_MEM_ALIGN TU_ATTR_ALIGNED(4)
|
||||
#define CFG_TUH_MEM_ALIGN CFG_TUSB_MEM_ALIGN
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
|
||||
Reference in New Issue
Block a user