summaryrefslogtreecommitdiff
path: root/src/class
diff options
context:
space:
mode:
authorRocky04 <[email protected]>2024-01-15 16:27:22 +0100
committerGitHub <[email protected]>2024-01-15 16:27:22 +0100
commit78a1d4c482606cac398ee09b55a4dab04f400ae3 (patch)
tree35cfffecd9f4f390265b24c489f3708a811ce31a /src/class
parent3c4184dc15fad3eccf53c247a1c8de56bd4bd517 (diff)
parent4b3b401ce37e12eaf4c85a5184d94327c28c70a5 (diff)
Merge branch 'master' into test-mode-support
Diffstat (limited to 'src/class')
-rw-r--r--src/class/audio/audio_device.c543
-rw-r--r--src/class/audio/audio_device.h6
-rwxr-xr-xsrc/class/bth/bth_device.c4
-rwxr-xr-xsrc/class/bth/bth_device.h7
-rw-r--r--src/class/cdc/cdc.h20
-rw-r--r--src/class/cdc/cdc_host.c9
-rw-r--r--src/class/cdc/cdc_host.h2
-rw-r--r--src/class/cdc/serial/cp210x.h2
-rw-r--r--src/class/cdc/serial/ftdi_sio.h5
-rw-r--r--src/class/hid/hid_host.c10
-rw-r--r--src/class/hid/hid_host.h4
-rw-r--r--src/class/msc/msc_host.c265
-rw-r--r--src/class/msc/msc_host.h8
13 files changed, 513 insertions, 372 deletions
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 1a7ce7870..d438d0715 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -110,24 +110,36 @@
#error Maximum number of audio functions restricted to three!
#endif
+// Put sw_buf in USB section only if necessary
+#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING
+#define IN_SW_BUF_MEM_SECTION
+#else
+#define IN_SW_BUF_MEM_SECTION CFG_TUD_MEM_SECTION
+#endif
+#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING
+#define OUT_SW_BUF_MEM_SECTION
+#else
+#define OUT_SW_BUF_MEM_SECTION CFG_TUD_MEM_SECTION
+#endif
+
// 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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
+ IN_SW_BUF_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
+ IN_SW_BUF_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
+ IN_SW_BUF_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
@@ -154,21 +166,21 @@
// 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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
+ OUT_SW_BUF_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
+ OUT_SW_BUF_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
+ OUT_SW_BUF_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
@@ -217,7 +229,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
// Software encoding/decoding support FIFOs
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
+ CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
@@ -225,7 +237,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
+ CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
@@ -233,7 +245,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
+ CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
@@ -243,7 +255,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
+ CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
@@ -251,7 +263,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
+ CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
@@ -259,7 +271,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
- CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
+ 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
@@ -364,14 +376,21 @@ typedef struct
#endif
#endif
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+ uint32_t sample_rate_tx;
+ uint16_t packet_sz_tx[3];
+ uint8_t bclock_id_tx;
+ uint8_t interval_tx;
+#endif
+
// Encoding parameters - parameters are set when alternate AS interface is set by host
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL)
audio_format_type_t format_type_tx;
uint8_t n_channels_tx;
+ uint8_t n_bytes_per_sampe_tx;
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
audio_data_format_type_I_t format_type_I_tx;
- uint8_t n_bytes_per_sampe_tx;
uint8_t n_channels_per_ff_tx;
uint8_t n_ff_used_tx;
#endif
@@ -444,7 +463,7 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id);
static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id);
static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio);
-#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
+#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && 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);
static inline uint8_t tu_desc_subtype(void const* desc)
@@ -453,6 +472,11 @@ static inline uint8_t tu_desc_subtype(void const* desc)
}
#endif
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+static bool audiod_calc_tx_packet_sz(audiod_function_t* audio);
+static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t data_count, uint16_t fifo_depth, uint16_t max_size);
+#endif
+
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq);
#endif
@@ -631,73 +655,55 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
// Decoding according to 2.3.1.5 Audio Streams
// Helper function
-static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used)
+static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesPerSample, void * dst, const void * dst_end, void * src, uint8_t const n_ff_used)
{
+ // Due to one FIFO contains 2 channels, data always aligned to (nBytesPerSample * 2)
+ uint16_t * dst16 = dst;
+ uint16_t * src16 = src;
+ const uint16_t * dst_end16 = dst_end;
+ uint32_t * dst32 = dst;
+ uint32_t * src32 = src;
+ const uint32_t * dst_end32 = dst_end;
- // This function is an optimized version of
- // while((uint8_t *)dst < dst_end)
- // {
- // memcpy(dst, src, nBytesToCopy);
- // dst = (uint8_t *)dst + nBytesToCopy;
- // src += nBytesToCopy * n_ff_used;
- // }
-
- // Optimize for fast half word copies
- typedef struct{
- uint16_t val;
- } __attribute((__packed__)) unaligned_uint16_t;
-
- // Optimize for fast word copies
- typedef struct{
- uint32_t val;
- } __attribute((__packed__)) unaligned_uint32_t;
-
- switch (nBytesToCopy)
+ if (nBytesPerSample == 1)
{
- case 1:
- while((uint8_t *)dst < dst_end)
- {
- *(uint8_t *)dst++ = *src;
- src += n_ff_used;
- }
- break;
-
- case 2:
- while((uint8_t *)dst < dst_end)
- {
- *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
- dst += 2;
- src += 2 * n_ff_used;
- }
- break;
-
- case 3:
- while((uint8_t *)dst < dst_end)
- {
- // memcpy(dst, src, 3);
- // dst = (uint8_t *)dst + 3;
- // src += 3 * n_ff_used;
-
- // TODO: Is there a faster way to copy 3 bytes?
- *(uint8_t *)dst++ = *src++;
- *(uint8_t *)dst++ = *src++;
- *(uint8_t *)dst++ = *src++;
-
- src += 3 * (n_ff_used - 1);
- }
- break;
-
- case 4:
- while((uint8_t *)dst < dst_end)
- {
- *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
- dst += 4;
- src += 4 * n_ff_used;
- }
- break;
+ while(dst16 < dst_end16)
+ {
+ *dst16++ = *src16++;
+ src16 += n_ff_used - 1;
+ }
+ return src16;
+ }
+ else if (nBytesPerSample == 2)
+ {
+ while(dst32 < dst_end32)
+ {
+ *dst32++ = *src32++;
+ src32 += n_ff_used - 1;
+ }
+ return src32;
+ }
+ else if (nBytesPerSample == 3)
+ {
+ while(dst16 < dst_end16)
+ {
+ *dst16++ = *src16++;
+ *dst16++ = *src16++;
+ *dst16++ = *src16++;
+ src16 += 3 * (n_ff_used - 1);
+ }
+ return src16;
+ }
+ else // nBytesPerSample == 4
+ {
+ while(dst32 < dst_end32)
+ {
+ *dst32++ = *src32++;
+ *dst32++ = *src32++;
+ src32 += 2 * (n_ff_used - 1);
+ }
+ return src32;
}
-
- return src;
}
static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
@@ -839,7 +845,6 @@ uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint1
#endif
-
// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write.
@@ -904,9 +909,12 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio)
#else
// No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule
-
+#if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+ // packet_sz_tx is based on total packet size, here we want size for each support buffer.
+ n_bytes_tx = audiod_tx_packet_size(audio->packet_sz_tx, tu_fifo_count(&audio->ep_in_ff), audio->ep_in_ff.depth, audio->ep_in_sz);
+#else
n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO
-
+#endif
#if USE_LINEAR_BUFFER_TX
tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx);
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
@@ -944,64 +952,55 @@ range [-1, +1)
* */
// Helper function
-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)
+static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesPerSample, void * src, const void * src_end, void * dst, uint8_t const n_ff_used)
{
- // Optimize for fast half word copies
- typedef struct{
- uint16_t val;
- } __attribute((__packed__)) unaligned_uint16_t;
+ // Due to one FIFO contains 2 channels, data always aligned to (nBytesPerSample * 2)
+ uint16_t * dst16 = dst;
+ uint16_t * src16 = src;
+ const uint16_t * src_end16 = src_end;
+ uint32_t * dst32 = dst;
+ uint32_t * src32 = src;
+ const uint32_t * src_end32 = src_end;
- // Optimize for fast word copies
- typedef struct{
- uint32_t val;
- } __attribute((__packed__)) unaligned_uint32_t;
-
- switch (nBytesToCopy)
+ if (nBytesPerSample == 1)
{
- case 1:
- while(src < src_end)
- {
- *dst = *src++;
- dst += n_ff_used;
- }
- break;
-
- case 2:
- while(src < src_end)
- {
- *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
- src += 2;
- dst += 2 * n_ff_used;
- }
- break;
-
- case 3:
- 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++ = *src++;
- *dst++ = *src++;
- *dst++ = *src++;
-
- dst += 3 * (n_ff_used - 1);
- }
- break;
-
- case 4:
- while(src < src_end)
- {
- *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
- src += 4;
- dst += 4 * n_ff_used;
- }
- break;
+ while(src16 < src_end16)
+ {
+ *dst16++ = *src16++;
+ dst16 += n_ff_used - 1;
+ }
+ return dst16;
+ }
+ else if (nBytesPerSample == 2)
+ {
+ while(src32 < src_end32)
+ {
+ *dst32++ = *src32++;
+ dst32 += n_ff_used - 1;
+ }
+ return dst32;
+ }
+ else if (nBytesPerSample == 3)
+ {
+ while(src16 < src_end16)
+ {
+ *dst16++ = *src16++;
+ *dst16++ = *src16++;
+ *dst16++ = *src16++;
+ dst16 += 3 * (n_ff_used - 1);
+ }
+ return dst16;
+ }
+ else // nBytesPerSample == 4
+ {
+ while(src32 < src_end32)
+ {
+ *dst32++ = *src32++;
+ *dst32++ = *src32++;
+ dst32 += 2 * (n_ff_used - 1);
+ }
+ return dst32;
}
-
- return dst;
}
static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio)
@@ -1014,8 +1013,6 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
// Determine amount of samples
uint8_t const n_ff_used = audio->n_ff_used_tx;
- uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx;
- uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes
uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]);
uint8_t cnt_ff;
@@ -1028,14 +1025,23 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
}
}
- // Check if there is enough
+#if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+ const uint16_t norm_packet_sz_tx[3] = {audio->packet_sz_tx[0] / n_ff_used,
+ audio->packet_sz_tx[1] / n_ff_used,
+ audio->packet_sz_tx[2] / n_ff_used};
+ // packet_sz_tx is based on total packet size, here we want size for each support buffer.
+ nBytesPerFFToSend = audiod_tx_packet_size(norm_packet_sz_tx, nBytesPerFFToSend, audio->tx_supp_ff[0].depth, audio->ep_in_sz / n_ff_used);
+ // Check if there is enough data
+ if (nBytesPerFFToSend == 0) return 0;
+#else
+ // Check if there is enough data
if (nBytesPerFFToSend == 0) return 0;
-
// Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
- nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF);
-
+ nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, audio->ep_in_sz / n_ff_used);
// Round to full number of samples (flooring)
- nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy;
+ uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx;
+ nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize;
+#endif
// Encode
uint8_t * dst;
@@ -1298,7 +1304,7 @@ void audiod_init(void)
#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
// Set encoding parameters for Type_I formats
-#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
@@ -1478,82 +1484,116 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
}
#if USE_ISO_EP_ALLOCATION
+ {
#if CFG_TUD_AUDIO_ENABLE_EP_IN
- uint8_t ep_in = 0;
- uint16_t ep_in_size = 0;
+ uint8_t ep_in = 0;
+ uint16_t ep_in_size = 0;
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
- uint8_t ep_out = 0;
- uint16_t ep_out_size = 0;
+ uint8_t ep_out = 0;
+ uint16_t ep_out_size = 0;
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- uint8_t ep_fb = 0;
+ uint8_t ep_fb = 0;
#endif
-
- uint8_t const *p_desc = _audiod_fct[i].p_desc;
- uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
- while (p_desc < p_desc_end)
- {
- if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
+ uint8_t const *p_desc = _audiod_fct[i].p_desc;
+ uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
+ while (p_desc < p_desc_end)
{
- tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
+ if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
{
- #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- // Explicit feedback EP
- if (desc_ep->bmAttributes.usage == 1)
+ tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+ if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
{
- ep_fb = desc_ep->bEndpointAddress;
- }
+ #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ // Explicit feedback EP
+ if (desc_ep->bmAttributes.usage == 1)
+ {
+ ep_fb = desc_ep->bEndpointAddress;
+ }
#endif
- // Data EP
- if (desc_ep->bmAttributes.usage == 0)
- {
- if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
+ // Data EP
+ if (desc_ep->bmAttributes.usage == 0)
{
+ if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
+ {
#if CFG_TUD_AUDIO_ENABLE_EP_IN
- ep_in = desc_ep->bEndpointAddress;
- ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
+ ep_in = desc_ep->bEndpointAddress;
+ ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
#endif
- } else
- {
+ } else
+ {
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
- ep_out = desc_ep->bEndpointAddress;
- ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
+ ep_out = desc_ep->bEndpointAddress;
+ ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
#endif
+ }
}
- }
+ }
}
+
+ p_desc = tu_desc_next(p_desc);
}
- p_desc = tu_desc_next(p_desc);
- }
#if CFG_TUD_AUDIO_ENABLE_EP_IN
- if (ep_in)
- {
- usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size);
- }
+ if (ep_in)
+ {
+ usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size);
+ }
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (ep_out)
- {
- usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size);
- }
+ if (ep_out)
+ {
+ usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size);
+ }
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- if (ep_fb)
- {
- usbd_edpt_iso_alloc(rhport, ep_fb, 4);
- }
+ if (ep_fb)
+ {
+ usbd_edpt_iso_alloc(rhport, ep_fb, 4);
+ }
#endif
-
+ }
#endif // USE_ISO_EP_ALLOCATION
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+ {
+ uint8_t const *p_desc = _audiod_fct[i].p_desc;
+ uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
+ // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
+ while (p_desc_end - p_desc > 0)
+ {
+ if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
+ {
+ tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+ if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
+ {
+ if (desc_ep->bmAttributes.usage == 0)
+ {
+ if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
+ {
+ _audiod_fct[i].interval_tx = desc_ep->bInterval;
+ }
+ }
+ }
+ } else
+ if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL)
+ {
+ if(tu_unaligned_read16(p_desc + 4) == AUDIO_TERM_TYPE_USB_STREAMING)
+ {
+ _audiod_fct[i].bclock_id_tx = p_desc[8];
+ }
+ }
+ p_desc = tu_desc_next(p_desc);
+ }
+ }
+#endif // CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+
break;
}
}
@@ -1634,6 +1674,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
audio->ep_in = 0; // Necessary?
+ #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+ audio->packet_sz_tx[0] = 0;
+ audio->packet_sz_tx[1] = 0;
+ audio->packet_sz_tx[2] = 0;
+ #endif
}
#endif // CFG_TUD_AUDIO_ENABLE_EP_IN
@@ -1684,7 +1729,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// Find correct interface
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt)
{
-#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
uint8_t const * p_desc_parse_for_params = p_desc;
#endif
// From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary
@@ -1713,12 +1758,13 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
audio->ep_in_sz = tu_edpt_packet_size(desc_ep);
// If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters
- #if CFG_TUD_AUDIO_ENABLE_ENCODING
+ #if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
// Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
- #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
- const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx);
+ #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
+ const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx))
+ * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx));
for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
{
tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
@@ -1850,6 +1896,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
if (disable) usbd_sof_enable(rhport, false);
#endif
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+ audiod_calc_tx_packet_sz(audio);
+#endif
+
tud_control_status(rhport, p_request);
return true;
@@ -2292,6 +2342,19 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
// Copy into buffer
TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz, data, (size_t)len));
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+ // Find data for sampling_frequency_control
+ if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE)
+ {
+ uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+ uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+ if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO_CS_REQ_CUR)
+ {
+ _audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf);
+ }
+ }
+#endif
+
// Schedule transmit
return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len);
}
@@ -2431,7 +2494,7 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id)
return false;
}
-#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
+#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING)
// p_desc points to the AS interface of alternate setting zero
// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter
// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for!
@@ -2469,7 +2532,7 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
}
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
if (as_itf == audio->ep_out_as_intf_num)
{
audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
@@ -2482,7 +2545,7 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
}
// Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats)
-#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I)
{
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -2502,7 +2565,7 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
}
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
if (as_itf == audio->ep_out_as_intf_num)
{
audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
@@ -2518,6 +2581,96 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
}
#endif
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+
+static bool audiod_calc_tx_packet_sz(audiod_function_t* audio)
+{
+ TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I);
+ TU_VERIFY(audio->n_channels_tx);
+ TU_VERIFY(audio->n_bytes_per_sampe_tx);
+ TU_VERIFY(audio->interval_tx);
+ TU_VERIFY(audio->sample_rate_tx);
+
+ const uint8_t interval = (tud_speed_get() == TUSB_SPEED_FULL) ? audio->interval_tx : 1 << (audio->interval_tx - 1);
+
+ const uint16_t sample_normimal = (uint16_t)(audio->sample_rate_tx * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
+ const uint16_t sample_reminder = (uint16_t)(audio->sample_rate_tx * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
+
+ const uint16_t packet_sz_tx_min = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx);
+ const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sampe_tx);
+ const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx);
+
+ // Endpoint size must larger than packet size
+ TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz);
+
+ // Frmt20.pdf 2.3.1.1 USB Packets
+ if (sample_reminder)
+ {
+ // All virtual frame packets must either contain INT(nav) audio slots (small VFP) or INT(nav)+1 (large VFP) audio slots
+ audio->packet_sz_tx[0] = packet_sz_tx_norm;
+ audio->packet_sz_tx[1] = packet_sz_tx_norm;
+ audio->packet_sz_tx[2] = packet_sz_tx_max;
+ } else
+ {
+ // In the case where nav = INT(nav), ni may vary between INT(nav)-1 (small VFP), INT(nav)
+ // (medium VFP) and INT(nav)+1 (large VFP).
+ audio->packet_sz_tx[0] = packet_sz_tx_min;
+ audio->packet_sz_tx[1] = packet_sz_tx_norm;
+ audio->packet_sz_tx[2] = packet_sz_tx_max;
+ }
+
+ return true;
+}
+
+static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t data_count, uint16_t fifo_depth, uint16_t max_depth)
+{
+ // Flow control need a FIFO size of at least 4*Navg
+ if(norminal_size[1] && norminal_size[1] <= fifo_depth * 4)
+ {
+ // Use blackout to prioritize normal size packet
+ static int ctrl_blackout = 0;
+ uint16_t packet_size;
+ uint16_t slot_size = norminal_size[2] - norminal_size[1];
+ if (data_count < norminal_size[0])
+ {
+ // If you get here frequently, then your I2S clock deviation is too big !
+ packet_size = 0;
+ } else
+ if (data_count < fifo_depth / 2 - slot_size && !ctrl_blackout)
+ {
+ packet_size = norminal_size[0];
+ ctrl_blackout = 10;
+ } else
+ if (data_count > fifo_depth / 2 + slot_size && !ctrl_blackout)
+ {
+ packet_size = norminal_size[2];
+ if(norminal_size[0] == norminal_size[1])
+ {
+ // nav > INT(nav), eg. 44.1k, 88.2k
+ ctrl_blackout = 0;
+ } else
+ {
+ // nav = INT(nav), eg. 48k, 96k
+ ctrl_blackout = 10;
+ }
+ } else
+ {
+ packet_size = norminal_size[1];
+ if (ctrl_blackout)
+ {
+ ctrl_blackout--;
+ }
+ }
+ // Normally this cap is not necessary
+ return tu_min16(packet_size, max_depth);
+ } else
+ {
+ return tu_min16(data_count, max_depth);
+ }
+}
+
+#endif
+
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h
index 7c88b99fc..ef3e12a06 100644
--- a/src/class/audio/audio_device.h
+++ b/src/class/audio/audio_device.h
@@ -181,6 +181,11 @@
#endif
#endif
+// (For TYPE-I format only) Flow control is necessary to allow IN ep send correct amount of data, unless it's a virtual device where data is perfectly synchronized to USB clock.
+#ifndef CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+#define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1
+#endif
+
// Enable/disable feedback EP (required for asynchronous RX applications)
#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1
@@ -392,6 +397,7 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_i
uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len);
#endif
+
//--------------------------------------------------------------------+
// Application API (Interface0)
//--------------------------------------------------------------------+
diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c
index c5c74d26a..f145e2ead 100755
--- a/src/class/bth/bth_device.c
+++ b/src/class/bth/bth_device.c
@@ -204,7 +204,9 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c
request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE)
{
// HCI command packet addressing for single function Primary Controllers
- TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0);
+ // also compatible with historical mode if enabled
+ TU_VERIFY((request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0) ||
+ (CFG_TUD_BTH_HISTORICAL_COMPATIBLE && request->bRequest == 0xe0));
}
else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE)
{
diff --git a/src/class/bth/bth_device.h b/src/class/bth/bth_device.h
index 921bd7a1a..e782c532b 100755
--- a/src/class/bth/bth_device.h
+++ b/src/class/bth/bth_device.h
@@ -36,10 +36,17 @@
#ifndef CFG_TUD_BTH_EVENT_EPSIZE
#define CFG_TUD_BTH_EVENT_EPSIZE 16
#endif
+
#ifndef CFG_TUD_BTH_DATA_EPSIZE
#define CFG_TUD_BTH_DATA_EPSIZE 64
#endif
+// Allow BTH class to work in historically compatibility mode where the bRequest is always 0xe0.
+// See Bluetooth Core v5.3, Vol. 4, Part B, Section 2.2
+#ifndef CFG_TUD_BTH_HISTORICAL_COMPATIBLE
+#define CFG_TUD_BTH_HISTORICAL_COMPATIBLE 0
+#endif
+
typedef struct TU_ATTR_PACKED
{
uint16_t op_code;
diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h
index 4658e43af..deec32ae4 100644
--- a/src/class/cdc/cdc.h
+++ b/src/class/cdc/cdc.h
@@ -182,21 +182,23 @@ typedef enum
CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60,
}cdc_management_request_t;
-enum
-{
+enum {
CDC_CONTROL_LINE_STATE_DTR = 0x01,
CDC_CONTROL_LINE_STATE_RTS = 0x02,
};
-enum
-{
- CDC_LINE_CONDING_STOP_BITS_1 = 0, // 1 bit
- CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits
- CDC_LINE_CONDING_STOP_BITS_2 = 2, // 2 bits
+enum {
+ CDC_LINE_CODING_STOP_BITS_1 = 0, // 1 bit
+ CDC_LINE_CODING_STOP_BITS_1_5 = 1, // 1.5 bits
+ CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits
};
-enum
-{
+// TODO Backward compatible for typos. Maybe removed in the future release
+#define CDC_LINE_CONDING_STOP_BITS_1 CDC_LINE_CODING_STOP_BITS_1
+#define CDC_LINE_CONDING_STOP_BITS_1_5 CDC_LINE_CODING_STOP_BITS_1_5
+#define CDC_LINE_CONDING_STOP_BITS_2 CDC_LINE_CODING_STOP_BITS_2
+
+enum {
CDC_LINE_CODING_PARITY_NONE = 0,
CDC_LINE_CODING_PARITY_ODD = 1,
CDC_LINE_CODING_PARITY_EVEN = 2,
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 53e15710e..79477ef53 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -80,6 +80,7 @@ static cdch_interface_t cdch_data[CFG_TUH_CDC];
//--------------------------------------------------------------------+
//------------- ACM prototypes -------------//
+static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
static void acm_process_config(tuh_xfer_t* xfer);
static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
@@ -90,7 +91,7 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe
#if CFG_TUH_CDC_FTDI
#include "serial/ftdi_sio.h"
-static uint16_t const ftdi_pids[] = { TU_FTDI_PID_LIST };
+static uint16_t const ftdi_pids[] = { CFG_TUH_CDC_FTDI_PID_LIST };
enum {
FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0])
};
@@ -109,7 +110,7 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu
#if CFG_TUH_CDC_CP210X
#include "serial/cp210x.h"
-static uint16_t const cp210x_pids[] = { TU_CP210X_PID_LIST };
+static uint16_t const cp210x_pids[] = { CFG_TUH_CDC_CP210X_PID_LIST };
enum {
CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0])
};
@@ -605,8 +606,6 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
// Enumeration
//--------------------------------------------------------------------+
-static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
-
static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep)
{
for(size_t i=0; i<2; i++)
@@ -642,7 +641,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d
return acm_open(daddr, itf_desc, max_len);
}
#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X
- else if ( 0xff == itf_desc->bInterfaceClass )
+ else if ( TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass )
{
uint16_t vid, pid;
TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid));
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
index 19552f1ee..9e5edd94e 100644
--- a/src/class/cdc/cdc_host.h
+++ b/src/class/cdc/cdc_host.h
@@ -44,7 +44,7 @@
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM
-//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
+//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
//#endif
// RX FIFO size
diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h
index b01417092..2c749f522 100644
--- a/src/class/cdc/serial/cp210x.h
+++ b/src/class/cdc/serial/cp210x.h
@@ -29,8 +29,6 @@
// https://www.silabs.com/documents/public/application-notes/AN571.pdf
#define TU_CP210X_VID 0x10C4
-#define TU_CP210X_PID_LIST \
- 0xEA60, 0xEA70
/* Config request codes */
#define CP210X_IFC_ENABLE 0x00
diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h
index 6916e4031..0825f0719 100644
--- a/src/class/cdc/serial/ftdi_sio.h
+++ b/src/class/cdc/serial/ftdi_sio.h
@@ -25,11 +25,8 @@
#ifndef TUSB_FTDI_SIO_H
#define TUSB_FTDI_SIO_H
-// VID/PID for matching FTDI devices
+// VID for matching FTDI devices
#define TU_FTDI_VID 0x0403
-#define TU_FTDI_PID_LIST \
- 0x6001, 0x6006, 0x6010, 0x6011, 0x6014, 0x6015, 0x8372, 0xFBFA, \
- 0xcd18
// Commands
#define FTDI_SIO_RESET 0 /* Reset the port */
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index a3551c85a..db52b503f 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -67,6 +67,8 @@ typedef struct
CFG_TUH_MEM_SECTION
tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID];
+tu_static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT;
+
//--------------------------------------------------------------------+
// Helper
//--------------------------------------------------------------------+
@@ -211,6 +213,10 @@ static void set_protocol_complete(tuh_xfer_t* xfer)
}
}
+void tuh_hid_set_default_protocol(uint8_t protocol) {
+ _hidh_default_protocol = protocol;
+}
+
static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
TU_LOG_DRV("HID Set Protocol = %d\r\n", protocol);
@@ -521,7 +527,7 @@ bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_
p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength);
// Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config
- p_hid->protocol_mode = HID_PROTOCOL_BOOT;
+ p_hid->protocol_mode = _hidh_default_protocol;
if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass )
{
p_hid->itf_protocol = desc_itf->bInterfaceProtocol;
@@ -591,7 +597,7 @@ static void process_set_config(tuh_xfer_t* xfer)
break;
case CONFIG_SET_PROTOCOL:
- _hidh_set_protocol(daddr, p_hid->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC);
+ _hidh_set_protocol(daddr, p_hid->itf_num, _hidh_default_protocol, process_set_config, CONFIG_GET_REPORT_DESC);
break;
case CONFIG_GET_REPORT_DESC:
diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h
index 08ad421d2..238b7c627 100644
--- a/src/class/hid/hid_host.h
+++ b/src/class/hid/hid_host.h
@@ -97,6 +97,10 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr,
// Application can use set_protocol() to switch back to Report protocol.
uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t idx);
+// Device by default is enumerated in Boot protocol for simplicity. Application
+// can use this to modify the default protocol for next enumeration.
+void tuh_hid_set_default_protocol(uint8_t protocol);
+
// 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)
bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t idx, uint8_t protocol);
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
index da264142c..39f2d9f1c 100644
--- a/src/class/msc/msc_host.c
+++ b/src/class/msc/msc_host.c
@@ -43,16 +43,14 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
-enum
-{
+enum {
MSC_STAGE_IDLE = 0,
MSC_STAGE_CMD,
MSC_STAGE_DATA,
MSC_STAGE_STATUS,
};
-typedef struct
-{
+typedef struct {
uint8_t itf_num;
uint8_t ep_in;
uint8_t ep_out;
@@ -69,13 +67,13 @@ typedef struct
//------------- SCSI -------------//
uint8_t stage;
- void* buffer;
+ void* buffer;
tuh_msc_complete_cb_t complete_cb;
uintptr_t complete_arg;
CFG_TUH_MEM_ALIGN msc_cbw_t cbw;
CFG_TUH_MEM_ALIGN msc_csw_t csw;
-}msch_interface_t;
+} msch_interface_t;
CFG_TUH_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX];
@@ -86,40 +84,34 @@ static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)];
// FIXME potential nul reference
TU_ATTR_ALWAYS_INLINE
-static inline msch_interface_t* get_itf(uint8_t dev_addr)
-{
- return &_msch_itf[dev_addr-1];
+static inline msch_interface_t* get_itf(uint8_t dev_addr) {
+ return &_msch_itf[dev_addr - 1];
}
//--------------------------------------------------------------------+
// PUBLIC API
//--------------------------------------------------------------------+
-uint8_t tuh_msc_get_maxlun(uint8_t dev_addr)
-{
+uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) {
msch_interface_t* p_msc = get_itf(dev_addr);
return p_msc->max_lun;
}
-uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun)
-{
+uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun) {
msch_interface_t* p_msc = get_itf(dev_addr);
return p_msc->capacity[lun].block_count;
}
-uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun)
-{
+uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun) {
msch_interface_t* p_msc = get_itf(dev_addr);
return p_msc->capacity[lun].block_size;
}
-bool tuh_msc_mounted(uint8_t dev_addr)
-{
+bool tuh_msc_mounted(uint8_t dev_addr) {
msch_interface_t* p_msc = get_itf(dev_addr);
return p_msc->mounted;
}
-bool tuh_msc_ready(uint8_t dev_addr)
-{
+bool tuh_msc_ready(uint8_t dev_addr) {
msch_interface_t* p_msc = get_itf(dev_addr);
return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in) && !usbh_edpt_busy(dev_addr, p_msc->ep_out);
}
@@ -127,20 +119,20 @@ bool tuh_msc_ready(uint8_t dev_addr)
//--------------------------------------------------------------------+
// PUBLIC API: SCSI COMMAND
//--------------------------------------------------------------------+
-static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun)
-{
+static inline void cbw_init(msc_cbw_t* cbw, uint8_t lun) {
tu_memclr(cbw, sizeof(msc_cbw_t));
cbw->signature = MSC_CBW_SIGNATURE;
cbw->tag = 0x54555342; // TUSB
cbw->lun = lun;
}
-bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
-{
- msch_interface_t* p_msc = get_itf(dev_addr);
+bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data,
+ tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
+ msch_interface_t* p_msc = get_itf(daddr);
TU_VERIFY(p_msc->configured);
- // TODO claim endpoint
+ // claim endpoint
+ TU_VERIFY(usbh_edpt_claim(daddr, p_msc->ep_out));
p_msc->cbw = *cbw;
p_msc->stage = MSC_STAGE_CMD;
@@ -148,15 +140,18 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu
p_msc->complete_cb = complete_cb;
p_msc->complete_arg = arg;
- TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)));
+ if (!usbh_edpt_xfer(daddr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))) {
+ usbh_edpt_release(daddr, p_msc->ep_out);
+ return false;
+ }
return true;
}
-bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
-{
- msch_interface_t* p_msc = get_itf(dev_addr);
- TU_VERIFY(p_msc->configured);
+bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response,
+ tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
+ msch_interface_t* p_msc = get_itf(dev_addr);
+ TU_VERIFY(p_msc->configured);
msc_cbw_t cbw;
cbw_init(&cbw, lun);
@@ -169,8 +164,8 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
}
-bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
-{
+bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response,
+ tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
msch_interface_t* p_msc = get_itf(dev_addr);
TU_VERIFY(p_msc->mounted);
@@ -181,18 +176,16 @@ bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* respons
cbw.dir = TUSB_DIR_IN_MASK;
cbw.cmd_len = sizeof(scsi_inquiry_t);
- scsi_inquiry_t const cmd_inquiry =
- {
- .cmd_code = SCSI_CMD_INQUIRY,
- .alloc_length = sizeof(scsi_inquiry_resp_t)
+ scsi_inquiry_t const cmd_inquiry = {
+ .cmd_code = SCSI_CMD_INQUIRY,
+ .alloc_length = sizeof(scsi_inquiry_resp_t)
};
memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len);
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
}
-bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
-{
+bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
msch_interface_t* p_msc = get_itf(dev_addr);
TU_VERIFY(p_msc->configured);
@@ -200,16 +193,16 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_
cbw_init(&cbw, lun);
cbw.total_bytes = 0;
- cbw.dir = TUSB_DIR_OUT;
- cbw.cmd_len = sizeof(scsi_test_unit_ready_t);
- cbw.command[0] = SCSI_CMD_TEST_UNIT_READY;
- cbw.command[1] = lun; // according to wiki TODO need verification
+ cbw.dir = TUSB_DIR_OUT;
+ cbw.cmd_len = sizeof(scsi_test_unit_ready_t);
+ cbw.command[0] = SCSI_CMD_TEST_UNIT_READY;
+ cbw.command[1] = lun; // according to wiki TODO need verification
return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg);
}
-bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
-{
+bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void* response,
+ tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
msc_cbw_t cbw;
cbw_init(&cbw, lun);
@@ -217,73 +210,64 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_ms
cbw.dir = TUSB_DIR_IN_MASK;
cbw.cmd_len = sizeof(scsi_request_sense_t);
- scsi_request_sense_t const cmd_request_sense =
- {
- .cmd_code = SCSI_CMD_REQUEST_SENSE,
- .alloc_length = 18
+ scsi_request_sense_t const cmd_request_sense = {
+ .cmd_code = SCSI_CMD_REQUEST_SENSE,
+ .alloc_length = 18
};
-
memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len);
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
}
-bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
-{
+bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void* buffer, uint32_t lba, uint16_t block_count,
+ tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
msch_interface_t* p_msc = get_itf(dev_addr);
TU_VERIFY(p_msc->mounted);
msc_cbw_t cbw;
cbw_init(&cbw, lun);
- cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
- cbw.dir = TUSB_DIR_IN_MASK;
- cbw.cmd_len = sizeof(scsi_read10_t);
+ cbw.total_bytes = block_count * p_msc->capacity[lun].block_size;
+ cbw.dir = TUSB_DIR_IN_MASK;
+ cbw.cmd_len = sizeof(scsi_read10_t);
- scsi_read10_t const cmd_read10 =
- {
- .cmd_code = SCSI_CMD_READ_10,
- .lba = tu_htonl(lba),
- .block_count = tu_htons(block_count)
+ scsi_read10_t const cmd_read10 = {
+ .cmd_code = SCSI_CMD_READ_10,
+ .lba = tu_htonl(lba),
+ .block_count = tu_htons(block_count)
};
-
memcpy(cbw.command, &cmd_read10, cbw.cmd_len);
return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg);
}
-bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
-{
+bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const* buffer, uint32_t lba, uint16_t block_count,
+ tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
msch_interface_t* p_msc = get_itf(dev_addr);
TU_VERIFY(p_msc->mounted);
msc_cbw_t cbw;
cbw_init(&cbw, lun);
- cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
+ cbw.total_bytes = block_count * p_msc->capacity[lun].block_size;
cbw.dir = TUSB_DIR_OUT;
cbw.cmd_len = sizeof(scsi_write10_t);
- scsi_write10_t const cmd_write10 =
- {
- .cmd_code = SCSI_CMD_WRITE_10,
- .lba = tu_htonl(lba),
- .block_count = tu_htons(block_count)
+ scsi_write10_t const cmd_write10 = {
+ .cmd_code = SCSI_CMD_WRITE_10,
+ .lba = tu_htonl(lba),
+ .block_count = tu_htons(block_count)
};
-
memcpy(cbw.command, &cmd_write10, cbw.cmd_len);
- return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb, arg);
+ return tuh_msc_scsi_command(dev_addr, &cbw, (void*) (uintptr_t) buffer, complete_cb, arg);
}
#if 0
// MSC interface Reset (not used now)
-bool tuh_msc_reset(uint8_t dev_addr)
-{
- tusb_control_request_t const new_request =
- {
- .bmRequestType_bit =
- {
+bool tuh_msc_reset(uint8_t dev_addr) {
+ tusb_control_request_t const new_request = {
+ .bmRequestType_bit = {
.recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_OUT
@@ -300,79 +284,71 @@ bool tuh_msc_reset(uint8_t dev_addr)
//--------------------------------------------------------------------+
// CLASS-USBH API
//--------------------------------------------------------------------+
-void msch_init(void)
-{
+void msch_init(void) {
tu_memclr(_msch_itf, sizeof(_msch_itf));
}
-void msch_close(uint8_t dev_addr)
-{
- TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
+void msch_close(uint8_t dev_addr) {
+ TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX,);
msch_interface_t* p_msc = get_itf(dev_addr);
- TU_VERIFY(p_msc->configured, );
+ TU_VERIFY(p_msc->configured,);
TU_LOG_DRV(" MSCh close addr = %d\r\n", dev_addr);
// invoke Application Callback
if (p_msc->mounted) {
- if(tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr);
+ if (tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr);
}
tu_memclr(p_msc, sizeof(msch_interface_t));
}
-bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
-{
+bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
msch_interface_t* p_msc = get_itf(dev_addr);
msc_cbw_t const * cbw = &p_msc->cbw;
msc_csw_t * csw = &p_msc->csw;
- switch (p_msc->stage)
- {
+ switch (p_msc->stage) {
case MSC_STAGE_CMD:
// Must be Command Block
- TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t));
+ TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t));
- if ( cbw->total_bytes && p_msc->buffer )
- {
+ if (cbw->total_bytes && p_msc->buffer) {
// Data stage if any
p_msc->stage = MSC_STAGE_DATA;
-
uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out;
TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes));
- }else
- {
+ } else {
// Status stage
p_msc->stage = MSC_STAGE_STATUS;
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
}
- break;
+ break;
case MSC_STAGE_DATA:
// Status stage
p_msc->stage = MSC_STAGE_STATUS;
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
- break;
+ break;
case MSC_STAGE_STATUS:
// SCSI op is complete
p_msc->stage = MSC_STAGE_IDLE;
- if (p_msc->complete_cb)
- {
- tuh_msc_complete_data_t const cb_data =
- {
- .cbw = cbw,
- .csw = csw,
- .scsi_data = p_msc->buffer,
- .user_arg = p_msc->complete_arg
+ if (p_msc->complete_cb) {
+ tuh_msc_complete_data_t const cb_data = {
+ .cbw = cbw,
+ .csw = csw,
+ .scsi_data = p_msc->buffer,
+ .user_arg = p_msc->complete_arg
};
p_msc->complete_cb(dev_addr, &cb_data);
}
- break;
+ break;
- // unknown state
- default: break;
+ // unknown state
+ default:
+ break;
}
return true;
@@ -381,39 +357,35 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
//--------------------------------------------------------------------+
// MSC Enumeration
//--------------------------------------------------------------------+
-
-static void config_get_maxlun_complete (tuh_xfer_t* xfer);
-static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data);
+static void config_get_maxlun_complete(tuh_xfer_t* xfer);
+static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
-bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
-{
+bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* desc_itf, uint16_t max_len) {
(void) rhport;
TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
- MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
+ MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
// msc driver length is fixed
- uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
+ uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) +
+ desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(drv_len <= max_len);
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);
+ 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++)
- {
+ 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(tuh_edpt_open(dev_addr, ep_desc));
- if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
- {
+ if (TUSB_DIR_IN == tu_edpt_dir(ep_desc->bEndpointAddress)) {
p_msc->ep_in = ep_desc->bEndpointAddress;
- }else
- {
+ } else {
p_msc->ep_out = ep_desc->bEndpointAddress;
}
- ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc);
+ ep_desc = (tusb_desc_endpoint_t const*) tu_desc_next(ep_desc);
}
p_msc->itf_num = desc_itf->bInterfaceNumber;
@@ -430,32 +402,31 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) {
//------------- Get Max Lun -------------//
TU_LOG_DRV("MSC Get Max Lun\r\n");
tusb_control_request_t const request = {
- .bmRequestType_bit = {
- .recipient = TUSB_REQ_RCPT_INTERFACE,
- .type = TUSB_REQ_TYPE_CLASS,
- .direction = TUSB_DIR_IN
- },
- .bRequest = MSC_REQ_GET_MAX_LUN,
- .wValue = 0,
- .wIndex = itf_num,
- .wLength = 1
+ .bmRequestType_bit = {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_CLASS,
+ .direction = TUSB_DIR_IN
+ },
+ .bRequest = MSC_REQ_GET_MAX_LUN,
+ .wValue = 0,
+ .wIndex = itf_num,
+ .wLength = 1
};
tuh_xfer_t xfer = {
- .daddr = dev_addr,
- .ep_addr = 0,
- .setup = &request,
- .buffer = _msch_buffer,
- .complete_cb = config_get_maxlun_complete,
- .user_data = 0
+ .daddr = dev_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = _msch_buffer,
+ .complete_cb = config_get_maxlun_complete,
+ .user_data = 0
};
TU_ASSERT(tuh_control_xfer(&xfer));
return true;
}
-static void config_get_maxlun_complete (tuh_xfer_t* xfer)
-{
+static void config_get_maxlun_complete(tuh_xfer_t* xfer) {
uint8_t const daddr = xfer->daddr;
msch_interface_t* p_msc = get_itf(daddr);
@@ -471,18 +442,16 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer)
tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0);
}
-static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
-{
+static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
msc_cbw_t const* cbw = cb_data->cbw;
msc_csw_t const* csw = cb_data->csw;
- if (csw->status == 0)
- {
+ if (csw->status == 0) {
// Unit is ready, read its capacity
TU_LOG_DRV("SCSI Read Capacity\r\n");
- tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0);
- }else
- {
+ tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer),
+ config_read_capacity_complete, 0);
+ } else {
// Note: During enumeration, some device fails Test Unit Ready and require a few retries
// with Request Sense to start working !!
// TODO limit number of retries
@@ -493,8 +462,7 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_d
return true;
}
-static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
-{
+static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
msc_cbw_t const* cbw = cb_data->cbw;
msc_csw_t const* csw = cb_data->csw;
@@ -503,8 +471,7 @@ static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_dat
return true;
}
-static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
-{
+static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
msc_cbw_t const* cbw = cb_data->cbw;
msc_csw_t const* csw = cb_data->csw;
diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h
index 6c0e5c9dd..9ca1b4703 100644
--- a/src/class/msc/msc_host.h
+++ b/src/class/msc/msc_host.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_MSC_HOST_H_
-#define _TUSB_MSC_HOST_H_
+#ifndef TUSB_MSC_HOST_H_
+#define TUSB_MSC_HOST_H_
#include "msc.h"
@@ -73,7 +73,7 @@ uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun);
// Perform a full SCSI command (cbw, data, csw) in non-blocking manner.
// Complete callback is invoked when SCSI op is complete.
// return true if success, false if there is already pending operation.
-bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
+bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
// Perform SCSI Inquiry command
// Complete callback is invoked when SCSI op is complete.
@@ -123,4 +123,4 @@ bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, ui
}
#endif
-#endif /* _TUSB_MSC_HOST_H_ */
+#endif