summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2021-07-17 12:10:35 +0200
committerGitHub <[email protected]>2021-07-17 12:10:35 +0200
commitb194aa240bba9211e01dd9eaf4562e00a7215666 (patch)
treeb9ef8962f6fdac517e7fc8575526f6cdec8467c1 /src
parent475742984f4d0f2b95c9c78dfff71814117feb90 (diff)
parent21bfd11683c4bb6e0996130bd1061a97d3049121 (diff)
Merge branch 'master' into dcd_same70
Diffstat (limited to 'src')
-rw-r--r--src/class/audio/audio.h29
-rw-r--r--src/class/audio/audio_device.c392
-rw-r--r--src/class/cdc/cdc_device.c10
-rw-r--r--src/class/cdc/cdc_host.c62
-rw-r--r--src/class/cdc/cdc_host.h10
-rw-r--r--src/class/dfu/dfu_device.c4
-rw-r--r--src/class/hid/hid_device.c28
-rw-r--r--src/class/hid/hid_host.c75
-rw-r--r--src/class/hid/hid_host.h17
-rw-r--r--src/class/midi/midi_device.c36
-rw-r--r--src/class/msc/msc_device.c20
-rw-r--r--src/class/msc/msc_host.c13
-rw-r--r--src/class/msc/msc_host.h20
-rw-r--r--src/common/tusb_common.h24
-rw-r--r--src/common/tusb_compiler.h16
-rw-r--r--src/common/tusb_fifo.c4
-rw-r--r--src/common/tusb_fifo.h4
-rw-r--r--src/common/tusb_verify.h2
-rw-r--r--src/device/usbd.c5
-rw-r--r--src/device/usbd.h5
-rw-r--r--src/device/usbd_control.c1
-rw-r--r--src/host/hub.c31
-rw-r--r--src/host/hub.h10
-rw-r--r--src/host/usbh.c86
-rw-r--r--src/host/usbh_classdriver.h10
-rw-r--r--src/host/usbh_control.c6
-rw-r--r--src/portable/microchip/samd/dcd_samd.c4
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c61
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c128
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c246
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c393
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h63
-rw-r--r--src/portable/renesas/usba/dcd_usba.c37
-rw-r--r--src/tusb_option.h6
34 files changed, 1001 insertions, 857 deletions
diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h
index 936f09104..f99061eae 100644
--- a/src/class/audio/audio.h
+++ b/src/class/audio/audio.h
@@ -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
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 8e4420ed0..404d28817 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -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)
+ uint8_t itf = TU_U16_LOW(p_request->wIndex);
+ uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+ if (entityID != 0)
{
- // Check if entity is present and get corresponding driver index
- TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+ 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);
+ // 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
+ break;
+
+ case TUSB_REQ_RCPT_ENDPOINT:
{
- if (tud_audio_set_req_itf_cb)
+ uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+ if (tud_audio_set_req_ep_cb)
{
- // Find index of audio driver structure and verify interface really exists
- TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+ // 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_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+ return tud_audio_set_req_ep_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
+ 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;
-
- 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)
- {
- // 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
- }
-
// Unknown/Unsupported recipient
default: TU_BREAKPOINT(); return false;
}
@@ -1754,73 +1773,75 @@ 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);
+ 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
+ }
+ 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)
{
- TU_LOG2(" No entity 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
+ }
}
}
}
- else
+ break;
+
+ case TUSB_REQ_RCPT_ENDPOINT:
{
- // Find index of audio driver structure and verify interface really exists
- TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+ 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)
{
- if (tud_audio_get_req_itf_cb)
+ if (tud_audio_get_req_ep_cb)
{
- return tud_audio_get_req_itf_cb(rhport, p_request);
+ return tud_audio_get_req_ep_cb(rhport, p_request);
}
else
{
- TU_LOG2(" No interface get request callback available!\r\n");
- return false; // Stall
+ TU_LOG2(" No EP 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)
- {
- 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;
-
// Unknown/Unsupported recipient
default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
}
@@ -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)
- {
- // Find index of audio driver structure and verify entity really exists
- TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
- }
- else
+ case TUSB_REQ_RCPT_INTERFACE:
{
- // 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
-
- uint8_t ep = TU_U16_LOW(p_request->wIndex);
+ case TUSB_REQ_RCPT_ENDPOINT:
+ {
+ 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))
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index a926081cc..68080c61d 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -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);
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 33f1a8ad3..fc7100e81 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -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;
-
- p_desc = tu_desc_next(itf_desc);
- p_cdc = get_itf(dev_addr);
+ cdch_data_t * 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)
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
index 6ff392709..edcd258a8 100644
--- a/src/class/cdc/cdc_host.h
+++ b/src/class/cdc/cdc_host.h
@@ -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
}
diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c
index 81045ff7b..c696d70a2 100644
--- a/src/class/dfu/dfu_device.c
+++ b/src/class/dfu/dfu_device.c
@@ -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;
}
diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c
index e44f282c4..a10e3a5e3 100644
--- a/src/class/hid/hid_device.c
+++ b/src/class/hid/hid_device.c
@@ -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;
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index cde5e23a5..40b6f5631 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -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)
{
diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h
index 2e4cce600..ef203123d 100644
--- a/src/class/hid/hid_host.h
+++ b/src/class/hid/hid_host.h
@@ -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
}
diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c
index 953ca26e6..c39e03976 100644
--- a/src/class/midi/midi_device.c
+++ b/src/class/midi/midi_device.c
@@ -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);
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index 7f13b4891..014e8b69e 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -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
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
index 7f98ef9b1..2c027deff 100644
--- a/src/class/msc/msc_host.c
+++ b/src/class/msc/msc_host.c
@@ -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)
diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h
index ce4fe64dc..9e4217ba5 100644
--- a/src/class/msc/msc_host.h
+++ b/src/class/msc/msc_host.h
@@ -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_ */
-
-/// @}
-/// @}
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index 889ad7b25..c8a66a879 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -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(...)
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
index 679060b20..0dd9ba016 100644
--- a/src/common/tusb_compiler.h
+++ b/src/common/tusb_compiler.h
@@ -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)))
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
index 1eb886aa1..73217cf75 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -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;
}
diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h
index cf299269d..18db289a1 100644
--- a/src/common/tusb_fifo.h
+++ b/src/common/tusb_fifo.h
@@ -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);
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index 542809899..56ba8bcd1 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -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)
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 2935defd0..af4fd58c4 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -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;
}
diff --git a/src/device/usbd.h b/src/device/usbd.h
index 0a0f0bf00..2de6a5cfd 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -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
diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c
index 724c652e6..7a8244699 100644
--- a/src/device/usbd_control.c
+++ b/src/device/usbd_control.c
@@ -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;
diff --git a/src/host/hub.c b/src/host/hub.c
index b2761184d..2ead5bed1 100644
--- a/src/host/hub.c
+++ b/src/host/hub.c
@@ -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;
-
- (*p_length) = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
+ hub_data[dev_addr-1].ep_in = desc_ep->bEndpointAddress;
- return true;
+ return drv_len;
}
void hub_close(uint8_t dev_addr)
diff --git a/src/host/hub.h b/src/host/hub.h
index a5111b8e7..c9ffe4985 100644
--- a/src/host/hub.h
+++ b/src/host/hub.h
@@ -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
}
diff --git a/src/host/usbh.c b/src/host/usbh.c
index 59246a663..93621c42a 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -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) )
+ // TODO Do we need to use IAD
+ // tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL;
+
+ // Class will always starts with Interface Association (if any) and then Interface descriptor
+ if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
{
- p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length
- }else
+ // desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc;
+ p_desc = tu_desc_next(p_desc);
+ }
+
+ 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++)
{
- tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
+ if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
+ }
- // 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;
- }
+ 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];
- if( drv_id >= USBH_CLASS_DRIVER_COUNT )
+ // 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];
-
- // 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;
+ TU_LOG2("%s open\r\n", driver->name);
- 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;
}
}
}
diff --git a/src/host/usbh_classdriver.h b/src/host/usbh_classdriver.h
index 07480fe8e..0736fefa1 100644
--- a/src/host/usbh_classdriver.h
+++ b/src/host/usbh_classdriver.h
@@ -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
diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c
index 4dbf8592a..0bdb66fb5 100644
--- a/src/host/usbh_control.c
+++ b/src/host/usbh_control.c
@@ -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);
}
diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c
index 13e56453d..577bd0e05 100644
--- a/src/portable/microchip/samd/dcd_samd.c
+++ b/src/portable/microchip/samd/dcd_samd.c
@@ -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)
{
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 977ec6cdb..5f4fe08ad 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -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;
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index 0048270a6..f78a932f1 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -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;
+ }
+
+ ep->hw_data_buf = next_buffer_ptr;
+ next_buffer_ptr += size;
+
+ 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);
- 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]);
+ 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 reg = EP_CTRL_ENABLE_BITS
- | EP_CTRL_INTERRUPT_PER_BUFFER
- | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
- | dpram_offset;
+ // 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;
+ *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)
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index b575c6afc..40a0805c6 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -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_TRANS_COMPLETE_BITS)
- {
- handled |= USB_INTS_TRANS_COMPLETE_BITS;
- usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS;
- hw_trans_complete();
- }
-
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_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,42 +508,34 @@ 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;
- usb_hw->sie_ctrl = flags;
- return true;
-}
+ 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);
-uint32_t hcd_frame_number(uint8_t rhport)
-{
- return usb_hw->sof_rd;
-}
+ usb_hw->sie_ctrl = flags;
-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)
//{
// // EPX is shared, so multiple device addresses and endpoint addresses share that
@@ -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;
}
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index 31381e6c2..dc12e6d82 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -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)
- {
- // 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;
- }
+ uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL;
- // PID
- val |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
+ // PID
+ buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
+ ep->next_pid ^= 1u;
-#if TUSB_OPT_DEVICE_ENABLED
- 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;
-#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;
- }else
- {
- uint32_t packet_count = 1 + ((ep->transfer_size - 1) / ep->wMaxPacketSize);
-
- if ( packet_count & 0x01 )
- {
- ep->next_pid ^= 1u;
- }
- }
-#endif
+ // 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 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
+ if (buf_id) buf_ctrl = buf_ctrl << 16;
- // 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);
+ return buf_ctrl;
}
-
-void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
+// Prepare buffer control register value
+static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
{
- _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)]);
+ uint32_t ep_ctrl = *ep->endpoint_control;
- hw_endpoint_reset_transfer(ep);
- }
+ // always compute and start with buffer 0
+ uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL;
- // Fill in info now that we're kicking off the hw
- ep->total_len = total_len;
- ep->len = 0;
+ // 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);
- // 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));
+ 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)
- 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
+ buf_ctrl |= prepare_ep_buffer(ep, 1);
- _hw_endpoint_start_next_buffer(ep);
- _hw_endpoint_lock_update(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_sync(struct hw_endpoint *ep)
+void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
{
- // Update hw endpoint struct with info from hardware
- // after a buff status interrupt
+ _hw_endpoint_lock_update(ep, 1);
- uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
+ 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)]);
-#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;
+ hw_endpoint_reset_transfer(ep);
+ }
- // 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
+ // 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;
- // Get tranferred bytes after adjusted buf sel
- uint16_t const transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
+ uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
- // We are continuing a transfer here. If we are TX, we have successfullly
+ 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
- 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;
- }
+ assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
- // 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;
- }
+ 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;
}
-// Returns true if transfer is complete
-bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep)
+static void _hw_endpoint_xfer_sync (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);
- }
+ // Update hw endpoint struct with info from hardware
+ // after a buff status interrupt
- // 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
+ uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
+ TU_LOG(3, "_hw_endpoint_xfer_sync:\r\n");
+ print_bufctrl32(buf_ctrl);
- // Can happen because of programmer error so check for it
- if (ep->len > ep->total_len)
- {
- panic("Transferred more data than expected");
- }
+ // always sync buffer 0
+ uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
- // If we are done then notify tinyusb
- if (ep->len == ep->total_len)
+ // sync buffer 1 if double buffered
+ if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS )
+ {
+ if (buf0_bytes == ep->wMaxPacketSize)
{
- 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
+ // sync buffer 1 if not short packet
+ sync_ep_buffer(ep, 1);
+ }else
{
- _hw_endpoint_start_next_buffer(ep);
- }
+ // 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);
- _hw_endpoint_lock_update(ep, -1);
- // More work to do
- return false;
+ // 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
+ }
+ }
}
-void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start)
+// Returns true if transfer is complete
+bool hw_endpoint_xfer_continue(struct hw_endpoint *ep)
{
- // 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);
+ _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);
+ }
- assert(ep->configured);
+ // 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);
+ return true;
+ }
+ else
+ {
+ _hw_endpoint_start_next_buffer(ep);
+ }
- 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
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index 33f3ecd41..514152cd9 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -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
diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c
index 06ea1a3f9..338d5b0e6 100644
--- a/src/portable/renesas/usba/dcd_usba.c
+++ b/src/portable/renesas/usba/dcd_usba.c
@@ -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;
}
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 9b0ea4358..13d11fdfe 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -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 -------------//