Merge branch 'master' into dcd_same70

This commit is contained in:
HiFiPhile
2021-07-17 12:10:35 +02:00
committed by GitHub
108 changed files with 2530 additions and 1336 deletions

View File

@@ -489,7 +489,7 @@ typedef enum
AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2),
AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3),
AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4),
AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x100000000,
AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000,
} audio_data_format_type_I_t;
/// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification
@@ -823,6 +823,33 @@ typedef struct TU_ATTR_PACKED
uint16_t wLockDelay ; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field.
} audio_desc_cs_as_iso_data_ep_t;
// 5.2.2 Control Request Layout
typedef struct TU_ATTR_PACKED
{
union
{
struct TU_ATTR_PACKED
{
uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
uint8_t type : 2; ///< Request type tusb_request_type_t.
uint8_t direction : 1; ///< Direction type. tusb_dir_t
} bmRequestType_bit;
uint8_t bmRequestType;
};
uint8_t bRequest; ///< Request type audio_cs_req_t
uint8_t bChannelNumber;
uint8_t bControlSelector;
union
{
uint8_t bInterface;
uint8_t bEndpoint;
};
uint8_t bEntityID;
uint16_t wLength;
} audio_control_request_t;
//// 5.2.3 Control Request Parameter Block Layout
// 5.2.3.1 1-byte Control CUR Parameter Block

View File

@@ -102,19 +102,19 @@
// 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_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
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];
#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_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
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];
#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_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
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];
#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
@@ -126,32 +126,32 @@ osal_mutex_def_t ep_in_ff_mutex_wr_3;
// - 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_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
CFG_TUSB_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_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
CFG_TUSB_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_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
CFG_TUSB_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_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
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];
#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_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
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];
#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_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
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];
#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
@@ -163,52 +163,52 @@ osal_mutex_def_t ep_out_ff_mutex_rd_3;
// - 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_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
CFG_TUSB_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_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
CFG_TUSB_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_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
CFG_TUSB_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_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
CFG_TUSB_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_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
CFG_TUSB_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_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
CFG_TUSB_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
CFG_TUSB_MEM_ALIGN uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
CFG_TUSB_MEM_ALIGN uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
CFG_TUSB_MEM_ALIGN uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#endif
// 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_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_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];
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
#endif
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
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_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];
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
#endif
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
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_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];
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
@@ -218,21 +218,21 @@ osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
#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_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_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];
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
#endif
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
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_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];
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
#endif
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
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_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];
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
@@ -294,7 +294,7 @@ typedef struct
// Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
#endif
// Decoding parameters - parameters are set when alternate AS interface is set by host
@@ -393,12 +393,12 @@ static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio);
#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf);
#endif
static inline uint8_t tu_desc_subtype(void const* desc)
{
return ((uint8_t const*) desc)[2];
}
#endif
bool tud_audio_n_mounted(uint8_t func_id)
{
@@ -643,7 +643,6 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
// Determine amount of samples
uint8_t const n_ff_used = audio->n_ff_used_rx;
uint16_t const nBytesToCopy = audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx;
uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used;
uint8_t cnt_ff;
@@ -662,14 +661,14 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx];
dst_end = info.ptr_lin + info.len_lin;
src = audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, info.ptr_lin, dst_end, src, n_ff_used);
src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used);
// Handle wrapped part of FIFO
info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
if (info.len_wrap != 0)
{
dst_end = info.ptr_wrap + info.len_wrap;
audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, info.ptr_wrap, dst_end, src, n_ff_used);
audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used);
}
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
}
@@ -885,7 +884,7 @@ range [-1, +1)
* */
// Helper function
static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, void * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used)
static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used)
{
// Optimize for fast half word copies
typedef struct{
@@ -900,15 +899,15 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const
switch (nBytesToCopy)
{
case 1:
while((uint8_t *)src < src_end)
while(src < src_end)
{
*dst = *(uint8_t *)src++;
*dst = *src++;
dst += n_ff_used;
}
break;
case 2:
while((uint8_t *)src < src_end)
while(src < src_end)
{
*(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
src += 2;
@@ -917,23 +916,23 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const
break;
case 3:
while((uint8_t *)src < src_end)
while(src < src_end)
{
// memcpy(dst, src, 3);
// src = (uint8_t *)src + 3;
// dst += 3 * n_ff_used;
// TODO: Is there a faster way to copy 3 bytes?
*dst++ = *(uint8_t *)src++;
*dst++ = *(uint8_t *)src++;
*dst++ = *(uint8_t *)src++;
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
dst += 3 * (n_ff_used - 1);
}
break;
case 4:
while((uint8_t *)src < src_end)
while(src < src_end)
{
*(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
src += 4;
@@ -993,8 +992,8 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
if (info.len_lin != 0)
{
info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length
src_end = info.ptr_lin + info.len_lin;
dst = audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, info.ptr_lin, src_end, dst, n_ff_used);
src_end = (uint8_t *)info.ptr_lin + info.len_lin;
dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used);
// Limit up to desired length
info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
@@ -1002,8 +1001,8 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
// Handle wrapped part of FIFO
if (info.len_wrap != 0)
{
src_end = info.ptr_wrap + info.len_wrap;
audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, info.ptr_wrap, src_end, dst, n_ff_used);
src_end = (uint8_t *)info.ptr_wrap + info.len_wrap;
audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used);
}
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
@@ -1481,18 +1480,20 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
audio->ep_in_as_intf_num = 0;
usbd_edpt_close(rhport, audio->ep_in);
// Invoke callback - can be used to stop data sampling
if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
audio->ep_in = 0; // Necessary?
// Clear support FIFOs if used
#if CFG_TUD_AUDIO_ENABLE_ENCODING
// Clear FIFOs, since data is no longer valid
#if !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_clear(&audio->ep_in_ff);
#else
for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
{
tu_fifo_clear(&audio->tx_supp_ff[cnt]);
}
#endif
// Invoke callback - can be used to stop data sampling
if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
audio->ep_in = 0; // Necessary?
}
#endif
@@ -1502,16 +1503,22 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
{
audio->ep_out_as_intf_num = 0;
usbd_edpt_close(rhport, audio->ep_out);
audio->ep_out = 0; // Necessary?
// Clear support FIFOs if used
#if CFG_TUD_AUDIO_ENABLE_DECODING
// Clear FIFOs, since data is no longer valid
#if !CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_clear(&audio->ep_out_ff);
#else
for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
{
tu_fifo_clear(&audio->rx_supp_ff[cnt]);
}
#endif
// Invoke callback - can be used to stop data sampling
if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
audio->ep_out = 0; // Necessary?
// Close corresponding feedback EP
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
usbd_edpt_close(rhport, audio->ep_fb);
@@ -1605,9 +1612,17 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff );
#endif
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
// In case of asynchronous EP, call Cb after ep_fb is set
if (!(((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.sync == 0x01 && audio->ep_fb == 0))
{
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
}
#else
// Invoke callback
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
#endif
// Prepare for incoming data
#if USE_LINEAR_BUFFER_RX
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
@@ -1621,8 +1636,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
{
audio->ep_fb = ep_addr;
// Invoke callback
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
// Invoke callback after ep_out is set
if (audio->ep_out != 0)
{
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
}
}
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -1658,64 +1676,65 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
switch (p_request->bmRequestType_bit.recipient)
{
case TUSB_REQ_RCPT_INTERFACE: ; // The semicolon is there to enable a declaration right after the label
uint8_t itf = TU_U16_LOW(p_request->wIndex);
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
if (entityID != 0)
case TUSB_REQ_RCPT_INTERFACE:
{
if (tud_audio_set_req_entity_cb)
{
// Check if entity is present and get corresponding driver index
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
uint8_t itf = TU_U16_LOW(p_request->wIndex);
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
// Invoke callback
return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
if (entityID != 0)
{
if (tud_audio_set_req_entity_cb)
{
// Check if entity is present and get corresponding driver index
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
// Invoke callback
return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
TU_LOG2(" No entity set request callback available!\r\n");
return false; // In case no callback function is present or request can not be conducted we stall it
}
}
else
{
TU_LOG2(" No entity set request callback available!\r\n");
return false; // In case no callback function is present or request can not be conducted we stall it
if (tud_audio_set_req_itf_cb)
{
// Find index of audio driver structure and verify interface really exists
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
// Invoke callback
return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
TU_LOG2(" No interface set request callback available!\r\n");
return false; // In case no callback function is present or request can not be conducted we stall it
}
}
}
else
{
if (tud_audio_set_req_itf_cb)
{
// Find index of audio driver structure and verify interface really exists
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
// Invoke callback
return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
TU_LOG2(" No interface set request callback available!\r\n");
return false; // In case no callback function is present or request can not be conducted we stall it
}
}
break;
case TUSB_REQ_RCPT_ENDPOINT: ; // The semicolon is there to enable a declaration right after the label
uint8_t ep = TU_U16_LOW(p_request->wIndex);
if (tud_audio_set_req_ep_cb)
case TUSB_REQ_RCPT_ENDPOINT:
{
// Check if entity is present and get corresponding driver index
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
uint8_t ep = TU_U16_LOW(p_request->wIndex);
// Invoke callback
return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
TU_LOG2(" No EP set request callback available!\r\n");
return false; // In case no callback function is present or request can not be conducted we stall it
}
if (tud_audio_set_req_ep_cb)
{
// Check if entity is present and get corresponding driver index
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
// Invoke callback
return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
TU_LOG2(" No EP set request callback available!\r\n");
return false; // In case no callback function is present or request can not be conducted we stall it
}
}
break;
// Unknown/Unsupported recipient
default: TU_BREAKPOINT(); return false;
}
@@ -1754,69 +1773,71 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
// Conduct checks which depend on the recipient
switch (p_request->bmRequestType_bit.recipient)
{
case TUSB_REQ_RCPT_INTERFACE: ; // The semicolon is there to enable a declaration right after the label
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
// Verify if entity is present
if (entityID != 0)
case TUSB_REQ_RCPT_INTERFACE:
{
// Find index of audio driver structure and verify entity really exists
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
// Verify if entity is present
if (entityID != 0)
{
if (tud_audio_get_req_entity_cb)
// Find index of audio driver structure and verify entity really exists
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
return tud_audio_get_req_entity_cb(rhport, p_request);
}
else
{
TU_LOG2(" No entity get request callback available!\r\n");
return false; // Stall
if (tud_audio_get_req_entity_cb)
{
return tud_audio_get_req_entity_cb(rhport, p_request);
}
else
{
TU_LOG2(" No entity get request callback available!\r\n");
return false; // Stall
}
}
}
}
else
{
// Find index of audio driver structure and verify interface really exists
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
else
{
if (tud_audio_get_req_itf_cb)
// Find index of audio driver structure and verify interface really exists
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
return tud_audio_get_req_itf_cb(rhport, p_request);
}
else
{
TU_LOG2(" No interface get request callback available!\r\n");
return false; // Stall
if (tud_audio_get_req_itf_cb)
{
return tud_audio_get_req_itf_cb(rhport, p_request);
}
else
{
TU_LOG2(" No interface get request callback available!\r\n");
return false; // Stall
}
}
}
}
break;
case TUSB_REQ_RCPT_ENDPOINT: ; // The semicolon is there to enable a declaration right after the label
uint8_t ep = TU_U16_LOW(p_request->wIndex);
// Find index of audio driver structure and verify EP really exists
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
case TUSB_REQ_RCPT_ENDPOINT:
{
if (tud_audio_get_req_ep_cb)
uint8_t ep = TU_U16_LOW(p_request->wIndex);
// Find index of audio driver structure and verify EP really exists
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
return tud_audio_get_req_ep_cb(rhport, p_request);
}
else
{
TU_LOG2(" No EP get request callback available!\r\n");
return false; // Stall
if (tud_audio_get_req_ep_cb)
{
return tud_audio_get_req_ep_cb(rhport, p_request);
}
else
{
TU_LOG2(" No EP get request callback available!\r\n");
return false; // Stall
}
}
}
break;
@@ -1913,8 +1934,12 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
{
if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
// Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
return audiod_fb_send(rhport, &_audiod_fct[func_id]);
// Schedule a transmit with the new value if EP is not busy
if (!usbd_edpt_busy(rhport, _audiod_fct[func_id].ep_fb))
{
// Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
return audiod_fb_send(rhport, &_audiod_fct[func_id]);
}
}
#endif
#endif
@@ -1935,29 +1960,31 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
// Conduct checks which depend on the recipient
switch (p_request->bmRequestType_bit.recipient)
{
case TUSB_REQ_RCPT_INTERFACE: ; // The semicolon is there to enable a declaration right after the label
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
// Verify if entity is present
if (entityID != 0)
case TUSB_REQ_RCPT_INTERFACE:
{
// Find index of audio driver structure and verify entity really exists
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
}
else
{
// Find index of audio driver structure and verify interface really exists
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
// Verify if entity is present
if (entityID != 0)
{
// Find index of audio driver structure and verify entity really exists
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
}
else
{
// Find index of audio driver structure and verify interface really exists
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
}
}
break;
case TUSB_REQ_RCPT_ENDPOINT: ; // The semicolon is there to enable a declaration right after the label
case TUSB_REQ_RCPT_ENDPOINT:
{
uint8_t ep = TU_U16_LOW(p_request->wIndex);
uint8_t ep = TU_U16_LOW(p_request->wIndex);
// Find index of audio driver structure and verify EP really exists
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
// Find index of audio driver structure and verify EP really exists
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
}
break;
// Unknown/Unsupported recipient
@@ -1992,15 +2019,17 @@ static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio
while (p_desc < p_desc_end)
{
// We assume the number of alternate settings is increasing thus we return the index of alternate setting zero!
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0)
{
*idxItf = tmp;
*pp_desc_int = p_desc;
return true;
if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
{
*idxItf = tmp;
*pp_desc_int = p_desc;
return true;
}
// Increase index, bytes read, and pointer
tmp++;
}
// Increase index, bytes read, and pointer
tmp++;
p_desc = tu_desc_next(p_desc);
}
}
@@ -2137,10 +2166,10 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
if (as_itf == audio->ep_in_as_intf_num)
{
audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
audio->format_type_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType;
audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType);
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
audio->format_type_I_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats;
audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats);
#endif
}
#endif
@@ -2202,22 +2231,19 @@ bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
// Format the feedback value
if (_audiod_fct[func_id].rhport == 0)
{
uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
#if !TUD_OPT_HIGH_SPEED
uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
// For FS format is 10.14
*(fb++) = (feedback >> 2) & 0xFF;
*(fb++) = (feedback >> 10) & 0xFF;
*(fb++) = (feedback >> 18) & 0xFF;
// 4th byte is needed to work correctly with MS Windows
*fb = 0;
}
else
{
// For HS format is 16.16 as originally demanded
_audiod_fct[func_id].fb_val = feedback;
}
// For FS format is 10.14
*(fb++) = (feedback >> 2) & 0xFF;
*(fb++) = (feedback >> 10) & 0xFF;
*(fb++) = (feedback >> 18) & 0xFF;
// 4th byte is needed to work correctly with MS Windows
*fb = 0;
#else
// For HS format is 16.16 as originally demanded
_audiod_fct[func_id].fb_val = feedback;
#endif
// Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))

View File

@@ -273,9 +273,6 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0);
// Note: 0xFF can be used with RNDIS
TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA), 0);
// Find available interface
cdcd_interface_t * p_cdc = NULL;
for(uint8_t cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++)
@@ -303,10 +300,11 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
{
// notification endpoint if any
TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 );
// notification endpoint
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
p_cdc->ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 );
p_cdc->ep_notif = desc_ep->bEndpointAddress;
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);

View File

@@ -149,29 +149,27 @@ void cdch_init(void)
tu_memclr(cdch_data, sizeof(cdch_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
}
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
uint16_t cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{
// Only support ACM
TU_VERIFY( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass);
(void) max_len;
// Only support AT commands, no protocol and vendor specific commands.
TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
0xff == itf_desc->bInterfaceProtocol);
// Only support ACM subclass
// Protocol 0xFF can be RNDIS device for windows XP
TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass &&
0xFF != itf_desc->bInterfaceProtocol, 0);
uint8_t const * p_desc;
cdch_data_t * p_cdc;
cdch_data_t * p_cdc = get_itf(dev_addr);
p_desc = tu_desc_next(itf_desc);
p_cdc = get_itf(dev_addr);
p_cdc->itf_num = itf_desc->bInterfaceNumber;
p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com
p_cdc->itf_num = itf_desc->bInterfaceNumber;
p_cdc->itf_protocol = itf_desc->bInterfaceProtocol;
//------------- Communication Interface -------------//
(*p_length) = sizeof(tusb_desc_interface_t);
uint16_t drv_len = tu_desc_len(itf_desc);
uint8_t const * p_desc = tu_desc_next(itf_desc);
// Communication Functional Descriptors
while( TUSB_DESC_CS_INTERFACE == p_desc[DESC_OFFSET_TYPE] )
while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
{
if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
{
@@ -179,52 +177,52 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
}
(*p_length) += p_desc[DESC_OFFSET_LEN];
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
}
if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
{
// notification endpoint
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) p_desc;
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, ep_desc) );
p_cdc->ep_notif = ep_desc->bEndpointAddress;
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep), 0 );
p_cdc->ep_notif = desc_ep->bEndpointAddress;
(*p_length) += p_desc[DESC_OFFSET_LEN];
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
}
//------------- Data Interface (if any) -------------//
if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) &&
if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
{
(*p_length) += p_desc[DESC_OFFSET_LEN];
// next to endpoint descriptor
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
// data endpoints expected to be in pairs
for(uint32_t i=0; i<2; i++)
{
tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
TU_ASSERT(TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer, 0);
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep), 0);
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
{
p_cdc->ep_in = ep_desc->bEndpointAddress;
p_cdc->ep_in = desc_ep->bEndpointAddress;
}else
{
p_cdc->ep_out = ep_desc->bEndpointAddress;
p_cdc->ep_out = desc_ep->bEndpointAddress;
}
(*p_length) += p_desc[DESC_OFFSET_LEN];
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next( p_desc );
}
}
return true;
return drv_len;
}
bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num)

View File

@@ -121,11 +121,11 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
void cdch_init(void);
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num);
bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
void cdch_close(uint8_t dev_addr);
void cdch_init (void);
uint16_t cdch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num);
bool cdch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
void cdch_close (uint8_t dev_addr);
#ifdef __cplusplus
}

View File

@@ -247,7 +247,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_reque
static uint16_t dfu_req_upload(uint8_t rhport, tusb_control_request_t const * request, uint16_t block_num, uint16_t wLength)
{
TU_VERIFY( wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE);
TU_VERIFY( wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE, 0);
uint16_t retval = tud_dfu_req_upload_data_cb(block_num, (uint8_t *)_dfu_state_ctx.transfer_buf, wLength);
tud_control_xfer(rhport, request, _dfu_state_ctx.transfer_buf, retval);
return retval;
@@ -276,6 +276,7 @@ static void dfu_req_dnload_setup(uint8_t rhport, tusb_control_request_t const *
// if they wish, there still will be the internal control buffer copy to this buffer
// but this mode would provide zero copy from the class driver to the application
TU_VERIFY( request->wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE, );
// setup for data phase
tud_control_xfer(rhport, request, _dfu_state_ctx.transfer_buf, request->wLength);
}
@@ -283,6 +284,7 @@ static void dfu_req_dnload_setup(uint8_t rhport, tusb_control_request_t const *
static void dfu_req_dnload_reply(uint8_t rhport, tusb_control_request_t const * request)
{
(void) rhport;
TU_VERIFY( request->wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE, );
tud_dfu_req_dnload_data_cb(request->wValue, (uint8_t *)_dfu_state_ctx.transfer_buf, request->wLength);
_dfu_state_ctx.blk_transfer_in_proc = false;
}

View File

@@ -280,7 +280,21 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
uint16_t xferlen = tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, p_hid->epin_buf, request->wLength);
uint8_t* report_buf = p_hid->epin_buf;
uint16_t req_len = request->wLength;
uint16_t xferlen = 0;
// If host request a specific Report ID, add ID to as 1 byte of response
if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) )
{
*report_buf++ = report_id;
req_len--;
xferlen++;
}
xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len);
TU_ASSERT( xferlen > 0 );
tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen);
@@ -298,7 +312,17 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, p_hid->epout_buf, request->wLength);
uint8_t const* report_buf = p_hid->epout_buf;
uint16_t report_len = request->wLength;
// If host request a specific Report ID, extract report ID in buffer before invoking callback
if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) )
{
report_buf++;
report_len--;
}
tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len);
}
break;

View File

@@ -37,16 +37,6 @@
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
/*
"KEYBOARD" : in_len=8 , out_len=1, usage_page=0x01, usage=0x06 # Generic Desktop, Keyboard
"MOUSE" : in_len=4 , out_len=0, usage_page=0x01, usage=0x02 # Generic Desktop, Mouse
"CONSUMER" : in_len=2 , out_len=0, usage_page=0x0C, usage=0x01 # Consumer, Consumer Control
"SYS_CONTROL" : in_len=1 , out_len=0, usage_page=0x01, usage=0x80 # Generic Desktop, Sys Control
"GAMEPAD" : in_len=6 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad
"DIGITIZER" : in_len=5 , out_len=0, usage_page=0x0D, usage=0x02 # Digitizers, Pen
"XAC_COMPATIBLE_GAMEPAD" : in_len=3 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad
"RAW" : in_len=64, out_len=0, usage_page=0xFFAF, usage=0xAF # Vendor 0xFFAF "Adafruit", 0xAF
*/
typedef struct
{
uint8_t itf_num;
@@ -108,7 +98,7 @@ uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance)
return hid_itf->itf_protocol;
}
bool tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
{
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
return hid_itf->protocol_mode;
@@ -253,33 +243,37 @@ void hidh_close(uint8_t dev_addr)
// Enumeration
//--------------------------------------------------------------------+
static bool config_get_protocol (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static bool config_set_protocol (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static bool config_get_report_desc (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static bool config_get_report_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length)
uint16_t hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
(void) max_len;
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0);
uint16_t drv_len = sizeof(tusb_desc_interface_t);
uint8_t const *p_desc = (uint8_t const *) desc_itf;
//------------- HID descriptor -------------//
p_desc = tu_desc_next(p_desc);
tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType);
TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType, 0);
// not enough interface, try to increase CFG_TUH_HID
// TODO multiple devices
hidh_device_t* hid_dev = get_dev(dev_addr);
TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID);
TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0);
//------------- Endpoint Descriptor -------------//
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType, 0);
// TODO also open endpoint OUT
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep), 0 );
hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count);
hid_dev->inst_count++;
@@ -292,12 +286,13 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
hid_itf->report_desc_type = desc_hid->bReportType;
hid_itf->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength);
hid_itf->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode
// Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config
hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol;
*p_length = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
drv_len += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
return true;
return drv_len;
}
bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
@@ -324,43 +319,49 @@ bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
.wLength = 0
};
TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_get_protocol : config_get_report_desc) );
TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc) );
return true;
}
static bool config_get_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
// Force device to work in BOOT protocol
static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
// Stall is a valid response for SET_IDLE GET_PROTOCOL, therefore we could ignore its result
// Stall is a valid response for SET_IDLE, therefore we could ignore its result
(void) result;
uint8_t const itf_num = (uint8_t) request->wIndex;
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
TU_LOG2("HID Get Protocol\r\n");
TU_LOG2("HID Set Protocol\r\n");
hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
tusb_control_request_t const new_request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_IN
.direction = TUSB_DIR_OUT
},
.bRequest = HID_REQ_CONTROL_GET_PROTOCOL,
.wValue = 0,
.bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
.wValue = HID_PROTOCOL_BOOT,
.wIndex = hid_itf->itf_num,
.wLength = 1
.wLength = 0
};
TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, &hid_itf->protocol_mode, config_get_report_desc) );
return false;
TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_get_report_desc) );
return true;
}
static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
// Stall is a valid response for SET_IDLE GET_PROTOCOL, therefore we could ignore its result
(void) result;
// We can be here after SET_IDLE or SET_PROTOCOL (boot device)
// Trigger assert if result is not successful with set protocol
if ( request->bRequest != HID_REQ_CONTROL_SET_IDLE )
{
TU_ASSERT(result == XFER_RESULT_SUCCESS);
}
uint8_t const itf_num = (uint8_t) request->wIndex;
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
@@ -368,7 +369,7 @@ static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t cons
// Get Report Descriptor
// using usbh enumeration buffer since report descriptor can be very long
TU_ASSERT( hid_itf->report_desc_len <= CFG_TUH_ENUMERATION_BUFSZIE );
TU_ASSERT( hid_itf->report_desc_len <= CFG_TUH_ENUMERATION_BUFSIZE );
TU_LOG2("HID Get Report Descriptor\r\n");
tusb_control_request_t const new_request =
@@ -452,9 +453,9 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr,
uint8_t const data8 = desc_report[0];
TU_LOG2("tag = %d, type = %d, size = %d, data = ", tag, type, size);
for(uint32_t i=0; i<size; i++) TU_LOG2("%02X ", desc_report[i]);
TU_LOG2("\r\n");
TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size);
for(uint32_t i=0; i<size; i++) TU_LOG(3, "%02X ", desc_report[i]);
TU_LOG(3, "\r\n");
switch(type)
{

View File

@@ -66,9 +66,10 @@ bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance);
// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values
uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance);
// Get current active protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
// Note: as HID spec, device will be initialized in Report mode
bool tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance);
// Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
// Note: Device will be initialized in Boot protocol for simplicity.
// Application can use set_protocol() to switch back to Report protocol.
uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance);
// Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
// This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE)
@@ -118,11 +119,11 @@ TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t ins
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
void hidh_init(void);
bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length);
bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num);
bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
void hidh_close(uint8_t dev_addr);
void hidh_init (void);
uint16_t hidh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num);
bool hidh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
void hidh_close (uint8_t dev_addr);
#ifdef __cplusplus
}

View File

@@ -197,9 +197,11 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui
bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4])
{
midid_interface_t* p_midi = &_midid_itf[itf];
uint32_t num_read = tu_fifo_read_n(&p_midi->rx_ff, packet, 4);
_prep_out_transaction(p_midi);
midid_interface_t* midi = &_midid_itf[itf];
TU_VERIFY(midi->ep_out);
uint32_t const num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4);
_prep_out_transaction(midi);
return (num_read == 4);
}
@@ -234,19 +236,19 @@ static uint32_t write_flush(midid_interface_t* midi)
uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
{
midid_interface_t* midi = &_midid_itf[itf];
TU_VERIFY(midi->itf_num, 0);
TU_VERIFY(midi->ep_in, 0);
midid_stream_t* stream = &midi->stream_write;
uint32_t total_written = 0;
uint32_t i = 0;
while ( i < bufsize )
while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) )
{
uint8_t const data = buffer[i];
i++;
if ( stream->index == 0 )
{
// new event packet
//------------- New event packet -------------//
uint8_t const msg = data >> 4;
@@ -308,9 +310,9 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
}
else
{
// On-going (buffering) packet
//------------- On-going (buffering) packet -------------//
TU_ASSERT(stream->index < 4, total_written);
TU_ASSERT(stream->index < 4, i);
stream->buffer[stream->index] = data;
stream->index++;
@@ -333,27 +335,20 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
// complete current event packet, reset stream
stream->index = stream->total = 0;
// fifo overflow, here we assume FIFO is multiple of 4 and didn't check remaining before writing
if ( count != 4 ) break;
// updated written if succeeded
total_written = i;
// FIFO overflown, since we already check fifo remaining. It is probably race condition
TU_ASSERT(count == 4, i);
}
i++;
}
write_flush(midi);
return total_written;
return i;
}
bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4])
{
midid_interface_t* midi = &_midid_itf[itf];
if (midi->itf_num == 0) {
return 0;
}
TU_VERIFY(midi->ep_in);
if (tu_fifo_remaining(&midi->tx_ff) < 4) return false;
@@ -435,6 +430,7 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
}
p_midi->itf_num = desc_midi->bInterfaceNumber;
(void) p_midi->itf_num;
// next descriptor
drv_len += tu_desc_len(p_desc);

View File

@@ -37,6 +37,10 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
// Can be selectively disabled to reduce logging when troubleshooting other driver
#define MSC_DEBUG 2
enum
{
MSC_STAGE_CMD = 0,
@@ -99,7 +103,7 @@ static inline uint16_t rdwr10_get_blockcount(uint8_t const command[])
//--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= 2
static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
{
{ .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" },
{ .key = SCSI_CMD_INQUIRY , .data = "Inquiry" },
@@ -114,7 +118,7 @@ static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
{ .key = SCSI_CMD_WRITE_10 , .data = "Write10" }
};
static tu_lookup_table_t const _msc_scsi_cmd_table =
TU_ATTR_UNUSED static tu_lookup_table_t const _msc_scsi_cmd_table =
{
.count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup),
.items = _msc_scsi_cmd_lookup
@@ -232,8 +236,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
TU_ASSERT( event == XFER_RESULT_SUCCESS &&
xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE );
TU_LOG2(" SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
// TU_LOG2_MEM(p_cbw, xferred_bytes, 2);
TU_LOG(MSC_DEBUG, " SCSI Command: %s\r\n", 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;
p_csw->tag = p_cbw->tag;
@@ -305,8 +309,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
case MSC_STAGE_DATA:
TU_LOG2(" SCSI Data\r\n");
//TU_LOG2_MEM(_mscd_buf, xferred_bytes, 2);
TU_LOG(MSC_DEBUG, " SCSI Data\r\n");
//TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2);
// OUT transfer, invoke callback if needed
if ( !tu_bit_test(p_cbw->dir, 7) )
@@ -402,8 +406,8 @@ 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_LOG2(" SCSI Status: %u\r\n", p_csw->status);
// TU_LOG2_MEM(p_csw, xferred_bytes, 2);
TU_LOG(MSC_DEBUG, " SCSI Status: %u\r\n", p_csw->status);
// TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2);
// Invoke complete callback if defined
// Note: There is racing issue with samd51 + qspi flash testing with arduino

View File

@@ -360,18 +360,22 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* c
static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length)
uint16_t msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
// msc driver length is fixed
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
TU_ASSERT(drv_len <= max_len, 0);
msch_interface_t* p_msc = get_itf(dev_addr);
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf);
for(uint32_t i=0; i<2; i++)
{
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer, 0);
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc), 0);
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
{
@@ -385,9 +389,8 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
}
p_msc->itf_num = desc_itf->bInterfaceNumber;
(*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
return true;
return drv_len;
}
bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)

View File

@@ -41,13 +41,6 @@
#define CFG_TUH_MSC_MAXLUN 4
#endif
/** \addtogroup ClassDriver_MSC
* @{
* \defgroup MSC_Host Host
* The interface API includes status checking function, data transferring function and callback functions
* @{ */
typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
//--------------------------------------------------------------------+
@@ -113,17 +106,14 @@ TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr);
// Internal Class Driver API
//--------------------------------------------------------------------+
void msch_init(void);
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length);
bool msch_set_config(uint8_t dev_addr, uint8_t itf_num);
bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
void msch_close(uint8_t dev_addr);
void msch_init (void);
uint16_t msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
bool msch_set_config (uint8_t dev_addr, uint8_t itf_num);
bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
void msch_close (uint8_t dev_addr);
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_MSC_HOST_H_ */
/// @}
/// @}

View File

@@ -123,7 +123,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { retur
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
//------------- Mathematics -------------//
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_abs(int32_t value) { return (uint32_t)((value < 0) ? (-value) : value); }
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; }
/// inclusive range checking TODO remove
TU_ATTR_ALWAYS_INLINE static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper)
@@ -305,11 +305,11 @@ void tu_print_var(uint8_t const* buf, uint32_t bufsize)
}
// Log with Level
#define TU_LOG(n, ...) TU_LOG##n(__VA_ARGS__)
#define TU_LOG_MEM(n, ...) TU_LOG##n##_MEM(__VA_ARGS__)
#define TU_LOG_VAR(n, ...) TU_LOG##n##_VAR(__VA_ARGS__)
#define TU_LOG_INT(n, ...) TU_LOG##n##_INT(__VA_ARGS__)
#define TU_LOG_HEX(n, ...) TU_LOG##n##_HEX(__VA_ARGS__)
#define TU_LOG(n, ...) TU_XSTRCAT(TU_LOG, n)(__VA_ARGS__)
#define TU_LOG_MEM(n, ...) TU_XSTRCAT3(TU_LOG, n, _MEM)(__VA_ARGS__)
#define TU_LOG_VAR(n, ...) TU_XSTRCAT3(TU_LOG, n, _VAR)(__VA_ARGS__)
#define TU_LOG_INT(n, ...) TU_XSTRCAT3(TU_LOG, n, _INT)(__VA_ARGS__)
#define TU_LOG_HEX(n, ...) TU_XSTRCAT3(TU_LOG, n, _HEX)(__VA_ARGS__)
#define TU_LOG_LOCATION() tu_printf("%s: %d:\r\n", __PRETTY_FUNCTION__, __LINE__)
#define TU_LOG_FAILED() tu_printf("%s: %d: Failed\r\n", __PRETTY_FUNCTION__, __LINE__)
@@ -317,8 +317,8 @@ void tu_print_var(uint8_t const* buf, uint32_t bufsize)
#define TU_LOG1 tu_printf
#define TU_LOG1_MEM tu_print_mem
#define TU_LOG1_VAR(_x) tu_print_var((uint8_t const*)(_x), sizeof(*(_x)))
#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\n", (uint32_t) (_x) )
#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\n", (uint32_t) (_x) )
#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (uint32_t) (_x) )
#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (uint32_t) (_x) )
// Log Level 2: Warn
#if CFG_TUSB_DEBUG >= 2
@@ -373,6 +373,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
#endif
// TODO replace all TU_LOGn with TU_LOG(n)
#define TU_LOG0(...)
#define TU_LOG0_MEM(...)
#define TU_LOG0_VAR(...)
#define TU_LOG0_INT(...)
#define TU_LOG0_HEX(...)
#ifndef TU_LOG1
#define TU_LOG1(...)
#define TU_LOG1_MEM(...)

View File

@@ -32,10 +32,14 @@
#ifndef _TUSB_COMPILER_H_
#define _TUSB_COMPILER_H_
#define TU_STRING(x) #x ///< stringify without expand
#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify
#define TU_STRCAT(a, b) a##b ///< concat without expand
#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat
#define TU_STRING(x) #x ///< stringify without expand
#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify
#define TU_STRCAT(a, b) a##b ///< concat without expand
#define TU_STRCAT3(a, b, c) a##b##c ///< concat without expand
#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat
#define TU_XSTRCAT3(a, b, c) TU_STRCAT3(a, b, c) ///< expand then concat 3 tokens
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
#define _TU_COUNTER_ __COUNTER__
@@ -83,6 +87,10 @@
#define TU_BSWAP16(u16) (__builtin_bswap16(u16))
#define TU_BSWAP32(u32) (__builtin_bswap32(u32))
// List of obsolete callback function that is renamed and should not be defined.
// Put it here since only gcc support this pragma
#pragma GCC poison tud_vendor_control_request_cb
#elif defined(__TI_COMPILER_VERSION__)
#define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))

View File

@@ -325,7 +325,7 @@ static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
// We are exploiting the wrap around to the correct index
// TODO warning: assuming signed overflow does not occur when assuming that (X + c) < X is always false [-Wstrict-overflow]
if ((p > p + offset) || (p + offset > f->max_pointer_idx))
if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx))
{
p = (p + offset) + f->non_used_index_space;
}
@@ -342,7 +342,7 @@ static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
// We limit the index space of p such that a correct wrap around happens
// Check for a wrap around or if we are in unused index space - This has to be checked first!!
// We are exploiting the wrap around to the correct index
if ((p < p - offset) || (p - offset > f->max_pointer_idx))
if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx))
{
p = (p - offset) - f->non_used_index_space;
}

View File

@@ -86,8 +86,8 @@ typedef struct
.depth = _depth, \
.item_size = sizeof(_type), \
.overwritable = _overwritable, \
.max_pointer_idx = 2*(_depth)-1, \
.non_used_index_space = UINT16_MAX - (2*(_depth)-1), \
.max_pointer_idx = 2*(_depth)-1, \
}
#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
@@ -120,9 +120,9 @@ bool tu_fifo_peek (tu_fifo_t* f, void * p_buffer);
uint16_t tu_fifo_peek_n (tu_fifo_t* f, void * p_buffer, uint16_t n);
uint16_t tu_fifo_count (tu_fifo_t* f);
uint16_t tu_fifo_remaining (tu_fifo_t* f);
bool tu_fifo_empty (tu_fifo_t* f);
bool tu_fifo_full (tu_fifo_t* f);
uint16_t tu_fifo_remaining (tu_fifo_t* f);
bool tu_fifo_overflowed (tu_fifo_t* f);
void tu_fifo_correct_read_pointer (tu_fifo_t* f);

View File

@@ -75,7 +75,7 @@
#if CFG_TUSB_DEBUG
#include <stdio.h>
#define _MESS_ERR(_err) tu_printf("%s %d: failed, error = %s\r\n", __func__, __LINE__, tusb_strerr[_err])
#define _MESS_FAILED() tu_printf("%s %d: assert failed\r\n", __func__, __LINE__)
#define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
#else
#define _MESS_ERR(_err) do {} while (0)
#define _MESS_FAILED() do {} while (0)

View File

@@ -1243,7 +1243,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
TU_LOG2(" 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);
@@ -1254,14 +1254,13 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) )
{
TU_LOG2("OK\r\n");
return true;
}else
{
// DCD error, mark endpoint as ready to allow next transfer
_usbd_dev.ep_status[epnum][dir].busy = false;
_usbd_dev.ep_status[epnum][dir].claimed = 0;
TU_LOG2("failed\r\n");
TU_LOG2("FAILED\r\n");
TU_BREAKPOINT();
return false;
}

View File

@@ -542,6 +542,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\
// Calculate wMaxPacketSize of Endpoints
#define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \
((((_maxFrequency + ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 7999 : 999)) / ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 8000 : 1000)) + 1) * _nBytesPerSample * _nChannels)
//------------- TUD_USBTMC/USB488 -------------//
#define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
#define TUD_USBTMC_APP_SUBCLASS 0x03u

View File

@@ -186,6 +186,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(2, _usbd_ctrl_buf, xferred_bytes, 2);
}
_ctrl_xfer.total_xferred += xferred_bytes;

View File

@@ -144,29 +144,32 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_con
//--------------------------------------------------------------------+
void hub_init(void)
{
tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof( hub_interface_t));
tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(hub_interface_t));
}
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
uint16_t hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{
// not support multiple TT yet
if ( itf_desc->bInterfaceProtocol > 1 ) return false;
// hub driver does not support multiple TT yet
TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
0 == itf_desc->bInterfaceSubClass &&
1 <= itf_desc->bInterfaceProtocol, 0);
//------------- Open Interrupt Status Pipe -------------//
tusb_desc_endpoint_t const *ep_desc;
ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
// msc driver length is fixed
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
TU_ASSERT(drv_len <= max_len, 0);
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
TU_ASSERT(TUSB_XFER_INTERRUPT == ep_desc->bmAttributes.xfer);
//------------- Interrupt Status endpoint -------------//
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber;
hub_data[dev_addr-1].ep_in = ep_desc->bEndpointAddress;
hub_data[dev_addr-1].ep_in = desc_ep->bEndpointAddress;
(*p_length) = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
return true;
return drv_len;
}
void hub_close(uint8_t dev_addr)

View File

@@ -181,11 +181,11 @@ bool hub_status_pipe_queue(uint8_t dev_addr);
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
void hub_init(void);
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
bool hub_set_config(uint8_t dev_addr, uint8_t itf_num);
bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
void hub_close(uint8_t dev_addr);
void hub_init (void);
uint16_t hub_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
bool hub_set_config (uint8_t dev_addr, uint8_t itf_num);
bool hub_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
void hub_close (uint8_t dev_addr);
#ifdef __cplusplus
}

View File

@@ -130,7 +130,7 @@ CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1];
OSAL_QUEUE_DEF(OPT_MODE_HOST, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t);
static osal_queue_t _usbh_q;
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSZIE];
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
//------------- Helper Function Prototypes -------------//
static bool enum_new_device(hcd_event_t* event);
@@ -795,6 +795,8 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r
return false;
}
TU_ASSERT(tu_desc_type(_usbh_ctrl_buf) == TUSB_DESC_DEVICE);
// Reset device again before Set Address
TU_LOG2("Port reset \r\n");
@@ -907,7 +909,7 @@ static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_r
// Use offsetof to avoid pointer to the odd/misaligned address
memcpy(&total_len, (uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength), 2);
TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSZIE);
TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE);
// Get full configuration descriptor
TU_LOG2("Get Configuration Descriptor\r\n");
@@ -938,7 +940,7 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request
// Parse configuration & set up drivers
// Driver open aren't allowed to make any usb transfer yet
parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf);
TU_ASSERT( parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf) );
TU_LOG2("Set Configuration = %d\r\n", CONFIG_NUM);
tusb_control_request_t const new_request =
@@ -982,55 +984,61 @@ static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t co
static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
{
usbh_device_t* dev = &_usbh_devices[dev_addr];
uint8_t const* p_desc = (uint8_t const*) desc_cfg;
p_desc = tu_desc_next(p_desc);
uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
uint8_t const* p_desc = tu_desc_next(desc_cfg);
// parse each interfaces
while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength )
while( p_desc < desc_end )
{
// skip until we see interface descriptor
if ( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) )
{
p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length
}else
{
tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
// TODO Do we need to use IAD
// tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL;
// Check if class is supported
uint8_t drv_id;
for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
{
if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
}
// Class will always starts with Interface Association (if any) and then Interface descriptor
if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
{
// desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc;
p_desc = tu_desc_next(p_desc);
}
if( drv_id >= USBH_CLASS_DRIVER_COUNT )
TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) );
tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
uint16_t const remaining_len = desc_end-p_desc;
// Check if class is supported TODO drop class_code
uint8_t drv_id;
for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
{
if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
}
if( drv_id >= USBH_CLASS_DRIVER_COUNT )
{
// skip unsupported class
p_desc = tu_desc_next(p_desc);
}
else
{
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
// Interface number must not be used already TODO alternate interface
TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff );
dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
{
// skip unsupported class
// TODO Attach hub to Hub is not currently supported
// skip this interface
p_desc = tu_desc_next(p_desc);
}
else
{
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
TU_LOG2("%s open\r\n", driver->name);
// Interface number must not be used already TODO alternate interface
TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff );
dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
{
// TODO Attach hub to Hub is not currently supported
// skip this interface
p_desc = tu_desc_next(p_desc);
}
else
{
TU_LOG2("%s open\r\n", driver->name);
uint16_t itf_len = 0;
TU_ASSERT( driver->open(dev->rhport, dev_addr, desc_itf, &itf_len) );
TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) );
p_desc += itf_len;
}
uint16_t const itf_len = driver->open(dev->rhport, dev_addr, desc_itf, remaining_len);
TU_ASSERT( sizeof(tusb_desc_interface_t) <= itf_len && itf_len <= remaining_len);
p_desc += itf_len;
}
}
}

View File

@@ -45,11 +45,11 @@ typedef struct {
uint8_t class_code;
void (* const init )(void);
bool (* const open )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t* outlen);
bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
bool (* const xfer_cb )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
void (* const close )(uint8_t dev_addr);
void (* const init )(void);
uint16_t (* const open )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
bool (* const xfer_cb )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
void (* const close )(uint8_t dev_addr);
} usbh_class_driver_t;
// Call by class driver to tell USBH that it has complete the enumeration

View File

@@ -50,7 +50,7 @@ typedef struct
static usbh_control_xfer_t _ctrl_xfer;
//CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
//static uint8_t _tuh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSZIE];
//static uint8_t _tuh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
@@ -68,7 +68,7 @@ bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request,
_ctrl_xfer.stage = STAGE_SETUP;
_ctrl_xfer.complete_cb = complete_cb;
TU_LOG2("Control Setup: ");
TU_LOG2("Control Setup (addr = %u): ", dev_addr);
TU_LOG2_VAR(request);
TU_LOG2("\r\n");
@@ -119,7 +119,7 @@ bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t resu
if (request->wLength)
{
TU_LOG2("Control data:\r\n");
TU_LOG2("Control data (addr = %u):\r\n", dev_addr);
TU_LOG2_MEM(_ctrl_xfer.buffer, request->wLength, 2);
}

View File

@@ -29,7 +29,7 @@
#if TUSB_OPT_DEVICE_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X || \
CFG_TUSB_MCU == OPT_MCU_SAML22)
CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21)
#include "sam.h"
#include "device/dcd.h"
@@ -125,7 +125,7 @@ void dcd_int_disable(uint8_t rhport)
}
#elif CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
CFG_TUSB_MCU == OPT_MCU_SAML22
CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21
void dcd_int_enable(uint8_t rhport)
{

View File

@@ -108,13 +108,21 @@ static inline uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn)
}
#endif
// check if we are in ISR
TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
{
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false;
}
// helper to start DMA
// TODO use Cortex M4 LDREX and STREX command (atomic) to have better mutex access to EasyDMA
// since current implementation does not 100% guarded against race condition
static void edpt_dma_start(volatile uint32_t* reg_startep)
{
// Only one dma can be active
if ( _dcd.dma_pending )
{
if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)
if (is_in_isr())
{
// Called within ISR, use usbd task to defer later
usbd_defer_func( (osal_task_func_t) edpt_dma_start, (void*) reg_startep, true );
@@ -159,6 +167,17 @@ static void edpt_dma_end(void)
_dcd.dma_pending = 0;
}
// helper to set TASKS_EP0STATUS / TASKS_EP0RCVOUT since they also need EasyDMA
// However TASKS_EP0STATUS doesn't trigger any DMA transfer and got ENDED event subsequently
// Therefore dma_running state will be corrected right away
void start_ep0_task(volatile uint32_t* reg_task)
{
edpt_dma_start(reg_task);
// correct the dma_running++ in dma start
if (_dcd.dma_pending) _dcd.dma_pending--;
}
// helper getting td
static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir)
{
@@ -407,21 +426,18 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
if ( control_status )
{
// Status Phase also requires Easy DMA has to be available as well !!!!
// However TASKS_EP0STATUS doesn't trigger any DMA transfer and got ENDED event subsequently
// Therefore dma_running state will be corrected right away
edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
if (_dcd.dma_pending) _dcd.dma_pending--; // correct the dma_running++ in dma start
// Status Phase also requires EasyDMA has to be available as well !!!!
start_ep0_task(&NRF_USBD->TASKS_EP0STATUS);
// The nRF doesn't interrupt on status transmit so we queue up a success response.
dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, false);
dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, is_in_isr());
}
else if ( dir == TUSB_DIR_OUT )
{
if ( epnum == 0 )
{
// Accept next Control Out packet
NRF_USBD->TASKS_EP0RCVOUT = 1;
// Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
start_ep0_task(&NRF_USBD->TASKS_EP0RCVOUT);
}else
{
if ( xfer->data_received )
@@ -581,12 +597,6 @@ void dcd_int_handler(uint8_t rhport)
}
}
if ( int_status & EDPT_END_ALL_MASK )
{
// DMA complete move data from SRAM -> Endpoint
edpt_dma_end();
}
// Setup tokens are specific to the Control endpoint.
if ( int_status & USBD_INTEN_EP0SETUP_Msk )
{
@@ -607,6 +617,12 @@ void dcd_int_handler(uint8_t rhport)
}
}
if ( int_status & EDPT_END_ALL_MASK )
{
// DMA complete move data from SRAM -> Endpoint
edpt_dma_end();
}
//--------------------------------------------------------------------+
/* Control/Bulk/Interrupt (CBI) Transfer
*
@@ -655,8 +671,15 @@ void dcd_int_handler(uint8_t rhport)
{
if ( epnum == 0 )
{
// Accept next Control Out packet
NRF_USBD->TASKS_EP0RCVOUT = 1;
// Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
if ( _dcd.dma_pending )
{
// use usbd task to defer later
usbd_defer_func( (osal_task_func_t) start_ep0_task, (void*) &NRF_USBD->TASKS_EP0RCVOUT, true );
}else
{
start_ep0_task(&NRF_USBD->TASKS_EP0RCVOUT);
}
}else
{
// nRF auto accept next Bulk/Interrupt OUT packet
@@ -764,7 +787,7 @@ static bool hfclk_running(void)
#ifdef SOFTDEVICE_PRESENT
if ( is_sd_enabled() )
{
uint32_t is_running;
uint32_t is_running = 0;
(void) sd_clock_hfclk_is_running(&is_running);
return (is_running ? true : false);
}
@@ -973,7 +996,7 @@ void tusb_hal_nrf_power_event (uint32_t event)
hfclk_disable();
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false);
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr());
}
break;

View File

@@ -64,67 +64,48 @@ static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
static void _hw_endpoint_alloc(struct hw_endpoint *ep)
{
uint16_t size = tu_min16(64, ep->wMaxPacketSize);
// size must be multiple of 64
uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
// Assumes single buffered for now
ep->hw_data_buf = next_buffer_ptr;
next_buffer_ptr += size;
// Bits 0-5 are ignored by the controller so make sure these are 0
if ((uintptr_t)next_buffer_ptr & 0b111111u)
{
// Round up to the next 64
uint32_t fixptr = (uintptr_t)next_buffer_ptr;
fixptr &= ~0b111111u;
fixptr += 64;
pico_info("Rounding non 64 byte boundary buffer up from %x to %x\n", (uintptr_t)next_buffer_ptr, fixptr);
next_buffer_ptr = (uint8_t*)fixptr;
}
assert(((uintptr_t)next_buffer_ptr & 0b111111u) == 0);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
// double buffered for Control and Bulk endpoint
if ( ep->transfer_type == TUSB_XFER_CONTROL || ep->transfer_type == TUSB_XFER_BULK)
{
size *= 2u;
}
pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n",
size,
dpram_offset,
ep->hw_data_buf,
ep->num,
ep_dir_string[ep->in]);
ep->hw_data_buf = next_buffer_ptr;
next_buffer_ptr += size;
// Fill in endpoint control register with buffer offset
uint32_t reg = EP_CTRL_ENABLE_BITS
| EP_CTRL_INTERRUPT_PER_BUFFER
| (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
| dpram_offset;
assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
*ep->endpoint_control = reg;
pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n",
size,
dpram_offset,
ep->hw_data_buf,
tu_edpt_number(ep->ep_addr),
ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
// Fill in endpoint control register with buffer offset
uint32_t const reg = EP_CTRL_ENABLE_BITS | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
*ep->endpoint_control = reg;
}
static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
{
const uint8_t num = tu_edpt_number(ep_addr);
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
ep->ep_addr = ep_addr;
// For device, IN is a tx transfer and OUT is an rx transfer
ep->rx = (dir == TUSB_DIR_OUT);
// Response to a setup packet on EP0 starts with pid of 1
ep->next_pid = num == 0 ? 1u : 0u;
// Add some checks around the max packet size
if (transfer_type == TUSB_XFER_ISOCHRONOUS)
{
if (wMaxPacketSize > USB_MAX_ISO_PACKET_SIZE)
{
panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize);
}
}
else
{
if (wMaxPacketSize > USB_MAX_PACKET_SIZE)
{
panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize);
}
}
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;
@@ -164,6 +145,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t
// Now if it hasn't already been done
//alloc a buffer and fill in endpoint control register
// TODO device may change configuration (dynamic), should clear and reallocate
if(!(ep->configured))
{
_hw_endpoint_alloc(ep);
@@ -198,10 +180,10 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t b
_hw_endpoint_init(ep, ep_addr, wMaxPacketSize, bmAttributes);
}
static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool start)
static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_xfer(ep, buffer, total_bytes, start);
hw_endpoint_xfer_start(ep, buffer, total_bytes);
}
static void hw_handle_buff_status(void)
@@ -213,19 +195,16 @@ static void hw_handle_buff_status(void)
{
if (remaining_buffers & bit)
{
uint __unused which = (usb_hw->buf_cpu_should_handle & bit) ? 1 : 0;
// Should be single buffered
assert(which == 0);
// clear this in advance
usb_hw_clear->buf_status = bit;
// IN transfer for even i, OUT transfer for odd i
struct hw_endpoint *ep = hw_endpoint_get_by_num(i >> 1u, !(i & 1u));
// Continue xfer
bool done = _hw_endpoint_xfer_continue(ep);
bool done = hw_endpoint_xfer_continue(ep);
if (done)
{
// Notify
dcd_event_xfer_complete(0, ep->ep_addr, ep->len, XFER_RESULT_SUCCESS, true);
dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true);
hw_endpoint_reset_transfer(ep);
}
remaining_buffers &= ~bit;
@@ -251,7 +230,7 @@ static void ep0_0len_status(void)
{
// Send 0len complete response on EP0 IN
reset_ep0();
hw_endpoint_xfer(0x80, NULL, 0, true);
hw_endpoint_xfer(0x80, NULL, 0);
}
static void _hw_endpoint_stall(struct hw_endpoint *ep)
@@ -339,10 +318,7 @@ static void dcd_rp2040_irq(void)
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
// Only run enumeration walk-around if pull up is enabled
if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS )
{
rp2040_usb_device_enumeration_fix();
}
if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix();
#endif
}
@@ -402,9 +378,9 @@ void dcd_init (uint8_t rhport)
// EP0 always exists so init it now
// EP0 OUT
hw_endpoint_init(0x0, 64, 0);
hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
// EP0 IN
hw_endpoint_init(0x80, 64, 0);
hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
// Initializes the USB peripheral for device mode and enables it.
// Don't need to enable the pull up here. Force VBUS
@@ -470,23 +446,22 @@ void dcd_connect(uint8_t rhport)
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
{
pico_trace("dcd_edpt0_status_complete %d\n", rhport);
assert(rhport == 0);
(void) rhport;
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
request->bRequest == TUSB_REQ_SET_ADDRESS)
{
pico_trace("Set HW address %d\n", assigned_address);
usb_hw->dev_addr_ctrl = (uint8_t) request->wValue;
}
if ( request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
request->bRequest == TUSB_REQ_SET_ADDRESS )
{
pico_trace("Set HW address %d\n", request->wValue);
usb_hw->dev_addr_ctrl = (uint8_t) request->wValue;
}
reset_ep0();
reset_ep0();
}
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
pico_info("dcd_edpt_open %d %02x\n", rhport, desc_edpt->bEndpointAddress);
pico_info("dcd_edpt_open %02x\n", desc_edpt->bEndpointAddress);
assert(rhport == 0);
hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer);
return true;
@@ -495,21 +470,20 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
assert(rhport == 0);
// True means start new xfer
hw_endpoint_xfer(ep_addr, buffer, total_bytes, true);
hw_endpoint_xfer(ep_addr, buffer, total_bytes);
return true;
}
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
{
pico_trace("dcd_edpt_stall %d %02x\n", rhport, ep_addr);
pico_trace("dcd_edpt_stall %02x\n", ep_addr);
assert(rhport == 0);
hw_endpoint_stall(ep_addr);
}
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
{
pico_trace("dcd_edpt_clear_stall %d %02x\n", rhport, ep_addr);
pico_trace("dcd_edpt_clear_stall %02x\n", ep_addr);
assert(rhport == 0);
hw_endpoint_clear_stall(ep_addr);
}
@@ -517,9 +491,11 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
// usbd.c says: In progress transfers on this EP may be delivered after this call
pico_trace("dcd_edpt_close %d %02x\n", rhport, ep_addr);
(void) rhport;
(void) ep_addr;
// usbd.c says: In progress transfers on this EP may be delivered after this call
pico_trace("dcd_edpt_close %02x\n", ep_addr);
}
void dcd_int_handler(uint8_t rhport)

View File

@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
* Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -52,46 +53,30 @@
static_assert(PICO_USB_HOST_INTERRUPT_ENDPOINTS <= USB_MAX_ENDPOINTS, "");
// Host mode uses one shared endpoint register for non-interrupt endpoint
struct hw_endpoint eps[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS];
#define epx (eps[0])
static struct hw_endpoint ep_pool[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS];
#define epx (ep_pool[0])
#define usb_hw_set hw_set_alias(usb_hw)
#define usb_hw_set hw_set_alias(usb_hw)
#define usb_hw_clear hw_clear_alias(usb_hw)
// Used for hcd pipe busy.
// todo still a bit wasteful
// top bit set if valid
uint8_t dev_ep_map[CFG_TUSB_HOST_DEVICE_MAX][1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS][2];
// Flags we set by default in sie_ctrl (we add other bits on top)
static uint32_t sie_ctrl_base = USB_SIE_CTRL_SOF_EN_BITS |
USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
USB_SIE_CTRL_PULLDOWN_EN_BITS |
USB_SIE_CTRL_EP0_INT_1BUF_BITS;
enum {
SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
};
static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
{
uint8_t num = tu_edpt_number(ep_addr);
if (num == 0) {
return &epx;
}
uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0;
uint mapping = dev_ep_map[dev_addr-1][num][in];
pico_trace("Get dev addr %d ep %d = %d\n", dev_addr, ep_addr, mapping);
return mapping >= 128 ? eps + (mapping & 0x7fu) : NULL;
}
uint8_t num = tu_edpt_number(ep_addr);
if ( num == 0 ) return &epx;
static void set_dev_ep(uint8_t dev_addr, uint8_t ep_addr, struct hw_endpoint *ep)
{
uint8_t num = tu_edpt_number(ep_addr);
uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0;
uint32_t index = ep - eps;
hard_assert(index < TU_ARRAY_SIZE(eps));
// todo revisit why dev_addr can be 0 here
if (dev_addr) {
dev_ep_map[dev_addr-1][num][in] = 128u | index;
}
pico_trace("Set dev addr %d ep %d = %d\n", dev_addr, ep_addr, index);
for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ )
{
struct hw_endpoint *ep = &ep_pool[i];
if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep;
}
return NULL;
}
static inline uint8_t dev_speed(void)
@@ -111,15 +96,15 @@ static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result)
// Mark transfer as done before we tell the tinyusb stack
uint8_t dev_addr = ep->dev_addr;
uint8_t ep_addr = ep->ep_addr;
uint total_len = ep->total_len;
uint xferred_len = ep->xferred_len;
hw_endpoint_reset_transfer(ep);
hcd_event_xfer_complete(dev_addr, ep_addr, total_len, xfer_result, true);
hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true);
}
static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep)
{
usb_hw_clear->buf_status = bit;
bool done = _hw_endpoint_xfer_continue(ep);
bool done = hw_endpoint_xfer_continue(ep);
if (done)
{
hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
@@ -137,6 +122,17 @@ static void hw_handle_buff_status(void)
{
remaining_buffers &= ~bit;
struct hw_endpoint *ep = &epx;
uint32_t ep_ctrl = *ep->endpoint_control;
if (ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS)
{
TU_LOG(3, "Double Buffered: ");
}else
{
TU_LOG(3, "Single Buffered: ");
}
TU_LOG_HEX(3, ep_ctrl);
_handle_buff_status_bit(bit, ep);
}
@@ -153,7 +149,7 @@ static void hw_handle_buff_status(void)
if (remaining_buffers & bit)
{
remaining_buffers &= ~bit;
_handle_buff_status_bit(bit, &eps[i]);
_handle_buff_status_bit(bit, &ep_pool[i]);
}
}
@@ -165,19 +161,19 @@ static void hw_handle_buff_status(void)
static void hw_trans_complete(void)
{
struct hw_endpoint *ep = &epx;
assert(ep->active);
struct hw_endpoint *ep = &epx;
assert(ep->active);
if (ep->sent_setup)
{
pico_trace("Sent setup packet\n");
hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
}
else
{
// Don't care. Will handle this in buff status
return;
}
if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS)
{
pico_trace("Sent setup packet\n");
hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
}
else
{
// Don't care. Will handle this in buff status
return;
}
}
static void hcd_rp2040_irq(void)
@@ -202,20 +198,22 @@ static void hcd_rp2040_irq(void)
usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS;
}
if (status & USB_INTS_BUFF_STATUS_BITS)
{
handled |= USB_INTS_BUFF_STATUS_BITS;
TU_LOG(2, "Buffer complete\n");
// print_bufctrl32(*epx.buffer_control);
hw_handle_buff_status();
}
if (status & USB_INTS_TRANS_COMPLETE_BITS)
{
handled |= USB_INTS_TRANS_COMPLETE_BITS;
usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS;
TU_LOG(2, "Transfer complete\n");
hw_trans_complete();
}
if (status & USB_INTS_BUFF_STATUS_BITS)
{
handled |= USB_INTS_BUFF_STATUS_BITS;
// print_bufctrl32(*epx.buffer_control);
hw_handle_buff_status();
}
if (status & USB_INTS_STALL_BITS)
{
// We have rx'd a stall from the device
@@ -234,7 +232,7 @@ static void hcd_rp2040_irq(void)
if (status & USB_INTS_ERROR_DATA_SEQ_BITS)
{
usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS;
// print_bufctrl32(*epx.buffer_control);
print_bufctrl32(*epx.buffer_control);
panic("Data Seq Error \n");
}
@@ -247,9 +245,9 @@ static void hcd_rp2040_irq(void)
static struct hw_endpoint *_next_free_interrupt_ep(void)
{
struct hw_endpoint *ep = NULL;
for (uint i = 1; i < TU_ARRAY_SIZE(eps); i++)
for (uint i = 1; i < TU_ARRAY_SIZE(ep_pool); i++)
{
ep = &eps[i];
ep = &ep_pool[i];
if (!ep->configured)
{
// Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
@@ -263,6 +261,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void)
static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
{
struct hw_endpoint *ep = NULL;
if (transfer_type == TUSB_XFER_INTERRUPT)
{
ep = _next_free_interrupt_ep();
@@ -270,11 +269,11 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
assert(ep);
ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
// 0x180 for epx
// 0x1c0 for intep0
// 0x200 for intep1
// 0 for epx (double buffered): TODO increase to 1024 for ISO
// 2x64 for intep0
// 3x64 for intep1
// etc
ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 1)];
ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 2)];
}
else
{
@@ -283,6 +282,7 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
ep->endpoint_control = &usbh_dpram->epx_ctrl;
ep->hw_data_buf = &usbh_dpram->epx_data[0];
}
return ep;
}
@@ -303,7 +303,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
ep->rx = (dir == TUSB_DIR_IN);
// Response to a setup packet on EP0 starts with pid of 1
ep->next_pid = num == 0 ? 1u : 0u;
ep->next_pid = (num == 0 ? 1u : 0u);
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;
@@ -332,6 +332,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
// preamble
uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB);
// Assert the interrupt endpoint is IN_TO_HOST
// TODO Interrupt can also be OUT
assert(dir == TUSB_DIR_IN);
if (need_pre(dev_addr))
@@ -345,24 +346,9 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
// If it's an interrupt endpoint we need to set up the buffer control
// register
}
}
static void hw_endpoint_init(uint8_t dev_addr, const tusb_desc_endpoint_t *ep_desc)
{
// Allocated differently based on if it's an interrupt endpoint or not
struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
_hw_endpoint_init(ep,
dev_addr,
ep_desc->bEndpointAddress,
ep_desc->wMaxPacketSize.size,
ep_desc->bmAttributes.xfer,
ep_desc->bInterval);
// Map this struct to ep@device address
set_dev_ep(dev_addr, ep_desc->bEndpointAddress, ep);
}
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
@@ -377,11 +363,11 @@ bool hcd_init(uint8_t rhport)
irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
// clear epx and interrupt eps
memset(&eps, 0, sizeof(eps));
memset(&ep_pool, 0, sizeof(ep_pool));
// Enable in host mode with SOF / Keep alive on
usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
usb_hw->sie_ctrl = sie_ctrl_base;
usb_hw->sie_ctrl = SIE_CTRL_BASE;
usb_hw->inte = USB_INTE_BUFF_STATUS_BITS |
USB_INTE_HOST_CONN_DIS_BITS |
USB_INTE_HOST_RESUME_BITS |
@@ -409,7 +395,6 @@ bool hcd_port_connect_status(uint8_t rhport)
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
{
pico_trace("hcd_port_speed_get\n");
assert(rhport == 0);
// TODO: Should enumval this register
switch (dev_speed())
@@ -420,15 +405,25 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport)
return TUSB_SPEED_FULL;
default:
panic("Invalid speed\n");
return TUSB_SPEED_INVALID;
}
}
// Close all opened endpoint belong to this device
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
{
(void) rhport;
(void) dev_addr;
pico_trace("hcd_device_close %d\n", dev_addr);
}
uint32_t hcd_frame_number(uint8_t rhport)
{
(void) rhport;
return usb_hw->sof_rd;
}
void hcd_int_enable(uint8_t rhport)
{
assert(rhport == 0);
@@ -442,36 +437,70 @@ void hcd_int_disable(uint8_t rhport)
irq_set_enabled(USBCTRL_IRQ, false);
}
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
(void) rhport;
pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress);
// Allocated differently based on if it's an interrupt endpoint or not
struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
_hw_endpoint_init(ep,
dev_addr,
ep_desc->bEndpointAddress,
ep_desc->wMaxPacketSize.size,
ep_desc->bmAttributes.xfer,
ep_desc->bInterval);
return true;
}
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
{
pico_info("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen);
(void) rhport;
pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen);
uint8_t const ep_num = tu_edpt_number(ep_addr);
tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr);
// Get appropriate ep. Either EPX or interrupt endpoint
struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
assert(ep);
if (ep_addr != ep->ep_addr)
// Control endpoint can change direction 0x00 <-> 0x80
if ( ep_addr != ep->ep_addr )
{
// Direction has flipped so re init it but with same properties
// TODO treat IN and OUT as invidual endpoints
_hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0);
}
assert(ep_num == 0);
// True indicates this is the start of the transfer
_hw_endpoint_xfer(ep, buffer, buflen, true);
// Direction has flipped on endpoint control so re init it but with same properties
_hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0);
}
// If a normal transfer (non-interrupt) then initiate using
// sie ctrl registers. Otherwise interrupt ep registers should
// already be configured
if (ep == &epx) {
hw_endpoint_xfer_start(ep, buffer, buflen);
// That has set up buffer control, endpoint control etc
// for host we have to initiate the transfer
usb_hw->dev_addr_ctrl = dev_addr | (tu_edpt_number(ep_addr) << USB_ADDR_ENDP_ENDPOINT_LSB);
uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | sie_ctrl_base;
flags |= ep->rx ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS;
usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB);
uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE |
(ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS);
// Set pre if we are a low speed device on full speed hub
flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0;
usb_hw->sie_ctrl = flags;
}else
{
hw_endpoint_xfer_start(ep, buffer, buflen);
}
return true;
@@ -479,41 +508,33 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
{
pico_info("hcd_setup_send dev_addr %d\n", dev_addr);
(void) rhport;
// Copy data into setup packet buffer
memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8);
// Configure EP0 struct with setup info for the trans complete
struct hw_endpoint *ep = _hw_endpoint_allocate(0);
// EP0 out
_hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
assert(ep->configured);
ep->total_len = 8;
ep->transfer_size = 8;
ep->active = true;
ep->sent_setup = true;
ep->remaining_len = 8;
ep->active = true;
// Set device address
usb_hw->dev_addr_ctrl = dev_addr;
// Set pre if we are a low speed device on full speed hub
uint32_t flags = sie_ctrl_base | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS;
flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0;
uint32_t const flags = SIE_CTRL_BASE | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS |
(need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0);
usb_hw->sie_ctrl = flags;
return true;
}
uint32_t hcd_frame_number(uint8_t rhport)
{
return usb_hw->sof_rd;
}
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress);
hw_endpoint_init(dev_addr, ep_desc);
return true;
}
//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
//{
@@ -531,6 +552,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
{
(void) dev_addr;
(void) ep_addr;
panic("hcd_clear_stall");
return true;
}

View File

@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
* Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -43,42 +44,38 @@ static inline void _hw_endpoint_lock_update(struct hw_endpoint *ep, int delta) {
// sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
}
#if TUSB_OPT_HOST_ENABLED
static inline void _hw_endpoint_update_last_buf(struct hw_endpoint *ep)
{
ep->last_buf = (ep->len + ep->transfer_size == ep->total_len);
}
#endif
static void _hw_endpoint_xfer_sync(struct hw_endpoint *ep);
static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
void rp2040_usb_init(void)
{
// Reset usb controller
reset_block(RESETS_RESET_USBCTRL_BITS);
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
// Reset usb controller
reset_block(RESETS_RESET_USBCTRL_BITS);
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
// Clear any previous state just in case
memset(usb_hw, 0, sizeof(*usb_hw));
memset(usb_dpram, 0, sizeof(*usb_dpram));
// Clear any previous state just in case
memset(usb_hw, 0, sizeof(*usb_hw));
memset(usb_dpram, 0, sizeof(*usb_dpram));
// Mux the controller to the onboard usb phy
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
// Mux the controller to the onboard usb phy
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
// Force VBUS detect so the device thinks it is plugged into a host
// TODO support VBUs detect
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
// Force VBUS detect so the device thinks it is plugged into a host
// TODO support VBUs detect
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
}
void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
{
ep->stalled = false;
ep->active = false;
#if TUSB_OPT_HOST_ENABLED
ep->sent_setup = false;
#endif
ep->total_len = 0;
ep->len = 0;
ep->transfer_size = 0;
ep->user_buf = 0;
ep->stalled = false;
ep->active = false;
ep->remaining_len = 0;
ep->xferred_len = 0;
ep->user_buf = 0;
}
void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
@@ -111,215 +108,223 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
*ep->buffer_control = value;
}
void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
// prepare buffer, return buffer control
static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
{
// Prepare buffer control register value
uint32_t val = ep->transfer_size | USB_BUF_CTRL_AVAIL;
uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
ep->remaining_len -= buflen;
if (!ep->rx)
uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL;
// PID
buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
ep->next_pid ^= 1u;
if ( !ep->rx )
{
// Copy data from user buffer to hw buffer
memcpy(ep->hw_data_buf + buf_id*64, ep->user_buf, buflen);
ep->user_buf += buflen;
// Mark as full
buf_ctrl |= USB_BUF_CTRL_FULL;
}
// Is this the last buffer? Only really matters for host mode. Will trigger
// the trans complete irq but also stop it polling. We only really care about
// trans complete for setup packets being sent
if (ep->remaining_len == 0)
{
buf_ctrl |= USB_BUF_CTRL_LAST;
}
if (buf_id) buf_ctrl = buf_ctrl << 16;
return buf_ctrl;
}
// Prepare buffer control register value
static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
{
uint32_t ep_ctrl = *ep->endpoint_control;
// always compute and start with buffer 0
uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL;
// For now: skip double buffered for Device mode, OUT endpoint since
// host could send < 64 bytes and cause short packet on buffer0
// NOTE this could happen to Host mode IN endpoint
bool const force_single = !(usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) && !tu_edpt_dir(ep->ep_addr);
if(ep->remaining_len && !force_single)
{
// Use buffer 1 (double buffered) if there is still data
// TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
buf_ctrl |= prepare_ep_buffer(ep, 1);
// Set endpoint control double buffered bit if needed
ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER;
}else
{
// Single buffered since 1 is enough
ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
}
*ep->endpoint_control = ep_ctrl;
TU_LOG(3, "Prepare Buffer Control:\r\n");
print_bufctrl32(buf_ctrl);
// Finally, write to buffer_control which will trigger the transfer
// the next time the controller polls this dpram address
_hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
}
void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
{
_hw_endpoint_lock_update(ep, 1);
if ( ep->active )
{
// TODO: Is this acceptable for interrupt packets?
TU_LOG(1, "WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr),
ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
hw_endpoint_reset_transfer(ep);
}
// Fill in info now that we're kicking off the hw
ep->remaining_len = total_len;
ep->xferred_len = 0;
ep->active = true;
ep->user_buf = buffer;
_hw_endpoint_start_next_buffer(ep);
_hw_endpoint_lock_update(ep, -1);
}
// sync endpoint buffer and return transferred bytes
static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
{
uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
if (buf_id) buf_ctrl = buf_ctrl >> 16;
uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
if ( !ep->rx )
{
// We are continuing a transfer here. If we are TX, we have successfully
// sent some data can increase the length we have sent
assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
ep->xferred_len += xferred_bytes;
}else
{
// If we have received some data, so can increase the length
// we have received AFTER we have copied it to the user buffer at the appropriate offset
assert(buf_ctrl & USB_BUF_CTRL_FULL);
memcpy(ep->user_buf, ep->hw_data_buf + buf_id*64, xferred_bytes);
ep->xferred_len += xferred_bytes;
ep->user_buf += xferred_bytes;
}
// Short packet
if (xferred_bytes < ep->wMaxPacketSize)
{
pico_trace("Short rx transfer on buffer %d with %u bytes\n", buf_id, xferred_bytes);
// Reduce total length as this is last packet
ep->remaining_len = 0;
}
return xferred_bytes;
}
static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
{
// Update hw endpoint struct with info from hardware
// after a buff status interrupt
uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
TU_LOG(3, "_hw_endpoint_xfer_sync:\r\n");
print_bufctrl32(buf_ctrl);
// always sync buffer 0
uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
// sync buffer 1 if double buffered
if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS )
{
if (buf0_bytes == ep->wMaxPacketSize)
{
// Copy data from user buffer to hw buffer
memcpy(ep->hw_data_buf, &ep->user_buf[ep->len], ep->transfer_size);
// Mark as full
val |= USB_BUF_CTRL_FULL;
}
// PID
val |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
#if TUSB_OPT_DEVICE_ENABLED
ep->next_pid ^= 1u;
#else
// For Host (also device but since we dictate the endpoint size, following scenario does not occur)
// Next PID depends on the number of packet in case wMaxPacketSize < 64 (e.g Interrupt Endpoint 8, or 12)
// Special case with control status stage where PID is always DATA1
if ( ep->transfer_size == 0 )
{
// ZLP also toggle data
ep->next_pid ^= 1u;
// sync buffer 1 if not short packet
sync_ep_buffer(ep, 1);
}else
{
uint32_t packet_count = 1 + ((ep->transfer_size - 1) / ep->wMaxPacketSize);
// short packet on buffer 0
// TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example
// At this time (currently trigger per 2 buffer), the buffer1 is probably filled with data from
// the next transfer (not current one). For now we disable double buffered for device OUT
// NOTE this could happen to Host IN
#if 0
uint8_t const ep_num = tu_edpt_number(ep->ep_addr);
uint8_t const dir = (uint8_t) tu_edpt_dir(ep->ep_addr);
uint8_t const ep_id = 2*ep_num + (dir ? 0 : 1);
if ( packet_count & 0x01 )
{
ep->next_pid ^= 1u;
}
}
// abort queued transfer on buffer 1
usb_hw->abort |= TU_BIT(ep_id);
while ( !(usb_hw->abort_done & TU_BIT(ep_id)) ) {}
uint32_t ep_ctrl = *ep->endpoint_control;
ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
_hw_endpoint_buffer_control_set_value32(ep, 0);
usb_hw->abort &= ~TU_BIT(ep_id);
TU_LOG(3, "----SHORT PACKET buffer0 on EP %02X:\r\n", ep->ep_addr);
print_bufctrl32(buf_ctrl);
#endif
#if TUSB_OPT_HOST_ENABLED
// Is this the last buffer? Only really matters for host mode. Will trigger
// the trans complete irq but also stop it polling. We only really care about
// trans complete for setup packets being sent
if (ep->last_buf)
{
pico_trace("Last buf (%d bytes left)\n", ep->transfer_size);
val |= USB_BUF_CTRL_LAST;
}
#endif
// Finally, write to buffer_control which will trigger the transfer
// the next time the controller polls this dpram address
_hw_endpoint_buffer_control_set_value32(ep, val);
pico_trace("buffer control (0x%p) <- 0x%x\n", ep->buffer_control, val);
//print_bufctrl16(val);
}
void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
{
_hw_endpoint_lock_update(ep, 1);
pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
if (ep->active)
{
// TODO: Is this acceptable for interrupt packets?
pico_warn("WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
hw_endpoint_reset_transfer(ep);
}
// Fill in info now that we're kicking off the hw
ep->total_len = total_len;
ep->len = 0;
// Limit by packet size but not less 64 (i.e low speed 8 bytes EP0)
ep->transfer_size = tu_min16(total_len, tu_max16(64, ep->wMaxPacketSize));
ep->active = true;
ep->user_buf = buffer;
#if TUSB_OPT_HOST_ENABLED
// Recalculate if this is the last buffer
_hw_endpoint_update_last_buf(ep);
ep->buf_sel = 0;
#endif
_hw_endpoint_start_next_buffer(ep);
_hw_endpoint_lock_update(ep, -1);
}
void _hw_endpoint_xfer_sync(struct hw_endpoint *ep)
{
// Update hw endpoint struct with info from hardware
// after a buff status interrupt
uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
#if TUSB_OPT_HOST_ENABLED
// RP2040-E4
// tag::host_buf_sel_fix[]
// TODO need changes to support double buffering
if (ep->buf_sel == 1)
{
// Host can erroneously write status to top half of buf_ctrl register
buf_ctrl = buf_ctrl >> 16;
// update buf1 -> buf0 to prevent panic with "already available"
*ep->buffer_control = buf_ctrl;
}
// Flip buf sel for host
ep->buf_sel ^= 1u;
// end::host_buf_sel_fix[]
#endif
// Get tranferred bytes after adjusted buf sel
uint16_t const transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
// We are continuing a transfer here. If we are TX, we have successfullly
// sent some data can increase the length we have sent
if (!ep->rx)
{
assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
pico_trace("tx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl);
ep->len += transferred_bytes;
}
else
{
// If we are OUT we have recieved some data, so can increase the length
// we have recieved AFTER we have copied it to the user buffer at the appropriate
// offset
pico_trace("rx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl);
assert(buf_ctrl & USB_BUF_CTRL_FULL);
memcpy(&ep->user_buf[ep->len], ep->hw_data_buf, transferred_bytes);
ep->len += transferred_bytes;
}
// Sometimes the host will send less data than we expect...
// If this is a short out transfer update the total length of the transfer
// to be the current length
if ((ep->rx) && (transferred_bytes < ep->wMaxPacketSize))
{
pico_trace("Short rx transfer\n");
// Reduce total length as this is last packet
ep->total_len = ep->len;
}
}
}
// Returns true if transfer is complete
bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep)
bool hw_endpoint_xfer_continue(struct hw_endpoint *ep)
{
_hw_endpoint_lock_update(ep, 1);
// Part way through a transfer
if (!ep->active)
{
panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
}
_hw_endpoint_lock_update(ep, 1);
// Part way through a transfer
if (!ep->active)
{
panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
}
// Update EP struct from hardware state
_hw_endpoint_xfer_sync(ep);
// Now we have synced our state with the hardware. Is there more data to transfer?
// Limit by packet size but not less 64 (i.e low speed 8 bytes EP0)
uint16_t remaining_bytes = ep->total_len - ep->len;
ep->transfer_size = tu_min16(remaining_bytes, tu_max16(64, ep->wMaxPacketSize));
#if TUSB_OPT_HOST_ENABLED
_hw_endpoint_update_last_buf(ep);
#endif
// Can happen because of programmer error so check for it
if (ep->len > ep->total_len)
{
panic("Transferred more data than expected");
}
// If we are done then notify tinyusb
if (ep->len == ep->total_len)
{
pico_trace("Completed transfer of %d bytes on ep %d %s\n",
ep->len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
// Notify caller we are done so it can notify the tinyusb stack
_hw_endpoint_lock_update(ep, -1);
return true;
}
else
{
_hw_endpoint_start_next_buffer(ep);
}
// Update EP struct from hardware state
_hw_endpoint_xfer_sync(ep);
// Now we have synced our state with the hardware. Is there more data to transfer?
// If we are done then notify tinyusb
if (ep->remaining_len == 0)
{
pico_trace("Completed transfer of %d bytes on ep %d %s\n",
ep->xferred_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
// Notify caller we are done so it can notify the tinyusb stack
_hw_endpoint_lock_update(ep, -1);
// More work to do
return false;
}
return true;
}
else
{
_hw_endpoint_start_next_buffer(ep);
}
void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start)
{
// Trace
pico_trace("hw_endpoint_xfer ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
pico_trace(" total_len %d, start=%d\n", total_len, start);
assert(ep->configured);
if (start)
{
_hw_endpoint_xfer_start(ep, buffer, total_len);
}
else
{
_hw_endpoint_xfer_continue(ep);
}
_hw_endpoint_lock_update(ep, -1);
// More work to do
return false;
}
#endif

View File

@@ -17,23 +17,8 @@
#endif
#if false && !defined(NDEBUG)
#define pico_trace(format,args...) printf(format, ## args)
#else
#define pico_trace(format,...) ((void)0)
#endif
#if false && !defined(NDEBUG)
#define pico_info(format,args...) printf(format, ## args)
#else
#define pico_info(format,...) ((void)0)
#endif
#if false && !defined(NDEBUG)
#define pico_warn(format,args...) printf(format, ## args)
#else
#define pico_warn(format,...) ((void)0)
#endif
#define pico_info(...) TU_LOG(2, __VA_ARGS__)
#define pico_trace(...) TU_LOG(3, __VA_ARGS__)
// Hardware information per endpoint
struct hw_endpoint
@@ -50,6 +35,7 @@ struct hw_endpoint
// Endpoint control register
io_rw_32 *endpoint_control;
// Buffer control register
io_rw_32 *buffer_control;
@@ -61,27 +47,22 @@ struct hw_endpoint
// Current transfer information
bool active;
uint16_t total_len;
uint16_t len;
// Amount of data with the hardware
uint16_t transfer_size;
uint16_t remaining_len;
uint16_t xferred_len;
// User buffer in main memory
uint8_t *user_buf;
// Data needed from EP descriptor
uint16_t wMaxPacketSize;
// Interrupt, bulk, etc
uint8_t transfer_type;
#if TUSB_OPT_HOST_ENABLED
// Only needed for host mode
bool last_buf;
// RP2040-E4: HOST BUG. Host will incorrect write status to top half of buffer
// control register when doing transfers > 1 packet
uint8_t buf_sel;
// Only needed for host
uint8_t dev_addr;
bool sent_setup;
// If interrupt endpoint
uint8_t interrupt_num;
#endif
@@ -89,12 +70,10 @@ struct hw_endpoint
void rp2040_usb_init(void);
void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
void hw_endpoint_reset_transfer(struct hw_endpoint *ep);
void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start);
void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
void _hw_endpoint_xfer_sync(struct hw_endpoint *ep);
bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep);
void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask);
static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) {
return *ep->buffer_control;
@@ -134,14 +113,15 @@ typedef union TU_ATTR_PACKED
TU_VERIFY_STATIC(sizeof(rp2040_buffer_control_t) == 2, "size is not correct");
static inline void print_bufctrl16(uint32_t __unused u16)
#if CFG_TUSB_DEBUG >= 3
static inline void print_bufctrl16(uint32_t u16)
{
rp2040_buffer_control_t __unused bufctrl = {
rp2040_buffer_control_t bufctrl = {
.u16 = u16
};
TU_LOG(2, "len = %u, available = %u, stall = %u, reset = %u, toggle = %u, last = %u, full = %u\r\n",
bufctrl.xfer_len, bufctrl.available, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle, bufctrl.last_buf, bufctrl.full);
TU_LOG(3, "len = %u, available = %u, full = %u, last = %u, stall = %u, reset = %u, toggle = %u\r\n",
bufctrl.xfer_len, bufctrl.available, bufctrl.full, bufctrl.last_buf, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle);
}
static inline void print_bufctrl32(uint32_t u32)
@@ -149,12 +129,19 @@ static inline void print_bufctrl32(uint32_t u32)
uint16_t u16;
u16 = u32 >> 16;
TU_LOG(2, "Buffer Control 1 0x%x: ", u16);
TU_LOG(3, " Buffer Control 1 0x%x: ", u16);
print_bufctrl16(u16);
u16 = u32 & 0x0000ffff;
TU_LOG(2, "Buffer Control 0 0x%x: ", u16);
TU_LOG(3, " Buffer Control 0 0x%x: ", u16);
print_bufctrl16(u16);
}
#else
#define print_bufctrl16(u16)
#define print_bufctrl32(u32)
#endif
#endif

View File

@@ -26,8 +26,8 @@
#include "tusb_option.h"
#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X )
#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
CFG_TUSB_MCU == OPT_MCU_RX65X)
#include "device/dcd.h"
#include "iodefine.h"
@@ -63,7 +63,10 @@
#define USB_IS0_CTSQ_SETUP (1u)
#define USB_IS0_DVSQ_DEF (1u<<4)
#define USB_IS0_DVSQ_ADDR (2u<<4)
#define USB_IS0_DVSQ_SUSP (4u<<4)
#define USB_IS0_DVSQ_SUSP0 (4u<<4)
#define USB_IS0_DVSQ_SUSP1 (5u<<4)
#define USB_IS0_DVSQ_SUSP2 (6u<<4)
#define USB_IS0_DVSQ_SUSP3 (7u<<4)
#define USB_PIPECTR_PID_NAK (0u)
#define USB_PIPECTR_PID_BUF (1u)
@@ -125,6 +128,7 @@ typedef struct
{
pipe_state_t pipe[9];
uint8_t ep[2][16]; /* a lookup table for a pipe index from an endpoint address */
uint8_t suspended;
} dcd_data_t;
//--------------------------------------------------------------------+
@@ -517,7 +521,8 @@ void dcd_init(uint8_t rhport)
/* Setup default control pipe */
USB0.DCPMAXP.BIT.MXPS = 64;
USB0.INTENB0.WORD = USB_IS0_VBINT | USB_IS0_BRDY | USB_IS0_BEMP | USB_IS0_DVST | USB_IS0_CTRT;
USB0.INTENB0.WORD = USB_IS0_VBINT | USB_IS0_BRDY | USB_IS0_BEMP |
USB_IS0_DVST | USB_IS0_CTRT | USB_IS0_SOFR | USB_IS0_RESM;
USB0.BEMPENB.WORD = 1;
USB0.BRDYENB.WORD = 1;
@@ -547,7 +552,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
void dcd_remote_wakeup(uint8_t rhport)
{
(void)rhport;
/* TODO */
USB0.DVSTCTR0.BIT.WKUP = 1;
}
void dcd_connect(uint8_t rhport)
@@ -689,6 +694,22 @@ void dcd_int_handler(uint8_t rhport)
dcd_disconnect(rhport);
}
}
if (is0 & USB_IS0_RESM) {
dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
_dcd.suspended = 0;
}
if (is0 & USB_IS0_SOFR) {
if (_dcd.suspended) {
/* When USB host resumes caused by `dcd_remote_wakeup()`,
* RESM interrupt does not rise.
* Therefore we need to manually send resume event.
* Of course, when USB host resumes on its own,
* RESM interrupt rise properly, then this statements are ignored. */
dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
_dcd.suspended = 0;
}
dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
}
if (is0 & USB_IS0_DVST) {
switch (is0 & USB_IS0_DVSQ) {
case USB_IS0_DVSQ_DEF:
@@ -697,6 +718,12 @@ void dcd_int_handler(uint8_t rhport)
case USB_IS0_DVSQ_ADDR:
process_set_address(rhport);
break;
case USB_IS0_DVSQ_SUSP0:
case USB_IS0_DVSQ_SUSP1:
case USB_IS0_DVSQ_SUSP2:
case USB_IS0_DVSQ_SUSP3:
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
_dcd.suspended = 1;
default:
break;
}

View File

@@ -64,7 +64,6 @@
#define OPT_MCU_SAML21 206 ///< MicroChip SAML21
#define OPT_MCU_SAMX7X 207 ///< MicroChip SAME70, S70, V70, V71 family
// STM32
#define OPT_MCU_STM32F0 300 ///< ST STM32F0
#define OPT_MCU_STM32F1 301 ///< ST STM32F1
@@ -115,6 +114,7 @@
// Renesas RX
#define OPT_MCU_RX63X 1400 ///< Renesas RX63N/631
#define OPT_MCU_RX65X 1401 ///< Renesas RX65N/RX651
// Mind Motion
#define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327
@@ -280,8 +280,8 @@
#error there is no benefit enable hub with max device is 1. Please disable hub or increase CFG_TUSB_HOST_DEVICE_MAX
#endif
#ifndef CFG_TUH_ENUMERATION_BUFSZIE
#define CFG_TUH_ENUMERATION_BUFSZIE 256
#ifndef CFG_TUH_ENUMERATION_BUFSIZE
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#endif
//------------- CLASS -------------//