summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMengsk <[email protected]>2022-11-07 12:47:41 +0100
committerMengsk <[email protected]>2022-11-07 12:47:41 +0100
commit9d3d8fd5b0788b811ad283d10d37dfd1b1005224 (patch)
treef66b39fe968cc1a6e46e3074bbda9b907064bc15 /src
parent1eae139aa94130a63ecc4725852cb69c02566c82 (diff)
parente434a1dc0584e841da1ae4ff525bbe81a0f5514b (diff)
Merge branch 'master' of https://github.com/hathach/tinyusb into bsp_412
Diffstat (limited to 'src')
-rw-r--r--src/class/audio/audio_device.c317
-rw-r--r--src/class/audio/audio_device.h82
-rwxr-xr-xsrc/class/bth/bth_device.c8
-rw-r--r--src/class/cdc/cdc_device.c22
-rw-r--r--src/class/cdc/cdc_host.c35
-rw-r--r--src/class/cdc/cdc_host.h6
-rw-r--r--src/class/cdc/cdc_rndis_host.c12
-rw-r--r--src/class/cdc/cdc_rndis_host.h2
-rw-r--r--src/class/dfu/dfu_device.c4
-rw-r--r--src/class/dfu/dfu_rt_device.c2
-rw-r--r--src/class/hid/hid.h9
-rw-r--r--src/class/hid/hid_device.c22
-rw-r--r--src/class/hid/hid_device.h72
-rw-r--r--src/class/hid/hid_host.c316
-rw-r--r--src/class/midi/midi_device.c18
-rw-r--r--src/class/msc/msc_device.c97
-rw-r--r--src/class/msc/msc_device.h3
-rw-r--r--src/class/msc/msc_host.c44
-rw-r--r--src/class/net/ecm_rndis_device.c18
-rw-r--r--src/class/net/ncm_device.c11
-rw-r--r--src/class/usbtmc/usbtmc.h5
-rw-r--r--src/class/usbtmc/usbtmc_device.c102
-rw-r--r--src/class/usbtmc/usbtmc_device.h4
-rw-r--r--src/class/vendor/vendor_device.c39
-rw-r--r--src/class/vendor/vendor_device.h9
-rw-r--r--src/class/vendor/vendor_host.c2
-rw-r--r--src/class/vendor/vendor_host.h12
-rw-r--r--src/class/video/video.h79
-rw-r--r--src/class/video/video_device.c221
-rw-r--r--src/common/tusb_common.h164
-rw-r--r--src/common/tusb_compiler.h26
-rw-r--r--src/common/tusb_debug.h178
-rw-r--r--src/common/tusb_error.h75
-rw-r--r--src/common/tusb_fifo.c37
-rw-r--r--src/common/tusb_mcu.h299
-rw-r--r--src/common/tusb_private.h65
-rw-r--r--src/common/tusb_types.h39
-rw-r--r--src/common/tusb_verify.h55
-rw-r--r--src/device/dcd.h57
-rw-r--r--src/device/dcd_attr.h208
-rw-r--r--src/device/usbd.c306
-rw-r--r--src/device/usbd.h26
-rw-r--r--src/device/usbd_control.c6
-rw-r--r--src/device/usbd_pvt.h10
-rw-r--r--src/host/hcd.h84
-rw-r--r--src/host/hcd_attr.h105
-rw-r--r--src/host/hub.c244
-rw-r--r--src/host/hub.h33
-rw-r--r--src/host/usbh.c1617
-rw-r--r--src/host/usbh.h198
-rw-r--r--src/host/usbh_classdriver.h16
-rw-r--r--src/host/usbh_control.c138
-rw-r--r--src/osal/osal.h56
-rw-r--r--src/osal/osal_freertos.h51
-rw-r--r--src/osal/osal_mynewt.h24
-rw-r--r--src/osal/osal_none.h71
-rw-r--r--src/osal/osal_pico.h51
-rw-r--r--src/osal/osal_rtthread.h40
-rw-r--r--src/osal/osal_rtx4.h170
-rw-r--r--src/portable/bridgetek/ft9xx/dcd_ft9xx.c1117
-rw-r--r--src/portable/broadcom/synopsys/dcd_synopsys.c1267
-rw-r--r--src/portable/broadcom/synopsys/synopsys_common.h1476
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_imxrt.h58
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h45
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_type.h144
-rw-r--r--src/portable/chipidea/ci_hs/dcd_ci_hs.c644
-rw-r--r--src/portable/chipidea/ci_hs/hcd_ci_hs.c94
-rw-r--r--src/portable/dialog/da146xx/dcd_da146xx.c27
-rw-r--r--src/portable/ehci/ehci.c58
-rw-r--r--src/portable/ehci/ehci.h4
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c27
-rw-r--r--src/portable/mentor/musb/dcd_musb.c25
-rw-r--r--src/portable/mentor/musb/hcd_musb.c881
-rw-r--r--src/portable/microchip/pic/dcd_pic.c786
-rw-r--r--src/portable/microchip/pic32mz/dcd_pic32mz.c753
-rw-r--r--src/portable/microchip/pic32mz/usbhs_registers.h931
-rw-r--r--src/portable/microchip/samd/dcd_samd.c29
-rw-r--r--src/portable/microchip/samg/dcd_samg.c8
-rw-r--r--src/portable/microchip/samx7x/dcd_samx7x.c10
-rw-r--r--src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c10
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c191
-rw-r--r--src/portable/nuvoton/nuc120/dcd_nuc120.c10
-rw-r--r--src/portable/nuvoton/nuc121/dcd_nuc121.c10
-rw-r--r--src/portable/nuvoton/nuc505/dcd_nuc505.c10
-rw-r--r--src/portable/nxp/khci/dcd_khci.c10
-rw-r--r--src/portable/nxp/khci/hcd_khci.c626
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.c10
-rw-r--r--src/portable/nxp/lpc17_40/hcd_lpc17_40.c2
-rw-r--r--src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c117
-rw-r--r--src/portable/nxp/transdimension/dcd_transdimension.c24
-rw-r--r--src/portable/nxp/transdimension/hcd_transdimension.c10
-rw-r--r--src/portable/ohci/ohci.c15
-rw-r--r--src/portable/ohci/ohci.h9
-rw-r--r--src/portable/raspberrypi/pio_usb/dcd_pio_usb.c210
-rw-r--r--src/portable/raspberrypi/pio_usb/hcd_pio_usb.c225
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c94
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c271
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c32
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h23
-rw-r--r--src/portable/renesas/usba/dcd_usba.c18
-rw-r--r--src/portable/renesas/usba/hcd_usba.c875
-rw-r--r--src/portable/sony/cxd56/dcd_cxd56.c15
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c20
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h7
-rw-r--r--src/portable/st/synopsys/dcd_synopsys.c9
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c1219
-rw-r--r--src/portable/sunxi/musb_def.h643
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c134
-rw-r--r--src/portable/synopsys/dwc2/dwc2_bcm.h16
-rw-r--r--src/portable/synopsys/dwc2/dwc2_efm32.h12
-rw-r--r--src/portable/synopsys/dwc2/dwc2_esp32.h8
-rw-r--r--src/portable/synopsys/dwc2/dwc2_gd32.h13
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h59
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h25
-rw-r--r--src/portable/synopsys/dwc2/dwc2_xmc.h15
-rw-r--r--src/portable/template/dcd_template.c8
-rw-r--r--src/portable/ti/msp430x5xx/dcd_msp430x5xx.c23
-rw-r--r--src/portable/valentyusb/eptri/dcd_eptri.c15
-rw-r--r--src/tusb.c89
-rw-r--r--src/tusb.h10
-rw-r--r--src/tusb_option.h163
121 files changed, 14125 insertions, 5586 deletions
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index d9f2e284e..698fba566 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -50,7 +50,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO)
+#if (CFG_TUD_ENABLED && CFG_TUD_AUDIO)
//--------------------------------------------------------------------+
// INCLUDE
@@ -66,7 +66,7 @@
// Use ring buffer if it's available, some MCUs need extra RAM requirements
#ifndef TUD_AUDIO_PREFER_RING_BUFFER
-#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT
#define TUD_AUDIO_PREFER_RING_BUFFER 0
#else
#define TUD_AUDIO_PREFER_RING_BUFFER 1
@@ -102,7 +102,7 @@
CFG_TUSB_MCU == OPT_MCU_GD32VF103 || \
CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
CFG_TUSB_MCU == OPT_MCU_LPC43XX || \
- CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
+ CFG_TUSB_MCU == OPT_MCU_MIMXRT || \
CFG_TUSB_MCU == OPT_MCU_MSP432E4
#if TUD_AUDIO_PREFER_RING_BUFFER
#define USE_LINEAR_BUFFER 0
@@ -305,9 +305,35 @@ typedef struct
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format).
-#endif
+ struct {
+ uint32_t value; // Feedback value for asynchronous mode (in 16.16 format).
+ uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1.
+ uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1.
+
+ uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS)
+ uint8_t compute_method;
+
+ union {
+ uint8_t power_of_2; // pre-computed power of 2 shift
+ float float_const; // pre-computed float constant
+
+ struct {
+ uint32_t sample_freq;
+ uint32_t mclk_freq;
+ }fixed;
+
+#if 0 // implement later
+ struct {
+ uint32_t nominal_value;
+ uint32_t threshold_bytes;
+ }fifo_count;
#endif
+ }compute;
+
+ } feedback;
+#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_t ep_in_ff;
@@ -315,7 +341,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_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
+ 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
@@ -421,6 +447,10 @@ static inline uint8_t tu_desc_subtype(void const* desc)
}
#endif
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq);
+#endif
+
bool tud_audio_n_mounted(uint8_t func_id)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO);
@@ -511,7 +541,7 @@ tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
{
- uint8_t idxItf;
+ uint8_t idxItf = 0;
uint8_t const *dummy2;
uint8_t idx_audio_fct = 0;
@@ -522,7 +552,10 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
}
// Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO)
- if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
+ if (tud_audio_rx_done_pre_read_cb)
+ {
+ TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
+ }
#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -536,7 +569,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
case AUDIO_FORMAT_TYPE_I:
- switch (audio->format_type_I_tx)
+ switch (audio->format_type_I_rx)
{
case AUDIO_DATA_FORMAT_TYPE_I_PCM:
TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received));
@@ -576,7 +609,10 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
#endif
// Call a weak callback here - a possibility for user to get informed decoding was completed
- if (tud_audio_rx_done_post_read_cb) TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
+ if (tud_audio_rx_done_post_read_cb)
+ {
+ TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
+ }
return true;
}
@@ -1039,7 +1075,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio)
{
- return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->fb_val, 4);
+ return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4);
}
#endif
@@ -1510,7 +1546,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
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));
@@ -1543,7 +1579,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// Close corresponding feedback EP
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
usbd_edpt_close(rhport, audio->ep_fb);
- audio->ep_fb = 0; // Necessary?
+ audio->ep_fb = 0;
+ tu_memclr(&audio->feedback, sizeof(audio->feedback));
#endif
}
#endif
@@ -1592,7 +1629,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
- const uint16_t active_fifo_depth = (audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx;
+ const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx);
for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
{
tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
@@ -1602,8 +1639,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
#endif
#endif
- // Invoke callback - can be used to trigger data sampling if not already running
- if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
// Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded
// It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there
@@ -1635,16 +1670,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
#endif
#endif
-#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- // In case of asynchronous EP, call Cb after ep_fb is set
- if ( !(desc_ep->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);
@@ -1657,12 +1682,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback
{
audio->ep_fb = ep_addr;
+ audio->feedback.frame_shift = desc_ep->bInterval -1;
- // 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));
- }
+ // Enable SOF interrupt if callback is implemented
+ if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true);
}
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -1674,6 +1697,49 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
TU_VERIFY(foundEPs == nEps);
+ // Invoke one callback for a final set interface
+ if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ // Prepare feedback computation if callback is available
+ if (tud_audio_feedback_params_cb)
+ {
+ audio_feedback_params_t fb_param;
+
+ tud_audio_feedback_params_cb(func_id, alt, &fb_param);
+ audio->feedback.compute_method = fb_param.method;
+
+ // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame)
+ uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000;
+ audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16;
+ audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16;
+
+ switch(fb_param.method)
+ {
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
+ set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq);
+ break;
+
+ #if 0 // implement later
+ case AUDIO_FEEDBACK_METHOD_FIFO_COUNT:
+ {
+ uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16;
+ audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div);
+ audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes;
+
+ tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value);
+ }
+ break;
+ #endif
+
+ // nothing to do
+ default: break;
+ }
+ }
+#endif
+
// We are done - abort loop
break;
}
@@ -1682,6 +1748,20 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
p_desc = tu_desc_next(p_desc);
}
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ // Disable SOF interrupt if no driver has any enabled feedback EP
+ bool disable = true;
+ for(uint8_t i=0; i < CFG_TUD_AUDIO; i++)
+ {
+ if (_audiod_fct[i].ep_fb != 0)
+ {
+ disable = false;
+ break;
+ }
+ }
+ if (disable) usbd_sof_enable(rhport, false);
+#endif
+
tud_control_status(rhport, p_request);
return true;
@@ -1898,14 +1978,14 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
(void) xferred_bytes;
// Search for interface belonging to given end point address and proceed as required
- uint8_t func_id;
- for (func_id = 0; func_id < CFG_TUD_AUDIO; func_id++)
+ for (uint8_t func_id = 0; func_id < CFG_TUD_AUDIO; func_id++)
{
+ audiod_function_t* audio = &_audiod_fct[func_id];
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
// Data transmission of control interrupt finished
- if (_audiod_fct[func_id].ep_int_ctr == ep_addr)
+ if (audio->ep_int_ctr == ep_addr)
{
// According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49)
// In case there is nothing to send we have to return a NAK - this is taken care of by PHY ???
@@ -1922,7 +2002,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
#if CFG_TUD_AUDIO_ENABLE_EP_IN
// Data transmission of audio packet finished
- if (_audiod_fct[func_id].ep_in == ep_addr && _audiod_fct[func_id].alt_setting != 0)
+ if (audio->ep_in == ep_addr && audio->alt_setting != 0)
{
// USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified."
// That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available."
@@ -1933,7 +2013,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
// This is the only place where we can fill something into the EPs buffer!
// Load new data
- TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
+ TU_VERIFY(audiod_tx_done_cb(rhport, audio));
// Transmission of ZLP is done by audiod_tx_done_cb()
return true;
@@ -1943,24 +2023,24 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
// New audio packet received
- if (_audiod_fct[func_id].ep_out == ep_addr)
+ if (audio->ep_out == ep_addr)
{
- TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_fct[func_id], (uint16_t) xferred_bytes));
+ TU_VERIFY(audiod_rx_done_cb(rhport, audio, (uint16_t) xferred_bytes));
return true;
}
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
// Transmission of feedback EP finished
- if (_audiod_fct[func_id].ep_fb == ep_addr)
+ if (audio->ep_fb == ep_addr)
{
- if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
+ if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(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))
+ if (!usbd_edpt_busy(rhport, audio->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]);
+ return audiod_fb_send(rhport, audio);
}
}
#endif
@@ -1970,6 +2050,111 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
return false;
}
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+
+static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq)
+{
+ // Check if frame interval is within sane limits
+ // The interval value n_frames was taken from the descriptors within audiod_set_interface()
+
+ // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed
+ // this lower limit ensures the measures feedback value has sufficient precision
+ uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13;
+ uint32_t const n_frame = (1UL << audio->feedback.frame_shift);
+
+ if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame )
+ {
+ TU_LOG1(" UAC2 feedback interval too small\r\n"); TU_BREAKPOINT(); return false;
+ }
+
+ // Check if parameters really allow for a power of two division
+ if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq))
+ {
+ audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2;
+ audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq);
+ }
+ else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT)
+ {
+ audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift));
+ }
+ else
+ {
+ audio->feedback.compute.fixed.sample_freq = sample_freq;
+ audio->feedback.compute.fixed.mclk_freq = mclk_freq;
+ }
+
+ return true;
+}
+
+uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
+{
+ audiod_function_t* audio = &_audiod_fct[func_id];
+ uint32_t feedback;
+
+ switch (audio->feedback.compute_method)
+ {
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
+ feedback = (cycles << audio->feedback.compute.power_of_2);
+ break;
+
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
+ feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const);
+ break;
+
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
+ {
+ uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift);
+ feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq);
+ }
+ break;
+
+ default: return 0;
+ }
+
+ // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers
+ // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1.
+ // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot
+ // (audio slot = channel count samples).
+ if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value;
+ if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value;
+
+ tud_audio_n_fb_set(func_id, feedback);
+
+ return feedback;
+}
+#endif
+
+TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count)
+{
+ (void) rhport;
+ (void) frame_count;
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec
+ // Boiled down, the feedback value Ff = n_samples / (micro)frame.
+ // Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s)
+ // The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K)
+ // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames
+
+ // Iterate over audio functions and set feedback value
+ for(uint8_t i=0; i < CFG_TUD_AUDIO; i++)
+ {
+ audiod_function_t* audio = &_audiod_fct[i];
+
+ if (audio->ep_fb != 0)
+ {
+ // HS shift need to be adjusted since SOF event is generated for frame only
+ uint8_t const hs_adjust = (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0;
+ uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust);
+ if ( 0 == (frame_count & (interval-1)) )
+ {
+ if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift);
+ }
+ }
+ }
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+}
+
bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len)
{
// Handles only sending of data not receiving
@@ -2164,6 +2349,16 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id)
// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for!
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)
{
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
+ if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return; // Abort, this interface has no EP, this driver does not support this currently
+#endif
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
+ if (as_itf != audio->ep_in_as_intf_num) return;
+#endif
+#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
+ if (as_itf != audio->ep_out_as_intf_num) return;
+#endif
+
p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor
while (p_desc < p_desc_end)
@@ -2174,16 +2369,6 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
// Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels
if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL)
{
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently
-#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_in_as_intf_num) break;
-#endif
-#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_out_as_intf_num) break;
-#endif
-
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (as_itf == audio->ep_in_as_intf_num)
{
@@ -2247,24 +2432,28 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-// Input value feedback has to be in 16.16 format - the format will be converted according to speed settings automatically
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 !TUD_OPT_HIGH_SPEED
- uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION
+ if ( TUSB_SPEED_FULL == tud_speed_get() )
+ {
+ uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value;
- // 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;
+ // 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
#else
- // For HS format is 16.16 as originally demanded
- _audiod_fct[func_id].fb_val = feedback;
+ {
+ // Send value as-is, caller will choose the appropriate format
+ _audiod_fct[func_id].feedback.value = feedback;
+ }
#endif
// Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
@@ -2287,4 +2476,4 @@ uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio)
return 0;
}
-#endif //TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO
+#endif //CFG_TUD_ENABLED && CFG_TUD_AUDIO
diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h
index 5a469523c..0ef100fa4 100644
--- a/src/class/audio/audio_device.h
+++ b/src/class/audio/audio_device.h
@@ -186,6 +186,11 @@
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1
#endif
+// Enable/disable conversion from 16.16 to 10.14 format on full-speed devices. See tud_audio_n_fb_set().
+#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION
+#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1
+#endif
+
// Audio interrupt control EP size - disabled if 0
#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74)
@@ -453,14 +458,78 @@ TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_byte
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport);
-// User code should call this function with feedback value in 16.16 format for FS and HS.
-// Value will be corrected for FS to 10.14 format automatically.
-// (see Universal Serial Bus Specification Revision 2.0 5.12.4.2).
-// Feedback value will be sent at FB endpoint interval till it's changed.
+TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id);
+
+
+// determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 8 frames), i.e. a larger delay is introduced.
+
+// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter) - see tud_audio_set_fb_params(). Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller (e.g. 2 frames) and thus a smaller delay is possible, disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. This option is a great starting point to try the SOF ISR option but depending on your hardware setup (performance of the CPU) it might not work. If so, figure out why and use the next option. (The most critical point is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced).
+
+// Feedback value is determined by the user by use of SOF interrupt. The user may use tud_audio_sof_isr() which is called every SOF (of course only invoked when an alternate interface other than zero was set). The number of frames used to determine the feedback value for the currently active alternate setting can be get by tud_audio_get_fb_n_frames(). The feedback value must be set by use of tud_audio_n_fb_set().
+
+// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed.
+//
+// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). By default,
+// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb
+// expects 16.16 format and handles the conversion to 10.14 on FS.
+//
+// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the
+// driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format.
+
+// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value.
+
+// Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec
+// Boiled down, the feedback value Ff = n_samples / (micro)frame.
+// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s)
+// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K)
+// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames
+
bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback);
static inline bool tud_audio_fb_set(uint32_t feedback);
+
+// Update feedback value with passed cycles since last time this update function is called.
+// Typically called within tud_audio_sof_isr(). Required tud_audio_feedback_params_cb() is implemented
+// This function will also call tud_audio_feedback_set()
+// return feedback value in 16.16 for reference (0 for error)
+uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles);
+
+enum {
+ AUDIO_FEEDBACK_METHOD_DISABLED,
+ AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED,
+ AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT,
+ AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2,
+
+ // impelemnt later
+ // AUDIO_FEEDBACK_METHOD_FIFO_COUNT
+};
+
+typedef struct {
+ uint8_t method;
+ uint32_t sample_freq; // sample frequency in Hz
+
+ union {
+ struct {
+ uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to which sample clock is based on
+ }frequency;
+
+#if 0 // implement later
+ struct {
+ uint32_t threshold_bytes; // minimum number of bytes received to be considered as filled/ready
+ }fifo_count;
#endif
+ };
+}audio_feedback_params_t;
+
+// Invoked when needed to set feedback parameters
+TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param);
+
+// Callback in ISR context, invoked periodically according to feedback endpoint bInterval.
+// Could be used to compute and update feedback value, should be placed in RAM if possible
+// frame_number : current SOF count
+// interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor
+TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift);
+
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied);
@@ -602,10 +671,12 @@ static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t l
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+
static inline bool tud_audio_fb_set(uint32_t feedback)
{
return tud_audio_n_fb_set(0, feedback);
}
+
#endif
//--------------------------------------------------------------------+
@@ -616,6 +687,7 @@ void audiod_reset (uint8_t rhport);
uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
+void audiod_sof_isr (uint8_t rhport, uint32_t frame_count);
#ifdef __cplusplus
}
diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c
index 8ef609622..f96bb3552 100755
--- a/src/class/bth/bth_device.c
+++ b/src/class/bth/bth_device.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_BTH)
+#if (CFG_TUD_ENABLED && CFG_TUD_BTH)
//--------------------------------------------------------------------+
// INCLUDE
@@ -59,10 +59,12 @@ CFG_TUSB_MEM_SECTION btd_interface_t _btd_itf;
static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
{
+ uint8_t const rhport = 0;
+
// skip if previous transfer not complete
- TU_VERIFY(!usbd_edpt_busy(TUD_OPT_RHPORT, ep));
+ TU_VERIFY(!usbd_edpt_busy(rhport, ep));
- TU_ASSERT(usbd_edpt_xfer(TUD_OPT_RHPORT, ep, data, len));
+ TU_ASSERT(usbd_edpt_xfer(rhport, ep, data, len));
return true;
}
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index 74c116192..fab6f0035 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC)
+#if (CFG_TUD_ENABLED && CFG_TUD_CDC)
#include "device/usbd.h"
#include "device/usbd_pvt.h"
@@ -80,30 +80,32 @@ typedef struct
//--------------------------------------------------------------------+
CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
-static void _prep_out_transaction (cdcd_interface_t* p_cdc)
+static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
{
- uint8_t const rhport = TUD_OPT_RHPORT;
+ uint8_t const rhport = 0;
uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff);
// Prepare for incoming data but only allow what we can store in the ring buffer.
// TODO Actually we can still carry out the transfer, keeping count of received bytes
// and slowly move it to the FIFO when read().
// This pre-check reduces endpoint claiming
- TU_VERIFY(available >= sizeof(p_cdc->epout_buf), );
+ TU_VERIFY(available >= sizeof(p_cdc->epout_buf));
// claim endpoint
- TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out), );
+ TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out));
// fifo can be changed before endpoint is claimed
available = tu_fifo_remaining(&p_cdc->rx_ff);
if ( available >= sizeof(p_cdc->epout_buf) )
{
- usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf));
+ return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf));
}else
{
// Release endpoint since we don't make any transfer
usbd_edpt_release(rhport, p_cdc->ep_out);
+
+ return false;
}
}
@@ -143,7 +145,7 @@ uint32_t tud_cdc_n_available(uint8_t itf)
uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize)
{
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
- uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, bufsize);
+ uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) bufsize);
_prep_out_transaction(p_cdc);
return num_read;
}
@@ -166,7 +168,7 @@ void tud_cdc_n_read_flush (uint8_t itf)
uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
{
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
- uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, bufsize);
+ uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize);
// flush if queue more than packet size
if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE )
@@ -187,7 +189,7 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf)
// No data to send
if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0;
- uint8_t const rhport = TUD_OPT_RHPORT;
+ uint8_t const rhport = 0;
// Claim the endpoint
TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 );
@@ -433,7 +435,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Received new data
if ( ep_addr == p_cdc->ep_out )
{
- tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, xferred_bytes);
+ tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, (uint16_t) xferred_bytes);
// Check for wanted char and invoke callback if needed
if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) )
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index f4fb6c1d6..ee824cb4e 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_CDC)
+#if (CFG_TUH_ENABLED && CFG_TUH_CDC)
#include "host/usbh.h"
#include "host/usbh_classdriver.h"
@@ -100,29 +100,30 @@ bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool i
{
(void) is_notify;
TU_VERIFY( tuh_cdc_mounted(dev_addr) );
- TU_VERIFY( p_data != NULL && length, TUSB_ERROR_INVALID_PARA);
+ TU_VERIFY( p_data != NULL && length);
uint8_t const ep_out = cdch_data[dev_addr-1].ep_out;
if ( usbh_edpt_busy(dev_addr, ep_out) ) return false;
- return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, length);
+ return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length);
}
bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify)
{
(void) is_notify;
TU_VERIFY( tuh_cdc_mounted(dev_addr) );
- TU_VERIFY( p_buffer != NULL && length, TUSB_ERROR_INVALID_PARA);
+ TU_VERIFY( p_buffer != NULL && length );
uint8_t const ep_in = cdch_data[dev_addr-1].ep_in;
if ( usbh_edpt_busy(dev_addr, ep_in) ) return false;
- return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, length);
+ return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length);
}
-bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_complete_cb_t complete_cb)
+bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb)
{
cdch_data_t const * p_cdc = get_itf(dev_addr);
+
tusb_control_request_t const request =
{
.bmRequestType_bit =
@@ -132,13 +133,22 @@ bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_co
.direction = TUSB_DIR_OUT
},
.bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
- .wValue = (rts ? 2 : 0) | (dtr ? 1 : 0),
- .wIndex = p_cdc->itf_num,
+ .wValue = tu_htole16((uint16_t) ((dtr ? 1u : 0u) | (rts ? 2u : 0u))),
+ .wIndex = tu_htole16(p_cdc->itf_num),
.wLength = 0
};
- TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, complete_cb) );
- return true;
+ tuh_xfer_t xfer =
+ {
+ .daddr = dev_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = complete_cb,
+ .user_data = 0
+ };
+
+ return tuh_control_xfer(&xfer);
}
//--------------------------------------------------------------------+
@@ -151,6 +161,7 @@ void cdch_init(void)
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{
+ (void) rhport;
(void) max_len;
// Only support ACM subclass
@@ -186,7 +197,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
// notification endpoint
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
+ TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) );
p_cdc->ep_notif = desc_ep->bEndpointAddress;
drv_len += tu_desc_len(p_desc);
@@ -207,7 +218,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
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);
- TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
+ TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
{
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
index 0d435138b..33dbd2efb 100644
--- a/src/class/cdc/cdc_host.h
+++ b/src/class/cdc/cdc_host.h
@@ -42,14 +42,14 @@
* \defgroup CDC_Serial_Host Host
* @{ */
-bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_complete_cb_t complete_cb);
+bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb);
-static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_control_complete_cb_t complete_cb)
+static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb)
{
return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb);
}
-static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_control_complete_cb_t complete_cb)
+static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb)
{
return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb);
}
diff --git a/src/class/cdc/cdc_rndis_host.c b/src/class/cdc/cdc_rndis_host.c
index cc4ffd1cf..8f28f51ac 100644
--- a/src/class/cdc/cdc_rndis_host.c
+++ b/src/class/cdc/cdc_rndis_host.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_CDC && CFG_TUH_CDC_RNDIS)
+#if (CFG_TUH_ENABLED && CFG_TUH_CDC && CFG_TUH_CDC_RNDIS)
//--------------------------------------------------------------------+
// INCLUDE
@@ -35,6 +35,16 @@
#include "cdc_host.h"
#include "cdc_rndis_host.h"
+#if 0 // TODO remove subtask related macros later
+// Sub Task
+#define OSAL_SUBTASK_BEGIN
+#define OSAL_SUBTASK_END return TUSB_ERROR_NONE;
+
+#define STASK_RETURN(_error) return _error;
+#define STASK_INVOKE(_subtask, _status) (_status) = _subtask
+#define STASK_ASSERT(_cond) TU_VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED)
+#endif
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
diff --git a/src/class/cdc/cdc_rndis_host.h b/src/class/cdc/cdc_rndis_host.h
index 170cb3b0e..447cc4e97 100644
--- a/src/class/cdc/cdc_rndis_host.h
+++ b/src/class/cdc/cdc_rndis_host.h
@@ -50,7 +50,7 @@ typedef struct {
}rndish_data_t;
void rndish_init(void);
-tusb_error_t rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc);
+bool rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc);
void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes);
void rndish_close(uint8_t dev_addr);
diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c
index ddfa608e4..aa5891ca9 100644
--- a/src/class/dfu/dfu_device.c
+++ b/src/class/dfu/dfu_device.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_DFU)
+#if (CFG_TUD_ENABLED && CFG_TUD_DFU)
#include "device/usbd.h"
#include "device/usbd_pvt.h"
@@ -167,6 +167,8 @@ uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc,
uint8_t alt_count = 0;
uint16_t drv_len = 0;
+ TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU, 0);
+
while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU)
{
TU_ASSERT(max_len > drv_len, 0);
diff --git a/src/class/dfu/dfu_rt_device.c b/src/class/dfu/dfu_rt_device.c
index afee2aa1f..b9cd6096b 100644
--- a/src/class/dfu/dfu_rt_device.c
+++ b/src/class/dfu/dfu_rt_device.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_DFU_RUNTIME)
+#if (CFG_TUD_ENABLED && CFG_TUD_DFU_RUNTIME)
#include "device/usbd.h"
#include "device/usbd_pvt.h"
diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h
index 9265a2ede..44a464be1 100644
--- a/src/class/hid/hid.h
+++ b/src/class/hid/hid.h
@@ -43,7 +43,7 @@
/** \defgroup ClassDriver_HID_Common Common Definitions
* @{ */
- /// USB HID Descriptor
+/// USB HID Descriptor
typedef struct TU_ATTR_PACKED
{
uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */
@@ -645,7 +645,7 @@ enum {
#define HID_REPORT_SIZE_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, n)
#define HID_REPORT_ID(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, 1),
-#define HID_REPORT_ID_N(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, n),
+#define HID_REPORT_ID_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, n),
#define HID_REPORT_COUNT(x) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, 1)
#define HID_REPORT_COUNT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, n)
@@ -1106,7 +1106,10 @@ enum
{'8' , 0 }, /* 0x60 */ \
{'9' , 0 }, /* 0x61 */ \
{'0' , 0 }, /* 0x62 */ \
- {'0' , 0 }, /* 0x63 */ \
+ {'.' , 0 }, /* 0x63 */ \
+ {0 , 0 }, /* 0x64 */ \
+ {0 , 0 }, /* 0x65 */ \
+ {0 , 0 }, /* 0x66 */ \
{'=' , '=' }, /* 0x67 */ \
diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c
index 588b61254..8077e4deb 100644
--- a/src/class/hid/hid_device.c
+++ b/src/class/hid/hid_device.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_HID)
+#if (CFG_TUD_ENABLED && CFG_TUD_HID)
//--------------------------------------------------------------------+
// INCLUDE
@@ -76,11 +76,12 @@ static inline uint8_t get_index_by_itfnum(uint8_t itf_num)
//--------------------------------------------------------------------+
bool tud_hid_n_ready(uint8_t instance)
{
+ uint8_t const rhport = 0;
uint8_t const ep_in = _hidd_itf[instance].ep_in;
- return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(TUD_OPT_RHPORT, ep_in);
+ return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in);
}
-bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint8_t len)
+bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len)
{
uint8_t const rhport = 0;
hidd_interface_t * p_hid = &_hidd_itf[instance];
@@ -91,7 +92,7 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, u
// prepare data
if (report_id)
{
- len = tu_min8(len, CFG_TUD_HID_EP_BUFSIZE-1);
+ len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE-1);
p_hid->epin_buf[0] = report_id;
memcpy(p_hid->epin_buf+1, report, len);
@@ -99,11 +100,11 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, u
}else
{
// If report id = 0, skip ID field
- len = tu_min8(len, CFG_TUD_HID_EP_BUFSIZE);
+ len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE);
memcpy(p_hid->epin_buf, report, len);
}
- return usbd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->epin_buf, len);
+ return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len);
}
uint8_t tud_hid_n_interface_protocol(uint8_t instance)
@@ -172,7 +173,7 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
//--------------------------------------------------------------------+
void hidd_init(void)
{
- hidd_reset(TUD_OPT_RHPORT);
+ hidd_reset(0);
}
void hidd_reset(uint8_t rhport)
@@ -186,7 +187,8 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint1
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0);
// len = interface + hid + n*endpoints
- uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+ uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
+ desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(max_len >= drv_len, 0);
// Find available interface
@@ -401,13 +403,13 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
{
if (tud_hid_report_complete_cb)
{
- tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint8_t) xferred_bytes);
+ tud_hid_report_complete_cb(instance, p_hid->epin_buf, (/*uint16_t*/ uint8_t) xferred_bytes);
}
}
// Received report
else if (ep_addr == p_hid->ep_out)
{
- tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, xferred_bytes);
+ tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes);
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
}
diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h
index 7f67fa9cf..3143b1024 100644
--- a/src/class/hid/hid_device.h
+++ b/src/class/hid/hid_device.h
@@ -62,7 +62,7 @@ uint8_t tud_hid_n_interface_protocol(uint8_t instance);
uint8_t tud_hid_n_get_protocol(uint8_t instance);
// Send report to host
-bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint8_t len);
+bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len);
// KEYBOARD: convenient helper to send keyboard report if application
// use template layout report as defined by hid_keyboard_report_t
@@ -82,7 +82,7 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int
static inline bool tud_hid_ready(void);
static inline uint8_t tud_hid_interface_protocol(void);
static inline uint8_t tud_hid_get_protocol(void);
-static inline bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len);
+static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len);
static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
@@ -116,7 +116,7 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate);
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
-TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len);
+TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len );
//--------------------------------------------------------------------+
@@ -137,7 +137,7 @@ static inline uint8_t tud_hid_get_protocol(void)
return tud_hid_n_get_protocol(0);
}
-static inline bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len)
+static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len)
{
return tud_hid_n_report(0, report_id, report, len);
}
@@ -310,8 +310,8 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
HID_COLLECTION_END \
// Gamepad Report Descriptor Template
-// with 16 buttons, 2 joysticks and 1 hat/dpad with following layout
-// | X | Y | Z | Rz | Rx | Ry (1 byte each) | hat/DPAD (1 byte) | Button Map (2 bytes) |
+// with 32 buttons, 2 joysticks and 1 hat/dpad with following layout
+// | X | Y | Z | Rz | Rx | Ry (1 byte each) | hat/DPAD (1 byte) | Button Map (4 bytes) |
#define TUD_HID_REPORT_DESC_GAMEPAD(...) \
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\
@@ -319,37 +319,37 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
/* Report ID if any */\
__VA_ARGS__ \
/* 8 bit X, Y, Z, Rz, Rx, Ry (min -127, max 127 ) */ \
- HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
- HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
- HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
- HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\
- HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\
- HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\
- HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\
- HID_LOGICAL_MIN ( 0x81 ) ,\
- HID_LOGICAL_MAX ( 0x7f ) ,\
- HID_REPORT_COUNT ( 6 ) ,\
- HID_REPORT_SIZE ( 8 ) ,\
- HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
+ HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
+ HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
+ HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\
+ HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\
+ HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\
+ HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\
+ HID_LOGICAL_MIN ( 0x81 ) ,\
+ HID_LOGICAL_MAX ( 0x7f ) ,\
+ HID_REPORT_COUNT ( 6 ) ,\
+ HID_REPORT_SIZE ( 8 ) ,\
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
/* 8 bit DPad/Hat Button Map */ \
- HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
- HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\
- HID_LOGICAL_MIN ( 1 ) ,\
- HID_LOGICAL_MAX ( 8 ) ,\
- HID_PHYSICAL_MIN ( 0 ) ,\
- HID_PHYSICAL_MAX_N ( 315, 2 ) ,\
- HID_REPORT_COUNT ( 1 ) ,\
- HID_REPORT_SIZE ( 8 ) ,\
- HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
- /* 16 bit Button Map */ \
- HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
- HID_USAGE_MIN ( 1 ) ,\
- HID_USAGE_MAX ( 32 ) ,\
- HID_LOGICAL_MIN ( 0 ) ,\
- HID_LOGICAL_MAX ( 1 ) ,\
- HID_REPORT_COUNT ( 32 ) ,\
- HID_REPORT_SIZE ( 1 ) ,\
- HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
+ HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\
+ HID_LOGICAL_MIN ( 1 ) ,\
+ HID_LOGICAL_MAX ( 8 ) ,\
+ HID_PHYSICAL_MIN ( 0 ) ,\
+ HID_PHYSICAL_MAX_N ( 315, 2 ) ,\
+ HID_REPORT_COUNT ( 1 ) ,\
+ HID_REPORT_SIZE ( 8 ) ,\
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
+ /* 32 bit Button Map */ \
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
+ HID_USAGE_MIN ( 1 ) ,\
+ HID_USAGE_MAX ( 32 ) ,\
+ HID_LOGICAL_MIN ( 0 ) ,\
+ HID_LOGICAL_MAX ( 1 ) ,\
+ HID_REPORT_COUNT ( 32 ) ,\
+ HID_REPORT_SIZE ( 1 ) ,\
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
HID_COLLECTION_END \
// HID Generic Input & Output
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index f19f1ba81..ca745464c 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID)
+#if (CFG_TUH_ENABLED && CFG_TUH_HID)
#include "host/usbh.h"
#include "host/usbh_classdriver.h"
@@ -103,27 +103,27 @@ uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
return hid_itf->protocol_mode;
}
-static bool set_protocol_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static void set_protocol_complete(tuh_xfer_t* xfer)
{
- 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);
+ uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ uint8_t const daddr = xfer->daddr;
+ uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num);
+ hidh_interface_t* hid_itf = get_instance(daddr, instance);
- if (XFER_RESULT_SUCCESS == result) hid_itf->protocol_mode = (uint8_t) request->wValue;
+ if (XFER_RESULT_SUCCESS == xfer->result)
+ {
+ hid_itf->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue);
+ }
if (tuh_hid_set_protocol_complete_cb)
{
- tuh_hid_set_protocol_complete_cb(dev_addr, instance, hid_itf->protocol_mode);
+ tuh_hid_set_protocol_complete_cb(daddr, instance, hid_itf->protocol_mode);
}
-
- return true;
}
-bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol)
-{
- hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
- TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE);
+static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
TU_LOG2("HID Set Protocol = %d\r\n", protocol);
tusb_control_request_t const request =
@@ -136,30 +136,47 @@ bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol)
},
.bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
.wValue = protocol,
- .wIndex = hid_itf->itf_num,
+ .wIndex = itf_num,
.wLength = 0
};
- TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, set_protocol_complete) );
+ tuh_xfer_t xfer =
+ {
+ .daddr = dev_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
+ TU_ASSERT( tuh_control_xfer(&xfer) );
return true;
}
-static bool set_report_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol)
+{
+ hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+ TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE);
+
+ return _hidh_set_protocol(dev_addr, hid_itf->itf_num, protocol, set_protocol_complete, 0);
+}
+
+static void set_report_complete(tuh_xfer_t* xfer)
{
TU_LOG2("HID Set Report complete\r\n");
if (tuh_hid_set_report_complete_cb)
{
- uint8_t const itf_num = (uint8_t) request->wIndex;
- uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
+ uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ uint8_t const instance = get_instance_id_by_itfnum(xfer->daddr, itf_num);
- uint8_t const report_type = tu_u16_high(request->wValue);
- uint8_t const report_id = tu_u16_low(request->wValue);
+ uint8_t const report_type = tu_u16_high(xfer->setup->wValue);
+ uint8_t const report_id = tu_u16_low(xfer->setup->wValue);
- tuh_hid_set_report_complete_cb(dev_addr, instance, report_id, report_type, (result == XFER_RESULT_SUCCESS) ? request->wLength : 0);
+ tuh_hid_set_report_complete_cb(xfer->daddr, instance, report_id, report_type,
+ (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0);
}
-
- return true;
}
bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len)
@@ -181,7 +198,50 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u
.wLength = len
};
- TU_ASSERT( tuh_control_xfer(dev_addr, &request, report, set_report_complete) );
+ tuh_xfer_t xfer =
+ {
+ .daddr = dev_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = report,
+ .complete_cb = set_report_complete,
+ .user_data = 0
+ };
+
+ TU_ASSERT( tuh_control_xfer(&xfer) );
+ return true;
+}
+
+static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ // SET IDLE request, device can stall if not support this request
+ TU_LOG2("HID Set Idle \r\n");
+ tusb_control_request_t const request =
+ {
+ .bmRequestType_bit =
+ {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_CLASS,
+ .direction = TUSB_DIR_OUT
+ },
+ .bRequest = HID_REQ_CONTROL_SET_IDLE,
+ .wValue = idle_rate,
+ .wIndex = itf_num,
+ .wLength = 0
+ };
+
+ tuh_xfer_t xfer =
+ {
+ .daddr = dev_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
+ TU_ASSERT( tuh_control_xfer(&xfer) );
+
return true;
}
@@ -196,7 +256,13 @@ bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance)
// claim endpoint
TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) );
- return usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size);
+ if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) )
+ {
+ usbh_edpt_claim(dev_addr, hid_itf->ep_in);
+ return false;
+ }
+
+ return true;
}
//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance)
@@ -229,10 +295,10 @@ bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint3
{
TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance);
TU_LOG3_MEM(hid_itf->epin_buf, xferred_bytes, 2);
- tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, xferred_bytes);
+ tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, (uint16_t) xferred_bytes);
}else
{
- if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, xferred_bytes);
+ if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, (uint16_t) xferred_bytes);
}
return true;
@@ -256,22 +322,18 @@ void hidh_close(uint8_t dev_addr)
// Enumeration
//--------------------------------------------------------------------+
-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);
-
-static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
-
bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
+ (void) rhport;
(void) max_len;
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
- TU_LOG2("HID opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr);
+ TU_LOG2("[%u] HID opening Interface %u\r\n", dev_addr, desc_itf->bInterfaceNumber);
// len = interface + hid + n*endpoints
- uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+ uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
+ desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(max_len >= drv_len);
uint8_t const *p_desc = (uint8_t const *) desc_itf;
@@ -286,28 +348,35 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
hidh_device_t* hid_dev = get_dev(dev_addr);
TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0);
- //------------- Endpoint Descriptor -------------//
+ hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count);
+
+ //------------- Endpoint Descriptors -------------//
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);
- // first endpoint may be OUT, skip to IN endpoint
- // TODO also open endpoint OUT
- if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT)
+ for(int i = 0; i < desc_itf->bNumEndpoints; i++)
{
+ TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
+ TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) );
+
+ if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
+ {
+ hid_itf->ep_in = desc_ep->bEndpointAddress;
+ hid_itf->epin_size = tu_edpt_packet_size(desc_ep);
+ }
+ else
+ {
+ hid_itf->ep_out = desc_ep->bEndpointAddress;
+ hid_itf->epout_size = tu_edpt_packet_size(desc_ep);
+ }
+
p_desc = tu_desc_next(p_desc);
desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
}
- TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
-
- hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count);
hid_dev->inst_count++;
hid_itf->itf_num = desc_itf->bInterfaceNumber;
- hid_itf->ep_in = desc_ep->bEndpointAddress;
- hid_itf->epin_size = tu_edpt_packet_size(desc_ep);
// Assume bNumDescriptors = 1
hid_itf->report_desc_type = desc_hid->bReportType;
@@ -320,122 +389,93 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
return true;
}
-bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
-{
- uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
- hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
-
- // Idle rate = 0 mean only report when there is changes
- uint16_t const idle_rate = 0;
-
- // SET IDLE request, device can stall if not support this request
- TU_LOG2("HID Set Idle \r\n");
- tusb_control_request_t const request =
- {
- .bmRequestType_bit =
- {
- .recipient = TUSB_REQ_RCPT_INTERFACE,
- .type = TUSB_REQ_TYPE_CLASS,
- .direction = TUSB_DIR_OUT
- },
- .bRequest = HID_REQ_CONTROL_SET_IDLE,
- .wValue = idle_rate,
- .wIndex = itf_num,
- .wLength = 0
- };
+//--------------------------------------------------------------------+
+// Set Configure
+//--------------------------------------------------------------------+
- TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc) );
+enum {
+ CONFG_SET_IDLE,
+ CONFIG_SET_PROTOCOL,
+ CONFIG_GET_REPORT_DESC,
+ CONFIG_COMPLETE
+};
- return true;
-}
+static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
+static void process_set_config(tuh_xfer_t* xfer);
-// 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)
+bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
{
- // Stall is a valid response for SET_IDLE, therefore we could ignore its result
- (void) result;
+ tusb_control_request_t request;
+ request.wIndex = tu_htole16((uint16_t) itf_num);
- 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);
+ tuh_xfer_t xfer;
+ xfer.daddr = dev_addr;
+ xfer.result = XFER_RESULT_SUCCESS;
+ xfer.setup = &request;
+ xfer.user_data = CONFG_SET_IDLE;
- TU_LOG2("HID Set Protocol to Boot Mode\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_OUT
- },
- .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
- .wValue = HID_PROTOCOL_BOOT,
- .wIndex = hid_itf->itf_num,
- .wLength = 0
- };
+ // fake request to kick-off the set config process
+ process_set_config(&xfer);
- 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)
+static void process_set_config(tuh_xfer_t* xfer)
{
- // 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 )
+ // Stall is a valid response for SET_IDLE, therefore we could ignore its result
+ if ( xfer->setup->bRequest != HID_REQ_CONTROL_SET_IDLE )
{
- TU_ASSERT(result == XFER_RESULT_SUCCESS);
+ TU_ASSERT(xfer->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);
- hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+ uintptr_t const state = xfer->user_data;
+ uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ uint8_t const daddr = xfer->daddr;
- // Get Report Descriptor if possible
- // using usbh enumeration buffer since report descriptor can be very long
- if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE )
- {
- TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len);
+ uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num);
+ hidh_interface_t* hid_itf = get_instance(daddr, instance);
- // Driver is mounted without report descriptor
- config_driver_mount_complete(dev_addr, instance, NULL, 0);
- }else
+ switch(state)
{
- TU_LOG2("HID Get Report Descriptor\r\n");
- tusb_control_request_t const new_request =
+ case CONFG_SET_IDLE:
{
- .bmRequestType_bit =
- {
- .recipient = TUSB_REQ_RCPT_INTERFACE,
- .type = TUSB_REQ_TYPE_STANDARD,
- .direction = TUSB_DIR_IN
- },
- .bRequest = TUSB_REQ_GET_DESCRIPTOR,
- .wValue = tu_u16(hid_itf->report_desc_type, 0),
- .wIndex = itf_num,
- .wLength = hid_itf->report_desc_len
- };
-
- TU_ASSERT(tuh_control_xfer(dev_addr, &new_request, usbh_get_enum_buf(), config_get_report_desc_complete));
- }
+ // Idle rate = 0 mean only report when there is changes
+ const uint16_t idle_rate = 0;
+ const uintptr_t next_state = (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC;
+ _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state);
+ }
+ break;
- return true;
-}
+ case CONFIG_SET_PROTOCOL:
+ _hidh_set_protocol(daddr, hid_itf->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC);
+ break;
-static bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
-{
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
+ case CONFIG_GET_REPORT_DESC:
+ // Get Report Descriptor if possible
+ // using usbh enumeration buffer since report descriptor can be very long
+ if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE )
+ {
+ TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len);
- uint8_t const itf_num = (uint8_t) request->wIndex;
- uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
+ // Driver is mounted without report descriptor
+ config_driver_mount_complete(daddr, instance, NULL, 0);
+ }else
+ {
+ tuh_descriptor_get_hid_report(daddr, itf_num, hid_itf->report_desc_type, 0, usbh_get_enum_buf(), hid_itf->report_desc_len, process_set_config, CONFIG_COMPLETE);
+ }
+ break;
- uint8_t const* desc_report = usbh_get_enum_buf();
- uint16_t const desc_len = request->wLength;
+ case CONFIG_COMPLETE:
+ {
+ uint8_t const* desc_report = usbh_get_enum_buf();
+ uint16_t const desc_len = tu_le16toh(xfer->setup->wLength);
- config_driver_mount_complete(dev_addr, instance, desc_report, desc_len);
+ config_driver_mount_complete(daddr, instance, desc_report, desc_len);
+ }
+ break;
- return true;
+ default: break;
+ }
}
static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c
index b08b362f9..de41706e8 100644
--- a/src/class/midi/midi_device.c
+++ b/src/class/midi/midi_device.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MIDI)
+#if (CFG_TUD_ENABLED && CFG_TUD_MIDI)
//--------------------------------------------------------------------+
// INCLUDE
@@ -92,7 +92,7 @@ bool tud_midi_n_mounted (uint8_t itf)
static void _prep_out_transaction (midid_interface_t* p_midi)
{
- uint8_t const rhport = TUD_OPT_RHPORT;
+ uint8_t const rhport = 0;
uint16_t available = tu_fifo_remaining(&p_midi->rx_ff);
// Prepare for incoming data but only allow what we can store in the ring buffer.
@@ -127,7 +127,7 @@ uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num)
midid_stream_t const* stream = &midi->stream_read;
// when using with packet API stream total & index are both zero
- return tu_fifo_count(&midi->rx_ff) + (stream->total - stream->index);
+ return tu_fifo_count(&midi->rx_ff) + (uint8_t) (stream->total - stream->index);
}
uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize)
@@ -179,7 +179,7 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui
}
// Copy data up to bufsize
- uint32_t const count = tu_min32(stream->total - stream->index, bufsize);
+ uint8_t const count = (uint8_t) tu_min32(stream->total - stream->index, bufsize);
// Skip the header (1st byte) in the buffer
memcpy(buf8, stream->buffer + 1 + stream->index, count);
@@ -219,7 +219,7 @@ static uint32_t write_flush(midid_interface_t* midi)
// No data to send
if ( !tu_fifo_count(&midi->tx_ff) ) return 0;
- uint8_t const rhport = TUD_OPT_RHPORT;
+ uint8_t const rhport = 0;
// skip if previous transfer not complete
TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 );
@@ -276,13 +276,13 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE )
{
// Channel Voice Messages
- stream->buffer[0] = (cable_num << 4) | msg;
+ stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg);
stream->total = 4;
}
else if ( msg == 0xC || msg == 0xD)
{
// Channel Voice Messages, two-byte variants (Program Change and Channel Pressure)
- stream->buffer[0] = (cable_num << 4) | msg;
+ stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg);
stream->total = 3;
}
else if ( msg == 0xf )
@@ -312,7 +312,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
else
{
// Pack individual bytes if we don't support packing them into words.
- stream->buffer[0] = cable_num << 4 | 0xf;
+ stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf);
stream->buffer[2] = 0;
stream->buffer[3] = 0;
stream->index = 2;
@@ -513,7 +513,7 @@ bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32
// receive new data
if ( ep_addr == p_midi->ep_out )
{
- tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, xferred_bytes);
+ tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, (uint16_t) xferred_bytes);
// invoke receive callback if available
if (tud_midi_rx_cb) tud_midi_rx_cb(itf);
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index 97837b114..00b0a1d06 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -26,11 +26,11 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MSC)
+#if (CFG_TUD_ENABLED && CFG_TUD_MSC)
+#include "device/dcd.h" // for faking dcd_event_xfer_complete
#include "device/usbd.h"
#include "device/usbd_pvt.h"
-#include "device/dcd.h" // for faking dcd_event_xfer_complete
#include "msc_device.h"
@@ -209,7 +209,7 @@ TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
{ .key = SCSI_CMD_MODE_SELECT_6 , .data = "Mode_Select 6" },
{ .key = SCSI_CMD_MODE_SENSE_6 , .data = "Mode_Sense 6" },
{ .key = SCSI_CMD_START_STOP_UNIT , .data = "Start Stop Unit" },
- { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent Allow Medium Removal" },
+ { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent/Allow Medium Removal" },
{ .key = SCSI_CMD_READ_CAPACITY_10 , .data = "Read Capacity10" },
{ .key = SCSI_CMD_REQUEST_SENSE , .data = "Request Sense" },
{ .key = SCSI_CMD_READ_FORMAT_CAPACITY , .data = "Read Format Capacity" },
@@ -239,6 +239,12 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u
return true;
}
+static inline void set_sense_medium_not_present(uint8_t lun)
+{
+ // default sense is NOT READY, MEDIUM NOT PRESENT
+ tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00);
+}
+
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
@@ -406,7 +412,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
return false;
}
- TU_LOG(MSC_DEBUG, " SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
+ TU_LOG(MSC_DEBUG, " SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
//TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2);
p_csw->signature = MSC_CSW_SIGNATURE;
@@ -457,7 +463,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
{
// Didn't check for case 9 (Ho > Dn), which requires examining scsi command first
// but it is OK to just receive data then responded with failed status
- TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->total_len) );
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, (uint16_t) p_msc->total_len) );
}
}else
{
@@ -467,13 +473,13 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// Invoke user callback if not built-in
if ( (resplen < 0) && (p_msc->sense_key == 0) )
{
- resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
+ resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len);
}
if ( resplen < 0 )
{
// unsupported command
- TU_LOG(MSC_DEBUG, " SCSI unsupported command\r\n");
+ TU_LOG(MSC_DEBUG, " SCSI unsupported or failed command\r\n");
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
}
else if (resplen == 0)
@@ -500,7 +506,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
{
// cannot return more than host expect
p_msc->total_len = tu_min32((uint32_t) resplen, p_cbw->total_bytes);
- TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) p_msc->total_len) );
}
}
}
@@ -508,7 +514,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
case MSC_STAGE_DATA:
- TU_LOG(MSC_DEBUG, " SCSI Data\r\n");
+ TU_LOG(MSC_DEBUG, " SCSI Data [Lun%u]\r\n", p_cbw->lun);
//TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2);
if (SCSI_CMD_READ_10 == p_cbw->command[0])
@@ -535,7 +541,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// OUT transfer, invoke callback if needed
if ( !is_data_in(p_cbw->dir) )
{
- int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
+ int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len);
if ( cb_result < 0 )
{
@@ -569,7 +575,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// Wait for the Status phase to complete
if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) )
{
- TU_LOG(MSC_DEBUG, " SCSI Status = %u\r\n", p_csw->status);
+ TU_LOG(MSC_DEBUG, " SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status);
// TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2);
// Invoke complete callback if defined
@@ -654,8 +660,8 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
// Failed status response
resplen = - 1;
- // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
- if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+ // set default sense if not set by callback
+ if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun);
}
break;
@@ -670,8 +676,8 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
// Failed status response
resplen = - 1;
- // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
- if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+ // set default sense if not set by callback
+ if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun);
}
}
break;
@@ -691,17 +697,17 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
{
resplen = -1;
- // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
- if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+ // set default sense if not set by callback
+ if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun);
}else
{
scsi_read_capacity10_resp_t read_capa10;
- read_capa10.last_lba = tu_htonl(block_count-1);
+ read_capa10.last_lba = tu_htonl(block_count-1);
read_capa10.block_size = tu_htonl(block_size);
resplen = sizeof(read_capa10);
- memcpy(buffer, &read_capa10, resplen);
+ memcpy(buffer, &read_capa10, (size_t) resplen);
}
}
break;
@@ -727,15 +733,15 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
{
resplen = -1;
- // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
- if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+ // set default sense if not set by callback
+ if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun);
}else
{
read_fmt_capa.block_num = tu_htonl(block_count);
read_fmt_capa.block_size_u16 = tu_htons(block_size);
resplen = sizeof(read_fmt_capa);
- memcpy(buffer, &read_fmt_capa, resplen);
+ memcpy(buffer, &read_fmt_capa, (size_t) resplen);
}
}
break;
@@ -747,6 +753,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
.is_removable = 1,
.version = 2,
.response_data_format = 2,
+ .additional_length = sizeof(scsi_inquiry_resp_t) - 5,
};
// vendor_id, product_id, product_rev is space padded string
@@ -757,7 +764,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev);
resplen = sizeof(inquiry_rsp);
- memcpy(buffer, &inquiry_rsp, resplen);
+ memcpy(buffer, &inquiry_rsp, (size_t) resplen);
}
break;
@@ -765,10 +772,10 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
{
scsi_mode_sense6_resp_t mode_resp =
{
- .data_len = 3,
- .medium_type = 0,
- .write_protected = false,
- .reserved = 0,
+ .data_len = 3,
+ .medium_type = 0,
+ .write_protected = false,
+ .reserved = 0,
.block_descriptor_len = 0 // no block descriptor are included
};
@@ -781,7 +788,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
mode_resp.write_protected = !writable;
resplen = sizeof(mode_resp);
- memcpy(buffer, &mode_resp, resplen);
+ memcpy(buffer, &mode_resp, (size_t) resplen);
}
break;
@@ -789,18 +796,23 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
{
scsi_sense_fixed_resp_t sense_rsp =
{
- .response_code = 0x70,
+ .response_code = 0x70, // current, fixed format
.valid = 1
};
- sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8;
-
- sense_rsp.sense_key = p_msc->sense_key;
+ sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8;
+ sense_rsp.sense_key = (uint8_t) (p_msc->sense_key & 0x0F);
sense_rsp.add_sense_code = p_msc->add_sense_code;
sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier;
resplen = sizeof(sense_rsp);
- memcpy(buffer, &sense_rsp, resplen);
+ memcpy(buffer, &sense_rsp, (size_t) resplen);
+
+ // request sense callback could overwrite the sense data
+ if (tud_msc_request_sense_cb)
+ {
+ resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t) bufsize);
+ }
// Clear sense data after copy
tud_msc_set_sense(lun, 0, 0, 0);
@@ -835,8 +847,8 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
// negative means error -> endpoint is stalled & status in CSW set to failed
TU_LOG(MSC_DEBUG, " tud_msc_read10_cb() return -1\r\n");
- // Sense = Flash not ready for access
- tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_MEDIUM_ERROR, 0x33, 0x00);
+ // set sense
+ set_sense_medium_not_present(p_cbw->lun);
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
}
@@ -847,7 +859,7 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
}
else
{
- TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, nbytes), );
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) nbytes), );
}
}
@@ -871,7 +883,7 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
}
// remaining bytes capped at class buffer
- int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len);
+ uint16_t nbytes = (uint16_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len);
// Write10 callback will be called later when usb transfer complete
TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), );
@@ -900,8 +912,8 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3
// update actual byte before failed
p_msc->xferred_len += xferred_bytes;
- // Sense = Flash not ready for access
- tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_MEDIUM_ERROR, 0x33, 0x00);
+ // Set sense
+ set_sense_medium_not_present(p_cbw->lun);
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
}else
@@ -909,14 +921,15 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3
// Application consume less than what we got (including zero)
if ( (uint32_t) nbytes < xferred_bytes )
{
+ uint32_t const left_over = xferred_bytes - (uint32_t) nbytes;
if ( nbytes > 0 )
{
- p_msc->xferred_len += nbytes;
- memmove(_mscd_buf, _mscd_buf+nbytes, xferred_bytes-nbytes);
+ p_msc->xferred_len += (uint16_t) nbytes;
+ memmove(_mscd_buf, _mscd_buf+nbytes, left_over);
}
// simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter
- dcd_event_xfer_complete(rhport, p_msc->ep_out, xferred_bytes-nbytes, XFER_RESULT_SUCCESS, false);
+ dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false);
}
else
{
diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h
index d32694340..5839b168d 100644
--- a/src/class/msc/msc_device.h
+++ b/src/class/msc/msc_device.h
@@ -131,6 +131,9 @@ TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void);
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject);
+// Invoked when received REQUEST_SENSE
+TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize);
+
// Invoked when Read10 command is complete
TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
index fa6519956..934f79ff7 100644
--- a/src/class/msc/msc_host.c
+++ b/src/class/msc/msc_host.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED & CFG_TUH_MSC
+#if CFG_TUH_ENABLED && CFG_TUH_MSC
#include "host/usbh.h"
#include "host/usbh_classdriver.h"
@@ -325,19 +325,19 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
p_msc->stage = MSC_STAGE_DATA;
uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out;
- TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, cbw->total_bytes));
+ TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes));
}else
{
// Status stage
p_msc->stage = MSC_STAGE_STATUS;
- TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)));
+ TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
}
break;
case MSC_STAGE_DATA:
// Status stage
p_msc->stage = MSC_STAGE_STATUS;
- TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)));
+ TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
break;
case MSC_STAGE_STATUS:
@@ -358,18 +358,19 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
// MSC Enumeration
//--------------------------------------------------------------------+
-static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+static void config_get_maxlun_complete (tuh_xfer_t* xfer);
static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
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 max_len)
{
+ (void) rhport;
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);
+ uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(drv_len <= max_len);
msch_interface_t* p_msc = get_itf(dev_addr);
@@ -378,7 +379,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
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(tuh_edpt_open(dev_addr, ep_desc));
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
{
@@ -405,7 +406,7 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
//------------- Get Max Lun -------------//
TU_LOG2("MSC Get Max Lun\r\n");
- tusb_control_request_t request =
+ tusb_control_request_t const request =
{
.bmRequestType_bit =
{
@@ -418,27 +419,34 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
.wIndex = itf_num,
.wLength = 1
};
- TU_ASSERT(tuh_control_xfer(dev_addr, &request, &p_msc->max_lun, config_get_maxlun_complete));
+
+ tuh_xfer_t xfer =
+ {
+ .daddr = dev_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = &p_msc->max_lun,
+ .complete_cb = config_get_maxlun_complete,
+ .user_data = 0
+ };
+ TU_ASSERT(tuh_control_xfer(&xfer));
return true;
}
-static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static void config_get_maxlun_complete (tuh_xfer_t* xfer)
{
- (void) request;
-
- msch_interface_t* p_msc = get_itf(dev_addr);
+ uint8_t const daddr = xfer->daddr;
+ msch_interface_t* p_msc = get_itf(daddr);
// STALL means zero
- p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? _msch_buffer[0] : 0;
+ p_msc->max_lun = (XFER_RESULT_SUCCESS == xfer->result) ? _msch_buffer[0] : 0;
p_msc->max_lun++; // MAX LUN is minus 1 by specs
// TODO multiple LUN support
TU_LOG2("SCSI Test Unit Ready\r\n");
uint8_t const lun = 0;
- tuh_msc_test_unit_ready(dev_addr, lun, config_test_unit_ready_complete);
-
- return true;
+ tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete);
}
static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
@@ -476,7 +484,7 @@ static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw
// Capacity response field: Block size and Last LBA are both Big-Endian
scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer);
p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1;
- p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size);
+ p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size);
// Mark enumeration is complete
p_msc->mounted = true;
diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c
index c6cd388e3..5f316762f 100644
--- a/src/class/net/ecm_rndis_device.c
+++ b/src/class/net/ecm_rndis_device.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if ( TUSB_OPT_DEVICE_ENABLED && CFG_TUD_ECM_RNDIS )
+#if ( CFG_TUD_ENABLED && CFG_TUD_ECM_RNDIS )
#include "device/usbd.h"
#include "device/usbd_pvt.h"
@@ -108,20 +108,22 @@ static bool can_xmit;
void tud_network_recv_renew(void)
{
- usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_out, received, sizeof(received));
+ usbd_edpt_xfer(0, _netd_itf.ep_out, received, sizeof(received));
}
static void do_in_xfer(uint8_t *buf, uint16_t len)
{
can_xmit = false;
- usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_in, buf, len);
+ usbd_edpt_xfer(0, _netd_itf.ep_in, buf, len);
}
void netd_report(uint8_t *buf, uint16_t len)
{
+ uint8_t const rhport = 0;
+
// skip if previous report not yet acknowledged by host
- if ( usbd_edpt_busy(TUD_OPT_RHPORT, _netd_itf.ep_notif) ) return;
- usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_notif, buf, len);
+ if ( usbd_edpt_busy(rhport, _netd_itf.ep_notif) ) return;
+ usbd_edpt_xfer(rhport, _netd_itf.ep_notif, buf, len);
}
//--------------------------------------------------------------------+
@@ -316,11 +318,11 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *) ((void*) notify.rndis_buf);
uint32_t msglen = tu_le32toh(rndis_msg->MessageLength);
TU_ASSERT(msglen <= sizeof(notify.rndis_buf));
- tud_control_xfer(rhport, request, notify.rndis_buf, msglen);
+ tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) msglen);
}
else
{
- tud_control_xfer(rhport, request, notify.rndis_buf, sizeof(notify.rndis_buf));
+ tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) sizeof(notify.rndis_buf));
}
}
break;
@@ -367,7 +369,7 @@ static void handle_incoming_packet(uint32_t len)
}
}
- if (!tud_network_recv_cb(pnt, size))
+ if (!tud_network_recv_cb(pnt, (uint16_t) size))
{
/* if a buffer was never handled by user code, we must renew on the user's behalf */
tud_network_recv_renew();
diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c
index 3e131a85c..00892b49c 100644
--- a/src/class/net/ncm_device.c
+++ b/src/class/net/ncm_device.c
@@ -28,7 +28,7 @@
#include "tusb_option.h"
-#if ( TUSB_OPT_DEVICE_ENABLED && CFG_TUD_NCM )
+#if ( CFG_TUD_ENABLED && CFG_TUD_NCM )
#include "device/usbd.h"
#include "device/usbd_pvt.h"
@@ -188,7 +188,7 @@ static void ncm_start_tx(void) {
ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = 0;
// Kick off an endpoint transfer
- usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_in, ntb->data, ntb_length);
+ usbd_edpt_xfer(0, ncm_interface.ep_in, ntb->data, ntb_length);
ncm_interface.transferring = true;
// Swap to the other NTB and clear it out
@@ -229,7 +229,7 @@ void tud_network_recv_renew(void)
{
if (!ncm_interface.num_datagrams)
{
- usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb));
+ usbd_edpt_xfer(0, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb));
return;
}
@@ -316,14 +316,15 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
static void ncm_report(void)
{
+ uint8_t const rhport = 0;
if (ncm_interface.report_state == REPORT_SPEED) {
ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num;
- usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change));
+ usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change));
ncm_interface.report_state = REPORT_CONNECTED;
ncm_interface.report_pending = true;
} else if (ncm_interface.report_state == REPORT_CONNECTED) {
ncm_notify_connected.header.wIndex = ncm_interface.itf_num;
- usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected));
+ usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected));
ncm_interface.report_state = REPORT_DONE;
ncm_interface.report_pending = true;
}
diff --git a/src/class/usbtmc/usbtmc.h b/src/class/usbtmc/usbtmc.h
index 7d7005c2e..e7016ae24 100644
--- a/src/class/usbtmc/usbtmc.h
+++ b/src/class/usbtmc/usbtmc.h
@@ -189,7 +189,10 @@ typedef enum {
USBTMC_STATUS_FAILED = 0x80,
USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS = 0x81,
USBTMC_STATUS_SPLIT_NOT_IN_PROGRESS = 0x82,
- USBTMC_STATUS_SPLIT_IN_PROGRESS = 0x83
+ USBTMC_STATUS_SPLIT_IN_PROGRESS = 0x83,
+
+ /****** USBTMC 488 *************/
+ USB488_STATUS_INTERRUPT_IN_BUSY = 0x20
} usbtmc_status_enum;
/************************************************************
diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c
index 4bd1edf12..af4a92732 100644
--- a/src/class/usbtmc/usbtmc_device.c
+++ b/src/class/usbtmc/usbtmc_device.c
@@ -64,11 +64,12 @@
// USBTMC 3.2.2 error conditions not strictly followed
// No local lock-out, REN, or GTL.
// Clear message available status byte at the correct time? (488 4.3.1.3)
-
+// Ability to defer status byte transmission
+// Transmission of status byte in response to USB488 SRQ condition
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_USBTMC)
+#if (CFG_TUD_ENABLED && CFG_TUD_USBTMC)
#include "device/usbd.h"
#include "device/usbd_pvt.h"
@@ -80,6 +81,11 @@
static char logMsg[150];
#endif
+// Buffer size must be an exact multiple of the max packet size for both
+// bulk (up to 64 bytes for FS, 512 bytes for HS). In addation, this driver
+// imposes a minimum buffer size of 32 bytes.
+#define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
/*
* The state machine does not allow simultaneous reading and writing. This is
* consistent with USBTMC.
@@ -120,9 +126,12 @@ typedef struct
uint8_t ep_int_in;
// IN buffer is only used for first packet, not the remainder
// in order to deal with prepending header
- CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_MAX_PACKET_SIZE];
+ CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE];
+ uint32_t ep_bulk_in_wMaxPacketSize;
// OUT buffer receives one packet at a time
- CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_MAX_PACKET_SIZE];
+ CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE];
+ uint32_t ep_bulk_out_wMaxPacketSize;
+
uint32_t transfer_size_remaining; // also used for requested length for bulk IN.
uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes)
@@ -139,11 +148,8 @@ CFG_TUSB_MEM_SECTION static usbtmc_interface_state_t usbtmc_state =
.itf_id = 0xFF,
};
-// We need all headers to fit in a single packet in this implementation.
-TU_VERIFY_STATIC(USBTMCD_MAX_PACKET_SIZE >= 32u,"USBTMC dev EP packet size too small");
-TU_VERIFY_STATIC(
- (sizeof(usbtmc_state.ep_bulk_in_buf) % USBTMCD_MAX_PACKET_SIZE) == 0,
- "packet buffer must be a multiple of the packet size");
+// We need all headers to fit in a single packet in this implementation, 32 bytes will fit all standard USBTMC headers
+TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u,"USBTMC dev buffer size too small");
static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len);
static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen);
@@ -151,7 +157,6 @@ static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t pack
static uint8_t termChar;
static uint8_t termCharRequested = false;
-
osal_mutex_def_t usbtmcLockBuffer;
static osal_mutex_t usbtmcLock;
@@ -235,17 +240,19 @@ void usbtmcd_init_cb(void)
usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb();
#ifndef NDEBUG
# if CFG_TUD_USBTMC_ENABLE_488
- if(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger)
- TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL,);
- // Per USB488 spec: table 8
- TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly,);
- TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly,);
+ if (usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger) {
+ TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL,);
+ }
+ // Per USB488 spec: table 8
+ TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly,);
+ TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly,);
# endif
- if(usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse)
- TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL,);
+ if (usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse) {
+ TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL,);
+ }
#endif
- usbtmcLock = osal_mutex_create(&usbtmcLockBuffer);
+ usbtmcLock = osal_mutex_create(&usbtmcLockBuffer);
}
uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
@@ -280,12 +287,15 @@ uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc,
tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *)p_desc;
switch(ep_desc->bmAttributes.xfer) {
case TUSB_XFER_BULK:
- TU_ASSERT(tu_edpt_packet_size(ep_desc) == USBTMCD_MAX_PACKET_SIZE, 0);
+ // Ensure buffer is an exact multiple of the maxPacketSize
+ TU_ASSERT((USBTMCD_BUFFER_SIZE % tu_edpt_packet_size(ep_desc)) == 0, 0);
if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN)
{
usbtmc_state.ep_bulk_in = ep_desc->bEndpointAddress;
+ usbtmc_state.ep_bulk_in_wMaxPacketSize = tu_edpt_packet_size(ep_desc);
} else {
usbtmc_state.ep_bulk_out = ep_desc->bEndpointAddress;
+ usbtmc_state.ep_bulk_out_wMaxPacketSize = tu_edpt_packet_size(ep_desc);
}
break;
@@ -393,7 +403,7 @@ static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t pack
// return true upon failure, as we can assume error is being handled elsewhere.
TU_VERIFY(usbtmc_state.state == STATE_RCV,true);
- bool shortPacket = (packetLen < USBTMCD_MAX_PACKET_SIZE);
+ bool shortPacket = (packetLen < usbtmc_state.ep_bulk_out_wMaxPacketSize);
// Packet is to be considered complete when we get enough data or at a short packet.
bool atEnd = false;
@@ -520,7 +530,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
break;
case STATE_TX_INITIATED:
- if(usbtmc_state.transfer_size_remaining >=sizeof(usbtmc_state.ep_bulk_in_buf))
+ if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf))
{
// FIXME! This removes const below!
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in,
@@ -537,7 +547,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
usbtmc_state.transfer_size_remaining = 0;
usbtmc_state.devInBuffer = NULL;
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen) );
- if(((packetLen % USBTMCD_MAX_PACKET_SIZE) != 0) || (packetLen == 0 ))
+ if(((packetLen % usbtmc_state.ep_bulk_in_wMaxPacketSize) != 0) || (packetLen == 0 ))
{
usbtmc_state.state = STATE_TX_SHORTED;
}
@@ -587,18 +597,31 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request
{
uint32_t ep_addr = (request->wIndex);
+ // At this point, a transfer MAY be in progress. Based on USB spec, when clearing bulk EP HALT,
+ // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if
+ // the EP is not halted. The only USBD API interface to do this is to stall and then unstall the EP.
if(ep_addr == usbtmc_state.ep_bulk_out)
{
criticalEnter();
+ usbd_edpt_stall(rhport, (uint8_t)ep_addr);
+ usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr);
usbtmc_state.state = STATE_NAK; // USBD core has placed EP in NAK state for us
criticalLeave();
tud_usbtmc_bulkOut_clearFeature_cb();
}
else if (ep_addr == usbtmc_state.ep_bulk_in)
{
+ usbd_edpt_stall(rhport, (uint8_t)ep_addr);
+ usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr);
tud_usbtmc_bulkIn_clearFeature_cb();
}
- else
+ else if ((usbtmc_state.ep_int_in != 0) && (ep_addr == usbtmc_state.ep_int_in))
+ {
+ // Clearing interrupt in EP
+ usbd_edpt_stall(rhport, (uint8_t)ep_addr);
+ usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr);
+ }
+ else
{
return false;
}
@@ -678,7 +701,7 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request
usbtmc_state.transfer_size_remaining = 0u;
// Check if we've queued a short packet
criticalEnter();
- usbtmc_state.state = ((usbtmc_state.transfer_size_sent % USBTMCD_MAX_PACKET_SIZE) == 0) ?
+ usbtmc_state.state = ((usbtmc_state.transfer_size_sent % usbtmc_state.ep_bulk_in_wMaxPacketSize) == 0) ?
STATE_ABORTING_BULK_IN : STATE_ABORTING_BULK_IN_SHORTED;
criticalLeave();
if(usbtmc_state.transfer_size_sent == 0)
@@ -808,25 +831,32 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request
bTag = request->wValue & 0x7F;
TU_VERIFY(request->bmRequestType == 0xA1);
- TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero
+ TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero (USB488v1.0 Table 11)
TU_VERIFY(bTag >= 0x02 && bTag <= 127);
TU_VERIFY(request->wIndex == usbtmc_state.itf_id);
TU_VERIFY(request->wLength == 0x0003);
rsp.bTag = (uint8_t)bTag;
if(usbtmc_state.ep_int_in != 0)
{
- rsp.USBTMC_status = USBTMC_STATUS_SUCCESS;
- rsp.statusByte = 0x00; // Use interrupt endpoint, instead.
-
- usbtmc_read_stb_interrupt_488_t intMsg =
+ rsp.statusByte = 0x00; // Use interrupt endpoint, instead. Must be 0x00 (USB488v1.0 4.3.1.2)
+ if(usbd_edpt_busy(rhport, usbtmc_state.ep_int_in))
{
- .bNotify1 = {
- .one = 1,
- .bTag = bTag & 0x7Fu,
- },
- .StatusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status))
- };
- usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg, sizeof(intMsg));
+ rsp.USBTMC_status = USB488_STATUS_INTERRUPT_IN_BUSY;
+ }
+ else
+ {
+ rsp.USBTMC_status = USBTMC_STATUS_SUCCESS;
+ usbtmc_read_stb_interrupt_488_t intMsg =
+ {
+ .bNotify1 = {
+ .one = 1,
+ .bTag = bTag & 0x7Fu,
+ },
+ .StatusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status))
+ };
+ // Must be queued before control request response sent (USB488v1.0 4.3.1.2)
+ usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg, sizeof(intMsg));
+ }
}
else
{
diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h
index 0549a1569..144b3315d 100644
--- a/src/class/usbtmc/usbtmc_device.h
+++ b/src/class/usbtmc/usbtmc_device.h
@@ -35,10 +35,6 @@
#define CFG_TUD_USBTMC_ENABLE_488 (1)
#endif
-// USB spec says that full-speed must be 8,16,32, or 64.
-// However, this driver implementation requires it to be >=32
-#define USBTMCD_MAX_PACKET_SIZE (64u)
-
/***********************************************
* Functions to be implemeted by the class implementation
*/
diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c
index 8a4ca1d2e..3b81a108f 100644
--- a/src/class/vendor/vendor_device.c
+++ b/src/class/vendor/vendor_device.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_VENDOR)
+#if (CFG_TUD_ENABLED && CFG_TUD_VENDOR)
#include "device/usbd.h"
#include "device/usbd_pvt.h"
@@ -84,21 +84,23 @@ bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8)
//--------------------------------------------------------------------+
static void _prep_out_transaction (vendord_interface_t* p_itf)
{
+ uint8_t const rhport = 0;
+
// skip if previous transfer not complete
- if ( usbd_edpt_busy(TUD_OPT_RHPORT, p_itf->ep_out) ) return;
+ if ( usbd_edpt_busy(rhport, p_itf->ep_out) ) return;
// Prepare for incoming data but only allow what we can store in the ring buffer.
uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff);
if ( max_read >= CFG_TUD_VENDOR_EPSIZE )
{
- usbd_edpt_xfer(TUD_OPT_RHPORT, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE);
+ usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE);
}
}
uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize)
{
vendord_interface_t* p_itf = &_vendord_itf[itf];
- uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, bufsize);
+ uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, (uint16_t) bufsize);
_prep_out_transaction(p_itf);
return num_read;
}
@@ -113,24 +115,36 @@ void tud_vendor_n_read_flush (uint8_t itf)
//--------------------------------------------------------------------+
// Write API
//--------------------------------------------------------------------+
-static bool maybe_transmit(vendord_interface_t* p_itf)
+static uint16_t maybe_transmit(vendord_interface_t* p_itf)
{
+ uint8_t const rhport = 0;
+
// skip if previous transfer not complete
- TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, p_itf->ep_in) );
+ TU_VERIFY( !usbd_edpt_busy(rhport, p_itf->ep_in) );
uint16_t count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE);
if (count > 0)
{
- TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, p_itf->ep_in, p_itf->epin_buf, count) );
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count) );
}
- return true;
+ return count;
}
uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize)
{
vendord_interface_t* p_itf = &_vendord_itf[itf];
- uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, bufsize);
- maybe_transmit(p_itf);
+ uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize);
+ if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) {
+ maybe_transmit(p_itf);
+ }
+ return ret;
+}
+
+uint32_t tud_vendor_n_flush (uint8_t itf)
+{
+ vendord_interface_t* p_itf = &_vendord_itf[itf];
+ uint32_t ret = maybe_transmit(p_itf);
+
return ret;
}
@@ -217,7 +231,7 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui
if ( p_vendor->ep_in ) maybe_transmit(p_vendor);
}
- return (uintptr_t) p_desc - (uintptr_t) desc_itf;
+ return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf);
}
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
@@ -238,7 +252,7 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
if ( ep_addr == p_itf->ep_out )
{
// Receive new data
- tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, xferred_bytes);
+ tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t) xferred_bytes);
// Invoked callback if any
if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf);
@@ -247,6 +261,7 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
}
else if ( ep_addr == p_itf->ep_in )
{
+ if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes);
// Send complete, try to send more if possible
maybe_transmit(p_itf);
}
diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h
index d71c2a3e9..4a873e5fc 100644
--- a/src/class/vendor/vendor_device.h
+++ b/src/class/vendor/vendor_device.h
@@ -52,6 +52,7 @@ uint32_t tud_vendor_n_write_available (uint8_t itf);
static inline
uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str);
+uint32_t tud_vendor_n_flush (uint8_t itf);
//--------------------------------------------------------------------+
// Application API (Single Port)
@@ -64,6 +65,7 @@ static inline void tud_vendor_read_flush (void);
static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize);
static inline uint32_t tud_vendor_write_str (char const* str);
static inline uint32_t tud_vendor_write_available (void);
+static inline uint32_t tud_vendor_flush (void);
//--------------------------------------------------------------------+
// Application Callback API (weak is optional)
@@ -71,6 +73,8 @@ static inline uint32_t tud_vendor_write_available (void);
// Invoked when received new data
TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf);
+// Invoked when last rx transfer finished
+TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes);
//--------------------------------------------------------------------+
// Inline Functions
@@ -121,6 +125,11 @@ static inline uint32_t tud_vendor_write_available (void)
return tud_vendor_n_write_available(0);
}
+static inline uint32_t tud_vendor_flush (void)
+{
+ return tud_vendor_n_flush(0);
+}
+
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
diff --git a/src/class/vendor/vendor_host.c b/src/class/vendor/vendor_host.c
index 1e28e9af4..dbea1228d 100644
--- a/src/class/vendor/vendor_host.c
+++ b/src/class/vendor/vendor_host.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_VENDOR)
+#if (CFG_TUH_ENABLED && CFG_TUH_VENDOR)
//--------------------------------------------------------------------+
// INCLUDE
diff --git a/src/class/vendor/vendor_host.h b/src/class/vendor/vendor_host.h
index 07fa56c61..65223fbca 100644
--- a/src/class/vendor/vendor_host.h
+++ b/src/class/vendor/vendor_host.h
@@ -49,16 +49,16 @@ static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id,
return false;
}
-tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length);
-tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length);
+bool tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length);
+bool tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length);
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
-void cush_init(void);
-tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length);
-void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event);
-void cush_close(uint8_t dev_addr);
+void cush_init(void);
+bool cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length);
+void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event);
+void cush_close(uint8_t dev_addr);
#ifdef __cplusplus
}
diff --git a/src/class/video/video.h b/src/class/video/video.h
index 844746546..e8227ea60 100644
--- a/src/class/video/video.h
+++ b/src/class/video/video.h
@@ -303,6 +303,45 @@ typedef struct TU_ATTR_PACKED {
} tusb_desc_cs_video_fmt_uncompressed_t;
typedef struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint8_t bNumFrameDescriptors;
+ uint8_t bmFlags;
+ uint8_t bDefaultFrameIndex;
+ uint8_t bAspectRatioX;
+ uint8_t bAspectRatioY;
+ uint8_t bmInterlaceFlags;
+ uint8_t bCopyProtect;
+} tusb_desc_cs_video_fmt_mjpeg_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint32_t dwMaxVideoFrameBufferSize; /* deprecated */
+ uint8_t bFormatType;
+} tusb_desc_cs_video_fmt_dv_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint8_t bNumFrameDescriptors;
+ uint8_t guidFormat[16];
+ uint8_t bBitsPerPixel;
+ uint8_t bDefaultFrameIndex;
+ uint8_t bAspectRatioX;
+ uint8_t bAspectRatioY;
+ uint8_t bmInterlaceFlags;
+ uint8_t bCopyProtect;
+ uint8_t bVaribaleSize;
+} tusb_desc_cs_video_fmt_frame_based_t;
+
+typedef struct TU_ATTR_PACKED {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubType;
@@ -318,6 +357,24 @@ typedef struct TU_ATTR_PACKED {
uint32_t dwFrameInterval[];
} tusb_desc_cs_video_frm_uncompressed_t;
+typedef tusb_desc_cs_video_frm_uncompressed_t tusb_desc_cs_video_frm_mjpeg_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFrameIndex;
+ uint8_t bmCapabilities;
+ uint16_t wWidth;
+ uint16_t wHeight;
+ uint32_t dwMinBitRate;
+ uint32_t dwMaxBitRate;
+ uint32_t dwDefaultFrameInterval;
+ uint8_t bFrameIntervalType;
+ uint32_t dwBytesPerLine;
+ uint32_t dwFrameInterval[];
+} tusb_desc_cs_video_frm_frame_based_t;
+
//--------------------------------------------------------------------+
// Requests
//--------------------------------------------------------------------+
@@ -378,8 +435,11 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13
#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9
#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27
+#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26
+#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38
+#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26
#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6
/* 2.2 compression formats */
@@ -462,6 +522,25 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
_frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
+/* Motion-JPEG 3.1.1 Table 3-1 */
+#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG(_fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp) \
+ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_MJPEG, \
+ _fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp
+
+/* Motion-JPEG 3.1.1 Table 3-2 and 3-3 */
+#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \
+ TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_MJPEG, \
+ _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
+ U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \
+ U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep)
+
+/* Motion-JPEG 3.1.1 Table 3-2 and 3-4 */
+#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \
+ TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \
+ TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_MJPEG, \
+ _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
+ U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
+
/* 3.9.2.6 */
#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \
TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \
diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c
index eeb068197..a6d2724c1 100644
--- a/src/class/video/video_device.c
+++ b/src/class/video/video_device.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING)
+#if (CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING)
#include "device/usbd.h"
#include "device/usbd_pvt.h"
@@ -59,6 +59,34 @@ typedef struct TU_ATTR_PACKED {
uint8_t bEntityId;
} tusb_desc_cs_video_entity_itf_t;
+typedef union {
+ struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint8_t bNumFrameDescriptors;
+ };
+ tusb_desc_cs_video_fmt_uncompressed_t uncompressed;
+ tusb_desc_cs_video_fmt_mjpeg_t mjpeg;
+ tusb_desc_cs_video_fmt_frame_based_t frame_based;
+} tusb_desc_cs_video_fmt_t;
+
+typedef union {
+ struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFrameIndex;
+ uint8_t bmCapabilities;
+ uint16_t wWidth;
+ uint16_t wHeight;
+ };
+ tusb_desc_cs_video_frm_uncompressed_t uncompressed;
+ tusb_desc_cs_video_frm_mjpeg_t mjpeg;
+ tusb_desc_cs_video_frm_frame_based_t frame_based;
+} tusb_desc_cs_video_frm_t;
+
/* video streaming interface */
typedef struct TU_ATTR_PACKED {
uint8_t index_vc; /* index of bound video control interface */
@@ -243,6 +271,13 @@ static void const* _find_desc_ep(void const *beg, void const *end)
return end;
}
+/** Return the end of the video control descriptor. */
+static inline void const* _end_of_control_descriptor(void const *desc)
+{
+ tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)desc;
+ return desc + vc->std.bLength + vc->ctl.wTotalLength;
+}
+
/** Find the first entity descriptor with the entity ID
* specified by the argument belonging to the current video control descriptor.
*
@@ -253,10 +288,8 @@ static void const* _find_desc_ep(void const *beg, void const *end)
* @retval end did not found interface descriptor */
static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid)
{
- tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const*)desc;
- void const *beg = vc;
- void const *end = beg + vc->std.bLength + vc->ctl.wTotalLength;
- for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
+ void const *end = _end_of_control_descriptor(desc);
+ for (void const *cur = desc; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur;
if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype
&& itf->bDescriptorSubtype < VIDEO_CS_ITF_VC_MAX)
@@ -276,17 +309,38 @@ static inline void const* _end_of_streaming_descriptor(void const *desc)
}
/** Find the first format descriptor with the specified format number. */
-static inline tusb_desc_cs_video_fmt_uncompressed_t const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum)
+static inline void const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum)
{
- return (tusb_desc_cs_video_fmt_uncompressed_t const*)
- _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, fmtnum);
+ for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
+ uint8_t const *p = (uint8_t const *)cur;
+ uint_fast8_t fmt = p[2];
+ if ((fmt == VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED ||
+ fmt == VIDEO_CS_ITF_VS_FORMAT_MJPEG ||
+ fmt == VIDEO_CS_ITF_VS_FORMAT_DV ||
+ fmt == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) &&
+ fmtnum == p[3]) {
+ return cur;
+ }
+ cur = tu_desc_next(cur);
+ }
+ return end;
}
/** Find the first frame descriptor with the specified format number. */
-static inline tusb_desc_cs_video_frm_uncompressed_t const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum)
+static inline void const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum)
{
- return (tusb_desc_cs_video_frm_uncompressed_t const*)
- _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, frmnum);
+ for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
+ uint8_t const *p = (uint8_t const *)cur;
+ uint_fast8_t frm = p[2];
+ if ((frm == VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED ||
+ frm == VIDEO_CS_ITF_VS_FRAME_MJPEG ||
+ frm == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) &&
+ frmnum == p[3]) {
+ return cur;
+ }
+ cur = tu_desc_next(cur);
+ }
+ return end;
}
/** Set uniquely determined values to variables that have not been set
@@ -297,7 +351,7 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
{
tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
uint_fast8_t fmtnum = param->bFormatIndex;
- TU_ASSERT(fmtnum <= vs->stm.bNumFormats);
+ TU_ASSERT(vs && fmtnum <= vs->stm.bNumFormats);
if (!fmtnum) {
if (1 < vs->stm.bNumFormats) return true; /* Need to negotiate all variables. */
fmtnum = 1;
@@ -307,7 +361,6 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
/* Set the parameters determined by the format */
param->wKeyFrameRate = 1;
param->wPFrameRate = 0;
- param->wCompQuality = 1; /* 1 to 10000 */
param->wCompWindowSize = 1; /* GOP size? */
param->wDelay = 0; /* milliseconds */
param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */
@@ -319,8 +372,18 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
param->bBitDepthLuma = 8;
void const *end = _end_of_streaming_descriptor(vs);
- tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
+ tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
TU_ASSERT(fmt != end);
+
+ switch (fmt->bDescriptorSubType) {
+ case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
+ param->wCompQuality = 1; /* 1 to 10000 */
+ break;
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+ break;
+ default: return false;
+ }
+
uint_fast8_t frmnum = param->bFrameIndex;
TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors);
if (!frmnum) {
@@ -328,28 +391,39 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
frmnum = 1;
param->bFrameIndex = 1;
}
- tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
+ tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
TU_ASSERT(frm != end);
/* Set the parameters determined by the frame */
uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
if (!frame_size) {
- frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8;
+ switch (fmt->bDescriptorSubType) {
+ case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
+ frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8;
+ break;
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+ frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
+ break;
+ default: break;
+ }
param->dwMaxVideoFrameSize = frame_size;
}
uint_fast32_t interval = param->dwFrameInterval;
if (!interval) {
- if ((1 < frm->bFrameIntervalType) ||
- ((0 == frm->bFrameIntervalType) && (frm->dwFrameInterval[1] != frm->dwFrameInterval[0]))) {
+ if ((1 < frm->uncompressed.bFrameIntervalType) ||
+ ((0 == frm->uncompressed.bFrameIntervalType) &&
+ (frm->uncompressed.dwFrameInterval[1] != frm->uncompressed.dwFrameInterval[0]))) {
return true;
}
- interval = frm->dwFrameInterval[0];
+ interval = frm->uncompressed.dwFrameInterval[0];
param->dwFrameInterval = interval;
}
uint_fast32_t interval_ms = interval / 10000;
TU_ASSERT(interval_ms);
uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2;
+ if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size)
+ payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE;
param->dwMaxPayloadTransferSize = payload_size;
return true;
}
@@ -366,7 +440,8 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
if (!fmtnum) {
switch (request) {
case VIDEO_REQUEST_GET_MAX:
- param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats;
+ if (_get_desc_vs(stm))
+ param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats;
break;
case VIDEO_REQUEST_GET_MIN:
case VIDEO_REQUEST_GET_DEF:
@@ -393,8 +468,9 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
uint_fast8_t frmnum = param->bFrameIndex;
if (!frmnum) {
tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
+ TU_ASSERT(vs);
void const *end = _end_of_streaming_descriptor(vs);
- tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
+ tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
switch (request) {
case VIDEO_REQUEST_GET_MAX:
frmnum = fmt->bNumFrameDescriptors;
@@ -403,31 +479,50 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
frmnum = 1;
break;
case VIDEO_REQUEST_GET_DEF:
- frmnum = fmt->bDefaultFrameIndex;
+ switch (fmt->bDescriptorSubType) {
+ case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
+ frmnum = fmt->uncompressed.bDefaultFrameIndex;
+ break;
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+ frmnum = fmt->mjpeg.bDefaultFrameIndex;
+ break;
+ default: return false;
+ }
break;
default: return false;
}
- param->bFrameIndex = frmnum;
+ param->bFrameIndex = (uint8_t)frmnum;
/* Set the parameters determined by the frame */
- tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
- param->dwMaxVideoFrameSize = frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8;
+ tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
+ uint_fast32_t frame_size;
+ switch (fmt->bDescriptorSubType) {
+ case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
+ frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8;
+ break;
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+ frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
+ break;
+ default: return false;
+ }
+ param->dwMaxVideoFrameSize = frame_size;
return true;
}
if (!param->dwFrameInterval) {
tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
+ TU_ASSERT(vs);
void const *end = _end_of_streaming_descriptor(vs);
- tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
- tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
+ tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
+ tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
uint_fast32_t interval, interval_ms;
switch (request) {
case VIDEO_REQUEST_GET_MAX:
{
uint_fast32_t min_interval, max_interval;
- uint_fast8_t num_intervals = frm->bFrameIntervalType;
- max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1];
- min_interval = frm->dwFrameInterval[0];
+ uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
+ max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
+ min_interval = frm->uncompressed.dwFrameInterval[0];
interval = max_interval;
interval_ms = min_interval / 10000;
}
@@ -435,24 +530,24 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
case VIDEO_REQUEST_GET_MIN:
{
uint_fast32_t min_interval, max_interval;
- uint_fast8_t num_intervals = frm->bFrameIntervalType;
- max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1];
- min_interval = frm->dwFrameInterval[0];
+ uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
+ max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
+ min_interval = frm->uncompressed.dwFrameInterval[0];
interval = min_interval;
interval_ms = max_interval / 10000;
}
break;
case VIDEO_REQUEST_GET_DEF:
- interval = frm->dwDefaultFrameInterval;
+ interval = frm->uncompressed.dwDefaultFrameInterval;
interval_ms = interval / 10000;
break;
case VIDEO_REQUEST_GET_RES:
{
- uint_fast8_t num_intervals = frm->bFrameIntervalType;
+ uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
if (num_intervals) {
interval = 0;
} else {
- interval = frm->dwFrameInterval[2];
+ interval = frm->uncompressed.dwFrameInterval[2];
interval_ms = interval / 10000;
}
}
@@ -464,11 +559,15 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
param->dwMaxPayloadTransferSize = 0;
} else {
uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
+ uint_fast32_t payload_size;
if (!interval_ms) {
- param->dwMaxPayloadTransferSize = frame_size + 2;
+ payload_size = frame_size + 2;
} else {
- param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2;
+ payload_size = (frame_size + interval_ms - 1) / interval_ms + 2;
}
+ if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size)
+ payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE;
+ param->dwMaxPayloadTransferSize = payload_size;
}
return true;
}
@@ -485,7 +584,7 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self)
/* The next descriptor after the class-specific VC interface header descriptor. */
void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.bLength;
/* The end of the video control interface descriptor. */
- void const *end = (void const*)vc + vc->std.bLength + vc->ctl.wTotalLength;
+ void const *end = _end_of_control_descriptor(vc);
if (vc->std.bNumEndpoints) {
/* Find the notification endpoint descriptor. */
cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT);
@@ -517,7 +616,7 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t
TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING);
/* Update to point the end of the video control interface descriptor. */
- end = cur + vc->std.bLength + vc->ctl.wTotalLength;
+ end = _end_of_control_descriptor(cur);
/* Advance to the next descriptor after the class-specific VC interface header descriptor. */
cur += vc->std.bLength + vc->ctl.bLength;
TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints);
@@ -532,7 +631,7 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t
/* Open the notification endpoint */
TU_ASSERT(usbd_edpt_open(rhport, notif));
}
- self->cur = (void const*)vc - beg;
+ self->cur = (uint16_t) ((void const*)vc - beg);
return true;
}
@@ -550,7 +649,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) {
uint_fast16_t ofs_ep = stm->desc.ep[i];
if (!ofs_ep) break;
- uint_fast8_t ep_adr = _desc_ep_addr(desc + ofs_ep);
+ uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep);
usbd_edpt_close(rhport, ep_adr);
stm->desc.ep[i] = 0;
TU_LOG2(" close EP%02x\n", ep_adr);
@@ -567,13 +666,14 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
TU_VERIFY(cur < end);
uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints;
TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep));
- stm->desc.cur = cur - desc; /* Save the offset of the new settings */
+ stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */
if (!altnum) {
/* initialize streaming settings */
stm->max_payload_transfer_size = 0;
video_probe_and_commit_control_t *param =
(video_probe_and_commit_control_t *)&stm->ep_buf;
tu_memclr(param, sizeof(*param));
+ TU_LOG2(" done 0\n");
return _update_streaming_parameters(stm, param);
}
/* Open endpoints of the new settings. */
@@ -594,7 +694,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
stm->max_payload_transfer_size = max_size;
}
TU_ASSERT(usbd_edpt_open(rhport, ep));
- stm->desc.ep[i] = cur - desc;
+ stm->desc.ep[i] = (uint16_t) (cur - desc);
TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur));
}
/* initialize payload header */
@@ -602,6 +702,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
hdr->bHeaderLength = sizeof(*hdr);
hdr->bmHeaderInfo = 0;
+ TU_LOG2(" done\n");
return true;
}
@@ -674,7 +775,7 @@ static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage,
if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN);
- } else if (stage == CONTROL_STAGE_ACK) {
+ } else if (stage == CONTROL_STAGE_DATA) {
if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode);
}
return VIDEO_ERROR_NONE;
@@ -819,7 +920,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)),
VIDEO_ERROR_UNKNOWN);
- } else if (stage == CONTROL_STAGE_ACK) {
+ } else if (stage == CONTROL_STAGE_DATA) {
TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf),
VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
}
@@ -843,7 +944,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
video_probe_and_commit_control_t tmp;
tmp = *(video_probe_and_commit_control_t*)&self->ep_buf;
TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
- TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
+ TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN);
}
return VIDEO_ERROR_NONE;
@@ -860,7 +961,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
if (stage == CONTROL_STAGE_SETUP)
{
TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
- TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN);
+ TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t)&_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN);
}
return VIDEO_ERROR_NONE;
@@ -874,7 +975,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
- } else if (stage == CONTROL_STAGE_ACK) {
+ } else if (stage == CONTROL_STAGE_DATA) {
TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
if (tud_video_commit_cb) {
return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf);
@@ -976,7 +1077,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
/* Find EP address */
void const *desc = _videod_itf[stm->index_vc].beg;
- uint_fast8_t ep_addr = 0;
+ uint8_t ep_addr = 0;
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
uint_fast16_t ofs_ep = stm->desc.ep[i];
if (!ofs_ep) continue;
@@ -985,7 +1086,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
}
if (!ep_addr) return false;
- TU_VERIFY( usbd_edpt_claim(0, ep_addr));
+ TU_VERIFY( usbd_edpt_claim(0, ep_addr) );
/* update the packet header */
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf;
hdr->FrameID ^= 1;
@@ -994,7 +1095,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
stm->buffer = (uint8_t*)buffer;
stm->bufsize = bufsize;
uint_fast16_t pkt_len = _prepare_in_payload(stm);
- TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, pkt_len), 0);
+ TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
return true;
}
@@ -1034,7 +1135,7 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
/* Find available interface */
videod_interface_t *self = NULL;
- uint_fast8_t ctl_idx;
+ uint8_t ctl_idx;
for (ctl_idx = 0; ctl_idx < CFG_TUD_VIDEO; ++ctl_idx) {
if (_videod_itf[ctl_idx].beg) continue;
self = &_videod_itf[ctl_idx];
@@ -1051,10 +1152,10 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
uint_fast8_t bInCollection = vc->ctl.bInCollection;
/* Find the end of the video interface descriptor */
void const *cur = _next_desc_itf(itf_desc, end);
- for (uint_fast8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) {
+ for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) {
videod_streaming_interface_t *stm = NULL;
/* find free streaming interface handle */
- for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
+ for (uint8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
if (_videod_streaming_itf[i].desc.beg) continue;
stm = &_videod_streaming_itf[i];
self->stm[stm_idx] = i;
@@ -1063,12 +1164,12 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
TU_ASSERT(stm, 0);
stm->index_vc = ctl_idx;
stm->index_vs = stm_idx;
- stm->desc.beg = (uintptr_t)cur - (uintptr_t)itf_desc;
+ stm->desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
cur = _next_desc_itf(cur, end);
- stm->desc.end = (uintptr_t)cur - (uintptr_t)itf_desc;
+ stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
}
- self->len = (uintptr_t)cur - (uintptr_t)itf_desc;
- return (uintptr_t)cur - (uintptr_t)itf_desc;
+ self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
+ return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
}
// Invoked when a control transfer occurred on an interface of this class
@@ -1134,7 +1235,7 @@ bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
/* Claim the endpoint */
TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0);
uint_fast16_t pkt_len = _prepare_in_payload(stm);
- TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, pkt_len), 0);
+ TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
} else {
stm->buffer = NULL;
stm->bufsize = 0;
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index 9b9e2b007..b1ee40a1a 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -38,6 +38,7 @@
#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) )
#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) )
+#define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low)))
#define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff))
#define TU_U16_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff))
#define U16_TO_U8S_BE(_u16) TU_U16_HIGH(_u16), TU_U16_LOW(_u16)
@@ -70,24 +71,11 @@
#include "tusb_compiler.h"
#include "tusb_verify.h"
#include "tusb_types.h"
+#include "tusb_debug.h"
-#include "tusb_error.h" // TODO remove
#include "tusb_timeout.h" // TODO remove
//--------------------------------------------------------------------+
-// Internal Helper used by Host and Device Stack
-//--------------------------------------------------------------------+
-
-// Check if endpoint descriptor is valid per USB specs
-bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed);
-
-// Bind all endpoint of a interface descriptor to class driver
-void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
-
-// Calculate total length of n interfaces (depending on IAD)
-uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len);
-
-//--------------------------------------------------------------------+
// Internal Inline Functions
//--------------------------------------------------------------------+
@@ -146,12 +134,6 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { retur
//------------- Mathematics -------------//
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)
-{
- return (lower <= value) && (value <= upper);
-}
-
// log2 of a value is its MSB's position
// TODO use clz TODO remove
static inline uint8_t tu_log2(uint32_t value)
@@ -161,6 +143,16 @@ static inline uint8_t tu_log2(uint32_t value)
return result;
}
+//static inline uint8_t tu_log2(uint32_t value)
+//{
+// return sizeof(uint32_t) * CHAR_BIT - __builtin_clz(x) - 1;
+//}
+
+static inline bool tu_is_power_of_two(uint32_t value)
+{
+ return (value != 0) && ((value & (value - 1)) == 0);
+}
+
//------------- Unaligned Access -------------//
#if TUP_ARCH_STRICT_ALIGN
@@ -267,138 +259,6 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16 (void* mem, ui
+ TU_BIN8(dlsb))
#endif
-//--------------------------------------------------------------------+
-// Debug Function
-//--------------------------------------------------------------------+
-
-// CFG_TUSB_DEBUG for debugging
-// 0 : no debug
-// 1 : print error
-// 2 : print warning
-// 3 : print info
-#if CFG_TUSB_DEBUG
-
-void tu_print_mem(void const *buf, uint32_t count, uint8_t indent);
-
-#ifdef CFG_TUSB_DEBUG_PRINTF
- extern int CFG_TUSB_DEBUG_PRINTF(const char *format, ...);
- #define tu_printf CFG_TUSB_DEBUG_PRINTF
-#else
- #define tu_printf printf
-#endif
-
-static inline
-void tu_print_var(uint8_t const* buf, uint32_t bufsize)
-{
- for(uint32_t i=0; i<bufsize; i++) tu_printf("%02X ", buf[i]);
-}
-
-// Log with Level
-#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__)
-
-// Log Level 1: Error
-#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\r\n", (unsigned long) (_x) )
-#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (unsigned long) (_x) )
-
-// Log Level 2: Warn
-#if CFG_TUSB_DEBUG >= 2
- #define TU_LOG2 TU_LOG1
- #define TU_LOG2_MEM TU_LOG1_MEM
- #define TU_LOG2_VAR TU_LOG1_VAR
- #define TU_LOG2_INT TU_LOG1_INT
- #define TU_LOG2_HEX TU_LOG1_HEX
-#endif
-
-// Log Level 3: Info
-#if CFG_TUSB_DEBUG >= 3
- #define TU_LOG3 TU_LOG1
- #define TU_LOG3_MEM TU_LOG1_MEM
- #define TU_LOG3_VAR TU_LOG1_VAR
- #define TU_LOG3_INT TU_LOG1_INT
- #define TU_LOG3_HEX TU_LOG1_HEX
-#endif
-
-typedef struct
-{
- uint32_t key;
- const char* data;
-} tu_lookup_entry_t;
-
-typedef struct
-{
- uint16_t count;
- tu_lookup_entry_t const* items;
-} tu_lookup_table_t;
-
-static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key)
-{
- static char not_found[11];
-
- for(uint16_t i=0; i<p_table->count; i++)
- {
- if (p_table->items[i].key == key) return p_table->items[i].data;
- }
-
- // not found return the key value in hex
- sprintf(not_found, "0x%08lX", (unsigned long) key);
-
- return not_found;
-}
-
-#endif // CFG_TUSB_DEBUG
-
-#ifndef TU_LOG
-#define TU_LOG(n, ...)
-#define TU_LOG_MEM(n, ...)
-#define TU_LOG_VAR(n, ...)
-#define TU_LOG_INT(n, ...)
-#define TU_LOG_HEX(n, ...)
-#define TU_LOG_LOCATION()
-#define TU_LOG_FAILED()
-#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(...)
- #define TU_LOG1_VAR(...)
- #define TU_LOG1_INT(...)
- #define TU_LOG1_HEX(...)
-#endif
-
-#ifndef TU_LOG2
- #define TU_LOG2(...)
- #define TU_LOG2_MEM(...)
- #define TU_LOG2_VAR(...)
- #define TU_LOG2_INT(...)
- #define TU_LOG2_HEX(...)
-#endif
-
-#ifndef TU_LOG3
- #define TU_LOG3(...)
- #define TU_LOG3_MEM(...)
- #define TU_LOG3_VAR(...)
- #define TU_LOG3_INT(...)
- #define TU_LOG3_HEX(...)
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
index d3284c62a..2c30daf6f 100644
--- a/src/common/tusb_compiler.h
+++ b/src/common/tusb_compiler.h
@@ -51,10 +51,10 @@
#endif
// Compile-time Assert
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
- #define TU_VERIFY_STATIC _Static_assert
-#elif defined (__cplusplus) && __cplusplus >= 201103L
+#if defined (__cplusplus) && __cplusplus >= 201103L
#define TU_VERIFY_STATIC static_assert
+#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+ #define TU_VERIFY_STATIC _Static_assert
#elif defined(__CCRX__)
#define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(Line, __LINE__)[(const_expr) ? 1 : 0];
#else
@@ -75,7 +75,11 @@
* Nth position is the same as the number of arguments
* - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma)
*------------------------------------------------------------------*/
-#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__,_RSEQ_N())
+#if !defined(__CCRX__)
+#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__,_RSEQ_N())
+#else
+#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__,_RSEQ_N())
+#endif
#define _TU_NARG(...) _GET_NTH_ARG(__VA_ARGS__)
#define _GET_NTH_ARG( \
@@ -127,6 +131,12 @@
#define TU_ATTR_BIT_FIELD_ORDER_BEGIN
#define TU_ATTR_BIT_FIELD_ORDER_END
+ #if __has_attribute(__fallthrough__)
+ #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
+ #else
+ #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
+ #endif
+
// Endian conversion use well-known host to network (big endian) naming
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
@@ -137,9 +147,11 @@
#define TU_BSWAP16(u16) (__builtin_bswap16(u16))
#define TU_BSWAP32(u32) (__builtin_bswap32(u32))
+ #ifndef __ARMCC_VERSION
// 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
+ #pragma GCC poison tud_vendor_control_request_cb
+ #endif
#elif defined(__TI_COMPILER_VERSION__)
#define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
@@ -150,6 +162,7 @@
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
#define TU_ATTR_USED __attribute__ ((used))
+ #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
#define TU_ATTR_PACKED_BEGIN
#define TU_ATTR_PACKED_END
@@ -176,6 +189,7 @@
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
#define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used
+ #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
#define TU_ATTR_PACKED_BEGIN
#define TU_ATTR_PACKED_END
@@ -201,6 +215,7 @@
#define TU_ATTR_DEPRECATED(mess)
#define TU_ATTR_UNUSED
#define TU_ATTR_USED
+ #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
#define TU_ATTR_PACKED_BEGIN _Pragma("pack")
#define TU_ATTR_PACKED_END _Pragma("packoption")
@@ -221,6 +236,7 @@
#error "Compiler attribute porting is required"
#endif
+
#if (TU_BYTE_ORDER == TU_LITTLE_ENDIAN)
#define tu_htons(u16) (TU_BSWAP16(u16))
diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h
new file mode 100644
index 000000000..ac5bee6ec
--- /dev/null
+++ b/src/common/tusb_debug.h
@@ -0,0 +1,178 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_DEBUG_H_
+#define _TUSB_DEBUG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Debug
+//--------------------------------------------------------------------+
+
+// CFG_TUSB_DEBUG for debugging
+// 0 : no debug
+// 1 : print error
+// 2 : print warning
+// 3 : print info
+#if CFG_TUSB_DEBUG
+
+// Enum to String for debugging purposes
+#if CFG_TUSB_DEBUG >= 2
+extern char const* const tu_str_speed[];
+extern char const* const tu_str_std_request[];
+#endif
+
+void tu_print_mem(void const *buf, uint32_t count, uint8_t indent);
+
+#ifdef CFG_TUSB_DEBUG_PRINTF
+ extern int CFG_TUSB_DEBUG_PRINTF(const char *format, ...);
+ #define tu_printf CFG_TUSB_DEBUG_PRINTF
+#else
+ #define tu_printf printf
+#endif
+
+static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize)
+{
+ for(uint32_t i=0; i<bufsize; i++) tu_printf("%02X ", buf[i]);
+}
+
+// Log with Level
+#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_ARR(n, ...) TU_XSTRCAT3(TU_LOG, n, _ARR)(__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__)
+
+// Log Level 1: Error
+#define TU_LOG1 tu_printf
+#define TU_LOG1_MEM tu_print_mem
+#define TU_LOG1_ARR(_x, _n) tu_print_arr((uint8_t const*)(_x), _n)
+#define TU_LOG1_VAR(_x) tu_print_arr((uint8_t const*)(_x), sizeof(*(_x)))
+#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (unsigned long) (_x) )
+#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (unsigned long) (_x) )
+
+// Log Level 2: Warn
+#if CFG_TUSB_DEBUG >= 2
+ #define TU_LOG2 TU_LOG1
+ #define TU_LOG2_MEM TU_LOG1_MEM
+ #define TU_LOG2_ARR TU_LOG1_ARR
+ #define TU_LOG2_VAR TU_LOG1_VAR
+ #define TU_LOG2_INT TU_LOG1_INT
+ #define TU_LOG2_HEX TU_LOG1_HEX
+#endif
+
+// Log Level 3: Info
+#if CFG_TUSB_DEBUG >= 3
+ #define TU_LOG3 TU_LOG1
+ #define TU_LOG3_MEM TU_LOG1_MEM
+ #define TU_LOG3_ARR TU_LOG1_ARR
+ #define TU_LOG3_VAR TU_LOG1_VAR
+ #define TU_LOG3_INT TU_LOG1_INT
+ #define TU_LOG3_HEX TU_LOG1_HEX
+#endif
+
+typedef struct
+{
+ uint32_t key;
+ const char* data;
+} tu_lookup_entry_t;
+
+typedef struct
+{
+ uint16_t count;
+ tu_lookup_entry_t const* items;
+} tu_lookup_table_t;
+
+static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key)
+{
+ static char not_found[11];
+
+ for(uint16_t i=0; i<p_table->count; i++)
+ {
+ if (p_table->items[i].key == key) return p_table->items[i].data;
+ }
+
+ // not found return the key value in hex
+ snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key);
+
+ return not_found;
+}
+
+#endif // CFG_TUSB_DEBUG
+
+#ifndef TU_LOG
+ #define TU_LOG(n, ...)
+ #define TU_LOG_MEM(n, ...)
+ #define TU_LOG_VAR(n, ...)
+ #define TU_LOG_INT(n, ...)
+ #define TU_LOG_HEX(n, ...)
+ #define TU_LOG_LOCATION()
+ #define TU_LOG_FAILED()
+#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(...)
+ #define TU_LOG1_VAR(...)
+ #define TU_LOG1_INT(...)
+ #define TU_LOG1_HEX(...)
+#endif
+
+#ifndef TU_LOG2
+ #define TU_LOG2(...)
+ #define TU_LOG2_MEM(...)
+ #define TU_LOG2_VAR(...)
+ #define TU_LOG2_INT(...)
+ #define TU_LOG2_HEX(...)
+#endif
+
+#ifndef TU_LOG3
+ #define TU_LOG3(...)
+ #define TU_LOG3_MEM(...)
+ #define TU_LOG3_VAR(...)
+ #define TU_LOG3_INT(...)
+ #define TU_LOG3_HEX(...)
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_DEBUG_H_ */
diff --git a/src/common/tusb_error.h b/src/common/tusb_error.h
deleted file mode 100644
index d7ad8c318..000000000
--- a/src/common/tusb_error.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-/** \ingroup Group_Common
- * \defgroup Group_Error Error Codes
- * @{ */
-
-#ifndef _TUSB_ERRORS_H_
-#define _TUSB_ERRORS_H_
-
-#include "tusb_option.h"
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#define ERROR_ENUM(x) x,
-#define ERROR_STRING(x) #x,
-
-#define ERROR_TABLE(ENTRY) \
- ENTRY(TUSB_ERROR_NONE )\
- ENTRY(TUSB_ERROR_INVALID_PARA )\
- ENTRY(TUSB_ERROR_DEVICE_NOT_READY )\
- ENTRY(TUSB_ERROR_INTERFACE_IS_BUSY )\
- ENTRY(TUSB_ERROR_HCD_OPEN_PIPE_FAILED )\
- ENTRY(TUSB_ERROR_OSAL_TIMEOUT )\
- ENTRY(TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED )\
- ENTRY(TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED )\
- ENTRY(TUSB_ERROR_NOT_SUPPORTED )\
- ENTRY(TUSB_ERROR_NOT_ENOUGH_MEMORY )\
- ENTRY(TUSB_ERROR_FAILED )\
-
-/// \brief Error Code returned
-/// TODO obsolete and to be remove
-typedef enum
-{
- ERROR_TABLE(ERROR_ENUM)
- TUSB_ERROR_COUNT
-}tusb_error_t;
-
-#if CFG_TUSB_DEBUG
-/// Enum to String for debugging purposes. Only available if \ref CFG_TUSB_DEBUG > 0
-extern char const* const tusb_strerr[TUSB_ERROR_COUNT];
-#endif
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif /* _TUSB_ERRORS_H_ */
-
-/** @} */
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
index 564687e02..895b9208b 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -79,7 +79,7 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si
// Limit index space to 2*depth - this allows for a fast "modulo" calculation
// but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable
// only if overflow happens once (important for unsupervised DMA applications)
- f->max_pointer_idx = 2*depth - 1;
+ f->max_pointer_idx = (uint16_t) (2*depth - 1);
f->non_used_index_space = UINT16_MAX - f->max_pointer_idx;
f->rd_idx = f->wr_idx = 0;
@@ -205,7 +205,7 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t
uint8_t rem = nLin_bytes & 0x03;
if (rem > 0)
{
- uint8_t remrem = tu_min16(nWrap_bytes, 4-rem);
+ uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem);
nWrap_bytes -= remrem;
uint32_t tmp32 = *rx_fifo;
@@ -288,7 +288,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu
uint8_t rem = nLin_bytes & 0x03;
if (rem > 0)
{
- uint8_t remrem = tu_min16(nWrap_bytes, 4-rem);
+ uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem);
nWrap_bytes -= remrem;
uint32_t tmp32=0;
@@ -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
if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx))
{
- p = (p + offset) + f->non_used_index_space;
+ p = (uint16_t) ((p + offset) + f->non_used_index_space);
}
else
{
@@ -342,7 +342,7 @@ static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
// We are exploiting the wrap around to the correct index
if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx))
{
- p = (p - offset) - f->non_used_index_space;
+ p = (uint16_t) ((p - offset) - f->non_used_index_space);
}
else
{
@@ -716,7 +716,7 @@ 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)
{
_ff_lock(f->mutex_rd);
- bool ret = _tu_fifo_peek_n(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC);
+ uint16_t ret = _tu_fifo_peek_n(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC);
_ff_unlock(f->mutex_rd);
return ret;
}
@@ -741,21 +741,28 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data)
{
_ff_lock(f->mutex_wr);
- uint16_t w = f->wr_idx;
+ bool ret;
+ uint16_t const w = f->wr_idx;
- if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable ) return false;
+ if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable )
+ {
+ ret = false;
+ }else
+ {
+ uint16_t wRel = get_relative_pointer(f, w);
- uint16_t wRel = get_relative_pointer(f, w);
+ // Write data
+ _ff_push(f, data, wRel);
- // Write data
- _ff_push(f, data, wRel);
+ // Advance pointer
+ f->wr_idx = advance_pointer(f, w, 1);
- // Advance pointer
- f->wr_idx = advance_pointer(f, w, 1);
+ ret = true;
+ }
_ff_unlock(f->mutex_wr);
- return true;
+ return ret;
}
/******************************************************************************/
@@ -811,7 +818,7 @@ bool tu_fifo_clear(tu_fifo_t *f)
_ff_lock(f->mutex_rd);
f->rd_idx = f->wr_idx = 0;
- f->max_pointer_idx = 2*f->depth-1;
+ f->max_pointer_idx = (uint16_t) (2*f->depth-1);
f->non_used_index_space = UINT16_MAX - f->max_pointer_idx;
_ff_unlock(f->mutex_wr);
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
new file mode 100644
index 000000000..86c68baf8
--- /dev/null
+++ b/src/common/tusb_mcu.h
@@ -0,0 +1,299 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_MCU_H_
+#define TUSB_MCU_H_
+
+//--------------------------------------------------------------------+
+// Port Specific
+// TUP stand for TinyUSB Port (can be renamed)
+//--------------------------------------------------------------------+
+
+//------------- Unaligned Memory Access -------------//
+
+// ARMv7+ (M3-M7, M23-M33) can access unaligned memory
+#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7))
+ #define TUP_ARCH_STRICT_ALIGN 0
+#else
+ #define TUP_ARCH_STRICT_ALIGN 1
+#endif
+
+/* USB Controller Attributes for Device, Host or MCU (both)
+ * - ENDPOINT_MAX: max (logical) number of endpoint
+ * - ENDPOINT_EXCLUSIVE_NUMBER: endpoint number with different direction IN and OUT aren't allowed,
+ * e.g EP1 OUT & EP1 IN cannot exist together
+ * - RHPORT_HIGHSPEED: support highspeed with on-chip PHY
+ */
+
+//------------- NXP -------------//
+#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
+ #define TUP_DCD_ENDPOINT_MAX 5
+
+#elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX)
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_USBIP_OHCI
+
+#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+ // TODO USB0 has 6, USB1 has 4
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 FS
+
+#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX)
+ #define TUP_DCD_ENDPOINT_MAX 5
+
+#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX)
+ // TODO USB0 has 5, USB1 has 6
+ #define TUP_DCD_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(OPT_MCU_LPC55XX)
+ // TODO USB0 has 5, USB1 has 6
+ #define TUP_DCD_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(OPT_MCU_MIMXRT)
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 HS
+
+#elif TU_CHECK_MCU(OPT_MCU_MKL25ZXX, OPT_MCU_K32L2BXX)
+ #define TUP_DCD_ENDPOINT_MAX 16
+
+#elif TU_CHECK_MCU(OPT_MCU_MM32F327X)
+ #define TUP_DCD_ENDPOINT_MAX 16
+
+//------------- Nordic -------------//
+#elif TU_CHECK_MCU(OPT_MCU_NRF5X)
+ // 8 CBI + 1 ISO
+ #define TUP_DCD_ENDPOINT_MAX 9
+
+//------------- Microchip -------------//
+#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \
+ TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_SAMG)
+ #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+
+#elif TU_CHECK_MCU(OPT_MCU_SAMX7X)
+ #define TUP_DCD_ENDPOINT_MAX 10
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+
+#elif TU_CHECK_MCU(OPT_MCU_PIC32MZ)
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+
+#elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || \
+ TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33)
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+
+//------------- ST -------------//
+#elif TU_CHECK_MCU(OPT_MCU_STM32F0)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32F1)
+ #if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
+ defined (STM32F107xB) || defined (STM32F107xC)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ #define TUP_DCD_ENDPOINT_MAX 4
+ #else
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #endif
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32F2)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ // FS has 4 ep, HS has 5 ep
+ #define TUP_DCD_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32F3)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ // For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9
+ #define TUP_DCD_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32F7)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ // FS has 6, HS has 9
+ #define TUP_DCD_ENDPOINT_MAX 9
+
+ // MCU with on-chip HS Phy
+ #if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx)
+ #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS
+ #endif
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ #define TUP_DCD_ENDPOINT_MAX 9
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32L4)
+ #if defined (STM32L475xx) || defined (STM32L476xx) || \
+ defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
+ defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \
+ defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
+ defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ #define TUP_DCD_ENDPOINT_MAX 6
+ #else
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #endif
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32U5)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+ #define TUP_DCD_ENDPOINT_MAX 6
+
+//------------- Sony -------------//
+#elif TU_CHECK_MCU(OPT_MCU_CXD56)
+ #define TUP_DCD_ENDPOINT_MAX 7
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+
+//------------- TI -------------//
+#elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+//------------- ValentyUSB -------------//
+#elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI)
+ #define TUP_DCD_ENDPOINT_MAX 16
+
+//------------- Nuvoton -------------//
+#elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_NUC120)
+ #define TUP_DCD_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(OPT_MCU_NUC505)
+ #define TUP_DCD_ENDPOINT_MAX 12
+ #define TUP_RHPORT_HIGHSPEED 1
+
+//------------- Espressif -------------//
+#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ #define TUP_USBIP_DWC2
+ #define TUP_DCD_ENDPOINT_MAX 6
+
+//------------- Dialog -------------//
+#elif TU_CHECK_MCU(OPT_MCU_DA1469X)
+ #define TUP_DCD_ENDPOINT_MAX 4
+
+//------------- Raspberry Pi -------------//
+#elif TU_CHECK_MCU(OPT_MCU_RP2040)
+ #define TUP_DCD_ENDPOINT_MAX 16
+
+ #define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
+
+//------------- Silabs -------------//
+#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
+ #define TUP_USBIP_DWC2
+ #define TUP_DCD_ENDPOINT_MAX 7
+
+//------------- Renesas -------------//
+#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
+ #define TUP_DCD_ENDPOINT_MAX 10
+
+//------------- GigaDevice -------------//
+#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
+ #define TUP_USBIP_DWC2
+ #define TUP_DCD_ENDPOINT_MAX 4
+
+//------------- Broadcom -------------//
+#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
+ #define TUP_USBIP_DWC2
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
+
+//------------- Broadcom -------------//
+#elif TU_CHECK_MCU(OPT_MCU_XMC4000)
+ #define TUP_USBIP_DWC2
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+//------------- BridgeTek -------------//
+#elif TU_CHECK_MCU(OPT_MCU_FT90X)
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
+
+#elif TU_CHECK_MCU(OPT_MCU_FT93X)
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_RHPORT_HIGHSPEED 1
+
+//------------ Allwinner -------------//
+#elif TU_CHECK_MCU(OPT_MCU_F1C100S)
+ #define TUP_DCD_ENDPOINT_MAX 4
+
+#endif
+
+//--------------------------------------------------------------------+
+// Default Values
+//--------------------------------------------------------------------+
+
+#ifndef TUP_DCD_ENDPOINT_MAX
+ #warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8"
+ #define TUP_DCD_ENDPOINT_MAX 8
+#endif
+
+// Default to fullspeed if not defined
+#ifndef TUP_RHPORT_HIGHSPEED
+ #define TUP_RHPORT_HIGHSPEED 0
+#endif
+
+// fast function, normally mean placing function in SRAM
+#ifndef TU_ATTR_FAST_FUNC
+ #define TU_ATTR_FAST_FUNC
+#endif
+
+#endif
diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h
new file mode 100644
index 000000000..b34506f65
--- /dev/null
+++ b/src/common/tusb_private.h
@@ -0,0 +1,65 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+
+#ifndef _TUSB_PRIVATE_H_
+#define _TUSB_PRIVATE_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef struct TU_ATTR_PACKED
+{
+ volatile uint8_t busy : 1;
+ volatile uint8_t stalled : 1;
+ volatile uint8_t claimed : 1;
+}tu_edpt_state_t;
+
+//--------------------------------------------------------------------+
+// Internal Helper used by Host and Device Stack
+//--------------------------------------------------------------------+
+
+// Check if endpoint descriptor is valid per USB specs
+bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed);
+
+// Bind all endpoint of a interface descriptor to class driver
+void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
+
+// Calculate total length of n interfaces (depending on IAD)
+uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len);
+
+// Claim an endpoint with provided mutex
+bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex);
+
+// Release an endpoint with provided mutex
+bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_PRIVATE_H_ */
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
index 5b26f5aec..e11f08dd1 100644
--- a/src/common/tusb_types.h
+++ b/src/common/tusb_types.h
@@ -223,19 +223,13 @@ enum {
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
-/// Device State TODO remove
-typedef enum
-{
- TUSB_DEVICE_STATE_UNPLUG = 0 ,
- TUSB_DEVICE_STATE_CONFIGURED ,
- TUSB_DEVICE_STATE_SUSPENDED ,
-}tusb_device_state_t;
-
typedef enum
{
XFER_RESULT_SUCCESS,
XFER_RESULT_FAILED,
XFER_RESULT_STALLED,
+ XFER_RESULT_TIMEOUT,
+ XFER_RESULT_INVALID
}xfer_result_t;
enum // TODO remove
@@ -265,6 +259,7 @@ typedef enum
enum
{
+ CONTROL_STAGE_IDLE,
CONTROL_STAGE_SETUP,
CONTROL_STAGE_DATA,
CONTROL_STAGE_ACK
@@ -497,42 +492,56 @@ TU_ATTR_BIT_FIELD_ORDER_END
//--------------------------------------------------------------------+
// Get direction from Endpoint address
-static inline tusb_dir_t tu_edpt_dir(uint8_t addr)
+TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr)
{
return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
}
// Get Endpoint number from address
-static inline uint8_t tu_edpt_number(uint8_t addr)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr)
{
return (uint8_t)(addr & (~TUSB_DIR_IN_MASK));
}
-static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
{
return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0));
}
-static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep)
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep)
{
return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0);
}
+#if CFG_TUSB_DEBUG
+TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir)
+{
+ static const char *str[] = {"out", "in"};
+ return str[dir];
+}
+
+TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t)
+{
+ static const char *str[] = {"control", "isochronous", "bulk", "interrupt"};
+ return str[t];
+}
+#endif
+
//--------------------------------------------------------------------+
// Descriptor helper
//--------------------------------------------------------------------+
-static inline uint8_t const * tu_desc_next(void const* desc)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc)
{
uint8_t const* desc8 = (uint8_t const*) desc;
return desc8 + desc8[DESC_OFFSET_LEN];
}
-static inline uint8_t tu_desc_type(void const* desc)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc)
{
return ((uint8_t const*) desc)[DESC_OFFSET_TYPE];
}
-static inline uint8_t tu_desc_len(void const* desc)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc)
{
return ((uint8_t const*) desc)[DESC_OFFSET_LEN];
}
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index 56ba8bcd1..a52a6d269 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -37,31 +37,31 @@
* manipulation that you are told to stay away.
*
* This contains macros for both VERIFY and ASSERT:
- *
+ *
* VERIFY: Used when there is an error condition which is not the
* fault of the MCU. For example, bounds checking on data
* sent to the micro over USB should use this function.
* Another example is checking for buffer overflows, where
* returning from the active function causes a NAK.
- *
+ *
* ASSERT: Used for error conditions that are caused by MCU firmware
* bugs. This is used to discover bugs in the code more
* quickly. One example would be adding assertions in library
* function calls to confirm a function's (untainted)
* parameters are valid.
- *
+ *
* The difference in behavior is that ASSERT triggers a breakpoint while
* verify does not.
*
* #define TU_VERIFY(cond) if(cond) return false;
* #define TU_VERIFY(cond,ret) if(cond) return ret;
- *
+ *
* #define TU_VERIFY_HDLR(cond,handler) if(cond) {handler; return false;}
* #define TU_VERIFY_HDLR(cond,ret,handler) if(cond) {handler; return ret;}
*
* #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;}
* #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
- *
+ *
*------------------------------------------------------------------*/
#ifdef __cplusplus
@@ -74,15 +74,13 @@
#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__)
#else
- #define _MESS_ERR(_err) do {} while (0)
#define _MESS_FAILED() do {} while (0)
#endif
-// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
-#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
+// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33
+#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)
#define TU_BREAKPOINT() do \
{ \
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
@@ -92,6 +90,9 @@
#elif defined(__riscv)
#define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0)
+#elif defined(_mips)
+ #define TU_BREAKPOINT() do { __asm("sdbbp 0"); } while (0)
+
#else
#define TU_BREAKPOINT() do {} while (0)
#endif
@@ -101,8 +102,8 @@
*------------------------------------------------------------------*/
// Helper to implement optional parameter for TU_VERIFY Macro family
-#define GET_3RD_ARG(arg1, arg2, arg3, ...) arg3
-#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
+#define _GET_3RD_ARG(arg1, arg2, arg3, ...) arg3
+#define _GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/
#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do \
@@ -118,7 +119,7 @@
#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, , false)
#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, , _ret)
-#define TU_VERIFY(...) GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__)
+#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__)
/*------------------------------------------------------------------*/
@@ -129,7 +130,7 @@
#define TU_VERIFY_HDLR_2ARGS(_cond, _handler) TU_VERIFY_DEFINE(_cond, _handler, false)
#define TU_VERIFY_HDLR_3ARGS(_cond, _handler, _ret) TU_VERIFY_DEFINE(_cond, _handler, _ret)
-#define TU_VERIFY_HDLR(...) GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__)
+#define TU_VERIFY_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__)
/*------------------------------------------------------------------*/
/* ASSERT
@@ -141,33 +142,7 @@
#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret)
#ifndef TU_ASSERT
-#define TU_ASSERT(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
-#endif
-
-// TODO remove TU_ASSERT_ERR() later
-
-/*------------- Generator for TU_VERIFY_ERR and TU_VERIFY_ERR_HDLR -------------*/
-#define TU_VERIFY_ERR_DEF2(_error, _handler) do \
-{ \
- uint32_t _err = (uint32_t)(_error); \
- if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _err; } \
-} while(0)
-
-#define TU_VERIFY_ERR_DEF3(_error, _handler, _ret) do \
-{ \
- uint32_t _err = (uint32_t)(_error); \
- if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _ret; } \
-} while(0)
-
-/*------------------------------------------------------------------*/
-/* ASSERT Error
- * basically TU_VERIFY Error with TU_BREAKPOINT() as handler
- *------------------------------------------------------------------*/
-#define ASSERT_ERR_1ARGS(_error) TU_VERIFY_ERR_DEF2(_error, TU_BREAKPOINT())
-#define ASSERT_ERR_2ARGS(_error, _ret) TU_VERIFY_ERR_DEF3(_error, TU_BREAKPOINT(), _ret)
-
-#ifndef TU_ASSERT_ERR
-#define TU_ASSERT_ERR(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_ERR_2ARGS, ASSERT_ERR_1ARGS,UNUSED)(__VA_ARGS__)
+#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
#endif
/*------------------------------------------------------------------*/
diff --git a/src/device/dcd.h b/src/device/dcd.h
index c042cc708..c1780f656 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -30,7 +30,6 @@
#include "common/tusb_common.h"
#include "osal/osal.h"
#include "common/tusb_fifo.h"
-#include "dcd_attr.h"
#ifdef __cplusplus
extern "C" {
@@ -41,7 +40,7 @@
//--------------------------------------------------------------------+
#ifndef CFG_TUD_ENDPPOINT_MAX
- #define CFG_TUD_ENDPPOINT_MAX DCD_ATTR_ENDPOINT_MAX
+ #define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX
#endif
//--------------------------------------------------------------------+
@@ -78,6 +77,11 @@ typedef struct TU_ATTR_ALIGNED(4)
tusb_speed_t speed;
} bus_reset;
+ // SOF
+ struct {
+ uint32_t frame_count;
+ }sof;
+
// SETUP_RECEIVED
tusb_control_request_t setup_received;
@@ -106,14 +110,7 @@ typedef struct TU_ATTR_ALIGNED(4)
void dcd_init (uint8_t rhport);
// Interrupt Handler
-#if __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wredundant-decls"
-#endif
void dcd_int_handler(uint8_t rhport);
-#if __GNUC__
-#pragma GCC diagnostic pop
-#endif
// Enable device interrupt
void dcd_int_enable (uint8_t rhport);
@@ -133,6 +130,9 @@ void dcd_connect(uint8_t rhport) TU_ATTR_WEAK;
// Disconnect by disabling internal pull-up resistor on D+/D-
void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK;
+// Enable/Disable Start-of-frame interrupt. Default is disabled
+void dcd_sof_enable(uint8_t rhport, bool en);
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -175,16 +175,47 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
extern void dcd_event_handler(dcd_event_t const * event, bool in_isr);
// helper to send bus signal event
-extern void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr);
+TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr)
+{
+ dcd_event_t event = { .rhport = rhport, .event_id = eid };
+ dcd_event_handler(&event, in_isr);
+}
// helper to send bus reset event
-extern void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr);
+TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr)
+{
+ dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET };
+ event.bus_reset.speed = speed;
+ dcd_event_handler(&event, in_isr);
+}
// helper to send setup received
-extern void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr);
+TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr)
+{
+ dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED };
+ memcpy(&event.setup_received, setup, 8);
+
+ dcd_event_handler(&event, in_isr);
+}
// helper to send transfer complete event
-extern void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr);
+TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr)
+{
+ dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE };
+
+ event.xfer_complete.ep_addr = ep_addr;
+ event.xfer_complete.len = xferred_bytes;
+ event.xfer_complete.result = result;
+
+ dcd_event_handler(&event, in_isr);
+}
+
+static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr)
+{
+ dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SOF };
+ event.sof.frame_count = frame_count;
+ dcd_event_handler(&event, in_isr);
+}
#ifdef __cplusplus
}
diff --git a/src/device/dcd_attr.h b/src/device/dcd_attr.h
deleted file mode 100644
index 73d592e5c..000000000
--- a/src/device/dcd_attr.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2021, Ha Thach (tinyusb.org)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#ifndef TUSB_DCD_ATTR_H_
-#define TUSB_DCD_ATTR_H_
-
-#include "tusb_option.h"
-
-// Attribute includes
-// - ENDPOINT_MAX: max (logical) number of endpoint
-// - ENDPOINT_EXCLUSIVE_NUMBER: endpoint number with different direction IN and OUT aren't allowed,
-// e.g EP1 OUT & EP1 IN cannot exist together
-// - PORT_HIGHSPEED: mask to indicate which port support highspeed mode, bit0 for port0 and so on.
-
-//------------- NXP -------------//
-#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
- #define DCD_ATTR_ENDPOINT_MAX 5
-
-#elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX)
- #define DCD_ATTR_ENDPOINT_MAX 16
-
-#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
- // TODO USB0 has 6, USB1 has 4
- #define DCD_ATTR_ENDPOINT_MAX 6
-
-#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX)
- #define DCD_ATTR_ENDPOINT_MAX 5
-
-#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX)
- // TODO USB0 has 5, USB1 has 6
- #define DCD_ATTR_ENDPOINT_MAX 6
-
-#elif TU_CHECK_MCU(OPT_MCU_LPC55XX)
- // TODO USB0 has 5, USB1 has 6
- #define DCD_ATTR_ENDPOINT_MAX 6
-
-#elif TU_CHECK_MCU(OPT_MCU_MIMXRT10XX)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_MKL25ZXX, OPT_MCU_K32L2BXX)
- #define DCD_ATTR_ENDPOINT_MAX 16
-
-#elif TU_CHECK_MCU(OPT_MCU_MM32F327X)
- #define DCD_ATTR_ENDPOINT_MAX 16
-
-//------------- Nordic -------------//
-#elif TU_CHECK_MCU(OPT_MCU_NRF5X)
- // 8 CBI + 1 ISO
- #define DCD_ATTR_ENDPOINT_MAX 9
-
-//------------- Microchip -------------//
-#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \
- TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_SAMG)
- #define DCD_ATTR_ENDPOINT_MAX 6
- #define DCD_ATTR_ENDPOINT_EXCLUSIVE_NUMBER
-
-#elif TU_CHECK_MCU(OPT_MCU_SAMX7X)
- #define DCD_ATTR_ENDPOINT_MAX 10
- #define DCD_ATTR_ENDPOINT_EXCLUSIVE_NUMBER
-
-//------------- ST -------------//
-#elif TU_CHECK_MCU(OPT_MCU_STM32F0)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32F1)
- #if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
- defined (STM32F107xB) || defined (STM32F107xC)
- #define DCD_ATTR_ENDPOINT_MAX 4
- #define DCD_ATTR_DWC2_STM32
- #else
- #define DCD_ATTR_ENDPOINT_MAX 8
- #endif
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32F2)
- // FS has 4 ep, HS has 5 ep
- #define DCD_ATTR_ENDPOINT_MAX 6
- #define DCD_ATTR_DWC2_STM32
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32F3)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
- // For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9
- #define DCD_ATTR_ENDPOINT_MAX 6
- #define DCD_ATTR_DWC2_STM32
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32F7)
- // FS has 6, HS has 9
- #define DCD_ATTR_ENDPOINT_MAX 9
- #define DCD_ATTR_DWC2_STM32
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
- #define DCD_ATTR_ENDPOINT_MAX 9
- #define DCD_ATTR_DWC2_STM32
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32L4)
- #if defined (STM32L475xx) || defined (STM32L476xx) || \
- defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
- defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \
- defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
- defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
- #define DCD_ATTR_ENDPOINT_MAX 6
- #define DCD_ATTR_DWC2_STM32
- #else
- #define DCD_ATTR_ENDPOINT_MAX 8
- #endif
-
-//------------- Sony -------------//
-#elif TU_CHECK_MCU(OPT_MCU_CXD56)
- #define DCD_ATTR_ENDPOINT_MAX 7
- #define DCD_ATTR_ENDPOINT_EXCLUSIVE_NUMBER
-
-//------------- TI -------------//
-#elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-//------------- ValentyUSB -------------//
-#elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI)
- #define DCD_ATTR_ENDPOINT_MAX 16
-
-//------------- Nuvoton -------------//
-#elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_NUC120)
- #define DCD_ATTR_ENDPOINT_MAX 6
-
-#elif TU_CHECK_MCU(OPT_MCU_NUC505)
- #define DCD_ATTR_ENDPOINT_MAX 12
-
-//------------- Espressif -------------//
-#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
- #define DCD_ATTR_ENDPOINT_MAX 6
-
-//------------- Dialog -------------//
-#elif TU_CHECK_MCU(OPT_MCU_DA1469X)
- #define DCD_ATTR_ENDPOINT_MAX 4
-
-//------------- Raspberry Pi -------------//
-#elif TU_CHECK_MCU(OPT_MCU_RP2040)
- #define DCD_ATTR_ENDPOINT_MAX 16
-
-//------------- Silabs -------------//
-#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
- #define DCD_ATTR_ENDPOINT_MAX 7
-
-//------------- Renesas -------------//
-#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
- #define DCD_ATTR_ENDPOINT_MAX 10
-
-//------------- GigaDevice -------------//
-#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
- #define DCD_ATTR_ENDPOINT_MAX 4
-
-//------------- Broadcom -------------//
-#elif TU_CHECK_MCU(OPT_MCU_BCM2711)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-//------------- Broadcom -------------//
-#elif TU_CHECK_MCU(OPT_MCU_XMC4000)
- #define DCD_ATTR_ENDPOINT_MAX 8
-
-#else
- #warning "DCD_ATTR_ENDPOINT_MAX is not defined for this MCU, default to 8"
- #define DCD_ATTR_ENDPOINT_MAX 8
-#endif
-
-// Default to fullspeed if not defined
-//#ifndef PORT_HIGHSPEED
-// #define DCD_ATTR_PORT_HIGHSPEED 0x00
-//#endif
-
-#endif
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 6a5210b34..c199e647e 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -26,12 +26,14 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED
+#if CFG_TUD_ENABLED
+#include "device/dcd.h"
#include "tusb.h"
+#include "common/tusb_private.h"
+
#include "device/usbd.h"
#include "device/usbd_pvt.h"
-#include "device/dcd.h"
//--------------------------------------------------------------------+
// USBD Configuration
@@ -67,17 +69,10 @@ typedef struct
volatile uint8_t cfg_num; // current active configuration (0x00 is not configured)
uint8_t speed;
- uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
- uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid )
-
- struct TU_ATTR_PACKED
- {
- volatile bool busy : 1;
- volatile bool stalled : 1;
- volatile bool claimed : 1;
+ uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid)
+ uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
- // TODO merge ep2drv here, 4-bit should be sufficient
- }ep_status[CFG_TUD_ENDPPOINT_MAX][2];
+ tu_edpt_state_t ep_status[CFG_TUD_ENDPPOINT_MAX][2];
}usbd_device_t;
@@ -139,7 +134,7 @@ static usbd_class_driver_t const _usbd_driver[] =
.open = audiod_open,
.control_xfer_cb = audiod_control_xfer_cb,
.xfer_cb = audiod_xfer_cb,
- .sof = NULL
+ .sof = audiod_sof_isr
},
#endif
@@ -223,7 +218,7 @@ static usbd_class_driver_t const _usbd_driver[] =
.open = netd_open,
.control_xfer_cb = netd_control_xfer_cb,
.xfer_cb = netd_xfer_cb,
- .sof = NULL,
+ .sof = NULL,
},
#endif
@@ -269,11 +264,12 @@ static inline usbd_class_driver_t const * get_driver(uint8_t drvid)
// DCD Event
//--------------------------------------------------------------------+
-static bool _usbd_initialized = false;
+enum { RHPORT_INVALID = 0xFFu };
+static uint8_t _usbd_rhport = RHPORT_INVALID;
// Event queue
-// OPT_MODE_DEVICE is used by OS NONE for mutex (disable usb isr)
-OSAL_QUEUE_DEF(OPT_MODE_DEVICE, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
+// usbd_int_set() is used as mutex in OS NONE config
+OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
static osal_queue_t _usbd_q;
// Mutex for claiming endpoint, only needed when using with preempted RTOS
@@ -314,34 +310,15 @@ static char const* const _usbd_event_str[DCD_EVENT_COUNT] =
"Func Call"
};
-static char const* const _tusb_std_request_str[] =
-{
- "Get Status" ,
- "Clear Feature" ,
- "Reserved" ,
- "Set Feature" ,
- "Reserved" ,
- "Set Address" ,
- "Get Descriptor" ,
- "Set Descriptor" ,
- "Get Configuration" ,
- "Set Configuration" ,
- "Get Interface" ,
- "Set Interface" ,
- "Synch Frame"
-};
-
-static char const* const _tusb_speed_str[] = { "Full", "Low", "High" };
-
// for usbd_control to print the name of control complete driver
void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback)
{
for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++)
{
usbd_class_driver_t const * driver = get_driver(i);
- if ( driver->control_xfer_cb == callback )
+ if ( driver && driver->control_xfer_cb == callback )
{
- TU_LOG2(" %s control complete\r\n", driver->name);
+ TU_LOG(USBD_DBG, " %s control complete\r\n", driver->name);
return;
}
}
@@ -376,21 +353,21 @@ bool tud_remote_wakeup(void)
{
// only wake up host if this feature is supported and enabled and we are suspended
TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en );
- dcd_remote_wakeup(TUD_OPT_RHPORT);
+ dcd_remote_wakeup(_usbd_rhport);
return true;
}
bool tud_disconnect(void)
{
TU_VERIFY(dcd_disconnect);
- dcd_disconnect(TUD_OPT_RHPORT);
+ dcd_disconnect(_usbd_rhport);
return true;
}
bool tud_connect(void)
{
TU_VERIFY(dcd_connect);
- dcd_connect(TUD_OPT_RHPORT);
+ dcd_connect(_usbd_rhport);
return true;
}
@@ -399,15 +376,16 @@ bool tud_connect(void)
//--------------------------------------------------------------------+
bool tud_inited(void)
{
- return _usbd_initialized;
+ return _usbd_rhport != RHPORT_INVALID;
}
bool tud_init (uint8_t rhport)
{
// skip if already initialized
- if (_usbd_initialized) return _usbd_initialized;
+ if ( tud_inited() ) return true;
- TU_LOG2("USBD init\r\n");
+ TU_LOG(USBD_DBG, "USBD init on controller %u\r\n", rhport);
+ TU_LOG_INT(USBD_DBG, sizeof(usbd_device_t));
tu_varclr(&_usbd_dev);
@@ -431,16 +409,17 @@ bool tud_init (uint8_t rhport)
for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++)
{
usbd_class_driver_t const * driver = get_driver(i);
- TU_LOG2("%s init\r\n", driver->name);
+ TU_ASSERT(driver);
+ TU_LOG(USBD_DBG, "%s init\r\n", driver->name);
driver->init();
}
+ _usbd_rhport = rhport;
+
// Init device controller driver
dcd_init(rhport);
dcd_int_enable(rhport);
- _usbd_initialized = true;
-
return true;
}
@@ -448,7 +427,9 @@ static void configuration_reset(uint8_t rhport)
{
for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ )
{
- get_driver(i)->reset(rhport);
+ usbd_class_driver_t const * driver = get_driver(i);
+ TU_ASSERT(driver, );
+ driver->reset(rhport);
}
tu_varclr(&_usbd_dev);
@@ -488,8 +469,10 @@ bool tud_task_event_ready(void)
}
@endcode
*/
-void tud_task (void)
+void tud_task_ext(uint32_t timeout_ms, bool in_isr)
{
+ (void) in_isr; // not implemented yet
+
// Skip if stack is not initialized
if ( !tusb_inited() ) return;
@@ -497,24 +480,23 @@ void tud_task (void)
while (1)
{
dcd_event_t event;
-
- if ( !osal_queue_receive(_usbd_q, &event) ) return;
+ if ( !osal_queue_receive(_usbd_q, &event, timeout_ms) ) return;
#if CFG_TUSB_DEBUG >= 2
- if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG2("\r\n"); // extra line for setup
- TU_LOG2("USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED");
+ if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG(USBD_DBG, "\r\n"); // extra line for setup
+ TU_LOG(USBD_DBG, "USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED");
#endif
switch ( event.event_id )
{
case DCD_EVENT_BUS_RESET:
- TU_LOG2(": %s Speed\r\n", _tusb_speed_str[event.bus_reset.speed]);
+ TU_LOG(USBD_DBG, ": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]);
usbd_reset(event.rhport);
_usbd_dev.speed = event.bus_reset.speed;
break;
case DCD_EVENT_UNPLUGGED:
- TU_LOG2("\r\n");
+ TU_LOG(USBD_DBG, "\r\n");
usbd_reset(event.rhport);
// invoke callback
@@ -522,8 +504,8 @@ void tud_task (void)
break;
case DCD_EVENT_SETUP_RECEIVED:
- TU_LOG2_VAR(&event.setup_received);
- TU_LOG2("\r\n");
+ TU_LOG_VAR(USBD_DBG, &event.setup_received);
+ TU_LOG(USBD_DBG, "\r\n");
// Mark as connected after receiving 1st setup packet.
// But it is easier to set it every time instead of wasting time to check then set
@@ -538,7 +520,7 @@ void tud_task (void)
// Process control request
if ( !process_control_request(event.rhport, &event.setup_received) )
{
- TU_LOG2(" Stall EP0\r\n");
+ TU_LOG(USBD_DBG, " Stall EP0\r\n");
// Failed -> stall both control endpoint IN and OUT
dcd_edpt_stall(event.rhport, 0);
dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK);
@@ -552,7 +534,7 @@ void tud_task (void)
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const ep_dir = tu_edpt_dir(ep_addr);
- TU_LOG2("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
+ TU_LOG(USBD_DBG, "on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
_usbd_dev.ep_status[epnum][ep_dir].busy = false;
_usbd_dev.ep_status[epnum][ep_dir].claimed = 0;
@@ -566,7 +548,7 @@ void tud_task (void)
usbd_class_driver_t const * driver = get_driver( _usbd_dev.ep2drv[epnum][ep_dir] );
TU_ASSERT(driver, );
- TU_LOG2(" %s xfer callback\r\n", driver->name);
+ TU_LOG(USBD_DBG, " %s xfer callback\r\n", driver->name);
driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len);
}
}
@@ -578,43 +560,40 @@ void tud_task (void)
// e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected
if ( _usbd_dev.connected )
{
- TU_LOG2(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en);
+ TU_LOG(USBD_DBG, ": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en);
if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en);
}else
{
- TU_LOG2(" Skipped\r\n");
+ TU_LOG(USBD_DBG, " Skipped\r\n");
}
break;
case DCD_EVENT_RESUME:
if ( _usbd_dev.connected )
{
- TU_LOG2("\r\n");
+ TU_LOG(USBD_DBG, "\r\n");
if (tud_resume_cb) tud_resume_cb();
}else
{
- TU_LOG2(" Skipped\r\n");
- }
- break;
-
- case DCD_EVENT_SOF:
- TU_LOG2("\r\n");
- for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ )
- {
- usbd_class_driver_t const * driver = get_driver(i);
- if ( driver->sof ) driver->sof(event.rhport);
+ TU_LOG(USBD_DBG, " Skipped\r\n");
}
break;
case USBD_EVENT_FUNC_CALL:
- TU_LOG2("\r\n");
+ TU_LOG(USBD_DBG, "\r\n");
if ( event.func_call.func ) event.func_call.func(event.func_call.param);
break;
+ case DCD_EVENT_SOF:
default:
TU_BREAKPOINT();
break;
}
+
+#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO
+ // return if there is no more events, for application to run other background
+ if (osal_queue_empty(_usbd_q)) return;
+#endif
}
}
@@ -626,7 +605,7 @@ void tud_task (void)
static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request)
{
usbd_control_set_complete_callback(driver->control_xfer_cb);
- TU_LOG2(" %s control request\r\n", driver->name);
+ TU_LOG(USBD_DBG, " %s control request\r\n", driver->name);
return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request);
}
@@ -650,8 +629,8 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
#if CFG_TUSB_DEBUG >= 2
if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME)
{
- TU_LOG2(" %s", _tusb_std_request_str[p_request->bRequest]);
- if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG2("\r\n");
+ TU_LOG(USBD_DBG, " %s", tu_str_std_request[p_request->bRequest]);
+ if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG(USBD_DBG, "\r\n");
}
#endif
@@ -759,7 +738,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// Device status bit mask
// - Bit 0: Self Powered
// - Bit 1: Remote Wakeup enabled
- uint16_t status = (_usbd_dev.self_powered ? 1 : 0) | (_usbd_dev.remote_wakeup_en ? 2 : 0);
+ uint16_t status = (uint16_t) ((_usbd_dev.self_powered ? 1u : 0u) | (_usbd_dev.remote_wakeup_en ? 2u : 0u));
tud_control_xfer(rhport, p_request, &status, 2);
}
break;
@@ -891,8 +870,8 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION);
// Parse configuration descriptor
- _usbd_dev.remote_wakeup_support = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP) ? 1 : 0;
- _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED ) ? 1 : 0;
+ _usbd_dev.remote_wakeup_support = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP) ? 1u : 0u;
+ _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED ) ? 1u : 0u;
// Parse interface descriptor
uint8_t const * p_desc = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t);
@@ -919,17 +898,18 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
tusb_desc_interface_t const * desc_itf = (tusb_desc_interface_t const*) p_desc;
// Find driver for this interface
- uint16_t const remaining_len = desc_end-p_desc;
+ uint16_t const remaining_len = (uint16_t) (desc_end-p_desc);
uint8_t drv_id;
for (drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++)
{
usbd_class_driver_t const *driver = get_driver(drv_id);
+ TU_ASSERT(driver);
uint16_t const drv_len = driver->open(rhport, desc_itf, remaining_len);
if ( (sizeof(tusb_desc_interface_t) <= drv_len) && (drv_len <= remaining_len) )
{
// Open successfully
- TU_LOG2(" %s opened\r\n", driver->name);
+ TU_LOG(USBD_DBG, " %s opened\r\n", driver->name);
// Some drivers use 2 or more interfaces but may not have IAD e.g MIDI (always) or
// BTH (even CDC) with class in device descriptor (single interface)
@@ -988,7 +968,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
{
case TUSB_DESC_DEVICE:
{
- TU_LOG2(" Device\r\n");
+ TU_LOG(USBD_DBG, " Device\r\n");
void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb();
@@ -1008,11 +988,11 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
}
}
- break;
+ // break; // unreachable
case TUSB_DESC_BOS:
{
- TU_LOG2(" BOS\r\n");
+ TU_LOG(USBD_DBG, " BOS\r\n");
// requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
if (!tud_descriptor_bos_cb) return false;
@@ -1025,7 +1005,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
}
- break;
+ // break; // unreachable
case TUSB_DESC_CONFIGURATION:
case TUSB_DESC_OTHER_SPEED_CONFIG:
@@ -1034,12 +1014,12 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
if ( desc_type == TUSB_DESC_CONFIGURATION )
{
- TU_LOG2(" Configuration[%u]\r\n", desc_index);
+ TU_LOG(USBD_DBG, " Configuration[%u]\r\n", desc_index);
desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index);
}else
{
// Host only request this after getting Device Qualifier descriptor
- TU_LOG2(" Other Speed Configuration\r\n");
+ TU_LOG(USBD_DBG, " Other Speed Configuration\r\n");
TU_VERIFY( tud_descriptor_other_speed_configuration_cb );
desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
}
@@ -1051,11 +1031,11 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
}
- break;
+ // break; // unreachable
case TUSB_DESC_STRING:
{
- TU_LOG2(" String[%u]\r\n", desc_index);
+ TU_LOG(USBD_DBG, " String[%u]\r\n", desc_index);
// String Descriptor always uses the desc set from user
uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, tu_le16toh(p_request->wIndex));
@@ -1064,11 +1044,11 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
// first byte of descriptor is its size
return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str));
}
- break;
+ // break; // unreachable
case TUSB_DESC_DEVICE_QUALIFIER:
{
- TU_LOG2(" Device Qualifier\r\n");
+ TU_LOG(USBD_DBG, " Device Qualifier\r\n");
TU_VERIFY( tud_descriptor_device_qualifier_cb );
@@ -1078,7 +1058,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
// first byte of descriptor is its size
return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier));
}
- break;
+ // break; // unreachable
default: return false;
}
@@ -1087,7 +1067,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
//--------------------------------------------------------------------+
// DCD Event Handler
//--------------------------------------------------------------------+
-void dcd_event_handler(dcd_event_t const * event, bool in_isr)
+TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const * event, bool in_isr)
{
switch (event->event_id)
{
@@ -1121,14 +1101,27 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
break;
case DCD_EVENT_SOF:
+ // SOF driver handler in ISR context
+ for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++)
+ {
+ usbd_class_driver_t const * driver = get_driver(i);
+ if (driver && driver->sof)
+ {
+ driver->sof(event->rhport, event->sof.frame_count);
+ }
+ }
+
// Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup
// which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational
if ( _usbd_dev.suspended )
{
_usbd_dev.suspended = 0;
+
dcd_event_t const event_resume = { .rhport = event->rhport, .event_id = DCD_EVENT_RESUME };
osal_queue_send(_usbd_q, &event_resume, in_isr);
}
+
+ // skip osal queue for SOF in usbd task
break;
default:
@@ -1137,42 +1130,21 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
}
}
-void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr)
-{
- dcd_event_t event = { .rhport = rhport, .event_id = eid };
- dcd_event_handler(&event, in_isr);
-}
-
-void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr)
-{
- dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET };
- event.bus_reset.speed = speed;
- dcd_event_handler(&event, in_isr);
-}
-
-void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr)
-{
- dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED };
- memcpy(&event.setup_received, setup, 8);
-
- dcd_event_handler(&event, in_isr);
-}
-
-void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr)
-{
- dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE };
-
- event.xfer_complete.ep_addr = ep_addr;
- event.xfer_complete.len = xferred_bytes;
- event.xfer_complete.result = result;
-
- dcd_event_handler(&event, in_isr);
-}
-
//--------------------------------------------------------------------+
// USBD API For Class Driver
//--------------------------------------------------------------------+
+void usbd_int_set(bool enabled)
+{
+ if (enabled)
+ {
+ dcd_int_enable(_usbd_rhport);
+ }else
+ {
+ dcd_int_disable(_usbd_rhport);
+ }
+}
+
// Parse consecutive endpoint descriptors (IN & OUT)
bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in)
{
@@ -1218,6 +1190,8 @@ void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr)
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
{
+ rhport = _usbd_rhport;
+
TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX);
TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed));
@@ -1231,63 +1205,43 @@ bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
// TODO add this check later, also make sure we don't starve an out endpoint while suspending
// TU_VERIFY(tud_ready());
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
-#if CFG_TUSB_OS != OPT_OS_NONE
- // pre-check to help reducing mutex lock
- TU_VERIFY((_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 0));
- osal_mutex_lock(_usbd_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
-#endif
-
- // can only claim the endpoint if it is not busy and not claimed yet.
- bool const ret = (_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 0);
- if (ret)
- {
- _usbd_dev.ep_status[epnum][dir].claimed = 1;
- }
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir];
-#if CFG_TUSB_OS != OPT_OS_NONE
- osal_mutex_unlock(_usbd_mutex);
+#if TUSB_OPT_MUTEX
+ return tu_edpt_claim(ep_state, _usbd_mutex);
+#else
+ return tu_edpt_claim(ep_state, NULL);
#endif
-
- return ret;
}
bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
-#if CFG_TUSB_OS != OPT_OS_NONE
- osal_mutex_lock(_usbd_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
-#endif
-
- // can only release the endpoint if it is claimed and not busy
- bool const ret = (_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 1);
- if (ret)
- {
- _usbd_dev.ep_status[epnum][dir].claimed = 0;
- }
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir];
-#if CFG_TUSB_OS != OPT_OS_NONE
- osal_mutex_unlock(_usbd_mutex);
+#if TUSB_OPT_MUTEX
+ return tu_edpt_release(ep_state, _usbd_mutex);
+#else
+ return tu_edpt_release(ep_state, NULL);
#endif
-
- return ret;
}
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
+ rhport = _usbd_rhport;
+
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
// TODO skip ready() check for now since enumeration also use this API
// TU_VERIFY(tud_ready());
- TU_LOG2(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
+ TU_LOG(USBD_DBG, " 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);
@@ -1304,7 +1258,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
// DCD error, mark endpoint as ready to allow next transfer
_usbd_dev.ep_status[epnum][dir].busy = false;
_usbd_dev.ep_status[epnum][dir].claimed = 0;
- TU_LOG2("FAILED\r\n");
+ TU_LOG(USBD_DBG, "FAILED\r\n");
TU_BREAKPOINT();
return false;
}
@@ -1316,10 +1270,12 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
// into the USB buffer!
bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
{
+ rhport = _usbd_rhport;
+
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes);
+ TU_LOG(USBD_DBG, " Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes);
// Attempt to transfer on a busy endpoint, sound like an race condition !
TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
@@ -1330,14 +1286,14 @@ bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes))
{
- TU_LOG2("OK\r\n");
+ TU_LOG(USBD_DBG, "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_LOG(USBD_DBG, "failed\r\n");
TU_BREAKPOINT();
return false;
}
@@ -1355,6 +1311,7 @@ bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
+ rhport = _usbd_rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
@@ -1371,6 +1328,8 @@ void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
+ rhport = _usbd_rhport;
+
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
@@ -1402,8 +1361,10 @@ bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr)
*/
void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
+ rhport = _usbd_rhport;
+
TU_ASSERT(dcd_edpt_close, /**/);
- TU_LOG2(" CLOSING Endpoint: 0x%02X\r\n", ep_addr);
+ TU_LOG(USBD_DBG, " CLOSING Endpoint: 0x%02X\r\n", ep_addr);
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
@@ -1416,4 +1377,13 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
return;
}
+void usbd_sof_enable(uint8_t rhport, bool en)
+{
+ rhport = _usbd_rhport;
+
+ // TODO: Check needed if all drivers including the user sof_cb does not need an active SOF ISR any more.
+ // Only if all drivers switched off SOF calls the SOF interrupt may be disabled
+ dcd_sof_enable(rhport, en);
+}
+
#endif
diff --git a/src/device/usbd.h b/src/device/usbd.h
index ec34817fa..17b4d927b 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -43,14 +43,26 @@ bool tud_init (uint8_t rhport);
// Check if device stack is already initialized
bool tud_inited(void);
+// Task function should be called in main/rtos loop, extended version of tud_task()
+// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever
+// - in_isr: if function is called in ISR
+void tud_task_ext(uint32_t timeout_ms, bool in_isr);
+
// Task function should be called in main/rtos loop
-void tud_task (void);
+TU_ATTR_ALWAYS_INLINE static inline
+void tud_task (void)
+{
+ tud_task_ext(UINT32_MAX, false);
+}
-// Check if there is pending events need proccessing by tud_task()
+// Check if there is pending events need processing by tud_task()
bool tud_task_event_ready(void);
-// Interrupt handler, name alias to DCD
+#ifndef _TUSB_DCD_H_
extern void dcd_int_handler(uint8_t rhport);
+#endif
+
+// Interrupt handler, name alias to DCD
#define tud_int_handler dcd_int_handler
// Get current bus speed
@@ -453,7 +465,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
@@ -502,7 +514,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
@@ -550,7 +562,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\
@@ -558,7 +570,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
// 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)
+ ((((_maxFrequency + (TUD_OPT_HIGH_SPEED ? 7999 : 999)) / (TUD_OPT_HIGH_SPEED ? 8000 : 1000)) + 1) * _nBytesPerSample * _nChannels)
//--------------------------------------------------------------------+
diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c
index 7a8244699..0995ef669 100644
--- a/src/device/usbd_control.c
+++ b/src/device/usbd_control.c
@@ -26,11 +26,11 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED
+#if CFG_TUD_ENABLED
+#include "dcd.h"
#include "tusb.h"
#include "device/usbd_pvt.h"
-#include "dcd.h"
#if CFG_TUSB_DEBUG >= 2
extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback);
@@ -189,7 +189,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2);
}
- _ctrl_xfer.total_xferred += xferred_bytes;
+ _ctrl_xfer.total_xferred += (uint16_t) xferred_bytes;
_ctrl_xfer.buffer += xferred_bytes;
// Data Stage is complete when all request's length are transferred or
diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h
index 7607b9895..6fad46db3 100644
--- a/src/device/usbd_pvt.h
+++ b/src/device/usbd_pvt.h
@@ -48,7 +48,7 @@ typedef struct
uint16_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len);
bool (* control_xfer_cb ) (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
bool (* xfer_cb ) (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
- void (* sof ) (uint8_t rhport); /* optional */
+ void (* sof ) (uint8_t rhport, uint32_t frame_count); // optional
} usbd_class_driver_t;
// Invoked when initializing device stack to get additional class drivers.
@@ -58,8 +58,11 @@ usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR
typedef bool (*usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+void usbd_int_set(bool enabled);
+
//--------------------------------------------------------------------+
// USBD Endpoint API
+// Note: rhport should be 0 since device stack only support 1 rhport for now
//--------------------------------------------------------------------+
// Open an endpoint
@@ -78,7 +81,7 @@ bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
// If caller does not make any transfer, it must release endpoint for others.
bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr);
-// Release an endpoint without submitting a transfer
+// Release claimed endpoint without submitting a transfer
bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr);
// Check if endpoint is busy transferring
@@ -100,6 +103,9 @@ bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr)
return !usbd_edpt_busy(rhport, ep_addr) && !usbd_edpt_stalled(rhport, ep_addr);
}
+// Enable SOF interrupt
+void usbd_sof_enable(uint8_t rhport, bool en);
+
/*------------------------------------------------------------------*/
/* Helper
*------------------------------------------------------------------*/
diff --git a/src/host/hcd.h b/src/host/hcd.h
index eb53d2e80..deebc59d4 100644
--- a/src/host/hcd.h
+++ b/src/host/hcd.h
@@ -30,13 +30,25 @@
#include "common/tusb_common.h"
#include "osal/osal.h"
#include "common/tusb_fifo.h"
-#include "hcd_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
- //--------------------------------------------------------------------+
+//--------------------------------------------------------------------+
+// Configuration
+//--------------------------------------------------------------------+
+
+#ifndef CFG_TUH_ENDPOINT_MAX
+ #define CFG_TUH_ENDPOINT_MAX (CFG_TUH_HUB + CFG_TUH_HID*2 + CFG_TUH_MSC*2 + CFG_TUH_CDC*3)
+// #ifdef TUP_HCD_ENDPOINT_MAX
+// #define CFG_TUH_ENDPPOINT_MAX TUP_HCD_ENDPOINT_MAX
+// #else
+// #define
+// #endif
+#endif
+
+//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
typedef enum
@@ -82,30 +94,21 @@ typedef struct
} hcd_event_t;
-#if TUSB_OPT_HOST_ENABLED
-// Max number of endpoints per device
-enum {
- // TODO better computation
- HCD_MAX_ENDPOINT = CFG_TUH_DEVICE_MAX*(CFG_TUH_HUB + CFG_TUH_HID*2 + CFG_TUH_MSC*2 + CFG_TUH_CDC*3),
- HCD_MAX_XFER = HCD_MAX_ENDPOINT*2,
-};
-
-//#define HCD_MAX_ENDPOINT 16
-//#define HCD_MAX_XFER 16
-
-typedef struct {
+typedef struct
+{
uint8_t rhport;
uint8_t hub_addr;
uint8_t hub_port;
uint8_t speed;
} hcd_devtree_info_t;
-#endif
-
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
+// optional hcd configuration, called by tuh_config()
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) TU_ATTR_WEAK;
+
// Initialize controller to host mode
bool hcd_init(uint8_t rhport);
@@ -144,9 +147,16 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr);
// Endpoints API
//--------------------------------------------------------------------+
-bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]);
+// Open an endpoint
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
+
+// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen);
+
+// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]);
+
+// clear stall, data toggle is also reset to DATA0
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr);
//--------------------------------------------------------------------+
@@ -164,13 +174,47 @@ extern void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_i
extern void hcd_event_handler(hcd_event_t const* event, bool in_isr);
// Helper to send device attach event
-extern void hcd_event_device_attach(uint8_t rhport, bool in_isr);
+TU_ATTR_ALWAYS_INLINE static inline
+void hcd_event_device_attach(uint8_t rhport, bool in_isr)
+{
+ hcd_event_t event;
+ event.rhport = rhport;
+ event.event_id = HCD_EVENT_DEVICE_ATTACH;
+ event.connection.hub_addr = 0;
+ event.connection.hub_port = 0;
+ hcd_event_handler(&event, in_isr);
+}
// Helper to send device removal event
-extern void hcd_event_device_remove(uint8_t rhport, bool in_isr);
+TU_ATTR_ALWAYS_INLINE static inline
+void hcd_event_device_remove(uint8_t rhport, bool in_isr)
+{
+ hcd_event_t event;
+ event.rhport = rhport;
+ event.event_id = HCD_EVENT_DEVICE_REMOVE;
+ event.connection.hub_addr = 0;
+ event.connection.hub_port = 0;
+
+ hcd_event_handler(&event, in_isr);
+}
// Helper to send USB transfer event
-extern void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr);
+TU_ATTR_ALWAYS_INLINE static inline
+void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr)
+{
+ hcd_event_t event =
+ {
+ .rhport = 0, // TODO correct rhport
+ .event_id = HCD_EVENT_XFER_COMPLETE,
+ .dev_addr = dev_addr,
+ };
+ event.xfer_complete.ep_addr = ep_addr;
+ event.xfer_complete.result = result;
+ event.xfer_complete.len = xferred_bytes;
+
+
+ hcd_event_handler(&event, in_isr);
+}
#ifdef __cplusplus
}
diff --git a/src/host/hcd_attr.h b/src/host/hcd_attr.h
deleted file mode 100644
index 06011c63c..000000000
--- a/src/host/hcd_attr.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2021, Ha Thach (tinyusb.org)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#ifndef TUSB_HCD_ATTR_H_
-#define TUSB_HCD_ATTR_H_
-
-#include "tusb_option.h"
-
-// Attribute includes
-// - ENDPOINT_MAX: max (logical) number of endpoint
-// - PORT_HIGHSPEED: mask to indicate which port support highspeed mode, bit0 for port0 and so on.
-
-//------------- NXP -------------//
-#if TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX)
- #define HCD_ATTR_OHCI
-
-#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
- #define HCD_ATTR_EHCI_TRANSDIMENSION
-
-#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX)
- // #define HCD_ATTR_EHCI_NXP_PTD
-
-#elif TU_CHECK_MCU(OPT_MCU_LPC55XX)
- // #define HCD_ATTR_EHCI_NXP_PTD
-
-#elif TU_CHECK_MCU(OPT_MCU_MIMXRT10XX)
- #define HCD_ATTR_EHCI_TRANSDIMENSION
-
-#elif TU_CHECK_MCU(OPT_MCU_MKL25ZXX)
-
-//------------- Microchip -------------//
-#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \
- TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22)
-
-#elif TU_CHECK_MCU(OPT_MCU_SAMG)
-
-#elif TU_CHECK_MCU(OPT_MCU_SAMX7X)
-
-//------------- ST -------------//
-#elif TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F1, OPT_MCU_STM32F3) || \
- TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32L4)
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32F2, OPT_MCU_STM32F3, OPT_MCU_STM32F4)
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32F7)
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
-
-//------------- Sony -------------//
-#elif TU_CHECK_MCU(OPT_MCU_CXD56)
-
-//------------- Nuvoton -------------//
-#elif TU_CHECK_MCU(OPT_MCU_NUC505)
-
-//------------- Espressif -------------//
-#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
-
-//------------- Raspberry Pi -------------//
-#elif TU_CHECK_MCU(OPT_MCU_RP2040)
-
-//------------- Silabs -------------//
-#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
-
-//------------- Renesas -------------//
-#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
-
-//#elif TU_CHECK_MCU(OPT_MCU_MM32F327X)
-// #define DCD_ATTR_ENDPOINT_MAX not known yet
-
-//------------- GigaDevice -------------//
-#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
-
-#else
-// #warning "DCD_ATTR_ENDPOINT_MAX is not defined for this MCU, default to 8"
-#endif
-
-// Default to fullspeed if not defined
-//#ifndef PORT_HIGHSPEED
-// #define DCD_ATTR_PORT_HIGHSPEED 0x00
-//#endif
-
-#endif
diff --git a/src/host/hub.c b/src/host/hub.c
index fd4dbd04a..3da5358b2 100644
--- a/src/host/hub.c
+++ b/src/host/hub.c
@@ -26,8 +26,9 @@
#include "tusb_option.h"
-#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HUB)
+#if (CFG_TUH_ENABLED && CFG_TUH_HUB)
+#include "hcd.h"
#include "usbh.h"
#include "usbh_classdriver.h"
#include "hub.h"
@@ -43,6 +44,7 @@ typedef struct
uint8_t status_change; // data from status change interrupt endpoint
hub_port_status_response_t port_status;
+ hub_status_response_t hub_status;
} hub_interface_t;
CFG_TUSB_MEM_SECTION static hub_interface_t hub_data[CFG_TUH_HUB];
@@ -54,7 +56,7 @@ static inline hub_interface_t* get_itf(uint8_t dev_addr)
return &hub_data[dev_addr-1-CFG_TUH_DEVICE_MAX];
}
-#if CFG_TUSB_DEBUG
+#if CFG_TUSB_DEBUG >= 2
static char const* const _hub_feature_str[] =
{
[HUB_FEATURE_PORT_CONNECTION ] = "PORT_CONNECTION",
@@ -77,13 +79,14 @@ static char const* const _hub_feature_str[] =
//--------------------------------------------------------------------+
// HUB
//--------------------------------------------------------------------+
-bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb)
+bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
tusb_control_request_t const request =
{
.bmRequestType_bit =
{
- .recipient = TUSB_REQ_RCPT_OTHER,
+ .recipient = (hub_port == 0) ? TUSB_REQ_RCPT_DEVICE : TUSB_REQ_RCPT_OTHER,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_OUT
},
@@ -93,18 +96,29 @@ bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
.wLength = 0
};
+ tuh_xfer_t xfer =
+ {
+ .daddr = hub_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
TU_LOG2("HUB Clear Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
- TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) );
+ TU_ASSERT( tuh_control_xfer(&xfer) );
return true;
}
-bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb)
+bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
tusb_control_request_t const request =
{
.bmRequestType_bit =
{
- .recipient = TUSB_REQ_RCPT_OTHER,
+ .recipient = (hub_port == 0) ? TUSB_REQ_RCPT_DEVICE : TUSB_REQ_RCPT_OTHER,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_OUT
},
@@ -114,23 +128,29 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, t
.wLength = 0
};
+ tuh_xfer_t xfer =
+ {
+ .daddr = hub_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
TU_LOG2("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
- TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) );
+ TU_ASSERT( tuh_control_xfer(&xfer) );
return true;
}
-bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb)
-{
- return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb);
-}
-
-bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb)
+bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
tusb_control_request_t const request =
{
.bmRequestType_bit =
{
- .recipient = TUSB_REQ_RCPT_OTHER,
+ .recipient = (hub_port == 0) ? TUSB_REQ_RCPT_DEVICE : TUSB_REQ_RCPT_OTHER,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_IN
},
@@ -140,8 +160,18 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_con
.wLength = 4
};
+ tuh_xfer_t xfer =
+ {
+ .daddr = hub_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = resp,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port);
- TU_ASSERT( tuh_control_xfer( hub_addr, &request, resp, complete_cb) );
+ TU_VERIFY( tuh_control_xfer(&xfer) );
return true;
}
@@ -155,6 +185,8 @@ void hub_init(void)
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{
+ (void) rhport;
+
TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
0 == itf_desc->bInterfaceSubClass);
@@ -171,7 +203,7 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
- TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
+ TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
hub_interface_t* p_hub = get_itf(dev_addr);
@@ -189,7 +221,7 @@ void hub_close(uint8_t dev_addr)
if (p_hub->ep_in) tu_memclr(p_hub, sizeof( hub_interface_t));
}
-bool hub_status_pipe_queue(uint8_t dev_addr)
+bool hub_edpt_status_xfer(uint8_t dev_addr)
{
hub_interface_t* hub_itf = get_itf(dev_addr);
return usbh_edpt_xfer(dev_addr, hub_itf->ep_in, &hub_itf->status_change, 1);
@@ -200,8 +232,8 @@ bool hub_status_pipe_queue(uint8_t dev_addr)
// Set Configure
//--------------------------------------------------------------------+
-static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+static void config_set_port_power (tuh_xfer_t* xfer);
+static void config_port_power_complete (tuh_xfer_t* xfer);
bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
{
@@ -223,17 +255,27 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
.wLength = sizeof(descriptor_hub_desc_t)
};
- TU_ASSERT( tuh_control_xfer(dev_addr, &request, _hub_buffer, config_set_port_power) );
+ tuh_xfer_t xfer =
+ {
+ .daddr = dev_addr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = _hub_buffer,
+ .complete_cb = config_set_port_power,
+ .user_data = 0
+ };
+
+ TU_ASSERT( tuh_control_xfer(&xfer) );
return true;
}
-static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static void config_set_port_power (tuh_xfer_t* xfer)
{
- (void) request;
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
+ TU_ASSERT(XFER_RESULT_SUCCESS == xfer->result, );
- hub_interface_t* p_hub = get_itf(dev_addr);
+ uint8_t const daddr = xfer->daddr;
+ hub_interface_t* p_hub = get_itf(daddr);
// only use number of ports in hub descriptor
descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer;
@@ -243,38 +285,39 @@ static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t cons
// Set Port Power to be able to detect connection, starting with port 1
uint8_t const hub_port = 1;
- return hub_port_set_feature(dev_addr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete);
+ hub_port_set_feature(daddr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
}
-static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static void config_port_power_complete (tuh_xfer_t* xfer)
{
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
- hub_interface_t* p_hub = get_itf(dev_addr);
+ TU_ASSERT(XFER_RESULT_SUCCESS == xfer->result, );
+
+ uint8_t const daddr = xfer->daddr;
+ hub_interface_t* p_hub = get_itf(daddr);
- if (request->wIndex == p_hub->port_count)
+ if (xfer->setup->wIndex == p_hub->port_count)
{
// All ports are power -> queue notification status endpoint and
// complete the SET CONFIGURATION
- TU_ASSERT( usbh_edpt_xfer(dev_addr, p_hub->ep_in, &p_hub->status_change, 1) );
+ TU_ASSERT( usbh_edpt_xfer(daddr, p_hub->ep_in, &p_hub->status_change, 1), );
- usbh_driver_set_config_complete(dev_addr, p_hub->itf_num);
+ usbh_driver_set_config_complete(daddr, p_hub->itf_num);
}else
{
// power next port
- uint8_t const hub_port = (uint8_t) (request->wIndex + 1);
- return hub_port_set_feature(dev_addr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete);
+ uint8_t const hub_port = (uint8_t) (xfer->setup->wIndex + 1);
+ hub_port_set_feature(daddr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
}
-
- return true;
}
//--------------------------------------------------------------------+
// Connection Changes
//--------------------------------------------------------------------+
-static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+static void hub_port_get_status_complete (tuh_xfer_t* xfer);
+static void hub_get_status_complete (tuh_xfer_t* xfer);
+static void connection_clear_conn_change_complete (tuh_xfer_t* xfer);
+static void connection_port_reset_complete (tuh_xfer_t* xfer);
// callback as response of interrupt endpoint polling
bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
@@ -285,15 +328,31 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
hub_interface_t* p_hub = get_itf(dev_addr);
- TU_LOG2(" Port Status Change = 0x%02X\r\n", p_hub->status_change);
+ TU_LOG2(" Hub Status Change = 0x%02X\r\n", p_hub->status_change);
- // Hub ignore bit0 in status change
- for (uint8_t port=1; port <= p_hub->port_count; port++)
+ // Hub bit 0 is for the hub device events
+ if (tu_bit_test(p_hub->status_change, 0))
+ {
+ if (hub_port_get_status(dev_addr, 0, &p_hub->hub_status, hub_get_status_complete, 0) == false)
+ {
+ //Hub status control transfer failed, retry
+ hub_edpt_status_xfer(dev_addr);
+ }
+ }
+ else
{
- if ( tu_bit_test(p_hub->status_change, port) )
+ // Hub bits 1 to n are hub port events
+ for (uint8_t port=1; port <= p_hub->port_count; port++)
{
- hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete);
- break;
+ if ( tu_bit_test(p_hub->status_change, port) )
+ {
+ if (hub_port_get_status(dev_addr, port, &p_hub->port_status, hub_port_get_status_complete, 0) == false)
+ {
+ //Hub status control transfer failed, retry
+ hub_edpt_status_xfer(dev_addr);
+ }
+ break;
+ }
}
}
@@ -302,12 +361,42 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
return true;
}
-static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static void hub_clear_feature_complete_stub(tuh_xfer_t* xfer)
{
- TU_ASSERT(result == XFER_RESULT_SUCCESS);
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
+ hub_edpt_status_xfer(xfer->daddr);
+}
- hub_interface_t* p_hub = get_itf(dev_addr);
- uint8_t const port_num = (uint8_t) request->wIndex;
+static void hub_get_status_complete (tuh_xfer_t* xfer)
+{
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
+
+ uint8_t const daddr = xfer->daddr;
+ hub_interface_t* p_hub = get_itf(daddr);
+ uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ TU_ASSERT(port_num == 0 , );
+
+ TU_LOG2("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, p_hub->hub_status.change.value);
+
+ if (p_hub->hub_status.change.local_power_source)
+ {
+ TU_LOG2("HUB Local Power Change, addr = %u\r\n", daddr);
+ hub_port_clear_feature(daddr, port_num, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE, hub_clear_feature_complete_stub, 0);
+ }
+ else if (p_hub->hub_status.change.over_current)
+ {
+ TU_LOG1("HUB Over Current, addr = %u\r\n", daddr);
+ hub_port_clear_feature(daddr, port_num, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE, hub_clear_feature_complete_stub, 0);
+ }
+}
+
+static void hub_port_get_status_complete (tuh_xfer_t* xfer)
+{
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
+
+ uint8_t const daddr = xfer->daddr;
+ hub_interface_t* p_hub = get_itf(daddr);
+ uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
// Connection change
if (p_hub->port_status.change.connection)
@@ -316,73 +405,86 @@ static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_reque
//TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
// Acknowledge Port Connection Change
- hub_port_clear_feature(dev_addr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete);
+ hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0);
}else
{
- // Other changes are: Enable, Suspend, Over Current, Reset, L1 state
+ // Clear other port status change interrupts. TODO Not currently handled - just cleared.
+ if (p_hub->port_status.change.port_enable)
+ {
+ hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE, hub_clear_feature_complete_stub, 0);
+ }
+ else if (p_hub->port_status.change.suspend)
+ {
+ hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE, hub_clear_feature_complete_stub, 0);
+ }
+ else if (p_hub->port_status.change.over_current)
+ {
+ hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE, hub_clear_feature_complete_stub, 0);
+ }
+ else if (p_hub->port_status.change.reset)
+ {
+ hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE, hub_clear_feature_complete_stub, 0);
+ }
+ // Other changes are: L1 state
// TODO clear change
// prepare for next hub status
// TODO continue with status_change, or maybe we can do it again with status
- hub_status_pipe_queue(dev_addr);
+ hub_edpt_status_xfer(daddr);
}
-
- return true;
}
-static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static void connection_clear_conn_change_complete (tuh_xfer_t* xfer)
{
- TU_ASSERT(result == XFER_RESULT_SUCCESS);
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
- hub_interface_t* p_hub = get_itf(dev_addr);
- uint8_t const port_num = (uint8_t) request->wIndex;
+ uint8_t const daddr = xfer->daddr;
+ hub_interface_t* p_hub = get_itf(daddr);
+ uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
if ( p_hub->port_status.status.connection )
{
// Reset port if attach event
- hub_port_reset(dev_addr, port_num, connection_port_reset_complete);
+ hub_port_reset(daddr, port_num, connection_port_reset_complete, 0);
}else
{
// submit detach event
hcd_event_t event =
{
- .rhport = usbh_get_rhport(dev_addr),
+ .rhport = usbh_get_rhport(daddr),
.event_id = HCD_EVENT_DEVICE_REMOVE,
.connection =
{
- .hub_addr = dev_addr,
+ .hub_addr = daddr,
.hub_port = port_num
}
};
hcd_event_handler(&event, false);
}
-
- return true;
}
-static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static void connection_port_reset_complete (tuh_xfer_t* xfer)
{
- TU_ASSERT(result == XFER_RESULT_SUCCESS);
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
- // hub_interface_t* p_hub = get_itf(dev_addr);
- uint8_t const port_num = (uint8_t) request->wIndex;
+ uint8_t const daddr = xfer->daddr;
+ // hub_interface_t* p_hub = get_itf(daddr);
+ uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
// submit attach event
hcd_event_t event =
{
- .rhport = usbh_get_rhport(dev_addr),
+ .rhport = usbh_get_rhport(daddr),
.event_id = HCD_EVENT_DEVICE_ATTACH,
.connection =
{
- .hub_addr = dev_addr,
+ .hub_addr = daddr,
.hub_port = port_num
}
};
hcd_event_handler(&event, false);
-
- return true;
}
#endif
diff --git a/src/host/hub.h b/src/host/hub.h
index c4d544193..390740e1f 100644
--- a/src/host/hub.h
+++ b/src/host/hub.h
@@ -171,12 +171,35 @@ typedef struct {
TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct");
-bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb);
-bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb);
+// Clear feature
+bool hub_port_clear_feature (uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Set feature
+bool hub_port_set_feature (uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Get port status
+bool hub_port_get_status (uint8_t hub_addr, uint8_t hub_port, void* resp,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Get status from Interrupt endpoint
+bool hub_edpt_status_xfer(uint8_t dev_addr);
+
+// Reset a port
+static inline bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb, user_data);
+}
+
+// Clear Reset Change
+static inline bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_port,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_data);
+}
-bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb);
-bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb);
-bool hub_status_pipe_queue(uint8_t dev_addr);
//--------------------------------------------------------------------+
// Internal Class Driver API
diff --git a/src/host/usbh.c b/src/host/usbh.c
index f74e7114c..9d618db92 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -26,10 +26,11 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED
+#if CFG_TUH_ENABLED
+#include "host/hcd.h"
#include "tusb.h"
-#include "host/usbh.h"
+#include "common/tusb_private.h"
#include "host/usbh_classdriver.h"
#include "hub.h"
@@ -37,15 +38,14 @@
// USBH Configuration
//--------------------------------------------------------------------+
-// TODO remove,update
-#ifndef CFG_TUH_EP_MAX
-#define CFG_TUH_EP_MAX 9
-#endif
-
#ifndef CFG_TUH_TASK_QUEUE_SZ
#define CFG_TUH_TASK_QUEUE_SZ 16
#endif
+#ifndef CFG_TUH_INTERFACE_MAX
+#define CFG_TUH_INTERFACE_MAX 8
+#endif
+
// Debug level of USBD
#define USBH_DBG_LVL 2
@@ -54,6 +54,7 @@
//--------------------------------------------------------------------+
// device0 struct must be strictly a subset of normal device struct
+// TODO refactor later
typedef struct
{
// port
@@ -62,73 +63,67 @@ typedef struct
uint8_t hub_port;
uint8_t speed;
- volatile struct TU_ATTR_PACKED
+ struct TU_ATTR_PACKED
{
- uint8_t connected : 1;
- uint8_t addressed : 1;
- uint8_t configured : 1;
- uint8_t suspended : 1;
+ volatile uint8_t connected : 1;
+ volatile uint8_t addressed : 1;
+ volatile uint8_t configured : 1;
+ volatile uint8_t suspended : 1;
};
+
} usbh_dev0_t;
typedef struct {
- // port
+ // port, must be same layout as usbh_dev0_t
uint8_t rhport;
uint8_t hub_addr;
uint8_t hub_port;
uint8_t speed;
- volatile struct TU_ATTR_PACKED
- {
- uint8_t connected : 1;
- uint8_t addressed : 1;
- uint8_t configured : 1;
- uint8_t suspended : 1;
+ // Device State
+ struct TU_ATTR_PACKED {
+ volatile uint8_t connected : 1;
+ volatile uint8_t addressed : 1;
+ volatile uint8_t configured : 1;
+ volatile uint8_t suspended : 1;
};
- //------------- device descriptor -------------//
+ // Device Descriptor
+ uint8_t ep0_size;
+
uint16_t vid;
uint16_t pid;
- uint8_t ep0_size;
uint8_t i_manufacturer;
uint8_t i_product;
uint8_t i_serial;
- //------------- configuration descriptor -------------//
+ // Configuration Descriptor
// uint8_t interface_count; // bNumInterfaces alias
- //------------- device -------------//
- volatile uint8_t state; // device state, value from enum tusbh_device_state_t
+ // Endpoint & Interface
+ uint8_t itf2drv[CFG_TUH_INTERFACE_MAX]; // map interface number to driver (0xff is invalid)
+ uint8_t ep2drv[CFG_TUH_ENDPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
- uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
- uint8_t ep2drv[CFG_TUH_EP_MAX][2]; // map endpoint to driver ( 0xff is invalid )
+ tu_edpt_state_t ep_status[CFG_TUH_ENDPOINT_MAX][2];
- struct TU_ATTR_PACKED
- {
- volatile bool busy : 1;
- volatile bool stalled : 1;
- volatile bool claimed : 1;
-
- // TODO merge ep2drv here, 4-bit should be sufficient
- }ep_status[CFG_TUH_EP_MAX][2];
-
- // Mutex for claiming endpoint, only needed when using with preempted RTOS
-#if CFG_TUSB_OS != OPT_OS_NONE
- osal_mutex_def_t mutexdef;
- osal_mutex_t mutex;
+#if CFG_TUH_API_EDPT_XFER
+ // TODO array can be CFG_TUH_ENDPOINT_MAX-1
+ struct {
+ tuh_xfer_cb_t complete_cb;
+ uintptr_t user_data;
+ }ep_callback[CFG_TUH_ENDPOINT_MAX][2];
#endif
} usbh_device_t;
-
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
// Invalid driver ID in itf2drv[] ep2drv[][] mapping
enum { DRVID_INVALID = 0xFFu };
-enum { ADDR_INVALID = 0xFFu };
+enum { CONTROLLER_INVALID = 0xFFu };
#if CFG_TUSB_DEBUG >= 2
#define DRIVER_NAME(_name) .name = _name,
@@ -204,53 +199,119 @@ enum { CONFIG_NUM = 1 }; // default to use configuration 1
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-static bool _usbh_initialized = false;
+// sum of end device + hub
+#define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB)
+
+static uint8_t _usbh_controller = CONTROLLER_INVALID;
// Device with address = 0 for enumeration
static usbh_dev0_t _dev0;
// all devices excluding zero-address
// hub address start from CFG_TUH_DEVICE_MAX+1
-CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[CFG_TUH_DEVICE_MAX + CFG_TUH_HUB];
+// TODO: hub can has its own simpler struct to save memory
+CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[TOTAL_DEVICES];
+
+// Mutex for claiming endpoint, only needed when using with preempted RTOS
+#if TUSB_OPT_MUTEX
+static osal_mutex_def_t _usbh_mutexdef;
+static osal_mutex_t _usbh_mutex;
+
+TU_ATTR_ALWAYS_INLINE static inline void usbh_lock(void)
+{
+ osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void usbh_unlock(void)
+{
+ osal_mutex_unlock(_usbh_mutex);
+}
+
+#else
+
+#define _usbh_mutex NULL
+
+#define usbh_lock()
+#define usbh_unlock()
+
+#endif
// Event queue
-// role device/host is used by OS NONE for mutex (disable usb isr)
-OSAL_QUEUE_DEF(OPT_MODE_HOST, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t);
+// usbh_int_set is used as mutex in OS NONE config
+OSAL_QUEUE_DEF(usbh_int_set, _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_BUFSIZE];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
+static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
+
+// Control transfer: since most controller does not support multiple control transfer
+// on multiple devices concurrently. And control transfer is not used much except enumeration
+// We will only execute control transfer one at a time.
+struct
+{
+ tusb_control_request_t request TU_ATTR_ALIGNED(4);
+ uint8_t* buffer;
+ tuh_xfer_cb_t complete_cb;
+ uintptr_t user_data;
+
+ uint8_t daddr;
+ volatile uint8_t stage;
+ volatile uint16_t actual_len;
+}_ctrl_xfer;
//------------- Helper Function -------------//
TU_ATTR_ALWAYS_INLINE
static inline usbh_device_t* get_device(uint8_t dev_addr)
{
- TU_ASSERT(dev_addr, NULL);
+ TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL);
return &_usbh_devices[dev_addr-1];
}
static bool enum_new_device(hcd_event_t* event);
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
+static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+// TODO rework time-related function later
+void osal_task_delay(uint32_t msec)
+{
+ (void) msec;
-// from usbh_control.c
-extern bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+ const uint32_t start = hcd_frame_number(_usbh_controller);
+ while ( ( hcd_frame_number(_usbh_controller) - start ) < msec ) {}
+}
+#endif
//--------------------------------------------------------------------+
// PUBLIC API (Parameter Verification is required)
//--------------------------------------------------------------------+
+
+bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param)
+{
+ if (hcd_configure)
+ {
+ return hcd_configure(rhport, cfg_id, cfg_param);
+ }else
+ {
+ return false;
+ }
+}
+
bool tuh_mounted(uint8_t dev_addr)
{
- return get_device(dev_addr)->configured;
+ usbh_device_t* dev = get_device(dev_addr);
+ TU_VERIFY(dev);
+ return dev->configured;
}
bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid)
{
*vid = *pid = 0;
- TU_VERIFY(tuh_mounted(dev_addr));
-
usbh_device_t const* dev = get_device(dev_addr);
+ TU_VERIFY(dev && dev->configured);
*vid = dev->vid;
*pid = dev->pid;
@@ -260,67 +321,65 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid)
tusb_speed_t tuh_speed_get (uint8_t dev_addr)
{
- return (tusb_speed_t) (dev_addr ? get_device(dev_addr)->speed : _dev0.speed);
+ usbh_device_t* dev = get_device(dev_addr);
+ return (tusb_speed_t) (dev ? get_device(dev_addr)->speed : _dev0.speed);
}
-#if CFG_TUSB_OS == OPT_OS_NONE
-void osal_task_delay(uint32_t msec)
+static void clear_device(usbh_device_t* dev)
{
- (void) msec;
-
- const uint32_t start = hcd_frame_number(TUH_OPT_RHPORT);
- while ( ( hcd_frame_number(TUH_OPT_RHPORT) - start ) < msec ) {}
+ tu_memclr(dev, sizeof(usbh_device_t));
+ memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
+ memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
}
-#endif
-
-//--------------------------------------------------------------------+
-// CLASS-USBD API (don't require to verify parameters)
-//--------------------------------------------------------------------+
bool tuh_inited(void)
{
- return _usbh_initialized;
+ return _usbh_controller != CONTROLLER_INVALID;
}
-bool tuh_init(uint8_t rhport)
+bool tuh_init(uint8_t controller_id)
{
// skip if already initialized
- if (_usbh_initialized) return _usbh_initialized;
+ if ( tuh_inited() ) return true;
- TU_LOG2("USBH init\r\n");
+ TU_LOG2("USBH init on controller %u\r\n", controller_id);
+ TU_LOG2_INT(sizeof(usbh_device_t));
+ TU_LOG2_INT(sizeof(hcd_event_t));
+ TU_LOG2_INT(sizeof(_ctrl_xfer));
+ TU_LOG2_INT(sizeof(tuh_xfer_t));
- tu_memclr(_usbh_devices, sizeof(_usbh_devices));
- tu_memclr(&_dev0, sizeof(_dev0));
-
- //------------- Enumeration & Reporter Task init -------------//
+ // Event queue
_usbh_q = osal_queue_create( &_usbh_qdef );
TU_ASSERT(_usbh_q != NULL);
- //------------- Semaphore, Mutex for Control Pipe -------------//
- for(uint8_t i=0; i<TU_ARRAY_SIZE(_usbh_devices); i++)
- {
- usbh_device_t * dev = &_usbh_devices[i];
-
-#if CFG_TUSB_OS != OPT_OS_NONE
- dev->mutex = osal_mutex_create(&dev->mutexdef);
- TU_ASSERT(dev->mutex);
+#if TUSB_OPT_MUTEX
+ // Mutex
+ _usbh_mutex = osal_mutex_create(&_usbh_mutexdef);
+ TU_ASSERT(_usbh_mutex);
#endif
- memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
- memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
+ // Device
+ tu_memclr(&_dev0, sizeof(_dev0));
+ tu_memclr(_usbh_devices, sizeof(_usbh_devices));
+ tu_memclr(&_ctrl_xfer, sizeof(_ctrl_xfer));
+
+ for(uint8_t i=0; i<TOTAL_DEVICES; i++)
+ {
+ clear_device(&_usbh_devices[i]);
}
- // Class drivers init
+ // Class drivers
for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
{
TU_LOG2("%s init\r\n", usbh_class_drivers[drv_id].name);
usbh_class_drivers[drv_id].init();
}
- TU_ASSERT(hcd_init(rhport));
- hcd_int_enable(rhport);
+ _usbh_controller = controller_id;;
+
+ TU_ASSERT(hcd_init(controller_id));
+ hcd_int_enable(controller_id);
- _usbh_initialized = true;
return true;
}
@@ -342,8 +401,10 @@ bool tuh_init(uint8_t rhport)
}
@endcode
*/
-void tuh_task(void)
+void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
{
+ (void) in_isr; // not implemented yet
+
// Skip if stack is not initialized
if ( !tusb_inited() ) return;
@@ -351,19 +412,19 @@ void tuh_task(void)
while (1)
{
hcd_event_t event;
- if ( !osal_queue_receive(_usbh_q, &event) ) return;
+ if ( !osal_queue_receive(_usbh_q, &event, timeout_ms) ) return;
switch (event.event_id)
{
case HCD_EVENT_DEVICE_ATTACH:
// TODO due to the shared _usbh_ctrl_buf, we must complete enumerating
// one device before enumerating another one.
- TU_LOG2("USBH DEVICE ATTACH\r\n");
+ TU_LOG2("[%u:] USBH DEVICE ATTACH\r\n", event.rhport);
enum_new_device(&event);
break;
case HCD_EVENT_DEVICE_REMOVE:
- TU_LOG2("USBH DEVICE REMOVED\r\n");
+ TU_LOG2("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
process_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port);
#if CFG_TUH_HUB
@@ -371,7 +432,7 @@ void tuh_task(void)
if ( event.connection.hub_addr != 0)
{
// done with hub, waiting for next data on status pipe
- (void) hub_status_pipe_queue( event.connection.hub_addr );
+ (void) hub_edpt_status_xfer( event.connection.hub_addr );
}
#endif
break;
@@ -393,7 +454,9 @@ void tuh_task(void)
else
{
usbh_device_t* dev = get_device(event.dev_addr);
- dev->ep_status[epnum][ep_dir].busy = false;
+ TU_ASSERT(dev, );
+
+ dev->ep_status[epnum][ep_dir].busy = 0;
dev->ep_status[epnum][ep_dir].claimed = 0;
if ( 0 == epnum )
@@ -402,10 +465,38 @@ void tuh_task(void)
}else
{
uint8_t drv_id = dev->ep2drv[epnum][ep_dir];
- TU_ASSERT(drv_id < USBH_CLASS_DRIVER_COUNT, );
+ if(drv_id < USBH_CLASS_DRIVER_COUNT)
+ {
+ TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
+ usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
+ }
+ else
+ {
+#if CFG_TUH_API_EDPT_XFER
+ tuh_xfer_cb_t complete_cb = dev->ep_callback[epnum][ep_dir].complete_cb;
+ if ( complete_cb )
+ {
+ tuh_xfer_t xfer =
+ {
+ .daddr = event.dev_addr,
+ .ep_addr = ep_addr,
+ .result = event.xfer_complete.result,
+ .actual_len = event.xfer_complete.len,
+ .buflen = 0, // not available
+ .buffer = NULL, // not available
+ .complete_cb = complete_cb,
+ .user_data = dev->ep_callback[epnum][ep_dir].user_data
+ };
- TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
- usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
+ complete_cb(&xfer);
+ }else
+#endif
+ {
+ // no driver/callback responsible for this transfer
+ TU_ASSERT(false, );
+ }
+
+ }
}
}
}
@@ -417,308 +508,381 @@ void tuh_task(void)
default: break;
}
+
+#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO
+ // return if there is no more events, for application to run other background
+ if (osal_queue_empty(_usbh_q)) return;
+#endif
}
}
//--------------------------------------------------------------------+
-// USBH API For Class Driver
+// Control transfer
//--------------------------------------------------------------------+
-uint8_t usbh_get_rhport(uint8_t dev_addr)
+static void _control_blocking_complete_cb(tuh_xfer_t* xfer)
{
- return (dev_addr == 0) ? _dev0.rhport : get_device(dev_addr)->rhport;
+ // update result
+ *((xfer_result_t*) xfer->user_data) = xfer->result;
}
-uint8_t* usbh_get_enum_buf(void)
+// TODO timeout_ms is not supported yet
+bool tuh_control_xfer (tuh_xfer_t* xfer)
{
- return _usbh_ctrl_buf;
-}
+ // EP0 with setup packet
+ TU_VERIFY(xfer->ep_addr == 0 && xfer->setup);
-//--------------------------------------------------------------------+
-// HCD Event Handler
-//--------------------------------------------------------------------+
+ // pre-check to help reducing mutex lock
+ TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
-void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info)
-{
- if (dev_addr)
- {
- usbh_device_t const* dev = get_device(dev_addr);
+ uint8_t const daddr = xfer->daddr;
- devtree_info->rhport = dev->rhport;
- devtree_info->hub_addr = dev->hub_addr;
- devtree_info->hub_port = dev->hub_port;
- devtree_info->speed = dev->speed;
- }else
- {
- devtree_info->rhport = _dev0.rhport;
- devtree_info->hub_addr = _dev0.hub_addr;
- devtree_info->hub_port = _dev0.hub_port;
- devtree_info->speed = _dev0.speed;
- }
-}
+ // TODO probably better to use semaphore as resource management than mutex
+ usbh_lock();
-void hcd_event_handler(hcd_event_t const* event, bool in_isr)
-{
- switch (event->event_id)
+ bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
+ if (is_idle)
{
- default:
- osal_queue_send(_usbh_q, event, in_isr);
- break;
+ _ctrl_xfer.stage = CONTROL_STAGE_SETUP;
+ _ctrl_xfer.daddr = daddr;
+ _ctrl_xfer.actual_len = 0;
+
+ _ctrl_xfer.request = (*xfer->setup);
+ _ctrl_xfer.buffer = xfer->buffer;
+ _ctrl_xfer.complete_cb = xfer->complete_cb;
+ _ctrl_xfer.user_data = xfer->user_data;
}
-}
-void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr)
-{
- hcd_event_t event =
+ usbh_unlock();
+
+ TU_VERIFY(is_idle);
+ const uint8_t rhport = usbh_get_rhport(daddr);
+
+ TU_LOG2("[%u:%u] %s: ", rhport, daddr, xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME ? tu_str_std_request[xfer->setup->bRequest] : "Unknown Request");
+ TU_LOG2_VAR(xfer->setup);
+ TU_LOG2("\r\n");
+
+ if (xfer->complete_cb)
{
- .rhport = 0, // TODO correct rhport
- .event_id = HCD_EVENT_XFER_COMPLETE,
- .dev_addr = dev_addr,
- .xfer_complete =
+ TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t const*) &_ctrl_xfer.request) );
+ }else
+ {
+ // blocking if complete callback is not provided
+ // change callback to internal blocking, and result as user argument
+ volatile xfer_result_t result = XFER_RESULT_INVALID;
+
+ // use user_data to point to xfer_result_t
+ _ctrl_xfer.user_data = (uintptr_t) &result;
+ _ctrl_xfer.complete_cb = _control_blocking_complete_cb;
+
+ TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.request) );
+
+ while (result == XFER_RESULT_INVALID)
{
- .ep_addr = ep_addr,
- .result = result,
- .len = xferred_bytes
+ // only need to call task if not preempted RTOS
+ #if CFG_TUSB_OS == OPT_OS_NONE || CFG_TUSB_OS == OPT_OS_PICO
+ tuh_task();
+ #endif
+
+ // TODO probably some timeout to prevent hanged
}
- };
- hcd_event_handler(&event, in_isr);
+ // update transfer result
+ xfer->result = result;
+ xfer->actual_len = _ctrl_xfer.actual_len;
+ }
+
+ return true;
}
-void hcd_event_device_attach(uint8_t rhport, bool in_isr)
+TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage)
{
- hcd_event_t event =
- {
- .rhport = rhport,
- .event_id = HCD_EVENT_DEVICE_ATTACH
- };
-
- event.connection.hub_addr = 0;
- event.connection.hub_port = 0;
-
- hcd_event_handler(&event, in_isr);
+ usbh_lock();
+ _ctrl_xfer.stage = stage;
+ usbh_unlock();
}
-void hcd_event_device_remove(uint8_t hostid, bool in_isr)
+static void _xfer_complete(uint8_t daddr, xfer_result_t result)
{
- hcd_event_t event =
+ TU_LOG2("\r\n");
+
+ // duplicate xfer since user can execute control transfer within callback
+ tusb_control_request_t const request = _ctrl_xfer.request;
+ tuh_xfer_t xfer_temp =
{
- .rhport = hostid,
- .event_id = HCD_EVENT_DEVICE_REMOVE
+ .daddr = daddr,
+ .ep_addr = 0,
+ .result = result,
+ .setup = &request,
+ .actual_len = (uint32_t) _ctrl_xfer.actual_len,
+ .buffer = _ctrl_xfer.buffer,
+ .complete_cb = _ctrl_xfer.complete_cb,
+ .user_data = _ctrl_xfer.user_data
};
- event.connection.hub_addr = 0;
- event.connection.hub_port = 0;
+ usbh_lock();
+ _ctrl_xfer.stage = CONTROL_STAGE_IDLE;
+ usbh_unlock();
- hcd_event_handler(&event, in_isr);
+ if (xfer_temp.complete_cb)
+ {
+ xfer_temp.complete_cb(&xfer_temp);
+ }
}
-
-// a device unplugged on hostid, hub_addr, hub_port
-// return true if found and unmounted device, false if cannot find
-void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
+static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
- //------------- find the all devices (star-network) under port that is unplugged -------------//
- // TODO mark as disconnected in ISR, also handle dev0
- for ( uint8_t dev_id = 0; dev_id < TU_ARRAY_SIZE(_usbh_devices); dev_id++ )
+ (void) ep_addr;
+
+ const uint8_t rhport = usbh_get_rhport(dev_addr);
+ tusb_control_request_t const * request = &_ctrl_xfer.request;
+
+ if (XFER_RESULT_SUCCESS != result)
{
- usbh_device_t* dev = &_usbh_devices[dev_id];
- uint8_t const dev_addr = dev_id+1;
+ TU_LOG1("[%u:%u] Control %s\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED");
- // TODO Hub multiple level
- if (dev->rhport == rhport &&
- (hub_addr == 0 || dev->hub_addr == hub_addr) && // hub_addr == 0 & hub_port == 0 means roothub
- (hub_port == 0 || dev->hub_port == hub_port) &&
- dev->state != TUSB_DEVICE_STATE_UNPLUG)
+ // terminate transfer if any stage failed
+ _xfer_complete(dev_addr, result);
+ }else
+ {
+ switch(_ctrl_xfer.stage)
{
- // Invoke callback before close driver
- if (tuh_umount_cb) tuh_umount_cb(dev_addr);
+ case CONTROL_STAGE_SETUP:
+ if (request->wLength)
+ {
+ // DATA stage: initial data toggle is always 1
+ _set_control_xfer_stage(CONTROL_STAGE_DATA);
+ TU_ASSERT( hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) );
+ return true;
+ }
+ TU_ATTR_FALLTHROUGH;
- // Close class driver
- for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
- {
- TU_LOG2("%s close\r\n", usbh_class_drivers[drv_id].name);
- usbh_class_drivers[drv_id].close(dev_addr);
- }
+ case CONTROL_STAGE_DATA:
+ if (request->wLength)
+ {
+ TU_LOG2("[%u:%u] Control data:\r\n", rhport, dev_addr);
+ TU_LOG2_MEM(_ctrl_xfer.buffer, xferred_bytes, 2);
+ }
- memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
- memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
+ _ctrl_xfer.actual_len = (uint16_t) xferred_bytes;
- hcd_device_close(rhport, dev_addr);
+ // ACK stage: toggle is always 1
+ _set_control_xfer_stage(CONTROL_STAGE_ACK);
+ TU_ASSERT( hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0) );
+ break;
+
+ case CONTROL_STAGE_ACK:
+ _xfer_complete(dev_addr, result);
+ break;
- dev->state = TUSB_DEVICE_STATE_UNPLUG;
+ default: return false;
}
}
+
+ return true;
}
//--------------------------------------------------------------------+
-// INTERNAL HELPER
+//
//--------------------------------------------------------------------+
-static uint8_t get_new_address(bool is_hub)
+
+bool tuh_edpt_xfer(tuh_xfer_t* xfer)
{
- uint8_t const start = (is_hub ? CFG_TUH_DEVICE_MAX : 0) + 1;
- uint8_t const count = (is_hub ? CFG_TUH_HUB : CFG_TUH_DEVICE_MAX);
+ uint8_t const daddr = xfer->daddr;
+ uint8_t const ep_addr = xfer->ep_addr;
+
+ TU_VERIFY(daddr && ep_addr);
+
+ TU_VERIFY(usbh_edpt_claim(daddr, ep_addr));
- for (uint8_t i=0; i < count; i++)
+ if ( !usbh_edpt_xfer_with_callback(daddr, ep_addr, xfer->buffer, (uint16_t) xfer->buflen, xfer->complete_cb, xfer->user_data) )
{
- uint8_t const addr = start + i;
- if (get_device(addr)->state == TUSB_DEVICE_STATE_UNPLUG) return addr;
+ usbh_edpt_release(daddr, ep_addr);
+ return false;
}
- return ADDR_INVALID;
+
+ return true;
}
-void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
+//--------------------------------------------------------------------+
+// USBH API For Class Driver
+//--------------------------------------------------------------------+
+
+uint8_t usbh_get_rhport(uint8_t dev_addr)
{
usbh_device_t* dev = get_device(dev_addr);
+ return dev ? dev->rhport : _dev0.rhport;
+}
- for(itf_num++; itf_num < sizeof(dev->itf2drv); itf_num++)
- {
- // continue with next valid interface
- // TODO skip IAD binding interface such as CDCs
- uint8_t const drv_id = dev->itf2drv[itf_num];
- if (drv_id != DRVID_INVALID)
- {
- usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
- TU_LOG2("%s set config: itf = %u\r\n", driver->name, itf_num);
- driver->set_config(dev_addr, itf_num);
- break;
- }
- }
+uint8_t* usbh_get_enum_buf(void)
+{
+ return _usbh_ctrl_buf;
+}
- // all interface are configured
- if (itf_num == sizeof(dev->itf2drv))
+void usbh_int_set(bool enabled)
+{
+ // TODO all host controller if multiple is used
+ if (enabled)
{
- // Invoke callback if available
- if (tuh_mount_cb) tuh_mount_cb(dev_addr);
+ hcd_int_enable(_usbh_controller);
+ }else
+ {
+ hcd_int_disable(_usbh_controller);
}
}
//--------------------------------------------------------------------+
-// Enumeration Process
-// is a lengthy process with a seires of control transfer to configure
-// newly attached device. Each step is handled by a function in this
-// section
-// TODO due to the shared _usbh_ctrl_buf, we must complete enumerating
-// one device before enumerating another one.
+// Endpoint API
//--------------------------------------------------------------------+
-static bool enum_request_addr0_device_desc(void);
-static bool enum_request_set_addr(void);
+// TODO has some duplication code with device, refactor later
+bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
+{
+ usbh_device_t* dev = get_device(dev_addr);
-static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_set_address_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_get_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_get_9byte_config_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_get_config_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_set_config_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
+ // addr0 only use tuh_control_xfer
+ TU_ASSERT(dev);
-#if CFG_TUH_HUB
-static bool enum_hub_clear_reset0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
-{
- (void) dev_addr; (void) request;
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
- enum_request_addr0_device_desc();
- return true;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ return tu_edpt_claim(&dev->ep_status[epnum][dir], _usbh_mutex);
}
-static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+// TODO has some duplication code with device, refactor later
+bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
{
- (void) dev_addr; (void) request;
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
+ usbh_device_t* dev = get_device(dev_addr);
- enum_request_set_addr();
+ // addr0 only use tuh_control_xfer
+ TU_ASSERT(dev);
- // done with hub, waiting for next data on status pipe
- (void) hub_status_pipe_queue( _dev0.hub_addr );
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- return true;
+ return tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex);
}
-static bool enum_hub_get_status1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+// TODO has some duplication code with device, refactor later
+bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
- (void) dev_addr; (void) request;
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
+ (void) complete_cb;
+ (void) user_data;
- hub_port_status_response_t port_status;
- memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t));
+ usbh_device_t* dev = get_device(dev_addr);
+ TU_VERIFY(dev);
- // Acknowledge Port Reset Change if Reset Successful
- if (port_status.change.reset)
- {
- TU_ASSERT( hub_port_clear_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) );
- }
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ tu_edpt_state_t* ep_state = &dev->ep_status[epnum][dir];
- return true;
-}
+ TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
-static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
-{
- (void) dev_addr; (void) request;
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
+ // Attempt to transfer on a busy endpoint, sound like an race condition !
+ TU_ASSERT(ep_state->busy == 0);
- hub_port_status_response_t port_status;
- memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t));
+ // Set busy first since the actual transfer can be complete before hcd_edpt_xfer()
+ // could return and USBH task can preempt and clear the busy
+ ep_state->busy = 1;
+
+#if CFG_TUH_API_EDPT_XFER
+ dev->ep_callback[epnum][dir].complete_cb = complete_cb;
+ dev->ep_callback[epnum][dir].user_data = user_data;
+#endif
- if ( !port_status.status.connection )
+ if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
{
- // device unplugged while delaying, nothing else to do, queue hub status
- return hub_status_pipe_queue(dev_addr);
+ TU_LOG2("OK\r\n");
+ return true;
+ }else
+ {
+ // HCD error, mark endpoint as ready to allow next transfer
+ ep_state->busy = 0;
+ ep_state->claimed = 0;
+ TU_LOG1("Failed\r\n");
+ TU_BREAKPOINT();
+ return false;
}
+}
- _dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH :
- (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
+static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
+{
+ TU_LOG2("[%u:%u] Open EP0 with Size = %u\r\n", usbh_get_rhport(dev_addr), dev_addr, max_packet_size);
- // Acknowledge Port Reset Change
- if (port_status.change.reset)
+ tusb_desc_endpoint_t ep0_desc =
{
- hub_port_clear_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset0_complete);
- }
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+ .bEndpointAddress = 0,
+ .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
+ .wMaxPacketSize = max_packet_size,
+ .bInterval = 0
+ };
- return true;
+ return hcd_edpt_open(usbh_get_rhport(dev_addr), dev_addr, &ep0_desc);
}
-#endif
-static bool enum_new_device(hcd_event_t* event)
+bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
{
- _dev0.rhport = event->rhport; // TODO refractor integrate to device_pool
- _dev0.hub_addr = event->connection.hub_addr;
- _dev0.hub_port = event->connection.hub_port;
+ TU_ASSERT( tu_edpt_validate(desc_ep, tuh_speed_get(dev_addr)) );
- //------------- connected/disconnected directly with roothub -------------//
- if (_dev0.hub_addr == 0)
- {
- // wait until device is stable TODO non blocking
- osal_task_delay(RESET_DELAY);
+ return hcd_edpt_open(usbh_get_rhport(dev_addr), dev_addr, desc_ep);
+}
- // device unplugged while delaying
- if ( !hcd_port_connect_status(_dev0.rhport) ) return true;
+bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
- _dev0.speed = hcd_port_speed_get(_dev0.rhport );
+ usbh_device_t* dev = get_device(dev_addr);
+ TU_VERIFY(dev);
- enum_request_addr0_device_desc();
- }
-#if CFG_TUH_HUB
- //------------- connected/disconnected via hub -------------//
- else
+ return dev->ep_status[epnum][dir].busy;
+}
+
+//--------------------------------------------------------------------+
+// HCD Event Handler
+//--------------------------------------------------------------------+
+
+void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info)
+{
+ usbh_device_t const* dev = get_device(dev_addr);
+
+ if (dev)
{
- // wait until device is stable
- osal_task_delay(RESET_DELAY);
- TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete) );
+ devtree_info->rhport = dev->rhport;
+ devtree_info->hub_addr = dev->hub_addr;
+ devtree_info->hub_port = dev->hub_port;
+ devtree_info->speed = dev->speed;
+ }else
+ {
+ devtree_info->rhport = _dev0.rhport;
+ devtree_info->hub_addr = _dev0.hub_addr;
+ devtree_info->hub_port = _dev0.hub_port;
+ devtree_info->speed = _dev0.speed;
}
-#endif // CFG_TUH_HUB
-
- return true;
}
-static bool enum_request_addr0_device_desc(void)
+TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
{
- // TODO probably doesn't need to open/close each enumeration
- uint8_t const addr0 = 0;
- TU_ASSERT( usbh_edpt_control_open(addr0, 8) );
+ switch (event->event_id)
+ {
+ default:
+ osal_queue_send(_usbh_q, event, in_isr);
+ break;
+ }
+}
+
+//--------------------------------------------------------------------+
+// Descriptors Async
+//--------------------------------------------------------------------+
- //------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------//
- TU_LOG2("Get 8 byte of Device Descriptor\r\n");
+// generic helper to get a descriptor
+// if blocking, user_data could be pointed to xfer_result
+static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
tusb_control_request_t const request =
{
.bmRequestType_bit =
@@ -728,82 +892,133 @@ static bool enum_request_addr0_device_desc(void)
.direction = TUSB_DIR_IN
},
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
- .wValue = TUSB_DESC_DEVICE << 8,
- .wIndex = 0,
- .wLength = 8
+ .wValue = tu_htole16( TU_U16(type, index) ),
+ .wIndex = tu_htole16(language_id),
+ .wLength = tu_htole16(len)
};
- TU_ASSERT( tuh_control_xfer(addr0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete) );
- return true;
-}
+ tuh_xfer_t xfer =
+ {
+ .daddr = daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = buffer,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
-// After Get Device Descriptor of Address 0
-static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
-{
- (void) request;
- TU_ASSERT(0 == dev_addr);
+ bool const ret = tuh_control_xfer(&xfer);
- if (XFER_RESULT_SUCCESS != result)
+ // if blocking, user_data could be pointed to xfer_result
+ if ( !complete_cb && user_data )
{
-#if CFG_TUH_HUB
- // TODO remove, waiting for next data on status pipe
- if (_dev0.hub_addr != 0) hub_status_pipe_queue(_dev0.hub_addr);
-#endif
-
- return false;
+ *((xfer_result_t*) user_data) = xfer.result;
}
- tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
- TU_ASSERT( tu_desc_type(desc_device) == TUSB_DESC_DEVICE );
+ return ret;
+}
- // Reset device again before Set Address
- TU_LOG2("Port reset \r\n");
+bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ return _get_descriptor(daddr, type, index, 0x0000, buffer, len, complete_cb, user_data);
+}
- if (_dev0.hub_addr == 0)
- {
- // connected directly to roothub
- hcd_port_reset( _dev0.rhport ); // reset port after 8 byte descriptor
- osal_task_delay(RESET_DELAY);
+bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ len = tu_min16(len, sizeof(tusb_desc_device_t));
+ return tuh_descriptor_get(daddr, TUSB_DESC_DEVICE, 0, buffer, len, complete_cb, user_data);
+}
- enum_request_set_addr();
- }
-#if CFG_TUH_HUB
- else
- {
- // after RESET_DELAY the hub_port_reset() already complete
- TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, NULL) );
- osal_task_delay(RESET_DELAY);
+bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ return tuh_descriptor_get(daddr, TUSB_DESC_CONFIGURATION, index, buffer, len, complete_cb, user_data);
+}
- tuh_task(); // FIXME temporarily to clean up port_reset control transfer
+//------------- String Descriptor -------------//
- TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) );
- }
-#endif
+bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ return _get_descriptor(daddr, TUSB_DESC_STRING, index, language_id, buffer, len, complete_cb, user_data);
+}
- return true;
+// Get manufacturer string descriptor
+bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ usbh_device_t const* dev = get_device(daddr);
+ TU_VERIFY(dev && dev->i_manufacturer);
+ return tuh_descriptor_get_string(daddr, dev->i_manufacturer, language_id, buffer, len, complete_cb, user_data);
}
-static bool enum_request_set_addr(void)
+// Get product string descriptor
+bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
- uint8_t const addr0 = 0;
- tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
+ usbh_device_t const* dev = get_device(daddr);
+ TU_VERIFY(dev && dev->i_product);
+ return tuh_descriptor_get_string(daddr, dev->i_product, language_id, buffer, len, complete_cb, user_data);
+}
- // Get new address
- uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
- TU_ASSERT(new_addr != ADDR_INVALID);
+// Get serial string descriptor
+bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ usbh_device_t const* dev = get_device(daddr);
+ TU_VERIFY(dev && dev->i_serial);
+ return tuh_descriptor_get_string(daddr, dev->i_serial, language_id, buffer, len, complete_cb, user_data);
+}
- TU_LOG2("Set Address = %d\r\n", new_addr);
+// Get HID report descriptor
+// if blocking, user_data could be pointed to xfer_result
+bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ TU_LOG2("HID Get Report Descriptor\r\n");
+ tusb_control_request_t const request =
+ {
+ .bmRequestType_bit =
+ {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_STANDARD,
+ .direction = TUSB_DIR_IN
+ },
+ .bRequest = TUSB_REQ_GET_DESCRIPTOR,
+ .wValue = tu_htole16(TU_U16(desc_type, index)),
+ .wIndex = tu_htole16((uint16_t) itf_num),
+ .wLength = len
+ };
- usbh_device_t* new_dev = get_device(new_addr);
+ tuh_xfer_t xfer =
+ {
+ .daddr = daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = buffer,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
- new_dev->rhport = _dev0.rhport;
- new_dev->hub_addr = _dev0.hub_addr;
- new_dev->hub_port = _dev0.hub_port;
- new_dev->speed = _dev0.speed;
- new_dev->connected = 1;
- new_dev->ep0_size = desc_device->bMaxPacketSize0;
+ bool const ret = tuh_control_xfer(&xfer);
- tusb_control_request_t const new_request =
+ // if blocking, user_data could be pointed to xfer_result
+ if ( !complete_cb && user_data )
+ {
+ *((xfer_result_t*) user_data) = xfer.result;
+ }
+
+ return ret;
+}
+
+bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ TU_LOG2("Set Configuration = %d\r\n", config_num);
+
+ tusb_control_request_t const request =
{
.bmRequestType_bit =
{
@@ -811,137 +1026,437 @@ static bool enum_request_set_addr(void)
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_OUT
},
- .bRequest = TUSB_REQ_SET_ADDRESS,
- .wValue = new_addr,
+ .bRequest = TUSB_REQ_SET_CONFIGURATION,
+ .wValue = tu_htole16(config_num),
.wIndex = 0,
.wLength = 0
};
- TU_ASSERT( tuh_control_xfer(addr0, &new_request, NULL, enum_set_address_complete) );
+ tuh_xfer_t xfer =
+ {
+ .daddr = daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
- return true;
+ return tuh_control_xfer(&xfer);
}
-// After SET_ADDRESS is complete
-static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+//--------------------------------------------------------------------+
+// Descriptor Sync
+//--------------------------------------------------------------------+
+
+#define _CONTROL_SYNC_API(_async_func, ...) \
+ xfer_result_t result = XFER_RESULT_INVALID;\
+ TU_VERIFY(_async_func(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \
+ return (uint8_t) result
+
+uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len)
{
- TU_ASSERT(0 == dev_addr);
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
+ _CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len);
+}
- uint8_t const new_addr = (uint8_t const) request->wValue;
+uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len)
+{
+ _CONTROL_SYNC_API(tuh_descriptor_get_device, daddr, buffer, len);
+}
- usbh_device_t* new_dev = get_device(new_addr);
- new_dev->addressed = 1;
+uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len)
+{
+ _CONTROL_SYNC_API(tuh_descriptor_get_configuration, daddr, index, buffer, len);
+}
+
+uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len)
+{
+ _CONTROL_SYNC_API(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len);
+}
- // TODO close device 0, may not be needed
- hcd_device_close(_dev0.rhport, 0);
+uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len)
+{
+ _CONTROL_SYNC_API(tuh_descriptor_get_string, daddr, index, language_id, buffer, len);
+}
- // open control pipe for new address
- TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_size) );
+uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len)
+{
+ _CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len);
+}
+
+uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len)
+{
+ _CONTROL_SYNC_API(tuh_descriptor_get_product_string, daddr, language_id, buffer, len);
+}
- // Get full device descriptor
- TU_LOG2("Get Device Descriptor\r\n");
- tusb_control_request_t const new_request =
+uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len)
+{
+ _CONTROL_SYNC_API(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len);
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+TU_ATTR_ALWAYS_INLINE
+static inline bool is_hub_addr(uint8_t daddr)
+{
+ return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX);
+}
+
+// a device unplugged from rhport:hub_addr:hub_port
+static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
+{
+ //------------- find the all devices (star-network) under port that is unplugged -------------//
+ // TODO mark as disconnected in ISR, also handle dev0
+ for ( uint8_t dev_id = 0; dev_id < TU_ARRAY_SIZE(_usbh_devices); dev_id++ )
{
- .bmRequestType_bit =
+ usbh_device_t* dev = &_usbh_devices[dev_id];
+ uint8_t const dev_addr = dev_id+1;
+
+ // TODO Hub multiple level
+ if (dev->rhport == rhport &&
+ (hub_addr == 0 || dev->hub_addr == hub_addr) && // hub_addr = 0 means roothub
+ (hub_port == 0 || dev->hub_port == hub_port) && // hub_port = 0 means all devices of downstream hub
+ dev->connected)
{
- .recipient = TUSB_REQ_RCPT_DEVICE,
- .type = TUSB_REQ_TYPE_STANDARD,
- .direction = TUSB_DIR_IN
- },
- .bRequest = TUSB_REQ_GET_DESCRIPTOR,
- .wValue = TUSB_DESC_DEVICE << 8,
- .wIndex = 0,
- .wLength = sizeof(tusb_desc_device_t)
- };
+ TU_LOG2(" Address = %u\r\n", dev_addr);
- TU_ASSERT(tuh_control_xfer(new_addr, &new_request, _usbh_ctrl_buf, enum_get_device_desc_complete));
+ if (is_hub_addr(dev_addr))
+ {
+ TU_LOG(USBH_DBG_LVL, "HUB address = %u is unmounted\r\n", dev_addr);
+ // If the device itself is a usb hub, unplug downstream devices.
+ // FIXME un-roll recursive calls to prevent potential stack overflow
+ process_device_unplugged(rhport, dev_addr, 0);
+ }else
+ {
+ // Invoke callback before closing driver
+ if (tuh_umount_cb) tuh_umount_cb(dev_addr);
+ }
- return true;
+ // Close class driver
+ for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
+ {
+ TU_LOG2("%s close\r\n", usbh_class_drivers[drv_id].name);
+ usbh_class_drivers[drv_id].close(dev_addr);
+ }
+
+ hcd_device_close(rhport, dev_addr);
+ clear_device(dev);
+ // abort on-going control xfer if any
+ if (_ctrl_xfer.daddr == dev_addr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
+ }
+ }
}
-static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
-{
- (void) request;
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
+//--------------------------------------------------------------------+
+// Enumeration Process
+// is a lengthy process with a series of control transfer to configure
+// newly attached device.
+// NOTE: due to the shared _usbh_ctrl_buf, we must complete enumerating
+// one device before enumerating another one.
+//--------------------------------------------------------------------+
- tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
- usbh_device_t* dev = get_device(dev_addr);
+enum {
+ ENUM_IDLE,
+ ENUM_RESET_1, // 1st reset when attached
+ //ENUM_HUB_GET_STATUS_1,
+ ENUM_HUB_CLEAR_RESET_1,
+ ENUM_ADDR0_DEVICE_DESC,
+ ENUM_RESET_2, // 2nd reset before set address (not used)
+ ENUM_HUB_GET_STATUS_2,
+ ENUM_HUB_CLEAR_RESET_2,
+ ENUM_SET_ADDR,
- dev->vid = desc_device->idVendor;
- dev->pid = desc_device->idProduct;
- dev->i_manufacturer = desc_device->iManufacturer;
- dev->i_product = desc_device->iProduct;
- dev->i_serial = desc_device->iSerialNumber;
+ ENUM_GET_DEVICE_DESC,
+ ENUM_GET_9BYTE_CONFIG_DESC,
+ ENUM_GET_FULL_CONFIG_DESC,
+ ENUM_SET_CONFIG,
+ ENUM_CONFIG_DRIVER
+};
-// if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf);
+static bool enum_request_set_addr(void);
+static bool _parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
+static void enum_full_complete(void);
- TU_LOG2("Get 9 bytes of Configuration Descriptor\r\n");
- tusb_control_request_t const new_request =
+// process device enumeration
+static void process_enumeration(tuh_xfer_t* xfer)
+{
+ if (XFER_RESULT_SUCCESS != xfer->result)
{
- .bmRequestType_bit =
+ // stop enumeration, maybe we could retry this
+ enum_full_complete();
+ return;
+ }
+
+ uint8_t const daddr = xfer->daddr;
+ uintptr_t const state = xfer->user_data;
+
+ switch(state)
+ {
+#if CFG_TUH_HUB
+ //case ENUM_HUB_GET_STATUS_1: break;
+
+ case ENUM_HUB_CLEAR_RESET_1:
{
- .recipient = TUSB_REQ_RCPT_DEVICE,
- .type = TUSB_REQ_TYPE_STANDARD,
- .direction = TUSB_DIR_IN
- },
- .bRequest = TUSB_REQ_GET_DESCRIPTOR,
- .wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1),
- .wIndex = 0,
- .wLength = 9
- };
+ hub_port_status_response_t port_status;
+ memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t));
+
+ if ( !port_status.status.connection )
+ {
+ // device unplugged while delaying, nothing else to do
+ enum_full_complete();
+ return;
+ }
- TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_9byte_config_desc_complete) );
+ _dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH :
+ (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
- return true;
+ // Acknowledge Port Reset Change
+ if (port_status.change.reset)
+ {
+ hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port, process_enumeration, ENUM_ADDR0_DEVICE_DESC);
+ }
+ }
+ break;
+
+ case ENUM_HUB_GET_STATUS_2:
+ osal_task_delay(RESET_DELAY);
+ TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, process_enumeration, ENUM_HUB_CLEAR_RESET_2), );
+ break;
+
+ case ENUM_HUB_CLEAR_RESET_2:
+ {
+ hub_port_status_response_t port_status;
+ memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t));
+
+ // Acknowledge Port Reset Change if Reset Successful
+ if (port_status.change.reset)
+ {
+ TU_ASSERT( hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port, process_enumeration, ENUM_SET_ADDR), );
+ }
+ }
+ break;
+#endif
+
+ case ENUM_ADDR0_DEVICE_DESC:
+ {
+ // TODO probably doesn't need to open/close each enumeration
+ uint8_t const addr0 = 0;
+ TU_ASSERT( usbh_edpt_control_open(addr0, 8), );
+
+ // Get first 8 bytes of device descriptor for Control Endpoint size
+ TU_LOG2("Get 8 byte of Device Descriptor\r\n");
+ TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_ctrl_buf, 8, process_enumeration, ENUM_SET_ADDR), );
+ }
+ break;
+
+#if 0
+ case ENUM_RESET_2:
+ // TODO not used by now, but may be needed for some devices !?
+ // Reset device again before Set Address
+ TU_LOG2("Port reset2 \r\n");
+ if (_dev0.hub_addr == 0)
+ {
+ // connected directly to roothub
+ hcd_port_reset( _dev0.rhport );
+ osal_task_delay(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
+ // sof of controller may not running while reseting
+ hcd_port_reset_end(_dev0.rhport);
+ // TODO: fall through to SET ADDRESS, refactor later
+ }
+ #if CFG_TUH_HUB
+ else
+ {
+ // after RESET_DELAY the hub_port_reset() already complete
+ TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, process_enumeration, ENUM_HUB_GET_STATUS_2), );
+ break;
+ }
+ #endif
+ __attribute__((fallthrough));
+#endif
+
+ case ENUM_SET_ADDR:
+ enum_request_set_addr();
+ break;
+
+ case ENUM_GET_DEVICE_DESC:
+ {
+ uint8_t const new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue);
+
+ usbh_device_t* new_dev = get_device(new_addr);
+ TU_ASSERT(new_dev, );
+ new_dev->addressed = 1;
+
+ // Close device 0
+ hcd_device_close(_dev0.rhport, 0);
+
+ // open control pipe for new address
+ TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_size), );
+
+ // Get full device descriptor
+ TU_LOG2("Get Device Descriptor\r\n");
+ TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_ctrl_buf, sizeof(tusb_desc_device_t), process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC), );
+ }
+ break;
+
+ case ENUM_GET_9BYTE_CONFIG_DESC:
+ {
+ tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
+ usbh_device_t* dev = get_device(daddr);
+ TU_ASSERT(dev, );
+
+ dev->vid = desc_device->idVendor;
+ dev->pid = desc_device->idProduct;
+ dev->i_manufacturer = desc_device->iManufacturer;
+ dev->i_product = desc_device->iProduct;
+ dev->i_serial = desc_device->iSerialNumber;
+
+ // if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf);
+
+ // Get 9-byte for total length
+ uint8_t const config_idx = CONFIG_NUM - 1;
+ TU_LOG2("Get Configuration[0] Descriptor (9 bytes)\r\n");
+ TU_ASSERT( tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, 9, process_enumeration, ENUM_GET_FULL_CONFIG_DESC), );
+ }
+ break;
+
+ case ENUM_GET_FULL_CONFIG_DESC:
+ {
+ uint8_t const * desc_config = _usbh_ctrl_buf;
+
+ // Use offsetof to avoid pointer to the odd/misaligned address
+ uint16_t const total_len = tu_le16toh( tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)) );
+
+ // TODO not enough buffer to hold configuration descriptor
+ TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE, );
+
+ // Get full configuration descriptor
+ uint8_t const config_idx = CONFIG_NUM - 1;
+ TU_LOG2("Get Configuration[0] Descriptor\r\n");
+ TU_ASSERT( tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, total_len, process_enumeration, ENUM_SET_CONFIG), );
+ }
+ break;
+
+ case ENUM_SET_CONFIG:
+ // Parse configuration & set up drivers
+ // Driver open aren't allowed to make any usb transfer yet
+ TU_ASSERT( _parse_configuration_descriptor(daddr, (tusb_desc_configuration_t*) _usbh_ctrl_buf), );
+
+ TU_ASSERT( tuh_configuration_set(daddr, CONFIG_NUM, process_enumeration, ENUM_CONFIG_DRIVER), );
+ break;
+
+ case ENUM_CONFIG_DRIVER:
+ {
+ TU_LOG2("Device configured\r\n");
+ usbh_device_t* dev = get_device(daddr);
+ TU_ASSERT(dev, );
+
+ dev->configured = 1;
+
+ // Start the Set Configuration process for interfaces (itf = DRVID_INVALID)
+ // Since driver can perform control transfer within its set_config, this is done asynchronously.
+ // The process continue with next interface when class driver complete its sequence with usbh_driver_set_config_complete()
+ // TODO use separated API instead of using DRVID_INVALID
+ usbh_driver_set_config_complete(daddr, DRVID_INVALID);
+ }
+ break;
+
+ default:
+ // stop enumeration if unknown state
+ enum_full_complete();
+ break;
+ }
}
-static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_new_device(hcd_event_t* event)
{
- (void) request;
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
+ _dev0.rhport = event->rhport;
+ _dev0.hub_addr = event->connection.hub_addr;
+ _dev0.hub_port = event->connection.hub_port;
- // TODO not enough buffer to hold configuration descriptor
- uint8_t const * desc_config = _usbh_ctrl_buf;
+ if (_dev0.hub_addr == 0)
+ {
+ // connected/disconnected directly with roothub
+ // wait until device is stable TODO non blocking
+ hcd_port_reset(_dev0.rhport);
+ osal_task_delay(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
+ // sof of controller may not running while reseting
+ hcd_port_reset_end( _dev0.rhport);
- // Use offsetof to avoid pointer to the odd/misaligned address
- uint16_t const total_len = tu_le16toh( tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)) );
+ // device unplugged while delaying
+ if ( !hcd_port_connect_status(_dev0.rhport) ) return true;
- TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE);
+ _dev0.speed = hcd_port_speed_get(_dev0.rhport );
+ TU_LOG2("%s Speed\r\n", tu_str_speed[_dev0.speed]);
- // Get full configuration descriptor
- TU_LOG2("Get Configuration Descriptor\r\n");
- tusb_control_request_t const new_request =
- {
- .bmRequestType_bit =
- {
- .recipient = TUSB_REQ_RCPT_DEVICE,
- .type = TUSB_REQ_TYPE_STANDARD,
- .direction = TUSB_DIR_IN
- },
- .bRequest = TUSB_REQ_GET_DESCRIPTOR,
- .wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1),
- .wIndex = 0,
- .wLength = total_len
+ // fake transfer to kick-off the enumeration process
+ tuh_xfer_t xfer;
+ xfer.daddr = 0;
+ xfer.result = XFER_RESULT_SUCCESS;
+ xfer.user_data = ENUM_ADDR0_DEVICE_DESC;
- };
+ process_enumeration(&xfer);
+
+ }
+#if CFG_TUH_HUB
+ else
+ {
+ // connected/disconnected via external hub
+ // wait until device is stable
+ osal_task_delay(RESET_DELAY);
- TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_config_desc_complete) );
+ // ENUM_HUB_GET_STATUS
+ //TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete, 0) );
+ TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, process_enumeration, ENUM_HUB_CLEAR_RESET_1) );
+ }
+#endif // hub
return true;
}
-static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static uint8_t get_new_address(bool is_hub)
+{
+ uint8_t start;
+ uint8_t end;
+ if ( is_hub )
+ {
+ start = CFG_TUH_DEVICE_MAX;
+ end = start + CFG_TUH_HUB;
+ }else
+ {
+ start = 0;
+ end = start + CFG_TUH_DEVICE_MAX;
+ }
+
+ for ( uint8_t idx = start; idx < end; idx++)
+ {
+ if (!_usbh_devices[idx].connected) return (idx+1);
+ }
+
+ return 0; // invalid address
+}
+
+static bool enum_request_set_addr(void)
{
- (void) request;
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
+ tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
+
+ // Get new address
+ uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
+ TU_ASSERT(new_addr != 0);
+
+ TU_LOG2("Set Address = %d\r\n", new_addr);
- // Parse configuration & set up drivers
- // Driver open aren't allowed to make any usb transfer yet
- TU_ASSERT( parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf) );
+ usbh_device_t* new_dev = get_device(new_addr);
- TU_LOG2("Set Configuration = %d\r\n", CONFIG_NUM);
- tusb_control_request_t const new_request =
+ new_dev->rhport = _dev0.rhport;
+ new_dev->hub_addr = _dev0.hub_addr;
+ new_dev->hub_port = _dev0.hub_port;
+ new_dev->speed = _dev0.speed;
+ new_dev->connected = 1;
+ new_dev->ep0_size = desc_device->bMaxPacketSize0;
+
+ tusb_control_request_t const request =
{
.bmRequestType_bit =
{
@@ -949,37 +1464,28 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_OUT
},
- .bRequest = TUSB_REQ_SET_CONFIGURATION,
- .wValue = CONFIG_NUM,
+ .bRequest = TUSB_REQ_SET_ADDRESS,
+ .wValue = tu_htole16(new_addr),
.wIndex = 0,
.wLength = 0
};
- TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, enum_set_config_complete) );
-
- return true;
-}
-
-static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
-{
- (void) request;
- TU_ASSERT(XFER_RESULT_SUCCESS == result);
-
- TU_LOG2("Device configured\r\n");
- usbh_device_t* dev = get_device(dev_addr);
- dev->configured = 1;
- dev->state = TUSB_DEVICE_STATE_CONFIGURED;
+ tuh_xfer_t xfer =
+ {
+ .daddr = 0, // dev0
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = process_enumeration,
+ .user_data = ENUM_GET_DEVICE_DESC
+ };
- // Start the Set Configuration process for interfaces (itf = DRVID_INVALID)
- // Since driver can perform control transfer within its set_config, this is done asynchronously.
- // The process continue with next interface when class driver complete its sequence with usbh_driver_set_config_complete()
- // TODO use separated API instead of using DRVID_INVALID
- usbh_driver_set_config_complete(dev_addr, DRVID_INVALID);
+ TU_ASSERT( tuh_control_xfer(&xfer) );
return true;
}
-static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
+static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
{
usbh_device_t* dev = get_device(dev_addr);
@@ -1019,43 +1525,34 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
}
#endif
- uint16_t const drv_len = tu_desc_get_interface_total_len(desc_itf, assoc_itf_count, desc_end-p_desc);
+ uint16_t const drv_len = tu_desc_get_interface_total_len(desc_itf, assoc_itf_count, (uint16_t) (desc_end-p_desc));
TU_ASSERT(drv_len >= sizeof(tusb_desc_interface_t));
- if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
- {
- // TODO Attach hub to Hub is not currently supported
- // skip this interface
- TU_LOG(USBH_DBG_LVL, "Only 1 level of HUB is supported\r\n");
- }
- else
+ // Find driver for this interface
+ uint8_t drv_id;
+ for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
{
- // Find driver for this interface
- uint8_t drv_id;
- for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
+ usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
+
+ if ( driver->open(dev->rhport, dev_addr, desc_itf, drv_len) )
{
- usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
+ // open successfully
+ TU_LOG2(" %s opened\r\n", driver->name);
- if ( driver->open(dev->rhport, dev_addr, desc_itf, drv_len) )
+ // bind (associated) interfaces to found driver
+ for(uint8_t i=0; i<assoc_itf_count; i++)
{
- // open successfully
- TU_LOG2(" %s opened\r\n", driver->name);
+ uint8_t const itf_num = desc_itf->bInterfaceNumber+i;
- // bind (associated) interfaces to found driver
- for(uint8_t i=0; i<assoc_itf_count; i++)
- {
- uint8_t const itf_num = desc_itf->bInterfaceNumber+i;
-
- // Interface number must not be used already
- TU_ASSERT( DRVID_INVALID == dev->itf2drv[itf_num] );
- dev->itf2drv[itf_num] = drv_id;
- }
+ // Interface number must not be used already
+ TU_ASSERT( DRVID_INVALID == dev->itf2drv[itf_num] );
+ dev->itf2drv[itf_num] = drv_id;
+ }
- // bind all endpoints to found driver
- tu_edpt_bind_driver(dev->ep2drv, desc_itf, drv_len, drv_id);
+ // bind all endpoints to found driver
+ tu_edpt_bind_driver(dev->ep2drv, desc_itf, drv_len, drv_id);
- break; // exit driver find loop
- }
+ break; // exit driver find loop
}
if( drv_id >= USBH_CLASS_DRIVER_COUNT )
@@ -1072,131 +1569,47 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
return true;
}
-//--------------------------------------------------------------------+
-// Endpoint API
-//--------------------------------------------------------------------+
-
-// TODO has some duplication code with device, refactor later
-bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
+void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
usbh_device_t* dev = get_device(dev_addr);
-#if CFG_TUSB_OS != OPT_OS_NONE
- // pre-check to help reducing mutex lock
- TU_VERIFY((dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0));
- osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
-#endif
-
- // can only claim the endpoint if it is not busy and not claimed yet.
- bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0);
- if (ret)
+ for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++)
{
- dev->ep_status[epnum][dir].claimed = 1;
+ // continue with next valid interface
+ // TODO skip IAD binding interface such as CDCs
+ uint8_t const drv_id = dev->itf2drv[itf_num];
+ if (drv_id != DRVID_INVALID)
+ {
+ usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
+ TU_LOG2("%s set config: itf = %u\r\n", driver->name, itf_num);
+ driver->set_config(dev_addr, itf_num);
+ break;
+ }
}
-#if CFG_TUSB_OS != OPT_OS_NONE
- osal_mutex_unlock(dev->mutex);
-#endif
-
- return ret;
-}
-
-// TODO has some duplication code with device, refactor later
-bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- usbh_device_t* dev = get_device(dev_addr);
-
-#if CFG_TUSB_OS != OPT_OS_NONE
- osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
-#endif
-
- // can only release the endpoint if it is claimed and not busy
- bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 1);
- if (ret)
+ // all interface are configured
+ if (itf_num == CFG_TUH_INTERFACE_MAX)
{
- dev->ep_status[epnum][dir].claimed = 0;
- }
-
-#if CFG_TUSB_OS != OPT_OS_NONE
- osal_mutex_unlock(dev->mutex);
-#endif
-
- return ret;
-}
-
-// TODO has some duplication code with device, refactor later
-bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- usbh_device_t* dev = get_device(dev_addr);
-
- TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
-
- // Attempt to transfer on a busy endpoint, sound like an race condition !
- TU_ASSERT(dev->ep_status[epnum][dir].busy == 0);
-
- // Set busy first since the actual transfer can be complete before hcd_edpt_xfer()
- // could return and USBH task can preempt and clear the busy
- dev->ep_status[epnum][dir].busy = true;
+ enum_full_complete();
- if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
- {
- TU_LOG2("OK\r\n");
- return true;
- }else
- {
- // HCD error, mark endpoint as ready to allow next transfer
- dev->ep_status[epnum][dir].busy = false;
- dev->ep_status[epnum][dir].claimed = 0;
- TU_LOG2("failed\r\n");
- TU_BREAKPOINT();
- return false;
+ if (is_hub_addr(dev_addr))
+ {
+ TU_LOG(USBH_DBG_LVL, "HUB address = %u is mounted\r\n", dev_addr);
+ }else
+ {
+ // Invoke callback if available
+ if (tuh_mount_cb) tuh_mount_cb(dev_addr);
+ }
}
}
-static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
-{
- TU_LOG2("Open EP0 with Size = %u (addr = %u)\r\n", max_packet_size, dev_addr);
-
- tusb_desc_endpoint_t ep0_desc =
- {
- .bLength = sizeof(tusb_desc_endpoint_t),
- .bDescriptorType = TUSB_DESC_ENDPOINT,
- .bEndpointAddress = 0,
- .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
- .wMaxPacketSize = max_packet_size,
- .bInterval = 0
- };
-
- return hcd_edpt_open(usbh_get_rhport(dev_addr), dev_addr, &ep0_desc);
-}
-
-bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
-{
- usbh_device_t* dev = get_device(dev_addr);
- TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) dev->speed));
-
- return hcd_edpt_open(rhport, dev_addr, desc_ep);
-}
-
-bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
+static void enum_full_complete(void)
{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- usbh_device_t* dev = get_device(dev_addr);
+#if CFG_TUH_HUB
+ // get next hub status
+ if (_dev0.hub_addr) hub_edpt_status_xfer(_dev0.hub_addr);
+#endif
- return dev->ep_status[epnum][dir].busy;
}
-
-
#endif
diff --git a/src/host/usbh.h b/src/host/usbh.h
index 8411cad28..560a1ea23 100644
--- a/src/host/usbh.h
+++ b/src/host/usbh.h
@@ -32,65 +32,221 @@
#endif
#include "common/tusb_common.h"
-#include "hcd.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
-typedef bool (*tuh_control_complete_cb_t)(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+// forward declaration
+struct tuh_xfer_s;
+typedef struct tuh_xfer_s tuh_xfer_t;
+
+typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer);
+
+// Note1: layout and order of this will be changed in near future
+// it is advised to initialize it using member name
+// Note2: not all field is available/meaningful in callback,
+// some info is not saved by usbh to save SRAM
+struct tuh_xfer_s
+{
+ uint8_t daddr;
+ uint8_t ep_addr;
+
+ xfer_result_t result;
+ uint32_t actual_len; // excluding setup packet
+
+ union
+ {
+ tusb_control_request_t const* setup; // setup packet pointer if control transfer
+ uint32_t buflen; // expected length if not control transfer (not available in callback)
+ };
+
+ uint8_t* buffer; // not available in callback if not control transfer
+ tuh_xfer_cb_t complete_cb;
+ uintptr_t user_data;
+
+ // uint32_t timeout_ms; // place holder, not supported yet
+};
+
+// ConfigID for tuh_config()
+enum
+{
+ TUH_CFGID_RPI_PIO_USB_CONFIGURATION = OPT_MCU_RP2040 // cfg_param: pio_usb_configuration_t
+};
+
+//--------------------------------------------------------------------+
+// APPLICATION CALLBACK
+//--------------------------------------------------------------------+
+
+//TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device);
+
+// Invoked when device is mounted (configured)
+TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);
+
+/// Invoked when device is unmounted (bus reset/unplugged)
+TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr);
//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
+// Configure host stack behavior with dynamic or port-specific parameters.
+// Should be called before tuh_init()
+// - cfg_id : configure ID (TBD)
+// - cfg_param: configure data, structure depends on the ID
+bool tuh_configure(uint8_t controller_id, uint32_t cfg_id, const void* cfg_param);
+
// Init host stack
-bool tuh_init(uint8_t rhport);
+bool tuh_init(uint8_t controller_id);
// Check if host stack is already initialized
bool tuh_inited(void);
+// Task function should be called in main/rtos loop, extended version of tuh_task()
+// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever
+// - in_isr: if function is called in ISR
+void tuh_task_ext(uint32_t timeout_ms, bool in_isr);
+
// Task function should be called in main/rtos loop
-void tuh_task(void);
+TU_ATTR_ALWAYS_INLINE static inline
+void tuh_task(void)
+{
+ tuh_task_ext(UINT32_MAX, false);
+}
-// Interrupt handler, name alias to HCD
+#ifndef _TUSB_HCD_H_
extern void hcd_int_handler(uint8_t rhport);
+#endif
+
+// Interrupt handler, name alias to HCD
#define tuh_int_handler hcd_int_handler
-bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid);
-tusb_speed_t tuh_speed_get(uint8_t dev_addr);
+bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid);
+
+tusb_speed_t tuh_speed_get(uint8_t daddr);
// Check if device is connected and configured
-bool tuh_mounted(uint8_t dev_addr);
+bool tuh_mounted(uint8_t daddr);
// Check if device is suspended
-static inline bool tuh_suspended(uint8_t dev_addr)
+TU_ATTR_ALWAYS_INLINE static inline
+bool tuh_suspended(uint8_t daddr)
{
// TODO implement suspend & resume on host
- (void) dev_addr;
+ (void) daddr;
return false;
}
// Check if device is ready to communicate with
-TU_ATTR_ALWAYS_INLINE
-static inline bool tuh_ready(uint8_t dev_addr)
+TU_ATTR_ALWAYS_INLINE static inline
+bool tuh_ready(uint8_t daddr)
{
- return tuh_mounted(dev_addr) && !tuh_suspended(dev_addr);
+ return tuh_mounted(daddr) && !tuh_suspended(daddr);
}
-// Carry out control transfer
-bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb);
+//--------------------------------------------------------------------+
+// Transfer API
+//--------------------------------------------------------------------+
+
+// Submit a control transfer
+// - async: complete callback invoked when finished.
+// - sync : blocking if complete callback is NULL.
+bool tuh_control_xfer(tuh_xfer_t* xfer);
+
+// Submit a bulk/interrupt transfer
+// - async: complete callback invoked when finished.
+// - sync : blocking if complete callback is NULL.
+bool tuh_edpt_xfer(tuh_xfer_t* xfer);
+
+// Open an non-control endpoint
+bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep);
+
+// Set Configuration (control transfer)
+// config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1
+// true on success, false if there is on-going control transfer or incorrect parameters
+bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
//--------------------------------------------------------------------+
-// APPLICATION CALLBACK
+// Descriptors Asynchronous (non-blocking)
//--------------------------------------------------------------------+
-//TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device);
-// Invoked when device is mounted (configured)
-TU_ATTR_WEAK void tuh_mount_cb (uint8_t dev_addr);
+// Get an descriptor (control transfer)
+// true on success, false if there is on-going control transfer or incorrect parameters
+bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-/// Invoked when device is unmounted (bus reset/unplugged)
-TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr);
+// Get device descriptor (control transfer)
+// true on success, false if there is on-going control transfer or incorrect parameters
+bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Get configuration descriptor (control transfer)
+// true on success, false if there is on-going control transfer or incorrect parameters
+bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Get HID report descriptor (control transfer)
+// true on success, false if there is on-going control transfer or incorrect parameters
+bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Get string descriptor (control transfer)
+// true on success, false if there is on-going control transfer or incorrect parameters
+// Blocking if complete callback is NULL, in this case 'user_data' must contain xfer_result_t variable
+bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Get manufacturer string descriptor (control transfer)
+// true on success, false if there is on-going control transfer or incorrect parameters
+bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Get product string descriptor (control transfer)
+// true on success, false if there is on-going control transfer or incorrect parameters
+bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Get serial string descriptor (control transfer)
+// true on success, false if there is on-going control transfer or incorrect parameters
+bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+//--------------------------------------------------------------------+
+// Descriptors Synchronous (blocking)
+//--------------------------------------------------------------------+
+
+// Sync (blocking) version of tuh_descriptor_get()
+// return transfer result
+uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len);
+
+// Sync (blocking) version of tuh_descriptor_get_device()
+// return transfer result
+uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len);
+
+// Sync (blocking) version of tuh_descriptor_get_configuration()
+// return transfer result
+uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len);
+
+// Sync (blocking) version of tuh_descriptor_get_hid_report()
+// return transfer result
+uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len);
+
+// Sync (blocking) version of tuh_descriptor_get_string()
+// return transfer result
+uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len);
+
+// Sync (blocking) version of tuh_descriptor_get_manufacturer_string()
+// return transfer result
+uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
+
+// Sync (blocking) version of tuh_descriptor_get_product_string()
+// return transfer result
+uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
+
+// Sync (blocking) version of tuh_descriptor_get_serial_string()
+// return transfer result
+uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
#ifdef __cplusplus
}
diff --git a/src/host/usbh_classdriver.h b/src/host/usbh_classdriver.h
index 8bc2622aa..c156afea0 100644
--- a/src/host/usbh_classdriver.h
+++ b/src/host/usbh_classdriver.h
@@ -57,20 +57,28 @@ uint8_t usbh_get_rhport(uint8_t dev_addr);
uint8_t* usbh_get_enum_buf(void);
+void usbh_int_set(bool enabled);
+
//--------------------------------------------------------------------+
// USBH Endpoint API
//--------------------------------------------------------------------+
-// Open an endpoint
-bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep);
+// Submit a usb transfer with callback support, require CFG_TUH_API_EDPT_XFER
+bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+TU_ATTR_ALWAYS_INLINE
+static inline bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ return usbh_edpt_xfer_with_callback(dev_addr, ep_addr, buffer, total_bytes, NULL, 0);
+}
-// Submit a usb transfer
-bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
// Claim an endpoint before submitting a transfer.
// If caller does not make any transfer, it must release endpoint for others.
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr);
+// Release claimed endpoint without submitting a transfer
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr);
// Check if endpoint transferring is complete
diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c
deleted file mode 100644
index 9204576ac..000000000
--- a/src/host/usbh_control.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2020, Ha Thach (tinyusb.org)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#include "tusb_option.h"
-
-#if TUSB_OPT_HOST_ENABLED
-
-#include "tusb.h"
-#include "usbh_classdriver.h"
-
-enum
-{
- STAGE_SETUP,
- STAGE_DATA,
- STAGE_ACK
-};
-
-typedef struct
-{
- tusb_control_request_t request TU_ATTR_ALIGNED(4);
-
- uint8_t stage;
- uint8_t* buffer;
- tuh_control_complete_cb_t complete_cb;
-} usbh_control_xfer_t;
-
-static usbh_control_xfer_t _ctrl_xfer;
-
-//CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
-//static uint8_t _tuh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
-
-//--------------------------------------------------------------------+
-// MACRO TYPEDEF CONSTANT ENUM DECLARATION
-//--------------------------------------------------------------------+
-
-bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb)
-{
- // TODO need to claim the endpoint first
- const uint8_t rhport = usbh_get_rhport(dev_addr);
-
- _ctrl_xfer.request = (*request);
- _ctrl_xfer.buffer = buffer;
- _ctrl_xfer.stage = STAGE_SETUP;
- _ctrl_xfer.complete_cb = complete_cb;
-
- TU_LOG2("Control Setup (addr = %u): ", dev_addr);
- TU_LOG2_VAR(request);
- TU_LOG2("\r\n");
-
- // Send setup packet
- TU_ASSERT( hcd_setup_send(rhport, dev_addr, (uint8_t const*) &_ctrl_xfer.request) );
-
- return true;
-}
-
-static void _xfer_complete(uint8_t dev_addr, xfer_result_t result)
-{
- TU_LOG2("\r\n");
- if (_ctrl_xfer.complete_cb) _ctrl_xfer.complete_cb(dev_addr, &_ctrl_xfer.request, result);
-}
-
-bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
-{
- (void) ep_addr;
- (void) xferred_bytes;
-
- const uint8_t rhport = usbh_get_rhport(dev_addr);
-
- tusb_control_request_t const * request = &_ctrl_xfer.request;
-
- if (XFER_RESULT_SUCCESS != result)
- {
- TU_LOG2("Control failed: result = %d\r\n", result);
-
- // terminate transfer if any stage failed
- _xfer_complete(dev_addr, result);
- }else
- {
- switch(_ctrl_xfer.stage)
- {
- case STAGE_SETUP:
- _ctrl_xfer.stage = STAGE_DATA;
- if (request->wLength)
- {
- // DATA stage: initial data toggle is always 1
- hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength);
- return true;
- }
- __attribute__((fallthrough));
-
- case STAGE_DATA:
- _ctrl_xfer.stage = STAGE_ACK;
-
- if (request->wLength)
- {
- TU_LOG2("Control data (addr = %u):\r\n", dev_addr);
- TU_LOG2_MEM(_ctrl_xfer.buffer, request->wLength, 2);
- }
-
- // ACK stage: toggle is always 1
- hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0);
- break;
-
- case STAGE_ACK:
- _xfer_complete(dev_addr, result);
- break;
-
- default: return false;
- }
- }
-
- return true;
-}
-
-#endif
diff --git a/src/osal/osal.h b/src/osal/osal.h
index c8131d19d..9d11866df 100644
--- a/src/osal/osal.h
+++ b/src/osal/osal.h
@@ -31,9 +31,6 @@
extern "C" {
#endif
-/** \addtogroup group_osal
- * @{ */
-
#include "common/tusb_common.h"
// Return immediately
@@ -57,6 +54,8 @@ typedef void (*osal_task_func_t)( void * );
#include "osal_pico.h"
#elif CFG_TUSB_OS == OPT_OS_RTTHREAD
#include "osal_rtthread.h"
+#elif CFG_TUSB_OS == OPT_OS_RTX4
+ #include "osal_rtx4.h"
#elif CFG_TUSB_OS == OPT_OS_CUSTOM
#include "tusb_os_custom.h" // implemented by application
#else
@@ -65,47 +64,26 @@ typedef void (*osal_task_func_t)( void * );
//--------------------------------------------------------------------+
// OSAL Porting API
-//--------------------------------------------------------------------+
-
-#if __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wredundant-decls"
-#endif
-//------------- Semaphore -------------//
-static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
-static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
-static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec);
-
-static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed
+// Should be implemented as static inline function in osal_port.h header
+/*
+ osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
+ bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
+ bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec);
+ void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed
-//------------- Mutex -------------//
-static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
-static inline bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
-static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
+ osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
+ bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
+ bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
-//------------- Queue -------------//
-static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
-static inline bool osal_queue_receive(osal_queue_t qhdl, void* data);
-static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr);
-static inline bool osal_queue_empty(osal_queue_t qhdl);
-#if __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
-#if 0 // TODO remove subtask related macros later
-// Sub Task
-#define OSAL_SUBTASK_BEGIN
-#define OSAL_SUBTASK_END return TUSB_ERROR_NONE;
-
-#define STASK_RETURN(_error) return _error;
-#define STASK_INVOKE(_subtask, _status) (_status) = _subtask
-#define STASK_ASSERT(_cond) TU_VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED)
-#endif
+ osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
+ bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec);
+ bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr);
+ bool osal_queue_empty(osal_queue_t qhdl);
+*/
+//--------------------------------------------------------------------+
#ifdef __cplusplus
}
#endif
-/** @} */
-
#endif /* _TUSB_OSAL_H_ */
diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h
index 4573e01f5..52db336f5 100644
--- a/src/osal/osal_freertos.h
+++ b/src/osal/osal_freertos.h
@@ -37,10 +37,24 @@
extern "C" {
#endif
+TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec)
+{
+ if (msec == OSAL_TIMEOUT_WAIT_FOREVER) return portMAX_DELAY;
+ if (msec == 0) return 0;
+
+ uint32_t ticks = pdMS_TO_TICKS(msec);
+
+ // configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms
+ // we still need to delay at least 1 tick
+ if (ticks == 0) ticks =1 ;
+
+ return ticks;
+}
+
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-static inline void osal_task_delay(uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
{
vTaskDelay( pdMS_TO_TICKS(msec) );
}
@@ -51,12 +65,12 @@ static inline void osal_task_delay(uint32_t msec)
typedef StaticSemaphore_t osal_semaphore_def_t;
typedef SemaphoreHandle_t osal_semaphore_t;
-static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
{
return xSemaphoreCreateBinaryStatic(semdef);
}
-static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
{
if ( !in_isr )
{
@@ -68,6 +82,7 @@ static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken);
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
+ // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7
if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR();
#else
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
@@ -77,13 +92,12 @@ static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
}
}
-static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
{
- uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? portMAX_DELAY : pdMS_TO_TICKS(msec);
- return xSemaphoreTake(sem_hdl, ticks);
+ return xSemaphoreTake(sem_hdl, _osal_ms2tick(msec));
}
-static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
+TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
{
xQueueReset(sem_hdl);
}
@@ -94,17 +108,17 @@ static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
typedef StaticSemaphore_t osal_mutex_def_t;
typedef SemaphoreHandle_t osal_mutex_t;
-static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
{
return xSemaphoreCreateMutexStatic(mdef);
}
-static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
{
return osal_semaphore_wait(mutex_hdl, msec);
}
-static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
{
return xSemaphoreGive(mutex_hdl);
}
@@ -113,8 +127,8 @@ static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
// QUEUE API
//--------------------------------------------------------------------+
-// role device/host is used by OS NONE for mutex (disable usb isr) only
-#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
+// _int_set is not used with an RTOS
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
static _type _name##_##buf[_depth];\
osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf };
@@ -129,17 +143,17 @@ typedef struct
typedef QueueHandle_t osal_queue_t;
-static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
{
return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq);
}
-static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
{
- return xQueueReceive(qhdl, data, portMAX_DELAY);
+ return xQueueReceive(qhdl, data, _osal_ms2tick(msec));
}
-static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
{
if ( !in_isr )
{
@@ -151,6 +165,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in
BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken);
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
+ // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7
if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR();
#else
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
@@ -160,7 +175,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in
}
}
-static inline bool osal_queue_empty(osal_queue_t qhdl)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
{
return uxQueueMessagesWaiting(qhdl) == 0;
}
@@ -169,4 +184,4 @@ static inline bool osal_queue_empty(osal_queue_t qhdl)
}
#endif
-#endif /* _TUSB_OSAL_FREERTOS_H_ */
+#endif
diff --git a/src/osal/osal_mynewt.h b/src/osal/osal_mynewt.h
index 6882329c1..b8ea2087c 100644
--- a/src/osal/osal_mynewt.h
+++ b/src/osal/osal_mynewt.h
@@ -36,7 +36,7 @@
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-static inline void osal_task_delay(uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
{
os_time_delay( os_time_ms_to_ticks32(msec) );
}
@@ -47,18 +47,18 @@ static inline void osal_task_delay(uint32_t msec)
typedef struct os_sem osal_semaphore_def_t;
typedef struct os_sem* osal_semaphore_t;
-static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
{
return (os_sem_init(semdef, 0) == OS_OK) ? (osal_semaphore_t) semdef : NULL;
}
-static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
{
(void) in_isr;
return os_sem_release(sem_hdl) == OS_OK;
}
-static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec)
{
uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec);
return os_sem_pend(sem_hdl, ticks) == OS_OK;
@@ -75,18 +75,18 @@ static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
typedef struct os_mutex osal_mutex_def_t;
typedef struct os_mutex* osal_mutex_t;
-static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
{
return (os_mutex_init(mdef) == OS_OK) ? (osal_mutex_t) mdef : NULL;
}
-static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec)
{
uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec);
return os_mutex_pend(mutex_hdl, ticks) == OS_OK;
}
-static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
{
return os_mutex_release(mutex_hdl) == OS_OK;
}
@@ -96,7 +96,7 @@ static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
//--------------------------------------------------------------------+
// role device/host is used by OS NONE for mutex (disable usb isr) only
-#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
static _type _name##_##buf[_depth];\
static struct os_event _name##_##evbuf[_depth];\
osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, .evbuf = _name##_##evbuf};\
@@ -116,7 +116,7 @@ typedef struct
typedef osal_queue_def_t* osal_queue_t;
-static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
{
if ( OS_OK != os_mempool_init(&qdef->mpool, qdef->depth, qdef->item_sz, qdef->buf, "usbd queue") ) return NULL;
if ( OS_OK != os_mempool_init(&qdef->epool, qdef->depth, sizeof(struct os_event), qdef->evbuf, "usbd evqueue") ) return NULL;
@@ -125,8 +125,10 @@ static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
return (osal_queue_t) qdef;
}
-static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
{
+ (void) msec; // os_eventq_get() does not take timeout, always behave as msec = WAIT_FOREVER
+
struct os_event* ev;
ev = os_eventq_get(&qhdl->evq);
@@ -161,7 +163,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in
return true;
}
-static inline bool osal_queue_empty(osal_queue_t qhdl)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
{
return STAILQ_EMPTY(&qhdl->evq.evq_list);
}
diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h
index a1f997cf2..9c80e4548 100644
--- a/src/osal/osal_none.h
+++ b/src/osal/osal_none.h
@@ -46,13 +46,13 @@ typedef struct
typedef osal_semaphore_def_t* osal_semaphore_t;
-static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
{
semdef->count = 0;
return semdef;
}
-static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
{
(void) in_isr;
sem_hdl->count++;
@@ -60,7 +60,7 @@ static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
}
// TODO blocking for now
-static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
{
(void) msec;
@@ -70,7 +70,7 @@ static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
return true;
}
-static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
+TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
{
sem_hdl->count = 0;
}
@@ -82,18 +82,18 @@ static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
typedef osal_semaphore_def_t osal_mutex_def_t;
typedef osal_semaphore_t osal_mutex_t;
-static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
{
mdef->count = 1;
return mdef;
}
-static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
{
return osal_semaphore_wait(mutex_hdl, msec);
}
-static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
{
return osal_semaphore_post(mutex_hdl, false);
}
@@ -103,69 +103,46 @@ static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
//--------------------------------------------------------------------+
#include "common/tusb_fifo.h"
-// extern to avoid including dcd.h and hcd.h
-#if TUSB_OPT_DEVICE_ENABLED
-extern void dcd_int_disable(uint8_t rhport);
-extern void dcd_int_enable(uint8_t rhport);
-#endif
-
-#if TUSB_OPT_HOST_ENABLED
-extern void hcd_int_disable(uint8_t rhport);
-extern void hcd_int_enable(uint8_t rhport);
-#endif
-
typedef struct
{
- uint8_t role; // device or host
- tu_fifo_t ff;
+ void (*interrupt_set)(bool);
+ tu_fifo_t ff;
}osal_queue_def_t;
typedef osal_queue_def_t* osal_queue_t;
-// role device/host is used by OS NONE for mutex (disable usb isr) only
-#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
+// _int_set is used as mutex in OS NONE (disable/enable USB ISR)
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
osal_queue_def_t _name = { \
- .role = _role, \
+ .interrupt_set = _int_set, \
.ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
}
// lock queue by disable USB interrupt
-static inline void _osal_q_lock(osal_queue_t qhdl)
+TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl)
{
- (void) qhdl;
-
-#if TUSB_OPT_DEVICE_ENABLED
- if (qhdl->role == OPT_MODE_DEVICE) dcd_int_disable(TUD_OPT_RHPORT);
-#endif
-
-#if TUSB_OPT_HOST_ENABLED
- if (qhdl->role == OPT_MODE_HOST) hcd_int_disable(TUH_OPT_RHPORT);
-#endif
+ // disable dcd/hcd interrupt
+ qhdl->interrupt_set(false);
}
// unlock queue
-static inline void _osal_q_unlock(osal_queue_t qhdl)
+TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl)
{
- (void) qhdl;
-
-#if TUSB_OPT_DEVICE_ENABLED
- if (qhdl->role == OPT_MODE_DEVICE) dcd_int_enable(TUD_OPT_RHPORT);
-#endif
-
-#if TUSB_OPT_HOST_ENABLED
- if (qhdl->role == OPT_MODE_HOST) hcd_int_enable(TUH_OPT_RHPORT);
-#endif
+ // enable dcd/hcd interrupt
+ qhdl->interrupt_set(true);
}
-static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
{
tu_fifo_clear(&qdef->ff);
return (osal_queue_t) qdef;
}
-static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
{
+ (void) msec; // not used, always behave as msec = 0
+
_osal_q_lock(qhdl);
bool success = tu_fifo_read(&qhdl->ff, data);
_osal_q_unlock(qhdl);
@@ -173,7 +150,7 @@ static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
return success;
}
-static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
{
if (!in_isr) {
_osal_q_lock(qhdl);
@@ -190,7 +167,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in
return success;
}
-static inline bool osal_queue_empty(osal_queue_t qhdl)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
{
// Skip queue lock/unlock since this function is primarily called
// with interrupt disabled before going into low power mode
diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h
index 1c3366e01..8b428d642 100644
--- a/src/osal/osal_pico.h
+++ b/src/osal/osal_pico.h
@@ -39,7 +39,7 @@
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-static inline void osal_task_delay(uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
{
sleep_ms(msec);
}
@@ -49,25 +49,25 @@ static inline void osal_task_delay(uint32_t msec)
//--------------------------------------------------------------------+
typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t;
-static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
{
sem_init(semdef, 0, 255);
return semdef;
}
-static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
{
(void) in_isr;
sem_release(sem_hdl);
return true;
}
-static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
{
return sem_acquire_timeout_ms(sem_hdl, msec);
}
-static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
+TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
{
sem_reset(sem_hdl, 0);
}
@@ -78,21 +78,21 @@ static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
//--------------------------------------------------------------------+
typedef struct mutex osal_mutex_def_t, *osal_mutex_t;
-static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
{
- mutex_init(mdef);
- return mdef;
+ mutex_init(mdef);
+ return mdef;
}
-static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
{
- return mutex_enter_timeout_ms(mutex_hdl, msec);
+ return mutex_enter_timeout_ms(mutex_hdl, msec);
}
-static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
{
- mutex_exit(mutex_hdl);
- return true;
+ mutex_exit(mutex_hdl);
+ return true;
}
//--------------------------------------------------------------------+
@@ -100,11 +100,6 @@ static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
//--------------------------------------------------------------------+
#include "common/tusb_fifo.h"
-#if TUSB_OPT_HOST_ENABLED
-extern void hcd_int_disable(uint8_t rhport);
-extern void hcd_int_enable(uint8_t rhport);
-#endif
-
typedef struct
{
tu_fifo_t ff;
@@ -114,33 +109,35 @@ typedef struct
typedef osal_queue_def_t* osal_queue_t;
// role device/host is used by OS NONE for mutex (disable usb isr) only
-#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
osal_queue_def_t _name = { \
.ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
}
// lock queue by disable USB interrupt
-static inline void _osal_q_lock(osal_queue_t qhdl)
+TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl)
{
- critical_section_enter_blocking(&qhdl->critsec);
+ critical_section_enter_blocking(&qhdl->critsec);
}
// unlock queue
-static inline void _osal_q_unlock(osal_queue_t qhdl)
+TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl)
{
- critical_section_exit(&qhdl->critsec);
+ critical_section_exit(&qhdl->critsec);
}
-static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
{
critical_section_init(&qdef->critsec);
tu_fifo_clear(&qdef->ff);
return (osal_queue_t) qdef;
}
-static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
{
+ (void) msec; // not used, always behave as msec = 0
+
// TODO: revisit... docs say that mutexes are never used from IRQ context,
// however osal_queue_recieve may be. therefore my assumption is that
// the fifo mutex is not populated for queues used from an IRQ context
@@ -153,7 +150,7 @@ static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
return success;
}
-static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
{
// TODO: revisit... docs say that mutexes are never used from IRQ context,
// however osal_queue_recieve may be. therefore my assumption is that
@@ -170,7 +167,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in
return success;
}
-static inline bool osal_queue_empty(osal_queue_t qhdl)
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
{
// TODO: revisit; whether this is true or not currently, tu_fifo_empty is a single
// volatile read.
diff --git a/src/osal/osal_rtthread.h b/src/osal/osal_rtthread.h
index d5c062ac1..f8452bfb2 100644
--- a/src/osal/osal_rtthread.h
+++ b/src/osal/osal_rtthread.h
@@ -37,7 +37,7 @@ extern "C" {
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-static inline void osal_task_delay(uint32_t msec) {
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
rt_thread_mdelay(msec);
}
@@ -47,22 +47,22 @@ static inline void osal_task_delay(uint32_t msec) {
typedef struct rt_semaphore osal_semaphore_def_t;
typedef rt_sem_t osal_semaphore_t;
-static inline osal_semaphore_t
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t
osal_semaphore_create(osal_semaphore_def_t *semdef) {
- rt_sem_init(semdef, "tusb", 0, RT_IPC_FLAG_FIFO);
+ rt_sem_init(semdef, "tusb", 0, RT_IPC_FLAG_PRIO);
return semdef;
}
-static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
(void) in_isr;
return rt_sem_release(sem_hdl) == RT_EOK;
}
-static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
- return rt_sem_take(sem_hdl, rt_tick_from_millisecond(msec)) == RT_EOK;
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
+ return rt_sem_take(sem_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK;
}
-static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) {
+TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) {
// TODO: implement
}
@@ -72,16 +72,16 @@ static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) {
typedef struct rt_mutex osal_mutex_def_t;
typedef rt_mutex_t osal_mutex_t;
-static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
- rt_mutex_init(mdef, "tusb", RT_IPC_FLAG_FIFO);
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
+ rt_mutex_init(mdef, "tusb", RT_IPC_FLAG_PRIO);
return mdef;
}
-static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) {
- return rt_mutex_take(mutex_hdl, rt_tick_from_millisecond(msec)) == RT_EOK;
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) {
+ return rt_mutex_take(mutex_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK;
}
-static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
return rt_mutex_release(mutex_hdl) == RT_EOK;
}
@@ -90,7 +90,7 @@ static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
//--------------------------------------------------------------------+
// role device/host is used by OS NONE for mutex (disable usb isr) only
-#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
static _type _name##_##buf[_depth]; \
osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf };
@@ -104,22 +104,24 @@ typedef struct {
typedef rt_mq_t osal_queue_t;
-static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) {
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) {
rt_mq_init(&(qdef->sq), "tusb", qdef->buf, qdef->item_sz,
- qdef->item_sz * qdef->depth, RT_IPC_FLAG_FIFO);
+ qdef->item_sz * qdef->depth, RT_IPC_FLAG_PRIO);
return &(qdef->sq);
}
-static inline bool osal_queue_receive(osal_queue_t qhdl, void *data) {
- return rt_mq_recv(qhdl, data, qhdl->msg_size, RT_WAITING_FOREVER) == RT_EOK;
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) {
+
+ rt_tick_t tick = rt_tick_from_millisecond((rt_int32_t) msec);
+ return rt_mq_recv(qhdl, data, qhdl->msg_size, tick) == RT_EOK;
}
-static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) {
(void) in_isr;
return rt_mq_send(qhdl, (void *)data, qhdl->msg_size) == RT_EOK;
}
-static inline bool osal_queue_empty(osal_queue_t qhdl) {
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) {
return (qhdl->entry) == 0;
}
diff --git a/src/osal/osal_rtx4.h b/src/osal/osal_rtx4.h
new file mode 100644
index 000000000..dea1c12c8
--- /dev/null
+++ b/src/osal/osal_rtx4.h
@@ -0,0 +1,170 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_OSAL_RTX4_H_
+#define _TUSB_OSAL_RTX4_H_
+
+#include <rtl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TASK API
+//--------------------------------------------------------------------+
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
+{
+ uint16_t hi = msec >> 16;
+ uint16_t lo = msec;
+ while (hi--) {
+ os_dly_wait(0xFFFE);
+ }
+ os_dly_wait(lo);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) {
+ if (msec == OSAL_TIMEOUT_WAIT_FOREVER)
+ return 0xFFFF;
+ else if (msec >= 0xFFFE)
+ return 0xFFFE;
+ else
+ return msec;
+}
+
+//--------------------------------------------------------------------+
+// Semaphore API
+//--------------------------------------------------------------------+
+typedef OS_SEM osal_semaphore_def_t;
+typedef OS_ID osal_semaphore_t;
+
+TU_ATTR_ALWAYS_INLINE static inline OS_ID osal_semaphore_create(osal_semaphore_def_t* semdef) {
+ os_sem_init(semdef, 0);
+ return semdef;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
+ if ( !in_isr ) {
+ os_sem_send(sem_hdl);
+ } else {
+ isr_sem_send(sem_hdl);
+ }
+ return true;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) {
+ return os_sem_wait(sem_hdl, msec2wait(msec)) != OS_R_TMO;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) {
+ // TODO: implement
+}
+
+//--------------------------------------------------------------------+
+// MUTEX API (priority inheritance)
+//--------------------------------------------------------------------+
+typedef OS_MUT osal_mutex_def_t;
+typedef OS_ID osal_mutex_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
+{
+ os_mut_init(mdef);
+ return mdef;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
+{
+ return os_mut_wait(mutex_hdl, msec2wait(msec)) != OS_R_TMO;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
+{
+ return os_mut_release(mutex_hdl) == OS_R_OK;
+}
+
+//--------------------------------------------------------------------+
+// QUEUE API
+//--------------------------------------------------------------------+
+
+// role device/host is used by OS NONE for mutex (disable usb isr) only
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
+ os_mbx_declare(_name##__mbox, _depth); \
+ _declare_box(_name##__pool, sizeof(_type), _depth); \
+ osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .pool = _name##__pool, .mbox = _name##__mbox };
+
+
+typedef struct
+{
+ uint16_t depth;
+ uint16_t item_sz;
+ U32* pool;
+ U32* mbox;
+}osal_queue_def_t;
+
+typedef osal_queue_def_t* osal_queue_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
+{
+ os_mbx_init(qdef->mbox, (qdef->depth + 4) * 4);
+ _init_box(qdef->pool, ((qdef->item_sz+3)/4)*(qdef->depth) + 3, qdef->item_sz);
+ return qdef;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
+{
+ void* buf;
+ os_mbx_wait(qhdl->mbox, &buf, msec2wait(msec));
+ memcpy(data, buf, qhdl->item_sz);
+ _free_box(qhdl->pool, buf);
+ return true;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
+{
+ void* buf = _alloc_box(qhdl->pool);
+ memcpy(buf, data, qhdl->item_sz);
+ if ( !in_isr )
+ {
+ os_mbx_send(qhdl->mbox, buf, 0xFFFF);
+ }
+ else
+ {
+ isr_mbx_send(qhdl->mbox, buf);
+ }
+ return true;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
+{
+ return os_mbx_check(qhdl->mbox) == qhdl->depth;
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
new file mode 100644
index 000000000..2445593fe
--- /dev/null
+++ b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
@@ -0,0 +1,1117 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright 2021 Bridgetek Pte Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/*
+ * Contains code adapted from Bridgetek Pte Ltd via license terms stated
+ * in https://brtchip.com/BRTSourceCodeLicenseAgreement
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X)
+
+#include <stdint.h>
+#include <ft900.h>
+#include <registers/ft900_registers.h>
+
+#include "board.h"
+#include "bsp/board.h"
+
+#define USBD_USE_STREAMS
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+// Board code will determine the state of VBUS from USB host.
+extern int8_t board_ft90x_vbus(void);
+
+// Static array to store an incoming SETUP request for processing by tinyusb.
+static uint8_t _ft90x_setup_packet[8];
+
+struct ft90x_xfer_state
+{
+ volatile uint8_t valid; // Transfer is pending and total_size, remain_size, and buff_ptr are valid.
+ volatile int16_t total_size; // Total transfer size in bytes for this transfer.
+ volatile int16_t remain_size; // Total remaining in transfer.
+ volatile uint8_t *buff_ptr; // Pointer to buffer to transmit from or receive to.
+
+ uint8_t type; // Endpoint type. Of type USBD_ENDPOINT_TYPE from endpoint descriptor.
+ uint8_t dir; // Endpoint direction. TUSB_DIR_OUT or TUSB_DIR_IN. For control endpoint this is the current direction.
+ uint16_t buff_size; // Actual size of buffer RAM used by endpoint.
+ uint16_t size; // Max packet size for endpoint from endpoint descriptor.
+};
+// Endpoint description array for each endpoint.
+static struct ft90x_xfer_state ep_xfer[USBD_MAX_ENDPOINT_COUNT];
+// USB speed.
+static tusb_speed_t _speed;
+
+// Interrupt handlers.
+void _ft90x_usbd_ISR(void); // Interrupt handler for USB device.
+void ft90x_usbd_pm_ISR(void); // Interrupt handler for USB device for power management (called by board).
+
+// Internal functions forward declarations.
+static uint16_t _ft90x_edpt_xfer_out(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes);
+static uint16_t _ft90x_edpt_xfer_in(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes);
+static void _ft90x_reset_edpts(void);
+static inline void _ft90x_phy_enable(bool en);
+static void _ft90x_usb_speed(void);
+static void _dcd_ft90x_attach(void);
+static void _dcd_ft90x_detach(void) __attribute__((unused));
+static uint16_t _ft90x_dusb_in(uint8_t ep_number, const uint8_t *buffer, uint16_t length);
+static uint16_t _ft90x_dusb_out(uint8_t ep_number, uint8_t *buffer, uint16_t length);
+
+// Internal functions.
+
+// Manage an OUT transfer from the host.
+// This can be up-to the maximum packet size of the endpoint.
+// Continuation of a transfer beyond the maximum packet size is performed
+// by the interrupt handler.
+static uint16_t _ft90x_edpt_xfer_out(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes)
+{
+ //Note: this is called from only the interrupt handler when an OUT transfer is called.
+ uint16_t ep_size = ep_xfer[ep_number].size;
+ (void)ep_size;
+ if (xfer_bytes > ep_size)
+ {
+ xfer_bytes = ep_size;
+ }
+
+ // Wait until the endpoint has finished - it should be complete!
+ //while (!(USBD_EP_SR_REG(ep_number) & MASK_USBD_EPxSR_OPRDY))
+ //;
+
+ // Send the first packet of max packet size
+ xfer_bytes = _ft90x_dusb_out(ep_number, (uint8_t *)buffer, xfer_bytes);
+ if (ep_number == USBD_EP_0)
+ {
+ // Set flags to indicate data ready.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_OPRDY);
+ }
+ else
+ {
+ USBD_EP_SR_REG(ep_number) = (MASK_USBD_EPxSR_OPRDY);
+ }
+
+ return xfer_bytes;
+}
+
+// Manage an IN transfer to the host.
+// This can be up-to the maximum packet size of the endpoint.
+// Continuation of a transfer beyond the maximum packet size is performed
+// by the interrupt handler.
+static uint16_t _ft90x_edpt_xfer_in(uint8_t ep_number, uint8_t *buffer, uint16_t xfer_bytes)
+{
+ //Note: this may be called from the interrupt handler or from normal code.
+ uint8_t end = 0;
+ uint16_t ep_size = ep_xfer[ep_number].size;
+ (void)ep_size;
+
+ if ((xfer_bytes == 0) || (xfer_bytes < ep_size))
+ {
+ end = 1;
+ }
+ else
+ {
+ xfer_bytes = ep_size;
+ }
+
+ if (ep_number == USBD_EP_0)
+ {
+ // An IN direction SETUP can be interrupted by an OUT packet.
+ // This will result in a STALL generated by the silicon.
+ while (USBD_EP_SR_REG(USBD_EP_0) & MASK_USBD_EP0SR_STALL)
+ {
+ // Clear the STALL and finish the transaction.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_STALL);
+ }
+ }
+ else
+ {
+ uint8_t sr_reg;
+ // If there is data to transmit then wait until the IN buffer
+ // for the endpoint is empty.
+ do
+ {
+ sr_reg = USBD_EP_SR_REG(ep_number);
+ } while (sr_reg & MASK_USBD_EPxSR_INPRDY);
+
+ }
+
+ xfer_bytes = _ft90x_dusb_in(ep_number, (uint8_t *)buffer, xfer_bytes);
+
+ if (ep_number == USBD_EP_0)
+ {
+ if (end)
+ {
+ // Set flags to indicate data ready and transfer complete.
+ USBD_EP_SR_REG(USBD_EP_0) = MASK_USBD_EP0SR_INPRDY | MASK_USBD_EP0SR_DATAEND;
+ }
+ else
+ {
+ // Set flags to indicate data ready.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_INPRDY);
+ }
+ }
+ else
+ {
+ // Set flags to indicate data ready.
+ USBD_EP_SR_REG(ep_number) = (MASK_USBD_EPxSR_INPRDY);
+ }
+
+ return xfer_bytes;
+}
+
+// Reset all non-control endpoints to a default state.
+// Control endpoint is always enabled and ready. All others disabled.
+static void _ft90x_reset_edpts(void)
+{
+ // Disable all endpoints and remove configuration values.
+ for (int i = 1; i < USBD_MAX_ENDPOINT_COUNT; i++)
+ {
+ // Clear settings.
+ tu_memclr(&ep_xfer[i], sizeof(struct ft90x_xfer_state));
+ // Disable hardware.
+ USBD_EP_CR_REG(i) = 0;
+ }
+
+ // Enable interrupts from USB device control.
+ USBD_REG(cmie) = MASK_USBD_CMIE_ALL;
+}
+
+// Enable or disable the USB PHY.
+static inline void _ft90x_phy_enable(bool en)
+{
+ if (en)
+ SYS->PMCFG_L |= MASK_SYS_PMCFG_DEV_PHY_EN;
+ else
+ SYS->PMCFG_L &= ~MASK_SYS_PMCFG_DEV_PHY_EN;
+}
+
+// Safely connect to the USB.
+static void _dcd_ft90x_attach(void)
+{
+ uint8_t reg;
+
+ CRITICAL_SECTION_BEGIN
+ // Disable device responses.
+ USBD_REG(faddr) = 0;
+
+ // Reset USB Device.
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RESET_ALL;
+ // Disable device connect/disconnect/host reset detection.
+ SYS->PMCFG_H = MASK_SYS_PMCFG_DEV_DIS_DEV;
+ SYS->PMCFG_H = MASK_SYS_PMCFG_DEV_CONN_DEV;
+ SYS->PMCFG_L = SYS->PMCFG_L & (~MASK_SYS_PMCFG_DEV_DETECT_EN);
+
+ // Enable Chip USB device clock/PM configuration.
+ sys_enable(sys_device_usb_device);
+ CRITICAL_SECTION_END;
+
+ // Wait a short time to get started.
+ delayms(1);
+
+ CRITICAL_SECTION_BEGIN
+ // Turn off the device enable bit.
+#if BOARD_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED
+ USBD_REG(fctrl) = 0;
+#else // BOARD_TUD_MAX_SPEED == OPT_MODE_FULL_SPEED
+ //Set the full speed only bit if required.
+ USBD_REG(fctrl) = MASK_USBD_FCTRL_MODE_FS_ONLY;
+#endif // BOARD_TUD_MAX_SPEED
+
+ // Clear first reset and suspend interrupts.
+ do
+ {
+ reg = USBD_REG(cmif);
+ USBD_REG(cmif) = reg;
+ } while (reg);
+ // Clear any endpoint interrupts.
+ reg = USBD_REG(epif);
+ USBD_REG(epif) = reg;
+
+ // Disable all interrupts from USB device control before attaching interrupt.
+ USBD_REG(cmie) = 0;
+ CRITICAL_SECTION_END;
+
+ // Enable device connect/disconnect/host reset detection.
+ // Set device detect and remote wakeup enable interrupt enables.
+ SYS->PMCFG_L = SYS->PMCFG_L | MASK_SYS_PMCFG_DEV_DETECT_EN;
+
+#if defined(__FT930__)
+ // Setup VBUS detect
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_USB_VBUS_EN;
+#endif
+}
+
+// Gracefully disconnect from the USB.
+static void _dcd_ft90x_detach(void)
+{
+ // Disable device connect/disconnect/host reset detection.
+ SYS->PMCFG_L = SYS->PMCFG_L & (~MASK_SYS_PMCFG_DEV_DETECT_EN);
+
+#if defined(__FT930__)
+ // Disable VBUS detection.
+ SYS->MSC0CFG = SYS->MSC0CFG & (~MASK_SYS_MSC0CFG_USB_VBUS_EN);
+#endif
+ CRITICAL_SECTION_BEGIN
+ // Disable interrupts from USB.
+ USBD_REG(epie) = 0;
+ USBD_REG(cmie) = 0;
+ // Turn off the device enable bit.
+ USBD_REG(fctrl) = 0;
+ CRITICAL_SECTION_END;
+
+ delayms(1);
+
+ // Disable USB PHY
+ dcd_disconnect(BOARD_TUD_RHPORT);
+ delayms(1);
+
+ // Disable Chip USB device clock/PM configuration.
+ sys_disable(sys_device_usb_device);
+
+ // Reset USB Device... Needed for Back voltage D+ to be <400mV
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RESET_ALL;
+
+ delayms(1);
+ // Set device detect and remote wakeup enable interrupt enables.
+ SYS->PMCFG_L = SYS->PMCFG_L | MASK_SYS_PMCFG_DEV_DETECT_EN;
+
+#if defined(__FT930__)
+ // Setup VBUS detect
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_USB_VBUS_EN;
+#endif
+}
+
+// Determine the speed of the USB to which we are connected.
+// Set the speed of the PHY accordingly.
+// High speed can be disabled through CFG_TUSB_RHPORT0_MODE or CFG_TUD_MAX_SPEED settings.
+static void _ft90x_usb_speed(void)
+{
+ uint8_t fctrl_val;
+
+ // If USB device function is already enabled then disable it.
+ if (USBD_REG(fctrl) & MASK_USBD_FCTRL_USB_DEV_EN) {
+ USBD_REG(fctrl) = (USBD_REG(fctrl) & (~MASK_USBD_FCTRL_USB_DEV_EN));
+ delayus(200);
+ }
+
+#if BOARD_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED
+
+ /* Detect high or full speed */
+ fctrl_val = MASK_USBD_FCTRL_USB_DEV_EN;
+#if defined(__FT900__)
+ if (!sys_check_ft900_revB())//if 90x series is rev C
+ {
+ fctrl_val |= MASK_USBD_FCTRL_IMP_PERF;
+ }
+#endif
+ USBD_REG(fctrl) = fctrl_val;
+
+#if defined(__FT930__)
+ delayus(200);
+
+ _speed = (SYS->MSC0CFG & MASK_SYS_MSC0CFG_HIGH_SPED_MODE) ?
+ TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
+#else /* __FT930__ */
+ /* Detection by SOF */
+ while (!(USBD_REG(cmif) & MASK_USBD_CMIF_SOFIRQ));
+ USBD_REG(cmif) = MASK_USBD_CMIF_SOFIRQ;
+ delayus(125 + 5);
+ _speed = (USBD_REG(cmif) & MASK_USBD_CMIF_SOFIRQ) ?
+ TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
+ dcd_event_bus_reset(BOARD_TUD_RHPORT, _speed, true);
+
+#endif /* !__FT930__ */
+
+#else // BOARD_TUD_MAX_SPEED == OPT_MODE_FULL_SPEED
+
+ /* User force set to full speed */
+ _speed = TUSB_SPEED_FULL;
+ fctrl_val =
+ MASK_USBD_FCTRL_USB_DEV_EN | MASK_USBD_FCTRL_MODE_FS_ONLY;
+#if defined(__FT900__)
+ if (!sys_check_ft900_revB())//if 90x series is rev C
+ {
+ fctrl_val |= MASK_USBD_FCTRL_IMP_PERF;
+ }
+#endif
+ USBD_REG(fctrl) = fctrl_val;
+ dcd_event_bus_reset(BOARD_TUD_RHPORT, _speed, true);
+ return;
+
+#endif // BOARD_TUD_MAX_SPEED
+}
+
+// Send a buffer to the USB IN FIFO.
+// When the macro USBD_USE_STREAMS is defined this will stream a buffer of data
+// to the FIFO using the most efficient MCU streamout combination.
+// If streaming is disabled then it will send each byte of the buffer in turn
+// to the FIFO. The is no reason to not stream.
+// The total number of bytes sent to the FIFO is returned.
+static uint16_t _ft90x_dusb_in(uint8_t ep_number, const uint8_t *buffer, uint16_t length)
+{
+ uint16_t bytes_read = 0;
+ uint16_t buff_size = length;
+
+#ifdef USBD_USE_STREAMS
+ volatile uint8_t *data_reg;
+
+ data_reg = (volatile uint8_t *)&(USBD->ep[ep_number].epxfifo);
+ if (buff_size)
+ {
+ if (((uint32_t)buffer) % 4 == 0)
+ {
+ uint16_t aligned = buff_size & (~3);
+ uint16_t left = buff_size & 3;
+
+ if (aligned)
+ {
+ __asm__ volatile("streamout.l %0,%1,%2"
+ :
+ : "r"(data_reg), "r"(buffer), "r"(aligned));
+ buffer += aligned;
+ }
+ if (left)
+ {
+ __asm__ volatile("streamout.b %0,%1,%2"
+ :
+ : "r"(data_reg), "r"(buffer), "r"(left));
+ }
+ }
+ else
+ {
+ __asm__ volatile("streamout.b %0,%1,%2"
+ :
+ : "r"(data_reg), "r"(buffer), "r"(buff_size));
+ }
+ bytes_read = buff_size;
+ }
+#else // USBD_USE_STREAMS
+
+ bytes_read = buff_size;
+ while (buff_size--)
+ {
+ USBD_EP_FIFO_REG(ep_number) = *buffer++;
+ };
+
+#endif // USBD_USE_STREAMS
+
+ return bytes_read;
+}
+
+// Receive a buffer from the USB OUT FIFO.
+// When the macro USBD_USE_STREAMS is defined this will stream from the FIFO
+// to a buffer of data using the most efficient MCU streamin combination.
+// If streaming is disabled then it will receive each byte from the FIFO in turn
+// to the buffer. The is no reason to not stream.
+// The total number of bytes received from the FIFO is returned.
+static uint16_t _ft90x_dusb_out(uint8_t ep_number, uint8_t *buffer, uint16_t length)
+{
+#ifdef USBD_USE_STREAMS
+ volatile uint8_t *data_reg;
+#endif // USBD_USE_STREAMS
+ uint16_t bytes_read = 0;
+ uint16_t buff_size = length;
+
+ if (length > 0)
+ {
+ if (ep_number == USBD_EP_0)
+ {
+ buff_size = USBD_EP_CNT_REG(USBD_EP_0);
+ }
+ else
+ {
+ if (USBD_EP_SR_REG(ep_number) & (MASK_USBD_EPxSR_OPRDY))
+ {
+ buff_size = USBD_EP_CNT_REG(ep_number);
+ }
+ }
+ }
+
+ // Only read as many bytes as we have space for.
+ if (buff_size > length)
+ buff_size = length;
+
+#ifdef USBD_USE_STREAMS
+ data_reg = (volatile uint8_t *)&(USBD->ep[ep_number].epxfifo);
+ if (buff_size)
+ {
+ if ((uint32_t)buffer % 4 == 0)
+ {
+ uint16_t aligned = buff_size & (~3);
+ uint16_t left = buff_size & 3;
+
+ if (aligned)
+ {
+ __asm__ volatile("streamin.l %0,%1,%2"
+ :
+ : "r"(buffer), "r"(data_reg), "r"(aligned));
+ buffer += aligned;
+ }
+ if (left)
+ {
+ __asm__ volatile("streamin.b %0,%1,%2"
+ :
+ : "r"(buffer), "r"(data_reg), "r"(left));
+ }
+ }
+ else
+ {
+ __asm__ volatile("streamin.b %0,%1,%2"
+ :
+ : "r"(buffer), "r"(data_reg), "r"(buff_size));
+ }
+ bytes_read = buff_size;
+ }
+#else // USBD_USE_STREAMS
+
+ bytes_read = buff_size;
+ while (buff_size--)
+ {
+ *buffer++ = USBD_EP_FIFO_REG(ep_number);
+ }
+
+#endif // USBD_USE_STREAMS
+
+ return bytes_read;
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+// Initialize controller to device mode
+void dcd_init(uint8_t rhport)
+{
+ TU_LOG2("FT90x initialisation\r\n");
+
+ _dcd_ft90x_attach();
+
+ interrupt_attach(interrupt_usb_device, (int8_t)interrupt_usb_device, _ft90x_usbd_ISR);
+
+ dcd_connect(rhport);
+}
+
+// Enable device interrupt
+void dcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG3("FT90x int enable\r\n");
+
+ // Peripheral devices interrupt enable.
+ interrupt_enable_globally();
+}
+
+// Disable device interrupt
+void dcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG3("FT90x int disable\r\n");
+
+ // Peripheral devices interrupt disable.
+ interrupt_disable_globally();
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ (void)dev_addr;
+
+ // Respond with status. There is no checking that the address is in range.
+ dcd_edpt_xfer(rhport, tu_edpt_addr(USBD_EP_0, TUSB_DIR_IN), NULL, 0);
+
+ // Set the update bit for the address register.
+ dev_addr |= 0x80;
+
+ // Modify the address register within a critical section.
+ CRITICAL_SECTION_BEGIN
+ {
+ USBD_REG(faddr) = dev_addr;
+ }
+ CRITICAL_SECTION_END;
+}
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+#if 0 // never called
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
+{
+ (void) rhport;
+
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD )
+ {
+ if (request->bRequest == TUSB_REQ_SET_ADDRESS)
+ {
+ }
+ else if (request->bRequest == TUSB_REQ_SET_CONFIGURATION)
+ {
+ }
+ }
+}
+#endif // 0
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void)rhport;
+
+ SYS->MSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RMWAKEUP;
+
+ // Atleast 2 ms of delay needed for RESUME Data K state.
+ delayms(2);
+
+ SYS->MSC0CFG &= ~MASK_SYS_MSC0CFG_DEV_RMWAKEUP;
+
+ // Enable USB PHY and determine current bus speed.
+ dcd_connect(rhport);
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG2("FT90x connect\r\n");
+
+ CRITICAL_SECTION_BEGIN
+ // Is device connected?
+ if (board_ft90x_vbus())
+ {
+ // Clear/disable address register.
+ USBD_REG(faddr) = 0;
+ _ft90x_phy_enable(true);
+
+ // Determine bus speed and signal speed to tusb.
+ _ft90x_usb_speed();
+ }
+
+ // Setup the control endpoint only.
+#if CFG_TUD_ENDPOINT0_SIZE == 64
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_64 << BIT_USBD_EP0_MAX_SIZE);
+#elif CFG_TUD_ENDPOINT0_SIZE == 32
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_32 << BIT_USBD_EP0_MAX_SIZE);
+#elif CFG_TUD_ENDPOINT0_SIZE == 16
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_16 << BIT_USBD_EP0_MAX_SIZE);
+#elif CFG_TUD_ENDPOINT0_SIZE == 8
+ USBD_EP_CR_REG(USBD_EP_0) = (USBD_EP0_MAX_SIZE_8 << BIT_USBD_EP0_MAX_SIZE);
+#else
+#error "CFG_TUD_ENDPOINT0_SIZE must be defined with a value of 8, 16, 32 or 64."
+#endif
+ CRITICAL_SECTION_END;
+
+ // Configure the control endpoint.
+ ep_xfer[USBD_EP_0].size = CFG_TUD_ENDPOINT0_SIZE;
+ ep_xfer[USBD_EP_0].type = TUSB_XFER_CONTROL;
+
+ // Enable interrupts on EP0.
+ USBD_REG(epie) = (MASK_USBD_EPIE_EP0IE);
+
+ // Restore default endpoint state.
+ _ft90x_reset_edpts();
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void)rhport;
+ TU_LOG2("FT90x disconnect\r\n");
+
+ // Disable the USB PHY.
+ _ft90x_phy_enable(false);
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc)
+{
+ (void)rhport;
+ uint8_t const ep_number = tu_edpt_number(ep_desc->bEndpointAddress);
+ uint8_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
+ uint8_t const ep_type = ep_desc->bmAttributes.xfer;
+ uint16_t const ep_size = tu_edpt_packet_size(ep_desc); // Mask size per packet, bits 10..0.
+ uint16_t ep_buff_size;
+ uint8_t ep_reg_size = USBD_EP_MAX_SIZE_8;
+ uint8_t ep_reg_data = 0;
+ int16_t total_ram;
+
+ TU_LOG2("FT90x endpoint open %d %c\r\n", ep_number, ep_dir?'I':'O');
+
+ // Check that the requested endpoint number is allowable.
+ if (ep_number >= USBD_MAX_ENDPOINT_COUNT)
+ {
+ TU_LOG1("FT90x endpoint not valid: requested %d max %d\r\n", ep_number, USBD_MAX_ENDPOINT_COUNT);
+ return false;
+ }
+
+ // Calculate the physical size of the endpoint as a power of 2. This may be more than
+ // the requested size.
+ while (ep_size > (8 * (1 << ep_reg_size)))
+ {
+ ep_reg_size++;
+ }
+ if (ep_reg_size > USBD_EP_MAX_SIZE_1024)
+ {
+ TU_LOG1("FT90x endpoint size not valid: requested %d max 1024\r\n", ep_size);
+ return false;
+ }
+ // Calculate actual amount of buffer RAM used by this endpoint. This may be more than the
+ // requested size.
+ ep_buff_size = 8 << ep_reg_size;
+
+ if (ep_number > 0)
+ {
+ // Set EP cmd parameters...
+ ep_reg_data |= (ep_reg_size << BIT_USBD_EP_MAX_SIZE);
+
+ if (ep_xfer[ep_number].type != USBD_EP_TYPE_DISABLED)
+ {
+ // This could be because an endpoint has been assigned with the same number.
+ // On FT90x, IN and OUT endpoints may not have the same number. e.g. There
+ // cannot been an 0x81 and 0x01 endpoint.
+ TU_LOG1("FT90x endpoint %d already assigned\r\n", ep_number);
+ return false;
+ }
+
+ // Check that there is enough buffer RAM to allocate to this new endpoint.
+ // Available buffer RAM depends on the device revision.
+ // The IN and OUT buffer RAM should be the same size.
+ if (ep_dir == USBD_DIR_IN)
+ total_ram = USBD_RAMTOTAL_IN;
+ else
+ total_ram = USBD_RAMTOTAL_OUT;
+ // Work out how much has been allocated to existing endpoints.
+ // The total RAM allocated shoudl alsyes be a positive number as this
+ // algorithm should not let it go below zero.
+ for (int i = 1; i < USBD_MAX_ENDPOINT_COUNT; i++)
+ {
+ if (ep_xfer[i].type != USBD_EP_TYPE_DISABLED)
+ {
+ if (ep_xfer[i].dir == ep_dir)
+ {
+ total_ram -= ep_xfer[i].buff_size;
+ }
+ }
+ }
+ // The control endpoint is taken into account as well.
+ total_ram -= ep_xfer[0].buff_size;
+ // Make sure we have enough space. The corner case is having zero bytes
+ // free which means that total_ram must be signed as zero bytes free is
+ // allowable.
+ if (total_ram < ep_buff_size)
+ {
+ TU_LOG1("FT90x insufficient buffer RAM for endpoint %d\r\n", ep_number);
+ return false;
+ }
+
+ // Set the type of this endpoint in the control register.
+ if (ep_type == USBD_EP_BULK)
+ ep_reg_data |= (USBD_EP_DIS_BULK << BIT_USBD_EP_CONTROL_DIS);
+ else if (ep_type == USBD_EP_INT)
+ ep_reg_data |= (USBD_EP_DIS_INT << BIT_USBD_EP_CONTROL_DIS);
+ else if (ep_type == USBD_EP_ISOC)
+ ep_reg_data |= (USBD_EP_DIS_ISO << BIT_USBD_EP_CONTROL_DIS);
+ // Set the direction of this endpoint in the control register.
+ if (ep_dir == USBD_DIR_IN)
+ ep_reg_data |= MASK_USBD_EPxCR_DIR;
+ // Do not perform double buffering.
+ //if (<double buffering flag> != USBD_DB_OFF)
+ //ep_reg_data |= MASK_USBD_EPxCR_DB;
+ // Set the control endpoint for this endpoint.
+ USBD_EP_CR_REG(ep_number) = ep_reg_data;
+ TU_LOG2("FT90x endpoint setting %x\r\n", ep_reg_data);
+ }
+ else
+ {
+ // Set the control register for endpoint zero.
+ USBD_EP_CR_REG(USBD_EP_0) = (ep_reg_size << BIT_USBD_EP0_MAX_SIZE);
+ }
+
+ // Store the endpoint characteristics for later reference.
+ ep_xfer[ep_number].dir = ep_dir;
+ ep_xfer[ep_number].type = ep_type;
+ ep_xfer[ep_number].size = ep_size;
+ ep_xfer[ep_number].buff_size = ep_buff_size;
+
+ CRITICAL_SECTION_BEGIN
+ // Clear register transaction continuation and signalling state.
+ ep_xfer[ep_number].valid = 0;
+ ep_xfer[ep_number].buff_ptr = NULL;
+ ep_xfer[ep_number].total_size = 0;
+ ep_xfer[ep_number].remain_size = 0;
+ CRITICAL_SECTION_END
+
+ return true;
+}
+
+// Close all endpoints.
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void)rhport;
+ // Reset the endpoint configurations.
+ _ft90x_reset_edpts();
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ uint8_t ep_number = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+ uint16_t xfer_bytes;
+ bool status = false;
+
+ // We will attempt to transfer the buffer. If it is less than or equal to the endpoint
+ // maximum packet size then the whole buffer will be transferred. If it is larger then
+ // the interrupt handler will transfer the remainder.
+ // ep_xfer is used to tell the interrupt handler what to do.
+ // ep_xfer can be used at interrupt level to continue transfers.
+ CRITICAL_SECTION_BEGIN
+ // Transfer currently in progress.
+ if (ep_xfer[ep_number].valid == 0)
+ {
+ status = true;
+
+ ep_xfer[ep_number].total_size = total_bytes;
+ ep_xfer[ep_number].remain_size = total_bytes;
+ ep_xfer[ep_number].buff_ptr = buffer;
+ ep_xfer[ep_number].valid = 1;
+
+ if (ep_number == USBD_EP_0)
+ {
+ ep_xfer[USBD_EP_0].dir = dir;
+ }
+ else
+ {
+ // Enable the interrupt for this endpoint allowing the interrupt handler to report
+ // continue the transfer and signal completion.
+ USBD_REG(epie) = USBD_REG(epie) | (1 << ep_number);
+ }
+
+ if (dir == TUSB_DIR_IN)
+ {
+ // For IN transfers send the first packet as a starter. Interrupt handler to complete
+ // this if it is larger than one packet.
+ xfer_bytes = _ft90x_edpt_xfer_in(ep_number, buffer, total_bytes);
+
+ ep_xfer[ep_number].buff_ptr += xfer_bytes;
+ ep_xfer[ep_number].remain_size -= xfer_bytes;
+ }
+ }
+ CRITICAL_SECTION_END
+
+ return status;
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
+{
+ (void)rhport;
+ (void)ep_addr;
+ (void)ff;
+ (void)total_bytes;
+ bool status = false;
+ return status;
+}
+
+// Stall endpoint (non-control endpoint)
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t ep_number = tu_edpt_number(ep_addr);
+ (void)rhport;
+
+ CRITICAL_SECTION_BEGIN
+ if (ep_number == USBD_EP_0)
+ {
+ USBD_EP_CR_REG(USBD_EP_0) = USBD_EP_CR_REG(USBD_EP_0) |
+ MASK_USBD_EP0CR_SDSTL;
+ }
+ else
+ {
+ USBD_EP_CR_REG(ep_number) = USBD_EP_CR_REG(ep_number) |
+ MASK_USBD_EPxCR_SDSTL;
+ USBD_EP_SR_REG(ep_number) = MASK_USBD_EPxSR_CLR_TOGGLE |
+ MASK_USBD_EPxSR_FIFO_FLUSH;
+ }
+ CRITICAL_SECTION_END
+}
+
+// Clear stall (non-control endpoint), data toggle is also reset to DATA0
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t ep_number = tu_edpt_number(ep_addr);
+ (void)rhport;
+
+ if (ep_number > USBD_EP_0)
+ {
+ CRITICAL_SECTION_BEGIN
+ USBD_EP_CR_REG(ep_number) = USBD_EP_CR_REG(ep_number) &
+ (~MASK_USBD_EPxCR_SDSTL);
+ USBD_EP_SR_REG(ep_number) = MASK_USBD_EPxSR_CLR_TOGGLE;
+
+ // Allow transfers to restart.
+ ep_xfer[ep_number].valid = 0;
+ ep_xfer[ep_number].remain_size = 0;
+ CRITICAL_SECTION_END
+ }
+}
+
+// Interrupt handling.
+
+void _ft90x_usbd_ISR(void)
+{
+ tud_int_handler(BOARD_TUD_RHPORT); // Resolves to dcd_int_handler().
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ (void)rhport;
+
+ // Read the Common Interrupt Flag Register.
+ uint8_t cmif = USBD_REG(cmif);
+ // Read the Endpoint Interrupt Flag Register.
+#if defined(__FT930__)
+ // This is 16 bits on FT93x.
+ uint16_t epif = USBD_REG(epif);
+#else
+ // This is 8 bits on FT90x.
+ uint8_t epif = USBD_REG(epif);
+#endif
+
+ if (cmif & MASK_USBD_CMIF_ALL)
+ {
+ // Clear all CMIF bits.
+ USBD_REG(cmif) = MASK_USBD_CMIF_ALL;
+ if (cmif & MASK_USBD_CMIF_PHYIRQ) //Handle PHY interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_PIDIRQ) //Handle PIDIRQ interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_CRC16IRQ) //Handle CRC16IRQ interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_CRC5IRQ) //Handle CRC5 interrupt
+ {
+ }
+ if (cmif & MASK_USBD_CMIF_RSTIRQ) //Handle Reset interrupt
+ {
+ // Reset endpoints to default state.
+ _ft90x_reset_edpts();
+ dcd_event_bus_reset(BOARD_TUD_RHPORT, _speed, true);
+ }
+ if (cmif & MASK_USBD_CMIF_SUSIRQ) //Handle Suspend interrupt
+ {
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_SUSPEND, true);
+ }
+ if (cmif & MASK_USBD_CMIF_RESIRQ) //Handle Resume interrupt
+ {
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_RESUME, true);
+ }
+ if (cmif & MASK_USBD_CMIF_SOFIRQ) //Handle SOF interrupt
+ {
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_SOF, true);
+ }
+ }
+ // Handle endpoint interrupts.
+ if (epif)
+ {
+ uint16_t xfer_bytes;
+
+ // Check for EP0 interrupts pending.
+ if (epif & MASK_USBD_EPIF_EP0IRQ)
+ {
+ // Clear interrupt register.
+ USBD_REG(epif) = MASK_USBD_EPIF_EP0IRQ;
+
+ // Test for an incoming SETUP request on the control endpoint.
+ if (USBD_EP_SR_REG(USBD_EP_0) & MASK_USBD_EP0SR_SETUP)
+ {
+ // If protocol STALL, End the STALL signalling.
+ if (USBD_EP_CR_REG(USBD_EP_0) & MASK_USBD_EP0CR_SDSTL)
+ {
+ // STALL end.
+ USBD_EP_CR_REG(USBD_EP_0) = USBD_EP_CR_REG(USBD_EP_0) &
+ (~MASK_USBD_EP0CR_SDSTL);
+ // Clear STALL send.
+ USBD_EP_SR_REG(USBD_EP_0) = MASK_USBD_EP0SR_STALL;
+ }
+
+ // Host has sent a SETUP packet. Recieve this into the setup packet store.
+ _ft90x_dusb_out(USBD_EP_0, (uint8_t *)_ft90x_setup_packet, sizeof(USB_device_request));
+
+ // Send the packet to tinyusb.
+ dcd_event_setup_received(BOARD_TUD_RHPORT, _ft90x_setup_packet, true);
+
+ // Clear the interrupt that signals a SETUP packet is received.
+ USBD_EP_SR_REG(USBD_EP_0) = (MASK_USBD_EP0SR_SETUP);
+
+ // Allow new transfers on the control endpoint.
+ ep_xfer[USBD_EP_0].valid = 0;
+ return;
+ }
+ else
+ {
+ // Check for a complete or partially complete transfers on EP0.
+ if (ep_xfer[USBD_EP_0].valid)
+ {
+ xfer_bytes = (uint16_t)ep_xfer[USBD_EP_0].total_size;
+
+ // Transfer incoming data from an OUT packet to the buffer supplied.
+ if (ep_xfer[USBD_EP_0].dir == TUSB_DIR_OUT)
+ {
+ xfer_bytes = _ft90x_edpt_xfer_out(USBD_EP_0, (uint8_t *)ep_xfer[USBD_EP_0].buff_ptr, xfer_bytes);
+ }
+ // Now signal completion of data packet.
+ dcd_event_xfer_complete(BOARD_TUD_RHPORT, (ep_xfer[USBD_EP_0].dir ? TUSB_DIR_IN_MASK : 0), xfer_bytes, XFER_RESULT_SUCCESS, true);
+
+ // Allow new transfers on the control endpoint.
+ ep_xfer[USBD_EP_0].valid = 0;
+ }
+ }
+ }
+ else // !(epif & MASK_USBD_EPIF_EP0IRQ)
+ {
+ // Mask out currently disabled endpoints.
+ epif &= USBD_REG(epie);
+
+ // Handle complete and partially complete transfers for each endpoint.
+ for (uint8_t ep_number = 1; ep_number < USBD_MAX_ENDPOINT_COUNT; ep_number++)
+ {
+ if ((epif & MASK_USBD_EPIF_IRQ(ep_number)) == 0)
+ {
+ // No pending interrupt for this endpoint.
+ continue;
+ }
+
+ if (ep_xfer[ep_number].valid)
+ {
+ xfer_bytes = 0;
+ uint8_t ep_dirmask = (ep_xfer[ep_number].dir ? TUSB_DIR_IN_MASK : 0);
+
+ // Clear interrupt register for this endpoint.
+ USBD_REG(epif) = MASK_USBD_EPIF_IRQ(ep_number);
+
+ // Start or continue an OUT transfer.
+ if (ep_xfer[ep_number].dir == TUSB_DIR_OUT)
+ {
+ xfer_bytes = _ft90x_edpt_xfer_out(ep_number,
+ (uint8_t *)ep_xfer[ep_number].buff_ptr,
+ (uint16_t)ep_xfer[ep_number].remain_size);
+
+ ep_xfer[ep_number].buff_ptr += xfer_bytes;
+ ep_xfer[ep_number].remain_size -= xfer_bytes;
+ }
+ // continue an IN transfer
+ else // if (ep_xfer[ep_number].dir == TUSB_DIR_IN)
+ {
+ if (ep_xfer[ep_number].remain_size > 0)
+ {
+ xfer_bytes = _ft90x_edpt_xfer_in(ep_number,
+ (uint8_t *)ep_xfer[ep_number].buff_ptr,
+ (uint16_t)ep_xfer[ep_number].remain_size);
+
+ ep_xfer[ep_number].buff_ptr += xfer_bytes;
+ ep_xfer[ep_number].remain_size -= xfer_bytes;
+ }
+ }
+
+ // When the transfer is complete...
+ if (ep_xfer[ep_number].remain_size == 0)
+ {
+ // Signal tinyUSB.
+ dcd_event_xfer_complete(BOARD_TUD_RHPORT, ep_number | ep_dirmask, ep_xfer[ep_number].total_size, XFER_RESULT_SUCCESS, true);
+
+ // Allow new transfers on this endpoint.
+ ep_xfer[ep_number].valid = 0;
+
+ // Disable the interrupt for this endpoint now it is complete.
+ USBD_REG(epie) = USBD_REG(epie) & (~(1 << ep_number));
+ }
+ }
+ }
+ }
+ }
+}
+
+// Power management interrupt handler.
+// This handles USB device related power management interrupts only.
+void ft90x_usbd_pm_ISR(void)
+{
+ uint16_t pmcfg = SYS->PMCFG_H;
+
+ // Main interrupt handler is responible for
+ if (pmcfg & MASK_SYS_PMCFG_DEV_CONN_DEV)
+ {
+ // Signal connection interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_RESUME, true);
+ }
+
+ if (pmcfg & MASK_SYS_PMCFG_DEV_DIS_DEV)
+ {
+ // Signal disconnection interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_UNPLUGGED, true);
+ }
+
+ if (pmcfg & MASK_SYS_PMCFG_HOST_RST_DEV)
+ {
+ // Signal Host Reset interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_BUS_RESET, true);
+ }
+
+ if (pmcfg & MASK_SYS_PMCFG_HOST_RESUME_DEV)
+ {
+ // Signal Host Resume interrupt
+ SYS->PMCFG_H = MASK_SYS_PMCFG_PM_GPIO_IRQ_PEND;
+ if (!(SYS->MSC0CFG & MASK_SYS_MSC0CFG_DEV_RMWAKEUP))
+ {
+ // If we are driving K-state on Device USB port;
+ // We must maintain the 1ms requirement before resuming the phy
+ dcd_event_bus_signal(BOARD_TUD_RHPORT, DCD_EVENT_RESUME, true);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/broadcom/synopsys/dcd_synopsys.c b/src/portable/broadcom/synopsys/dcd_synopsys.c
deleted file mode 100644
index 494bb70ee..000000000
--- a/src/portable/broadcom/synopsys/dcd_synopsys.c
+++ /dev/null
@@ -1,1267 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- * Copyright (c) 2020 Jan Duempelmann
- * Copyright (c) 2020 Reinhard Panhuber
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_BCM2711 ) \
-
-
-#include "synopsys_common.h"
-
-#include "broadcom/interrupts.h"
-
-// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
-// We disable SOF for now until needed later on
-#define USE_SOF 0
-
-// EP_MAX : Max number of bi-directional endpoints including EP0
-// EP_FIFO_SIZE : Size of dedicated USB SRAM
-#if CFG_TUSB_MCU == OPT_MCU_BCM2711
-// #include "bcm2711.h"
-#define EP_MAX_FS 8
-#define EP_FIFO_SIZE_FS 4096
-#define EP_MAX_HS 8
-#define EP_FIFO_SIZE_HS 4096
-#else
-#error "Unsupported MCUs"
-#endif
-
-#define EP_MAX 8
-#define EP_FIFO_SIZE 4096
-
-// Info on values here: https://github.com/torvalds/linux/blob/79160a603bdb51916226caf4a6616cc4e1c58a58/Documentation/devicetree/bindings/usb/dwc2.yaml
-
-// From: https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/bcm283x.dtsi
-// usb: usb@7e980000 {
-// compatible = "brcm,bcm2835-usb";
-// reg = <0x7e980000 0x10000>;
-// interrupts = <1 9>;
-// #address-cells = <1>;
-// #size-cells = <0>;
-// clocks = <&clk_usb>;
-// clock-names = "otg";
-// phys = <&usbphy>;
-// phy-names = "usb2-phy";
-// };
-
-// From: https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/bcm283x-rpi-usb-otg.dtsi
-// SPDX-License-Identifier: GPL-2.0
-// &usb {
-// dr_mode = "otg";
-// g-rx-fifo-size = <256>;
-// g-np-tx-fifo-size = <32>;
-
-// * According to dwc2 the sum of all device EP
-// * fifo sizes shouldn't exceed 3776 bytes.
-
-// g-tx-fifo-size = <256 256 512 512 512 768 768>;
-// };
-
-// From: https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/bcm2711-rpi.dtsi
-// &usb {
-// /* Enable the FIQ support */
-// reg = <0x7e980000 0x10000>,
-// <0x7e00b200 0x200>;
-// interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
-// <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
-// status = "disabled";
-// };
-
-// From: https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/bcm2711.dtsi
-// &usb {
-// interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-// };
-
-// From: https://github.com/torvalds/linux/blob/1d597682d3e669ec7021aa33d088ed3d136a5149/drivers/usb/dwc2/params.c
-// static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg)
-// {
-// struct dwc2_core_params *p = &hsotg->params;
-
-// p->host_rx_fifo_size = 774;
-// p->max_transfer_size = 65535;
-// p->max_packet_count = 511;
-// p->ahbcfg = 0x10;
-// }
-
-#include "device/dcd.h"
-
-TU_VERIFY_STATIC(sizeof(USB_OTG_GlobalTypeDef) == 0x140, "size is incorrect");
-
-//--------------------------------------------------------------------+
-// MACRO TYPEDEF CONSTANT ENUM
-//--------------------------------------------------------------------+
-
-#define RHPORT_REGS_BASE USB_OTG_GLOBAL_BASE
-
-#define GLOBAL_BASE(_port) ((USB_OTG_GlobalTypeDef*) RHPORT_REGS_BASE)
-#define DEVICE_BASE(_port) (USB_OTG_DeviceTypeDef *) (USB_OTG_DEVICE_BASE)
-#define OUT_EP_BASE(_port) (USB_OTG_OUTEndpointTypeDef *) (RHPORT_REGS_BASE + USB_OTG_OUT_ENDPOINT_BASE)
-#define IN_EP_BASE(_port) (USB_OTG_INEndpointTypeDef *) (RHPORT_REGS_BASE + USB_OTG_IN_ENDPOINT_BASE)
-#define FIFO_BASE(_port, _x) ((volatile uint32_t *) (RHPORT_REGS_BASE + USB_OTG_FIFO_BASE + (_x) * USB_OTG_FIFO_SIZE))
-
-enum
-{
- DCD_HIGH_SPEED = 0, // Highspeed mode
- DCD_FULL_SPEED_USE_HS = 1, // Full speed in Highspeed port (probably with internal PHY)
- DCD_FULL_SPEED = 3, // Full speed with internal PHY
-};
-
-static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
-
-typedef struct {
- uint8_t * buffer;
- tu_fifo_t * ff;
- uint16_t total_len;
- uint16_t max_size;
- uint8_t interval;
-} xfer_ctl_t;
-
-typedef volatile uint32_t * usb_fifo_t;
-
-xfer_ctl_t xfer_status[EP_MAX][2];
-#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
-
-// EP0 transfers are limited to 1 packet - larger sizes has to be split
-static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type
-
-// TX FIFO RAM allocation so far in words - RX FIFO size is readily available from usb_otg->GRXFSIZ
-static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs)
-static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size)
-
-// Calculate the RX FIFO size according to recommendations from reference manual
-static inline uint16_t calc_rx_ff_size(uint16_t ep_size)
-{
- return 15 + 2*(ep_size/4) + 2*EP_MAX;
-}
-
-static void update_grxfsiz(uint8_t rhport)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
-
- // Determine largest EP size for RX FIFO
- uint16_t max_epsize = 0;
- for (uint8_t epnum = 0; epnum < EP_MAX; epnum++)
- {
- max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size);
- }
-
- // Update size of RX FIFO
- usb_otg->GRXFSIZ = calc_rx_ff_size(max_epsize);
-}
-
-// Setup the control endpoint 0.
-static void bus_reset(uint8_t rhport)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- tu_memclr(xfer_status, sizeof(xfer_status));
- _out_ep_closed = false;
-
- // clear device address
- dev->DCFG &= ~USB_OTG_DCFG_DAD_Msk;
-
- // 1. NAK for all OUT endpoints
- for(uint8_t n = 0; n < EP_MAX; n++) {
- out_ep[n].DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
- }
-
- // 2. Un-mask interrupt bits
- dev->DAINTMSK = (1 << USB_OTG_DAINTMSK_OEPM_Pos) | (1 << USB_OTG_DAINTMSK_IEPM_Pos);
- dev->DOEPMSK = USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM;
- dev->DIEPMSK = USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM;
-
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // The FIFO is split up in a lower part where the RX FIFO is located and an upper part where the TX FIFOs start.
- // We do this to allow the RX FIFO to grow dynamically which is possible since the free space is located
- // between the RX and TX FIFOs. This is required by ISO OUT EPs which need a bigger FIFO than the standard
- // configuration done below.
- //
- // Dynamically FIFO sizes are of interest only for ISO EPs since all others are usually not opened and closed.
- // All EPs other than ISO are opened as soon as the driver starts up i.e. when the host sends a
- // configure interface command. Hence, all IN EPs other the ISO will be located at the top. IN ISO EPs are usually
- // opened when the host sends an additional command: setInterface. At this point in time
- // the ISO EP will be located next to the free space and can change its size. In case more IN EPs change its size
- // an additional memory
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO 0 |
- // --------------- (320 or 1024) - 16
- // | IN FIFO 1 |
- // --------------- (320 or 1024) - 16 - x
- // | . . . . |
- // --------------- (320 or 1024) - 16 - x - y - ... - z
- // | IN FIFO MAX |
- // ---------------
- // | FREE |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits):
- // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN
- //
- // - All EP OUT shared a unique OUT FIFO which uses
- // - 13 for setup packets + control words (up to 3 setup packets).
- // - 1 for global NAK (not required/used here).
- // - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1"
- // - 2 for each used OUT endpoint
- //
- // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum
- // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x EP_MAX = 47 + 2 x EP_MAX
- // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x EP_MAX = 271 + 2 x EP_MAX
- //
- // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge
- // of the overall picture yet. We will use the worst scenario: largest possible + EP_MAX
- //
- // For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO
- // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to
- // overwrite this.
-
- #if TUD_OPT_HIGH_SPEED
- usb_otg->GRXFSIZ = calc_rx_ff_size(512);
- #else
- usb_otg->GRXFSIZ = calc_rx_ff_size(64);
- #endif
-
- _allocated_fifo_words_tx = 16;
-
- // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
- usb_otg->DIEPTXF0_HNPTXFSIZ = (16 << USB_OTG_TX0FD_Pos) | (EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
-
- // Fixed control EP0 size to 64 bytes
- in_ep[0].DIEPCTL &= ~(0x03 << USB_OTG_DIEPCTL_MPSIZ_Pos);
- xfer_status[0][TUSB_DIR_OUT].max_size = xfer_status[0][TUSB_DIR_IN].max_size = 64;
-
- out_ep[0].DOEPTSIZ |= (3 << USB_OTG_DOEPTSIZ_STUPCNT_Pos);
-
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IEPINT;
-}
-
-// Set turn-around timeout according to link speed
-extern uint32_t SystemCoreClock;
-static void set_turnaround(USB_OTG_GlobalTypeDef * usb_otg, tusb_speed_t speed)
-{
- usb_otg->GUSBCFG &= ~USB_OTG_GUSBCFG_TRDT;
-
- if ( speed == TUSB_SPEED_HIGH )
- {
- // Use fixed 0x09 for Highspeed
- usb_otg->GUSBCFG |= (0x09 << USB_OTG_GUSBCFG_TRDT_Pos);
- }
- else
- {
- // Turnaround timeout depends on the MCU clock
- uint32_t turnaround;
-
- if ( SystemCoreClock >= 32000000U )
- turnaround = 0x6U;
- else if ( SystemCoreClock >= 27500000U )
- turnaround = 0x7U;
- else if ( SystemCoreClock >= 24000000U )
- turnaround = 0x8U;
- else if ( SystemCoreClock >= 21800000U )
- turnaround = 0x9U;
- else if ( SystemCoreClock >= 20000000U )
- turnaround = 0xAU;
- else if ( SystemCoreClock >= 18500000U )
- turnaround = 0xBU;
- else if ( SystemCoreClock >= 17200000U )
- turnaround = 0xCU;
- else if ( SystemCoreClock >= 16000000U )
- turnaround = 0xDU;
- else if ( SystemCoreClock >= 15000000U )
- turnaround = 0xEU;
- else
- turnaround = 0xFU;
-
- // Fullspeed depends on MCU clocks, but we will use 0x06 for 32+ Mhz
- usb_otg->GUSBCFG |= (turnaround << USB_OTG_GUSBCFG_TRDT_Pos);
- }
-}
-
-static tusb_speed_t get_speed(uint8_t rhport)
-{
- (void) rhport;
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- uint32_t const enum_spd = (dev->DSTS & USB_OTG_DSTS_ENUMSPD_Msk) >> USB_OTG_DSTS_ENUMSPD_Pos;
- return (enum_spd == DCD_HIGH_SPEED) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
-}
-
-static void set_speed(uint8_t rhport, tusb_speed_t speed)
-{
- uint32_t bitvalue;
-
- if ( rhport == 1 )
- {
- bitvalue = ((TUSB_SPEED_HIGH == speed) ? DCD_HIGH_SPEED : DCD_FULL_SPEED_USE_HS);
- }
- else
- {
- bitvalue = DCD_FULL_SPEED;
- }
-
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
-
- // Clear and set speed bits
- dev->DCFG &= ~(3 << USB_OTG_DCFG_DSPD_Pos);
- dev->DCFG |= (bitvalue << USB_OTG_DCFG_DSPD_Pos);
-}
-
-#if 0
-// From CM4IO xtal to usb hub, may not be correct
-#define HSE_VALUE 24000000
-
-static bool USB_HS_PHYCInit(void)
-{
- USB_HS_PHYC_GlobalTypeDef *usb_hs_phyc = (USB_HS_PHYC_GlobalTypeDef*) USB_HS_PHYC_CONTROLLER_BASE;
-
- // Enable LDO
- usb_hs_phyc->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE;
-
- // Wait until LDO ready
- while ( 0 == (usb_hs_phyc->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS) ) {}
-
- uint32_t phyc_pll = 0;
-
- // TODO Try to get HSE_VALUE from registers instead of depending CFLAGS
- switch ( HSE_VALUE )
- {
- case 12000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12MHZ ; break;
- case 12500000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ ; break;
- case 16000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_16MHZ ; break;
- case 24000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_24MHZ ; break;
- case 25000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_25MHZ ; break;
- case 32000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_Msk ; break; // Value not defined in header
- default:
- TU_ASSERT(0);
- }
- usb_hs_phyc->USB_HS_PHYC_PLL = phyc_pll;
-
- // Control the tuning interface of the High Speed PHY
- // Use magic value (USB_HS_PHYC_TUNE_VALUE) from ST driver
- usb_hs_phyc->USB_HS_PHYC_TUNE |= 0x00000F13U;
-
- // Enable PLL internal PHY
- usb_hs_phyc->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
-
- // Original ST code has 2 ms delay for PLL stabilization.
- // Primitive test shows that more than 10 USB un/replug cycle showed no error with enumeration
-
- return true;
-}
-#endif
-
-static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes)
-{
- (void) rhport;
-
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- // EP0 is limited to one packet each xfer
- // We use multiple transaction of xfer->max_size length to get a whole transfer done
- if(epnum == 0) {
- xfer_ctl_t * const xfer = XFER_CTL_BASE(epnum, dir);
- total_bytes = tu_min16(ep0_pending[dir], xfer->max_size);
- ep0_pending[dir] -= total_bytes;
- }
-
- // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here.
- if(dir == TUSB_DIR_IN) {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- in_ep[epnum].DIEPTSIZ = (num_packets << USB_OTG_DIEPTSIZ_PKTCNT_Pos) |
- ((total_bytes << USB_OTG_DIEPTSIZ_XFRSIZ_Pos) & USB_OTG_DIEPTSIZ_XFRSIZ_Msk);
-
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK;
- // For ISO endpoint set correct odd/even bit for next frame.
- if ((in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPTYP) == USB_OTG_DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1)
- {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (dev->DSTS & (1u << USB_OTG_DSTS_FNSOF_Pos));
- in_ep[epnum].DIEPCTL |= (odd_frame_now ? USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Msk : USB_OTG_DIEPCTL_SODDFRM_Msk);
- }
- // Enable fifo empty interrupt only if there are something to put in the fifo.
- if(total_bytes != 0) {
- dev->DIEPEMPMSK |= (1 << epnum);
- }
- } else {
- // A full OUT transfer (multiple packets, possibly) triggers XFRC.
- out_ep[epnum].DOEPTSIZ &= ~(USB_OTG_DOEPTSIZ_PKTCNT_Msk | USB_OTG_DOEPTSIZ_XFRSIZ);
- out_ep[epnum].DOEPTSIZ |= (num_packets << USB_OTG_DOEPTSIZ_PKTCNT_Pos) |
- ((total_bytes << USB_OTG_DOEPTSIZ_XFRSIZ_Pos) & USB_OTG_DOEPTSIZ_XFRSIZ_Msk);
-
- out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
- if ((out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPTYP) == USB_OTG_DOEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1)
- {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (dev->DSTS & (1u << USB_OTG_DSTS_FNSOF_Pos));
- out_ep[epnum].DOEPCTL |= (odd_frame_now ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Msk : USB_OTG_DOEPCTL_SODDFRM_Msk);
- }
- }
-}
-
-/*------------------------------------------------------------------*/
-/* Controller API
- *------------------------------------------------------------------*/
-
-TU_ATTR_UNUSED
-static void reset_core(USB_OTG_GlobalTypeDef * usb_otg) {
- while ((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0) {}
-
- TU_LOG(2, " resetting\r\n");
- usb_otg->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
- TU_LOG(2, " waiting\r\n");
- while ((usb_otg->GRSTCTL & (USB_OTG_GRSTCTL_AHBIDL | USB_OTG_GRSTCTL_CSRST)) != USB_OTG_GRSTCTL_AHBIDL) {}
- TU_LOG(2, " reset done\r\n");
-}
-
-void dcd_init (uint8_t rhport)
-{
- printf("test done\r\n");
- // Programming model begins in the last section of the chapter on the USB
- // peripheral in each Reference Manual.
- TU_LOG(2, " dcd_init\r\n");
-
- TU_LOG2("Test 123\r\n");
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
-
-#if 1
- // No VBUS sense
- usb_otg->GCCFG &= ~(1UL << 21); // USB_OTG_GCCFG_VBDEN
-
- // B-peripheral session valid override enable
- usb_otg->GOTGCTL |= (1UL << 6); // USB_OTG_GOTGCTL_BVALOEN
- usb_otg->GOTGCTL |= (1UL << 7); // USB_OTG_GOTGCTL_BVALOVAL
-
- // Force device mode
- usb_otg->GUSBCFG &= ~USB_OTG_GUSBCFG_FHMOD;
- usb_otg->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD;
-
- // deactivate internal PHY
- usb_otg->GCCFG &= ~USB_OTG_GCCFG_PWRDWN;
-
- // Init The UTMI Interface
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_TSDPS | USB_OTG_GUSBCFG_ULPIFSLS | USB_OTG_GUSBCFG_PHYSEL);
-
- // Select default internal VBUS Indicator and Drive for ULPI
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_ULPIEVBUSD | USB_OTG_GUSBCFG_ULPIEVBUSI);
-
- // Select UTMI Interface
- usb_otg->GUSBCFG &= ~(1UL << 4); // USB_OTG_GUSBCFG_ULPI_UTMI_SEL
- usb_otg->GCCFG |= (1UL << 32); // USB_OTG_GCCFG_PHYHSEN
-
- // Enables control of a High Speed USB PHY
- //USB_HS_PHYCInit();
-
- // Reset core after selecting PHY
- // Wait AHB IDLE, reset then wait until it is cleared
-// while ((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U) {}
-// usb_otg->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
-// while ((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST) {}
-
- reset_core(usb_otg);
-
- // Restart PHY clock
- *((volatile uint32_t *)(RHPORT_REGS_BASE + USB_OTG_PCGCCTL_BASE)) = 0;
-
-#else
-
- // ReadBackReg(&Core->Usb);
- // Core->Usb.UlpiDriveExternalVbus = 0;
- // Core->Usb.TsDlinePulseEnable = 0;
- // WriteThroughReg(&Core->Usb);
-
- // This sequence is modeled after: https://github.com/Chadderz121/csud/blob/e13b9355d043a9cdd384b335060f1bc0416df61e/source/hcd/dwc/designware20.c#L689
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_TSDPS | USB_OTG_GUSBCFG_ULPIEVBUSD);
- reset_core(usb_otg);
-
- // Core->Usb.ModeSelect = UTMI;
- // LOG_DEBUG("HCD: Interface: UTMI+.\n");
- // Core->Usb.PhyInterface = false;
-
- // HcdReset();
- TU_LOG2("init phy\r\n");
- usb_otg->GUSBCFG |= (1 << 4); // bit four sets UTMI+ mode
- usb_otg->GUSBCFG &= ~(1 << 3); // bit three disables phy interface
- reset_core(usb_otg);
-
- // LOG_DEBUG("HCD: ULPI FSLS configuration: disabled.\n");
- // Core->Usb.UlpiFsls = false;
- // Core->Usb.ulpi_clk_sus_m = false;
- usb_otg->GUSBCFG &= ~(USB_OTG_GUSBCFG_ULPIFSLS | USB_OTG_GUSBCFG_ULPICSM);
-
- // LOG_DEBUG("HCD: DMA configuration: enabled.\n");
- // Core->Ahb.DmaEnable = true;
- // Core->Ahb.DmaRemainderMode = Incremental;
- usb_otg->GAHBCFG &= ~(1 << 23); // Remainder mode
- usb_otg->GAHBCFG |= USB_OTG_GAHBCFG_DMAEN;
-
- // LOG_DEBUG("HCD: HNP/SRP configuration: HNP, SRP.\n");
- // Core->Usb.HnpCapable = true;
- // Core->Usb.SrpCapable = true;
- usb_otg->GUSBCFG |= USB_OTG_GUSBCFG_SRPCAP | USB_OTG_GUSBCFG_HNPCAP;
-
-#endif
-
- // Clear all interrupts
- usb_otg->GINTSTS |= usb_otg->GINTSTS;
-
- // Required as part of core initialization.
- // TODO: How should mode mismatch be handled? It will cause
- // the core to stop working/require reset.
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_OTGINT | USB_OTG_GINTMSK_MMISM;
-
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
-
- // If USB host misbehaves during status portion of control xfer
- // (non zero-length packet), send STALL back and discard.
- dev->DCFG |= USB_OTG_DCFG_NZLSOHSK;
-
- set_speed(rhport, TUSB_SPEED_HIGH);
-
- // TODO internal phy (full speed)
- usb_otg->GCCFG |= USB_OTG_GCCFG_PWRDWN;
-
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM |
- USB_OTG_GINTMSK_USBSUSPM | USB_OTG_GINTMSK_WUIM |
- USB_OTG_GINTMSK_RXFLVLM | (USE_SOF ? USB_OTG_GINTMSK_SOFM : 0);
-
- // Enable global interrupt
- usb_otg->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
-
- dcd_connect(rhport);
-}
-
-void dcd_int_enable (uint8_t rhport)
-{
- (void) rhport;
- BP_EnableIRQ(USB_IRQn);
-}
-
-void dcd_int_disable (uint8_t rhport)
-{
- (void) rhport;
- BP_DisableIRQ(USB_IRQn);
-}
-
-void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
-{
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- dev->DCFG = (dev->DCFG & ~USB_OTG_DCFG_DAD_Msk) | (dev_addr << USB_OTG_DCFG_DAD_Pos);
-
- // Response with status after changing device address
- dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
-}
-
-static void remote_wakeup_delay(void)
-{
- // try to delay for 1 ms
- uint32_t count = SystemCoreClock / 1000;
- while ( count-- )
- {
- // __NOP();
- }
-}
-
-void dcd_remote_wakeup(uint8_t rhport)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
-
- // set remote wakeup
- dev->DCTL |= USB_OTG_DCTL_RWUSIG;
-
- // enable SOF to detect bus resume
- usb_otg->GINTSTS = USB_OTG_GINTSTS_SOF;
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_SOFM;
-
- // Per specs: remote wakeup signal bit must be clear within 1-15ms
- remote_wakeup_delay();
-
- dev->DCTL &= ~USB_OTG_DCTL_RWUSIG;
-}
-
-void dcd_connect(uint8_t rhport)
-{
- (void) rhport;
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- dev->DCTL &= ~USB_OTG_DCTL_SDIS;
-}
-
-void dcd_disconnect(uint8_t rhport)
-{
- (void) rhport;
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- dev->DCTL |= USB_OTG_DCTL_SDIS;
-}
-
-
-/*------------------------------------------------------------------*/
-/* DCD Endpoint port
- *------------------------------------------------------------------*/
-
-bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
-
- TU_ASSERT(epnum < EP_MAX);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = tu_edpt_packet_size(desc_edpt);
- xfer->interval = desc_edpt->bInterval;
-
- uint16_t const fifo_size = (xfer->max_size + 3) / 4; // Round up to next full word
-
- if(dir == TUSB_DIR_OUT)
- {
- // Calculate required size of RX FIFO
- uint16_t const sz = calc_rx_ff_size(4*fifo_size);
-
- // If size_rx needs to be extended check if possible and if so enlarge it
- if (usb_otg->GRXFSIZ < sz)
- {
- TU_ASSERT(sz + _allocated_fifo_words_tx <= EP_FIFO_SIZE/4);
-
- // Enlarge RX FIFO
- usb_otg->GRXFSIZ = sz;
- }
-
- out_ep[epnum].DOEPCTL |= (1 << USB_OTG_DOEPCTL_USBAEP_Pos) |
- (desc_edpt->bmAttributes.xfer << USB_OTG_DOEPCTL_EPTYP_Pos) |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM : 0) |
- (xfer->max_size << USB_OTG_DOEPCTL_MPSIZ_Pos);
-
- dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_OEPM_Pos + epnum));
- }
- else
- {
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO 0 |
- // --------------- (320 or 1024) - 16
- // | IN FIFO 1 |
- // --------------- (320 or 1024) - 16 - x
- // | . . . . |
- // --------------- (320 or 1024) - 16 - x - y - ... - z
- // | IN FIFO MAX |
- // ---------------
- // | FREE |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // In FIFO is allocated by following rules:
- // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
-
- // Check if free space is available
- TU_ASSERT(_allocated_fifo_words_tx + fifo_size + usb_otg->GRXFSIZ <= EP_FIFO_SIZE/4);
-
- _allocated_fifo_words_tx += fifo_size;
-
- TU_LOG(2, " Allocated %u bytes at offset %u", fifo_size*4, EP_FIFO_SIZE-_allocated_fifo_words_tx*4);
-
- // DIEPTXF starts at FIFO #1.
- // Both TXFD and TXSA are in unit of 32-bit words.
- usb_otg->DIEPTXF[epnum - 1] = (fifo_size << USB_OTG_DIEPTXF_INEPTXFD_Pos) | (EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
-
- in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) |
- (epnum << USB_OTG_DIEPCTL_TXFNUM_Pos) |
- (desc_edpt->bmAttributes.xfer << USB_OTG_DIEPCTL_EPTYP_Pos) |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DIEPCTL_SD0PID_SEVNFRM : 0) |
- (xfer->max_size << USB_OTG_DIEPCTL_MPSIZ_Pos);
-
- dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum));
- }
-
- return true;
-}
-
-// Close all non-control endpoints, cancel all pending transfers if any.
-void dcd_edpt_close_all (uint8_t rhport)
-{
- (void) rhport;
-
-// USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- // Disable non-control interrupt
- dev->DAINTMSK = (1 << USB_OTG_DAINTMSK_OEPM_Pos) | (1 << USB_OTG_DAINTMSK_IEPM_Pos);
-
- for(uint8_t n = 1; n < EP_MAX; n++)
- {
- // disable OUT endpoint
- out_ep[n].DOEPCTL = 0;
- xfer_status[n][TUSB_DIR_OUT].max_size = 0;
-
- // disable IN endpoint
- in_ep[n].DIEPCTL = 0;
- xfer_status[n][TUSB_DIR_IN].max_size = 0;
- }
-
- // reset allocated fifo IN
- _allocated_fifo_words_tx = 16;
-}
-
-bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = buffer;
- xfer->ff = NULL;
- xfer->total_len = total_bytes;
-
- // EP0 can only handle one packet
- if(epnum == 0) {
- ep0_pending[dir] = total_bytes;
- // Schedule the first transaction for EP0 transfer
- edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]);
- return true;
- }
-
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint16_t const short_packet_size = total_bytes % xfer->max_size;
-
- // Zero-size packet is special case.
- if(short_packet_size > 0 || (total_bytes == 0)) {
- num_packets++;
- }
-
- // Schedule packets to be sent within interrupt
- edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
-
- return true;
-}
-
-// The number of bytes has to be given explicitly to allow more flexible control of how many
-// bytes should be written and second to keep the return value free to give back a boolean
-// success message. If total_bytes is too big, the FIFO will copy only what is available
-// into the USB buffer!
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
-{
- // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
- TU_ASSERT(ff->item_size == 1);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = NULL;
- xfer->ff = ff;
- xfer->total_len = total_bytes;
-
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint16_t const short_packet_size = total_bytes % xfer->max_size;
-
- // Zero-size packet is special case.
- if(short_packet_size > 0 || (total_bytes == 0)) num_packets++;
-
- // Schedule packets to be sent within interrupt
- edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes);
-
- return true;
-}
-
-static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall)
-{
- (void) rhport;
-
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if(dir == TUSB_DIR_IN) {
- // Only disable currently enabled non-control endpoint
- if ( (epnum == 0) || !(in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPENA) ){
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SNAK | (stall ? USB_OTG_DIEPCTL_STALL : 0);
- } else {
- // Stop transmitting packets and NAK IN xfers.
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
- while((in_ep[epnum].DIEPINT & USB_OTG_DIEPINT_INEPNE) == 0);
-
- // Disable the endpoint.
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPDIS | (stall ? USB_OTG_DIEPCTL_STALL : 0);
- while((in_ep[epnum].DIEPINT & USB_OTG_DIEPINT_EPDISD_Msk) == 0);
- in_ep[epnum].DIEPINT = USB_OTG_DIEPINT_EPDISD;
- }
-
- // Flush the FIFO, and wait until we have confirmed it cleared.
- usb_otg->GRSTCTL |= (epnum << USB_OTG_GRSTCTL_TXFNUM_Pos);
- usb_otg->GRSTCTL |= USB_OTG_GRSTCTL_TXFFLSH;
- while((usb_otg->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH_Msk) != 0);
- } else {
- // Only disable currently enabled non-control endpoint
- if ( (epnum == 0) || !(out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPENA) ){
- out_ep[epnum].DOEPCTL |= stall ? USB_OTG_DOEPCTL_STALL : 0;
- } else {
- // Asserting GONAK is required to STALL an OUT endpoint.
- // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
- // anyway, and it can't be cleared by user code. If this while loop never
- // finishes, we have bigger problems than just the stack.
- dev->DCTL |= USB_OTG_DCTL_SGONAK;
- while((usb_otg->GINTSTS & USB_OTG_GINTSTS_BOUTNAKEFF_Msk) == 0);
-
- // Ditto here- disable the endpoint.
- out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPDIS | (stall ? USB_OTG_DOEPCTL_STALL : 0);
- while((out_ep[epnum].DOEPINT & USB_OTG_DOEPINT_EPDISD_Msk) == 0);
- out_ep[epnum].DOEPINT = USB_OTG_DOEPINT_EPDISD;
-
- // Allow other OUT endpoints to keep receiving.
- dev->DCTL |= USB_OTG_DCTL_CGONAK;
- }
- }
-}
-
-/**
- * Close an endpoint.
- */
-void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
-{
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_edpt_disable(rhport, ep_addr, false);
-
- // Update max_size
- xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation
-
- if (dir == TUSB_DIR_IN)
- {
- uint16_t const fifo_size = (usb_otg->DIEPTXF[epnum - 1] & USB_OTG_DIEPTXF_INEPTXFD_Msk) >> USB_OTG_DIEPTXF_INEPTXFD_Pos;
- uint16_t const fifo_start = (usb_otg->DIEPTXF[epnum - 1] & USB_OTG_DIEPTXF_INEPTXSA_Msk) >> USB_OTG_DIEPTXF_INEPTXSA_Pos;
- // For now only the last opened endpoint can be closed without fuss.
- TU_ASSERT(fifo_start == EP_FIFO_SIZE/4 - _allocated_fifo_words_tx,);
- _allocated_fifo_words_tx -= fifo_size;
- }
- else
- {
- _out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty
- }
-}
-
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
-{
- dcd_edpt_disable(rhport, ep_addr, true);
-}
-
-void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
-{
- (void) rhport;
-
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- // Clear stall and reset data toggle
- if(dir == TUSB_DIR_IN) {
- in_ep[epnum].DIEPCTL &= ~USB_OTG_DIEPCTL_STALL;
- in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM;
- } else {
- out_ep[epnum].DOEPCTL &= ~USB_OTG_DOEPCTL_STALL;
- out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_SD0PID_SEVNFRM;
- }
-}
-
-/*------------------------------------------------------------------*/
-
-// Read a single data packet from receive FIFO
-static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len)
-{
- (void) rhport;
-
- usb_fifo_t rx_fifo = FIFO_BASE(rhport, 0);
-
- // Reading full available 32 bit words from fifo
- uint16_t full_words = len >> 2;
- for(uint16_t i = 0; i < full_words; i++) {
- uint32_t tmp = *rx_fifo;
- dst[0] = tmp & 0x000000FF;
- dst[1] = (tmp & 0x0000FF00) >> 8;
- dst[2] = (tmp & 0x00FF0000) >> 16;
- dst[3] = (tmp & 0xFF000000) >> 24;
- dst += 4;
- }
-
- // Read the remaining 1-3 bytes from fifo
- uint8_t bytes_rem = len & 0x03;
- if(bytes_rem != 0) {
- uint32_t tmp = *rx_fifo;
- dst[0] = tmp & 0x000000FF;
- if(bytes_rem > 1) {
- dst[1] = (tmp & 0x0000FF00) >> 8;
- }
- if(bytes_rem > 2) {
- dst[2] = (tmp & 0x00FF0000) >> 16;
- }
- }
-}
-
-// Write a single data packet to EPIN FIFO
-static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t * src, uint16_t len)
-{
- (void) rhport;
-
- usb_fifo_t tx_fifo = FIFO_BASE(rhport, fifo_num);
-
- // Pushing full available 32 bit words to fifo
- uint16_t full_words = len >> 2;
- for(uint16_t i = 0; i < full_words; i++){
- *tx_fifo = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
- src += 4;
- }
-
- // Write the remaining 1-3 bytes into fifo
- uint8_t bytes_rem = len & 0x03;
- if(bytes_rem){
- uint32_t tmp_word = 0;
- tmp_word |= src[0];
- if(bytes_rem > 1){
- tmp_word |= src[1] << 8;
- }
- if(bytes_rem > 2){
- tmp_word |= src[2] << 16;
- }
- *tx_fifo = tmp_word;
- }
-}
-
-static void handle_rxflvl_ints(uint8_t rhport, USB_OTG_OUTEndpointTypeDef * out_ep) {
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- usb_fifo_t rx_fifo = FIFO_BASE(rhport, 0);
-
- // Pop control word off FIFO
- uint32_t ctl_word = usb_otg->GRXSTSP;
- uint8_t pktsts = (ctl_word & USB_OTG_GRXSTSP_PKTSTS_Msk) >> USB_OTG_GRXSTSP_PKTSTS_Pos;
- uint8_t epnum = (ctl_word & USB_OTG_GRXSTSP_EPNUM_Msk) >> USB_OTG_GRXSTSP_EPNUM_Pos;
- uint16_t bcnt = (ctl_word & USB_OTG_GRXSTSP_BCNT_Msk) >> USB_OTG_GRXSTSP_BCNT_Pos;
-
- switch(pktsts) {
- case 0x01: // Global OUT NAK (Interrupt)
- break;
-
- case 0x02: // Out packet recvd
- {
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
-
- // Read packet off RxFIFO
- if (xfer->ff)
- {
- // Ring buffer
- tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *)(uintptr_t) rx_fifo, bcnt);
- }
- else
- {
- // Linear buffer
- read_fifo_packet(rhport, xfer->buffer, bcnt);
-
- // Increment pointer to xfer data
- xfer->buffer += bcnt;
- }
-
- // Truncate transfer length in case of short packet
- if(bcnt < xfer->max_size) {
- xfer->total_len -= (out_ep[epnum].DOEPTSIZ & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DOEPTSIZ_XFRSIZ_Pos;
- if(epnum == 0) {
- xfer->total_len -= ep0_pending[TUSB_DIR_OUT];
- ep0_pending[TUSB_DIR_OUT] = 0;
- }
- }
- }
- break;
-
- case 0x03: // Out packet done (Interrupt)
- break;
-
- case 0x04: // Setup packet done (Interrupt)
- out_ep[epnum].DOEPTSIZ |= (3 << USB_OTG_DOEPTSIZ_STUPCNT_Pos);
- break;
-
- case 0x06: // Setup packet recvd
- // We can receive up to three setup packets in succession, but
- // only the last one is valid.
- _setup_packet[0] = (* rx_fifo);
- _setup_packet[1] = (* rx_fifo);
- break;
-
- default: // Invalid
- TU_BREAKPOINT();
- break;
- }
-}
-
-static void handle_epout_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTypeDef * out_ep) {
- // DAINT for a given EP clears when DOEPINTx is cleared.
- // OEPINT will be cleared when DAINT's out bits are cleared.
- for(uint8_t n = 0; n < EP_MAX; n++) {
- xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
-
- if(dev->DAINT & (1 << (USB_OTG_DAINT_OEPINT_Pos + n))) {
- // SETUP packet Setup Phase done.
- if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_STUP) {
- out_ep[n].DOEPINT = USB_OTG_DOEPINT_STUP;
- dcd_event_setup_received(rhport, (uint8_t*) &_setup_packet[0], true);
- }
-
- // OUT XFER complete
- if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_XFRC) {
- out_ep[n].DOEPINT = USB_OTG_DOEPINT_XFRC;
-
- // EP0 can only handle one packet
- if((n == 0) && ep0_pending[TUSB_DIR_OUT]) {
- // Schedule another packet to be received.
- edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]);
- } else {
- dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
- }
- }
- }
-}
-
-static void handle_epin_ints(uint8_t rhport, USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointTypeDef * in_ep) {
- // DAINT for a given EP clears when DIEPINTx is cleared.
- // IEPINT will be cleared when DAINT's out bits are cleared.
- for ( uint8_t n = 0; n < EP_MAX; n++ )
- {
- xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
-
- if ( dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n)) )
- {
- // IN XFER complete (entire xfer).
- if ( in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC )
- {
- in_ep[n].DIEPINT = USB_OTG_DIEPINT_XFRC;
-
- // EP0 can only handle one packet
- if((n == 0) && ep0_pending[TUSB_DIR_IN]) {
- // Schedule another packet to be transmitted.
- edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]);
- } else {
- dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
- }
-
- // XFER FIFO empty
- if ( (in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE) && (dev->DIEPEMPMSK & (1 << n)) )
- {
- // DIEPINT's TXFE bit is read-only, software cannot clear it.
- // It will only be cleared by hardware when written bytes is more than
- // - 64 bytes or
- // - Half of TX FIFO size (configured by DIEPTXF)
-
- uint16_t remaining_packets = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_PKTCNT_Msk) >> USB_OTG_DIEPTSIZ_PKTCNT_Pos;
-
- // Process every single packet (only whole packets can be written to fifo)
- for(uint16_t i = 0; i < remaining_packets; i++)
- {
- uint16_t const remaining_bytes = (in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos;
-
- // Packet can not be larger than ep max size
- uint16_t const packet_size = tu_min16(remaining_bytes, xfer->max_size);
-
- // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current
- // EP has to be checked if the buffer can take another WHOLE packet
- if(packet_size > ((in_ep[n].DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV_Msk) << 2)) break;
-
- // Push packet to Tx-FIFO
- if (xfer->ff)
- {
- usb_fifo_t tx_fifo = FIFO_BASE(rhport, n);
- tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *)(uintptr_t) tx_fifo, packet_size);
- }
- else
- {
- write_fifo_packet(rhport, n, xfer->buffer, packet_size);
-
- // Increment pointer to xfer data
- xfer->buffer += packet_size;
- }
- }
-
- // Turn off TXFE if all bytes are written.
- if (((in_ep[n].DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ_Msk) >> USB_OTG_DIEPTSIZ_XFRSIZ_Pos) == 0)
- {
- dev->DIEPEMPMSK &= ~(1 << n);
- }
- }
- }
- }
-}
-
-void dcd_int_handler(uint8_t rhport)
-{
- USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
- USB_OTG_DeviceTypeDef * dev = DEVICE_BASE(rhport);
- USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE(rhport);
- USB_OTG_INEndpointTypeDef * in_ep = IN_EP_BASE(rhport);
-
- uint32_t const int_status = usb_otg->GINTSTS & usb_otg->GINTMSK;
-
- if(int_status & USB_OTG_GINTSTS_USBRST)
- {
- // USBRST is start of reset.
- usb_otg->GINTSTS = USB_OTG_GINTSTS_USBRST;
- bus_reset(rhport);
- }
-
- if(int_status & USB_OTG_GINTSTS_ENUMDNE)
- {
- // ENUMDNE is the end of reset where speed of the link is detected
-
- usb_otg->GINTSTS = USB_OTG_GINTSTS_ENUMDNE;
-
- tusb_speed_t const speed = get_speed(rhport);
-
- set_turnaround(usb_otg, speed);
- dcd_event_bus_reset(rhport, speed, true);
- }
-
- if(int_status & USB_OTG_GINTSTS_USBSUSP)
- {
- usb_otg->GINTSTS = USB_OTG_GINTSTS_USBSUSP;
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
-
- if(int_status & USB_OTG_GINTSTS_WKUINT)
- {
- usb_otg->GINTSTS = USB_OTG_GINTSTS_WKUINT;
- dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
- }
-
- // TODO check USB_OTG_GINTSTS_DISCINT for disconnect detection
- // if(int_status & USB_OTG_GINTSTS_DISCINT)
-
- if(int_status & USB_OTG_GINTSTS_OTGINT)
- {
- // OTG INT bit is read-only
- uint32_t const otg_int = usb_otg->GOTGINT;
-
- if (otg_int & USB_OTG_GOTGINT_SEDET)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
- }
-
- usb_otg->GOTGINT = otg_int;
- }
-
- if(int_status & USB_OTG_GINTSTS_SOF)
- {
- usb_otg->GINTSTS = USB_OTG_GINTSTS_SOF;
-
- // Disable SOF interrupt since currently only used for remote wakeup detection
- usb_otg->GINTMSK &= ~USB_OTG_GINTMSK_SOFM;
-
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
- }
-
- // RxFIFO non-empty interrupt handling.
- if(int_status & USB_OTG_GINTSTS_RXFLVL)
- {
- // RXFLVL bit is read-only
-
- // Mask out RXFLVL while reading data from FIFO
- usb_otg->GINTMSK &= ~USB_OTG_GINTMSK_RXFLVLM;
-
- // Loop until all available packets were handled
- do
- {
- handle_rxflvl_ints(rhport, out_ep);
- } while(usb_otg->GINTSTS & USB_OTG_GINTSTS_RXFLVL);
-
- // Manage RX FIFO size
- if (_out_ep_closed)
- {
- update_grxfsiz(rhport);
-
- // Disable flag
- _out_ep_closed = false;
- }
-
- usb_otg->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
- }
-
- // OUT endpoint interrupt handling.
- if(int_status & USB_OTG_GINTSTS_OEPINT)
- {
- // OEPINT is read-only
- handle_epout_ints(rhport, dev, out_ep);
- }
-
- // IN endpoint interrupt handling.
- if(int_status & USB_OTG_GINTSTS_IEPINT)
- {
- // IEPINT bit read-only
- handle_epin_ints(rhport, dev, in_ep);
- }
-
- // // Check for Incomplete isochronous IN transfer
- // if(int_status & USB_OTG_GINTSTS_IISOIXFR) {
- // printf(" IISOIXFR!\r\n");
- //// TU_LOG2(" IISOIXFR!\r\n");
- // }
-}
-
-#endif
diff --git a/src/portable/broadcom/synopsys/synopsys_common.h b/src/portable/broadcom/synopsys/synopsys_common.h
deleted file mode 100644
index 81ce3b4a9..000000000
--- a/src/portable/broadcom/synopsys/synopsys_common.h
+++ /dev/null
@@ -1,1476 +0,0 @@
-/**
- ******************************************************************************
- * @file synopsys_common.h
- * @author MCD Application Team
- * @brief CMSIS Cortex-M3 Device USB OTG peripheral Header File.
- * This file contains the USB OTG peripheral register's definitions, bits
- * definitions and memory mapping for STM32F1xx devices.
- *
- * This file contains:
- * - Data structures and the address mapping for the USB OTG peripheral
- * - The Peripheral's registers declarations and bits definition
- * - Macros to access the peripheral's registers hardware
- *
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
- * All rights reserved.</center></h2>
- *
- * This software component is licensed by ST under BSD 3-Clause license,
- * the "License"; You may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- * opensource.org/licenses/BSD-3-Clause
- *
- ******************************************************************************
- */
-
-#include "stdint.h"
-
-#pragma once
-
-#ifdef __cplusplus
- #define __I volatile
-#else
- #define __I volatile const
-#endif
-#define __O volatile
-#define __IO volatile
-#define __IM volatile const
-#define __OM volatile
-#define __IOM volatile
-
-/**
- * @brief __USB_OTG_Core_register
- */
-
-typedef struct
-{
- __IO uint32_t GOTGCTL; /*!< USB_OTG Control and Status Register Address offset: 000h */
- __IO uint32_t GOTGINT; /*!< USB_OTG Interrupt Register Address offset: 004h */
- __IO uint32_t GAHBCFG; /*!< Core AHB Configuration Register Address offset: 008h */
- __IO uint32_t GUSBCFG; /*!< Core USB Configuration Register Address offset: 00Ch */
- __IO uint32_t GRSTCTL; /*!< Core Reset Register Address offset: 010h */
- __IO uint32_t GINTSTS; /*!< Core Interrupt Register Address offset: 014h */
- __IO uint32_t GINTMSK; /*!< Core Interrupt Mask Register Address offset: 018h */
- __IO uint32_t GRXSTSR; /*!< Receive Sts Q Read Register Address offset: 01Ch */
- __IO uint32_t GRXSTSP; /*!< Receive Sts Q Read & POP Register Address offset: 020h */
- __IO uint32_t GRXFSIZ; /*!< Receive FIFO Size Register Address offset: 024h */
- __IO uint32_t DIEPTXF0_HNPTXFSIZ; /*!< EP0 / Non Periodic Tx FIFO Size Register Address offset: 028h */
- __IO uint32_t HNPTXSTS; /*!< Non Periodic Tx FIFO/Queue Sts reg Address offset: 02Ch */
- uint32_t Reserved30[2]; /*!< Reserved 030h*/
- __IO uint32_t GCCFG; /*!< General Purpose IO Register Address offset: 038h */
- __IO uint32_t CID; /*!< User ID Register 03Ch */
- __IO uint32_t GSNPSID; /* USB_OTG core ID 040h*/
- __IO uint32_t GHWCFG1; /* User HW config1 044h*/
- __IO uint32_t GHWCFG2; /* User HW config2 048h*/
- __IO uint32_t GHWCFG3; /*!< User HW config3 04Ch */
- uint32_t Reserved6; /*!< Reserved 050h */
- __IO uint32_t GLPMCFG; /*!< LPM Register 054h */
- __IO uint32_t GPWRDN; /*!< Power Down Register 058h */
- __IO uint32_t GDFIFOCFG; /*!< DFIFO Software Config Register 05Ch */
- __IO uint32_t GADPCTL; /*!< ADP Timer, Control and Status Register 60Ch */
- uint32_t Reserved43[39]; /*!< Reserved 058h-0FFh */
- __IO uint32_t HPTXFSIZ; /*!< Host Periodic Tx FIFO Size Reg Address offset: 100h */
- __IO uint32_t DIEPTXF[0x0F]; /*!< dev Periodic Transmit FIFO Address offset: 0x104 */
-} USB_OTG_GlobalTypeDef;
-
-
-
-/**
- * @brief __device_Registers
- */
-
-typedef struct
-{
- __IO uint32_t DCFG; /*!< dev Configuration Register Address offset: 800h*/
- __IO uint32_t DCTL; /*!< dev Control Register Address offset: 804h*/
- __IO uint32_t DSTS; /*!< dev Status Register (RO) Address offset: 808h*/
- uint32_t Reserved0C; /*!< Reserved 80Ch*/
- __IO uint32_t DIEPMSK; /*!< dev IN Endpoint Mask Address offset: 810h*/
- __IO uint32_t DOEPMSK; /*!< dev OUT Endpoint Mask Address offset: 814h*/
- __IO uint32_t DAINT; /*!< dev All Endpoints Itr Reg Address offset: 818h*/
- __IO uint32_t DAINTMSK; /*!< dev All Endpoints Itr Mask Address offset: 81Ch*/
- uint32_t Reserved20; /*!< Reserved 820h*/
- uint32_t Reserved9; /*!< Reserved 824h*/
- __IO uint32_t DVBUSDIS; /*!< dev VBUS discharge Register Address offset: 828h*/
- __IO uint32_t DVBUSPULSE; /*!< dev VBUS Pulse Register Address offset: 82Ch*/
- __IO uint32_t DTHRCTL; /*!< dev thr Address offset: 830h*/
- __IO uint32_t DIEPEMPMSK; /*!< dev empty msk Address offset: 834h*/
- __IO uint32_t DEACHINT; /*!< dedicated EP interrupt Address offset: 838h*/
- __IO uint32_t DEACHMSK; /*!< dedicated EP msk Address offset: 83Ch*/
- uint32_t Reserved40; /*!< dedicated EP mask Address offset: 840h*/
- __IO uint32_t DINEP1MSK; /*!< dedicated EP mask Address offset: 844h*/
- uint32_t Reserved44[15]; /*!< Reserved 844-87Ch*/
- __IO uint32_t DOUTEP1MSK; /*!< dedicated EP msk Address offset: 884h*/
-} USB_OTG_DeviceTypeDef;
-
-/**
- * @brief __IN_Endpoint-Specific_Register
- */
-
-typedef struct
-{
- __IO uint32_t DIEPCTL; /*!< dev IN Endpoint Control Reg 900h + (ep_num * 20h) + 00h*/
- uint32_t Reserved04; /*!< Reserved 900h + (ep_num * 20h) + 04h*/
- __IO uint32_t DIEPINT; /*!< dev IN Endpoint Itr Reg 900h + (ep_num * 20h) + 08h*/
- uint32_t Reserved0C; /*!< Reserved 900h + (ep_num * 20h) + 0Ch*/
- __IO uint32_t DIEPTSIZ; /*!< IN Endpoint Txfer Size 900h + (ep_num * 20h) + 10h*/
- __IO uint32_t DIEPDMA; /*!< IN Endpoint DMA Address Reg 900h + (ep_num * 20h) + 14h*/
- __IO uint32_t DTXFSTS; /*!< IN Endpoint Tx FIFO Status Reg 900h + (ep_num * 20h) + 18h*/
- uint32_t Reserved18; /*!< Reserved 900h+(ep_num*20h)+1Ch-900h+ (ep_num * 20h) + 1Ch*/
-} USB_OTG_INEndpointTypeDef;
-
-/**
- * @brief __OUT_Endpoint-Specific_Registers
- */
-
-typedef struct
-{
- __IO uint32_t DOEPCTL; /*!< dev OUT Endpoint Control Reg B00h + (ep_num * 20h) + 00h*/
- uint32_t Reserved04; /*!< Reserved B00h + (ep_num * 20h) + 04h*/
- __IO uint32_t DOEPINT; /*!< dev OUT Endpoint Itr Reg B00h + (ep_num * 20h) + 08h*/
- uint32_t Reserved0C; /*!< Reserved B00h + (ep_num * 20h) + 0Ch*/
- __IO uint32_t DOEPTSIZ; /*!< dev OUT Endpoint Txfer Size B00h + (ep_num * 20h) + 10h*/
- __IO uint32_t DOEPDMA; /*!< dev OUT Endpoint DMA Address B00h + (ep_num * 20h) + 14h*/
- uint32_t Reserved18[2]; /*!< Reserved B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch*/
-} USB_OTG_OUTEndpointTypeDef;
-
-/**
- * @brief __Host_Mode_Register_Structures
- */
-
-typedef struct
-{
- __IO uint32_t HCFG; /*!< Host Configuration Register 400h*/
- __IO uint32_t HFIR; /*!< Host Frame Interval Register 404h*/
- __IO uint32_t HFNUM; /*!< Host Frame Nbr/Frame Remaining 408h*/
- uint32_t Reserved40C; /*!< Reserved 40Ch*/
- __IO uint32_t HPTXSTS; /*!< Host Periodic Tx FIFO/ Queue Status 410h*/
- __IO uint32_t HAINT; /*!< Host All Channels Interrupt Register 414h*/
- __IO uint32_t HAINTMSK; /*!< Host All Channels Interrupt Mask 418h*/
-} USB_OTG_HostTypeDef;
-
-/**
- * @brief __Host_Channel_Specific_Registers
- */
-
-typedef struct
-{
- __IO uint32_t HCCHAR;
- __IO uint32_t HCSPLT;
- __IO uint32_t HCINT;
- __IO uint32_t HCINTMSK;
- __IO uint32_t HCTSIZ;
- __IO uint32_t HCDMA;
- uint32_t Reserved[2];
-} USB_OTG_HostChannelTypeDef;
-
-/*!< USB registers base address */
-#define USB_OTG_FS_PERIPH_BASE 0x50000000UL
-
-// #define USB_OTG_GLOBAL_BASE 0x00000000UL
-// #define USB_OTG_DEVICE_BASE 0x00000800UL
-#define USB_OTG_IN_ENDPOINT_BASE 0x00000900UL
-#define USB_OTG_OUT_ENDPOINT_BASE 0x00000B00UL
-#define USB_OTG_EP_REG_SIZE 0x00000020UL
-// #define USB_OTG_HOST_BASE 0x00000400UL
-#define USB_OTG_HOST_PORT_BASE 0x00000440UL
-#define USB_OTG_HOST_CHANNEL_BASE 0x00000500UL
-#define USB_OTG_HOST_CHANNEL_SIZE 0x00000020UL
-#define USB_OTG_PCGCCTL_BASE 0x00000E00UL
-#define USB_OTG_FIFO_BASE 0x00001000UL
-#define USB_OTG_FIFO_SIZE 0x00001000UL
-
-/******************************************************************************/
-/* */
-/* USB_OTG */
-/* */
-/******************************************************************************/
-/******************** Bit definition for USB_OTG_GOTGCTL register ***********/
-#define USB_OTG_GOTGCTL_SRQSCS_Pos (0U)
-#define USB_OTG_GOTGCTL_SRQSCS_Msk (0x1UL << USB_OTG_GOTGCTL_SRQSCS_Pos) /*!< 0x00000001 */
-#define USB_OTG_GOTGCTL_SRQSCS USB_OTG_GOTGCTL_SRQSCS_Msk /*!< Session request success */
-#define USB_OTG_GOTGCTL_SRQ_Pos (1U)
-#define USB_OTG_GOTGCTL_SRQ_Msk (0x1UL << USB_OTG_GOTGCTL_SRQ_Pos) /*!< 0x00000002 */
-#define USB_OTG_GOTGCTL_SRQ USB_OTG_GOTGCTL_SRQ_Msk /*!< Session request */
-#define USB_OTG_GOTGCTL_HNGSCS_Pos (8U)
-#define USB_OTG_GOTGCTL_HNGSCS_Msk (0x1UL << USB_OTG_GOTGCTL_HNGSCS_Pos) /*!< 0x00000100 */
-#define USB_OTG_GOTGCTL_HNGSCS USB_OTG_GOTGCTL_HNGSCS_Msk /*!< Host set HNP enable */
-#define USB_OTG_GOTGCTL_HNPRQ_Pos (9U)
-#define USB_OTG_GOTGCTL_HNPRQ_Msk (0x1UL << USB_OTG_GOTGCTL_HNPRQ_Pos) /*!< 0x00000200 */
-#define USB_OTG_GOTGCTL_HNPRQ USB_OTG_GOTGCTL_HNPRQ_Msk /*!< HNP request */
-#define USB_OTG_GOTGCTL_HSHNPEN_Pos (10U)
-#define USB_OTG_GOTGCTL_HSHNPEN_Msk (0x1UL << USB_OTG_GOTGCTL_HSHNPEN_Pos) /*!< 0x00000400 */
-#define USB_OTG_GOTGCTL_HSHNPEN USB_OTG_GOTGCTL_HSHNPEN_Msk /*!< Host set HNP enable */
-#define USB_OTG_GOTGCTL_DHNPEN_Pos (11U)
-#define USB_OTG_GOTGCTL_DHNPEN_Msk (0x1UL << USB_OTG_GOTGCTL_DHNPEN_Pos) /*!< 0x00000800 */
-#define USB_OTG_GOTGCTL_DHNPEN USB_OTG_GOTGCTL_DHNPEN_Msk /*!< Device HNP enabled */
-#define USB_OTG_GOTGCTL_CIDSTS_Pos (16U)
-#define USB_OTG_GOTGCTL_CIDSTS_Msk (0x1UL << USB_OTG_GOTGCTL_CIDSTS_Pos) /*!< 0x00010000 */
-#define USB_OTG_GOTGCTL_CIDSTS USB_OTG_GOTGCTL_CIDSTS_Msk /*!< Connector ID status */
-#define USB_OTG_GOTGCTL_DBCT_Pos (17U)
-#define USB_OTG_GOTGCTL_DBCT_Msk (0x1UL << USB_OTG_GOTGCTL_DBCT_Pos) /*!< 0x00020000 */
-#define USB_OTG_GOTGCTL_DBCT USB_OTG_GOTGCTL_DBCT_Msk /*!< Long/short debounce time */
-#define USB_OTG_GOTGCTL_ASVLD_Pos (18U)
-#define USB_OTG_GOTGCTL_ASVLD_Msk (0x1UL << USB_OTG_GOTGCTL_ASVLD_Pos) /*!< 0x00040000 */
-#define USB_OTG_GOTGCTL_ASVLD USB_OTG_GOTGCTL_ASVLD_Msk /*!< A-session valid */
-#define USB_OTG_GOTGCTL_BSVLD_Pos (19U)
-#define USB_OTG_GOTGCTL_BSVLD_Msk (0x1UL << USB_OTG_GOTGCTL_BSVLD_Pos) /*!< 0x00080000 */
-#define USB_OTG_GOTGCTL_BSVLD USB_OTG_GOTGCTL_BSVLD_Msk /*!< B-session valid */
-
-/******************** Bit definition for USB_OTG_HCFG register ********************/
-
-#define USB_OTG_HCFG_FSLSPCS_Pos (0U)
-#define USB_OTG_HCFG_FSLSPCS_Msk (0x3UL << USB_OTG_HCFG_FSLSPCS_Pos) /*!< 0x00000003 */
-#define USB_OTG_HCFG_FSLSPCS USB_OTG_HCFG_FSLSPCS_Msk /*!< FS/LS PHY clock select */
-#define USB_OTG_HCFG_FSLSPCS_0 (0x1UL << USB_OTG_HCFG_FSLSPCS_Pos) /*!< 0x00000001 */
-#define USB_OTG_HCFG_FSLSPCS_1 (0x2UL << USB_OTG_HCFG_FSLSPCS_Pos) /*!< 0x00000002 */
-#define USB_OTG_HCFG_FSLSS_Pos (2U)
-#define USB_OTG_HCFG_FSLSS_Msk (0x1UL << USB_OTG_HCFG_FSLSS_Pos) /*!< 0x00000004 */
-#define USB_OTG_HCFG_FSLSS USB_OTG_HCFG_FSLSS_Msk /*!< FS- and LS-only support */
-
-/******************** Bit definition for USB_OTG_DCFG register ********************/
-
-#define USB_OTG_DCFG_DSPD_Pos (0U)
-#define USB_OTG_DCFG_DSPD_Msk (0x3UL << USB_OTG_DCFG_DSPD_Pos) /*!< 0x00000003 */
-#define USB_OTG_DCFG_DSPD USB_OTG_DCFG_DSPD_Msk /*!< Device speed */
-#define USB_OTG_DCFG_DSPD_0 (0x1UL << USB_OTG_DCFG_DSPD_Pos) /*!< 0x00000001 */
-#define USB_OTG_DCFG_DSPD_1 (0x2UL << USB_OTG_DCFG_DSPD_Pos) /*!< 0x00000002 */
-#define USB_OTG_DCFG_NZLSOHSK_Pos (2U)
-#define USB_OTG_DCFG_NZLSOHSK_Msk (0x1UL << USB_OTG_DCFG_NZLSOHSK_Pos) /*!< 0x00000004 */
-#define USB_OTG_DCFG_NZLSOHSK USB_OTG_DCFG_NZLSOHSK_Msk /*!< Nonzero-length status OUT handshake */
-
-#define USB_OTG_DCFG_DAD_Pos (4U)
-#define USB_OTG_DCFG_DAD_Msk (0x7FUL << USB_OTG_DCFG_DAD_Pos) /*!< 0x000007F0 */
-#define USB_OTG_DCFG_DAD USB_OTG_DCFG_DAD_Msk /*!< Device address */
-#define USB_OTG_DCFG_DAD_0 (0x01UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000010 */
-#define USB_OTG_DCFG_DAD_1 (0x02UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000020 */
-#define USB_OTG_DCFG_DAD_2 (0x04UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000040 */
-#define USB_OTG_DCFG_DAD_3 (0x08UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000080 */
-#define USB_OTG_DCFG_DAD_4 (0x10UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000100 */
-#define USB_OTG_DCFG_DAD_5 (0x20UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000200 */
-#define USB_OTG_DCFG_DAD_6 (0x40UL << USB_OTG_DCFG_DAD_Pos) /*!< 0x00000400 */
-
-#define USB_OTG_DCFG_PFIVL_Pos (11U)
-#define USB_OTG_DCFG_PFIVL_Msk (0x3UL << USB_OTG_DCFG_PFIVL_Pos) /*!< 0x00001800 */
-#define USB_OTG_DCFG_PFIVL USB_OTG_DCFG_PFIVL_Msk /*!< Periodic (micro)frame interval */
-#define USB_OTG_DCFG_PFIVL_0 (0x1UL << USB_OTG_DCFG_PFIVL_Pos) /*!< 0x00000800 */
-#define USB_OTG_DCFG_PFIVL_1 (0x2UL << USB_OTG_DCFG_PFIVL_Pos) /*!< 0x00001000 */
-
-#define USB_OTG_DCFG_PERSCHIVL_Pos (24U)
-#define USB_OTG_DCFG_PERSCHIVL_Msk (0x3UL << USB_OTG_DCFG_PERSCHIVL_Pos) /*!< 0x03000000 */
-#define USB_OTG_DCFG_PERSCHIVL USB_OTG_DCFG_PERSCHIVL_Msk /*!< Periodic scheduling interval */
-#define USB_OTG_DCFG_PERSCHIVL_0 (0x1UL << USB_OTG_DCFG_PERSCHIVL_Pos) /*!< 0x01000000 */
-#define USB_OTG_DCFG_PERSCHIVL_1 (0x2UL << USB_OTG_DCFG_PERSCHIVL_Pos) /*!< 0x02000000 */
-
-/******************** Bit definition for USB_OTG_PCGCR register ********************/
-#define USB_OTG_PCGCR_STPPCLK_Pos (0U)
-#define USB_OTG_PCGCR_STPPCLK_Msk (0x1UL << USB_OTG_PCGCR_STPPCLK_Pos) /*!< 0x00000001 */
-#define USB_OTG_PCGCR_STPPCLK USB_OTG_PCGCR_STPPCLK_Msk /*!< Stop PHY clock */
-#define USB_OTG_PCGCR_GATEHCLK_Pos (1U)
-#define USB_OTG_PCGCR_GATEHCLK_Msk (0x1UL << USB_OTG_PCGCR_GATEHCLK_Pos) /*!< 0x00000002 */
-#define USB_OTG_PCGCR_GATEHCLK USB_OTG_PCGCR_GATEHCLK_Msk /*!< Gate HCLK */
-#define USB_OTG_PCGCR_PHYSUSP_Pos (4U)
-#define USB_OTG_PCGCR_PHYSUSP_Msk (0x1UL << USB_OTG_PCGCR_PHYSUSP_Pos) /*!< 0x00000010 */
-#define USB_OTG_PCGCR_PHYSUSP USB_OTG_PCGCR_PHYSUSP_Msk /*!< PHY suspended */
-
-/******************** Bit definition for USB_OTG_GOTGINT register ********************/
-#define USB_OTG_GOTGINT_SEDET_Pos (2U)
-#define USB_OTG_GOTGINT_SEDET_Msk (0x1UL << USB_OTG_GOTGINT_SEDET_Pos) /*!< 0x00000004 */
-#define USB_OTG_GOTGINT_SEDET USB_OTG_GOTGINT_SEDET_Msk /*!< Session end detected */
-#define USB_OTG_GOTGINT_SRSSCHG_Pos (8U)
-#define USB_OTG_GOTGINT_SRSSCHG_Msk (0x1UL << USB_OTG_GOTGINT_SRSSCHG_Pos) /*!< 0x00000100 */
-#define USB_OTG_GOTGINT_SRSSCHG USB_OTG_GOTGINT_SRSSCHG_Msk /*!< Session request success status change */
-#define USB_OTG_GOTGINT_HNSSCHG_Pos (9U)
-#define USB_OTG_GOTGINT_HNSSCHG_Msk (0x1UL << USB_OTG_GOTGINT_HNSSCHG_Pos) /*!< 0x00000200 */
-#define USB_OTG_GOTGINT_HNSSCHG USB_OTG_GOTGINT_HNSSCHG_Msk /*!< Host negotiation success status change */
-#define USB_OTG_GOTGINT_HNGDET_Pos (17U)
-#define USB_OTG_GOTGINT_HNGDET_Msk (0x1UL << USB_OTG_GOTGINT_HNGDET_Pos) /*!< 0x00020000 */
-#define USB_OTG_GOTGINT_HNGDET USB_OTG_GOTGINT_HNGDET_Msk /*!< Host negotiation detected */
-#define USB_OTG_GOTGINT_ADTOCHG_Pos (18U)
-#define USB_OTG_GOTGINT_ADTOCHG_Msk (0x1UL << USB_OTG_GOTGINT_ADTOCHG_Pos) /*!< 0x00040000 */
-#define USB_OTG_GOTGINT_ADTOCHG USB_OTG_GOTGINT_ADTOCHG_Msk /*!< A-device timeout change */
-#define USB_OTG_GOTGINT_DBCDNE_Pos (19U)
-#define USB_OTG_GOTGINT_DBCDNE_Msk (0x1UL << USB_OTG_GOTGINT_DBCDNE_Pos) /*!< 0x00080000 */
-#define USB_OTG_GOTGINT_DBCDNE USB_OTG_GOTGINT_DBCDNE_Msk /*!< Debounce done */
-
-/******************** Bit definition for USB_OTG_DCTL register ********************/
-#define USB_OTG_DCTL_RWUSIG_Pos (0U)
-#define USB_OTG_DCTL_RWUSIG_Msk (0x1UL << USB_OTG_DCTL_RWUSIG_Pos) /*!< 0x00000001 */
-#define USB_OTG_DCTL_RWUSIG USB_OTG_DCTL_RWUSIG_Msk /*!< Remote wakeup signaling */
-#define USB_OTG_DCTL_SDIS_Pos (1U)
-#define USB_OTG_DCTL_SDIS_Msk (0x1UL << USB_OTG_DCTL_SDIS_Pos) /*!< 0x00000002 */
-#define USB_OTG_DCTL_SDIS USB_OTG_DCTL_SDIS_Msk /*!< Soft disconnect */
-#define USB_OTG_DCTL_GINSTS_Pos (2U)
-#define USB_OTG_DCTL_GINSTS_Msk (0x1UL << USB_OTG_DCTL_GINSTS_Pos) /*!< 0x00000004 */
-#define USB_OTG_DCTL_GINSTS USB_OTG_DCTL_GINSTS_Msk /*!< Global IN NAK status */
-#define USB_OTG_DCTL_GONSTS_Pos (3U)
-#define USB_OTG_DCTL_GONSTS_Msk (0x1UL << USB_OTG_DCTL_GONSTS_Pos) /*!< 0x00000008 */
-#define USB_OTG_DCTL_GONSTS USB_OTG_DCTL_GONSTS_Msk /*!< Global OUT NAK status */
-
-#define USB_OTG_DCTL_TCTL_Pos (4U)
-#define USB_OTG_DCTL_TCTL_Msk (0x7UL << USB_OTG_DCTL_TCTL_Pos) /*!< 0x00000070 */
-#define USB_OTG_DCTL_TCTL USB_OTG_DCTL_TCTL_Msk /*!< Test control */
-#define USB_OTG_DCTL_TCTL_0 (0x1UL << USB_OTG_DCTL_TCTL_Pos) /*!< 0x00000010 */
-#define USB_OTG_DCTL_TCTL_1 (0x2UL << USB_OTG_DCTL_TCTL_Pos) /*!< 0x00000020 */
-#define USB_OTG_DCTL_TCTL_2 (0x4UL << USB_OTG_DCTL_TCTL_Pos) /*!< 0x00000040 */
-#define USB_OTG_DCTL_SGINAK_Pos (7U)
-#define USB_OTG_DCTL_SGINAK_Msk (0x1UL << USB_OTG_DCTL_SGINAK_Pos) /*!< 0x00000080 */
-#define USB_OTG_DCTL_SGINAK USB_OTG_DCTL_SGINAK_Msk /*!< Set global IN NAK */
-#define USB_OTG_DCTL_CGINAK_Pos (8U)
-#define USB_OTG_DCTL_CGINAK_Msk (0x1UL << USB_OTG_DCTL_CGINAK_Pos) /*!< 0x00000100 */
-#define USB_OTG_DCTL_CGINAK USB_OTG_DCTL_CGINAK_Msk /*!< Clear global IN NAK */
-#define USB_OTG_DCTL_SGONAK_Pos (9U)
-#define USB_OTG_DCTL_SGONAK_Msk (0x1UL << USB_OTG_DCTL_SGONAK_Pos) /*!< 0x00000200 */
-#define USB_OTG_DCTL_SGONAK USB_OTG_DCTL_SGONAK_Msk /*!< Set global OUT NAK */
-#define USB_OTG_DCTL_CGONAK_Pos (10U)
-#define USB_OTG_DCTL_CGONAK_Msk (0x1UL << USB_OTG_DCTL_CGONAK_Pos) /*!< 0x00000400 */
-#define USB_OTG_DCTL_CGONAK USB_OTG_DCTL_CGONAK_Msk /*!< Clear global OUT NAK */
-#define USB_OTG_DCTL_POPRGDNE_Pos (11U)
-#define USB_OTG_DCTL_POPRGDNE_Msk (0x1UL << USB_OTG_DCTL_POPRGDNE_Pos) /*!< 0x00000800 */
-#define USB_OTG_DCTL_POPRGDNE USB_OTG_DCTL_POPRGDNE_Msk /*!< Power-on programming done */
-
-/******************** Bit definition for USB_OTG_HFIR register ********************/
-#define USB_OTG_HFIR_FRIVL_Pos (0U)
-#define USB_OTG_HFIR_FRIVL_Msk (0xFFFFUL << USB_OTG_HFIR_FRIVL_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HFIR_FRIVL USB_OTG_HFIR_FRIVL_Msk /*!< Frame interval */
-
-/******************** Bit definition for USB_OTG_HFNUM register ********************/
-#define USB_OTG_HFNUM_FRNUM_Pos (0U)
-#define USB_OTG_HFNUM_FRNUM_Msk (0xFFFFUL << USB_OTG_HFNUM_FRNUM_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HFNUM_FRNUM USB_OTG_HFNUM_FRNUM_Msk /*!< Frame number */
-#define USB_OTG_HFNUM_FTREM_Pos (16U)
-#define USB_OTG_HFNUM_FTREM_Msk (0xFFFFUL << USB_OTG_HFNUM_FTREM_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_HFNUM_FTREM USB_OTG_HFNUM_FTREM_Msk /*!< Frame time remaining */
-
-/******************** Bit definition for USB_OTG_DSTS register ********************/
-#define USB_OTG_DSTS_SUSPSTS_Pos (0U)
-#define USB_OTG_DSTS_SUSPSTS_Msk (0x1UL << USB_OTG_DSTS_SUSPSTS_Pos) /*!< 0x00000001 */
-#define USB_OTG_DSTS_SUSPSTS USB_OTG_DSTS_SUSPSTS_Msk /*!< Suspend status */
-
-#define USB_OTG_DSTS_ENUMSPD_Pos (1U)
-#define USB_OTG_DSTS_ENUMSPD_Msk (0x3UL << USB_OTG_DSTS_ENUMSPD_Pos) /*!< 0x00000006 */
-#define USB_OTG_DSTS_ENUMSPD USB_OTG_DSTS_ENUMSPD_Msk /*!< Enumerated speed */
-#define USB_OTG_DSTS_ENUMSPD_0 (0x1UL << USB_OTG_DSTS_ENUMSPD_Pos) /*!< 0x00000002 */
-#define USB_OTG_DSTS_ENUMSPD_1 (0x2UL << USB_OTG_DSTS_ENUMSPD_Pos) /*!< 0x00000004 */
-#define USB_OTG_DSTS_EERR_Pos (3U)
-#define USB_OTG_DSTS_EERR_Msk (0x1UL << USB_OTG_DSTS_EERR_Pos) /*!< 0x00000008 */
-#define USB_OTG_DSTS_EERR USB_OTG_DSTS_EERR_Msk /*!< Erratic error */
-#define USB_OTG_DSTS_FNSOF_Pos (8U)
-#define USB_OTG_DSTS_FNSOF_Msk (0x3FFFUL << USB_OTG_DSTS_FNSOF_Pos) /*!< 0x003FFF00 */
-#define USB_OTG_DSTS_FNSOF USB_OTG_DSTS_FNSOF_Msk /*!< Frame number of the received SOF */
-
-/******************** Bit definition for USB_OTG_GAHBCFG register ********************/
-#define USB_OTG_GAHBCFG_GINT_Pos (0U)
-#define USB_OTG_GAHBCFG_GINT_Msk (0x1UL << USB_OTG_GAHBCFG_GINT_Pos) /*!< 0x00000001 */
-#define USB_OTG_GAHBCFG_GINT USB_OTG_GAHBCFG_GINT_Msk /*!< Global interrupt mask */
-#define USB_OTG_GAHBCFG_HBSTLEN_Pos (1U)
-#define USB_OTG_GAHBCFG_HBSTLEN_Msk (0xFUL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< 0x0000001E */
-#define USB_OTG_GAHBCFG_HBSTLEN USB_OTG_GAHBCFG_HBSTLEN_Msk /*!< Burst length/type */
-#define USB_OTG_GAHBCFG_HBSTLEN_0 (0x0UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< Single */
-#define USB_OTG_GAHBCFG_HBSTLEN_1 (0x1UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< INCR */
-#define USB_OTG_GAHBCFG_HBSTLEN_2 (0x3UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< INCR4 */
-#define USB_OTG_GAHBCFG_HBSTLEN_3 (0x5UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< INCR8 */
-#define USB_OTG_GAHBCFG_HBSTLEN_4 (0x7UL << USB_OTG_GAHBCFG_HBSTLEN_Pos) /*!< INCR16 */
-#define USB_OTG_GAHBCFG_DMAEN_Pos (5U)
-#define USB_OTG_GAHBCFG_DMAEN_Msk (0x1UL << USB_OTG_GAHBCFG_DMAEN_Pos) /*!< 0x00000020 */
-#define USB_OTG_GAHBCFG_DMAEN USB_OTG_GAHBCFG_DMAEN_Msk /*!< DMA enable */
-#define USB_OTG_GAHBCFG_TXFELVL_Pos (7U)
-#define USB_OTG_GAHBCFG_TXFELVL_Msk (0x1UL << USB_OTG_GAHBCFG_TXFELVL_Pos) /*!< 0x00000080 */
-#define USB_OTG_GAHBCFG_TXFELVL USB_OTG_GAHBCFG_TXFELVL_Msk /*!< TxFIFO empty level */
-#define USB_OTG_GAHBCFG_PTXFELVL_Pos (8U)
-#define USB_OTG_GAHBCFG_PTXFELVL_Msk (0x1UL << USB_OTG_GAHBCFG_PTXFELVL_Pos) /*!< 0x00000100 */
-#define USB_OTG_GAHBCFG_PTXFELVL USB_OTG_GAHBCFG_PTXFELVL_Msk /*!< Periodic TxFIFO empty level */
-
-/******************** Bit definition for USB_OTG_GUSBCFG register ********************/
-
-#define USB_OTG_GUSBCFG_TOCAL_Pos (0U)
-#define USB_OTG_GUSBCFG_TOCAL_Msk (0x7UL << USB_OTG_GUSBCFG_TOCAL_Pos) /*!< 0x00000007 */
-#define USB_OTG_GUSBCFG_TOCAL USB_OTG_GUSBCFG_TOCAL_Msk /*!< FS timeout calibration */
-#define USB_OTG_GUSBCFG_TOCAL_0 (0x1UL << USB_OTG_GUSBCFG_TOCAL_Pos) /*!< 0x00000001 */
-#define USB_OTG_GUSBCFG_TOCAL_1 (0x2UL << USB_OTG_GUSBCFG_TOCAL_Pos) /*!< 0x00000002 */
-#define USB_OTG_GUSBCFG_TOCAL_2 (0x4UL << USB_OTG_GUSBCFG_TOCAL_Pos) /*!< 0x00000004 */
-#define USB_OTG_GUSBCFG_PHYSEL_Pos (6U)
-#define USB_OTG_GUSBCFG_PHYSEL_Msk (0x1UL << USB_OTG_GUSBCFG_PHYSEL_Pos) /*!< 0x00000040 */
-#define USB_OTG_GUSBCFG_PHYSEL USB_OTG_GUSBCFG_PHYSEL_Msk /*!< USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select */
-#define USB_OTG_GUSBCFG_SRPCAP_Pos (8U)
-#define USB_OTG_GUSBCFG_SRPCAP_Msk (0x1UL << USB_OTG_GUSBCFG_SRPCAP_Pos) /*!< 0x00000100 */
-#define USB_OTG_GUSBCFG_SRPCAP USB_OTG_GUSBCFG_SRPCAP_Msk /*!< SRP-capable */
-#define USB_OTG_GUSBCFG_HNPCAP_Pos (9U)
-#define USB_OTG_GUSBCFG_HNPCAP_Msk (0x1UL << USB_OTG_GUSBCFG_HNPCAP_Pos) /*!< 0x00000200 */
-#define USB_OTG_GUSBCFG_HNPCAP USB_OTG_GUSBCFG_HNPCAP_Msk /*!< HNP-capable */
-#define USB_OTG_GUSBCFG_TRDT_Pos (10U)
-#define USB_OTG_GUSBCFG_TRDT_Msk (0xFUL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00003C00 */
-#define USB_OTG_GUSBCFG_TRDT USB_OTG_GUSBCFG_TRDT_Msk /*!< USB turnaround time */
-#define USB_OTG_GUSBCFG_TRDT_0 (0x1UL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00000400 */
-#define USB_OTG_GUSBCFG_TRDT_1 (0x2UL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00000800 */
-#define USB_OTG_GUSBCFG_TRDT_2 (0x4UL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00001000 */
-#define USB_OTG_GUSBCFG_TRDT_3 (0x8UL << USB_OTG_GUSBCFG_TRDT_Pos) /*!< 0x00002000 */
-#define USB_OTG_GUSBCFG_PHYLPCS_Pos (15U)
-#define USB_OTG_GUSBCFG_PHYLPCS_Msk (0x1UL << USB_OTG_GUSBCFG_PHYLPCS_Pos) /*!< 0x00008000 */
-#define USB_OTG_GUSBCFG_PHYLPCS USB_OTG_GUSBCFG_PHYLPCS_Msk /*!< PHY Low-power clock select */
-#define USB_OTG_GUSBCFG_ULPIFSLS_Pos (17U)
-#define USB_OTG_GUSBCFG_ULPIFSLS_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIFSLS_Pos) /*!< 0x00020000 */
-#define USB_OTG_GUSBCFG_ULPIFSLS USB_OTG_GUSBCFG_ULPIFSLS_Msk /*!< ULPI FS/LS select */
-#define USB_OTG_GUSBCFG_ULPIAR_Pos (18U)
-#define USB_OTG_GUSBCFG_ULPIAR_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIAR_Pos) /*!< 0x00040000 */
-#define USB_OTG_GUSBCFG_ULPIAR USB_OTG_GUSBCFG_ULPIAR_Msk /*!< ULPI Auto-resume */
-#define USB_OTG_GUSBCFG_ULPICSM_Pos (19U)
-#define USB_OTG_GUSBCFG_ULPICSM_Msk (0x1UL << USB_OTG_GUSBCFG_ULPICSM_Pos) /*!< 0x00080000 */
-#define USB_OTG_GUSBCFG_ULPICSM USB_OTG_GUSBCFG_ULPICSM_Msk /*!< ULPI Clock SuspendM */
-#define USB_OTG_GUSBCFG_ULPIEVBUSD_Pos (20U)
-#define USB_OTG_GUSBCFG_ULPIEVBUSD_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIEVBUSD_Pos) /*!< 0x00100000 */
-#define USB_OTG_GUSBCFG_ULPIEVBUSD USB_OTG_GUSBCFG_ULPIEVBUSD_Msk /*!< ULPI External VBUS Drive */
-#define USB_OTG_GUSBCFG_ULPIEVBUSI_Pos (21U)
-#define USB_OTG_GUSBCFG_ULPIEVBUSI_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIEVBUSI_Pos) /*!< 0x00200000 */
-#define USB_OTG_GUSBCFG_ULPIEVBUSI USB_OTG_GUSBCFG_ULPIEVBUSI_Msk /*!< ULPI external VBUS indicator */
-#define USB_OTG_GUSBCFG_TSDPS_Pos (22U)
-#define USB_OTG_GUSBCFG_TSDPS_Msk (0x1UL << USB_OTG_GUSBCFG_TSDPS_Pos) /*!< 0x00400000 */
-#define USB_OTG_GUSBCFG_TSDPS USB_OTG_GUSBCFG_TSDPS_Msk /*!< TermSel DLine pulsing selection */
-#define USB_OTG_GUSBCFG_PCCI_Pos (23U)
-#define USB_OTG_GUSBCFG_PCCI_Msk (0x1UL << USB_OTG_GUSBCFG_PCCI_Pos) /*!< 0x00800000 */
-#define USB_OTG_GUSBCFG_PCCI USB_OTG_GUSBCFG_PCCI_Msk /*!< Indicator complement */
-#define USB_OTG_GUSBCFG_PTCI_Pos (24U)
-#define USB_OTG_GUSBCFG_PTCI_Msk (0x1UL << USB_OTG_GUSBCFG_PTCI_Pos) /*!< 0x01000000 */
-#define USB_OTG_GUSBCFG_PTCI USB_OTG_GUSBCFG_PTCI_Msk /*!< Indicator pass through */
-#define USB_OTG_GUSBCFG_ULPIIPD_Pos (25U)
-#define USB_OTG_GUSBCFG_ULPIIPD_Msk (0x1UL << USB_OTG_GUSBCFG_ULPIIPD_Pos) /*!< 0x02000000 */
-#define USB_OTG_GUSBCFG_ULPIIPD USB_OTG_GUSBCFG_ULPIIPD_Msk /*!< ULPI interface protect disable */
-#define USB_OTG_GUSBCFG_FHMOD_Pos (29U)
-#define USB_OTG_GUSBCFG_FHMOD_Msk (0x1UL << USB_OTG_GUSBCFG_FHMOD_Pos) /*!< 0x20000000 */
-#define USB_OTG_GUSBCFG_FHMOD USB_OTG_GUSBCFG_FHMOD_Msk /*!< Forced host mode */
-#define USB_OTG_GUSBCFG_FDMOD_Pos (30U)
-#define USB_OTG_GUSBCFG_FDMOD_Msk (0x1UL << USB_OTG_GUSBCFG_FDMOD_Pos) /*!< 0x40000000 */
-#define USB_OTG_GUSBCFG_FDMOD USB_OTG_GUSBCFG_FDMOD_Msk /*!< Forced peripheral mode */
-#define USB_OTG_GUSBCFG_CTXPKT_Pos (31U)
-#define USB_OTG_GUSBCFG_CTXPKT_Msk (0x1UL << USB_OTG_GUSBCFG_CTXPKT_Pos) /*!< 0x80000000 */
-#define USB_OTG_GUSBCFG_CTXPKT USB_OTG_GUSBCFG_CTXPKT_Msk /*!< Corrupt Tx packet */
-
-/******************** Bit definition for USB_OTG_GRSTCTL register ********************/
-#define USB_OTG_GRSTCTL_CSRST_Pos (0U)
-#define USB_OTG_GRSTCTL_CSRST_Msk (0x1UL << USB_OTG_GRSTCTL_CSRST_Pos) /*!< 0x00000001 */
-#define USB_OTG_GRSTCTL_CSRST USB_OTG_GRSTCTL_CSRST_Msk /*!< Core soft reset */
-#define USB_OTG_GRSTCTL_HSRST_Pos (1U)
-#define USB_OTG_GRSTCTL_HSRST_Msk (0x1UL << USB_OTG_GRSTCTL_HSRST_Pos) /*!< 0x00000002 */
-#define USB_OTG_GRSTCTL_HSRST USB_OTG_GRSTCTL_HSRST_Msk /*!< HCLK soft reset */
-#define USB_OTG_GRSTCTL_FCRST_Pos (2U)
-#define USB_OTG_GRSTCTL_FCRST_Msk (0x1UL << USB_OTG_GRSTCTL_FCRST_Pos) /*!< 0x00000004 */
-#define USB_OTG_GRSTCTL_FCRST USB_OTG_GRSTCTL_FCRST_Msk /*!< Host frame counter reset */
-#define USB_OTG_GRSTCTL_RXFFLSH_Pos (4U)
-#define USB_OTG_GRSTCTL_RXFFLSH_Msk (0x1UL << USB_OTG_GRSTCTL_RXFFLSH_Pos) /*!< 0x00000010 */
-#define USB_OTG_GRSTCTL_RXFFLSH USB_OTG_GRSTCTL_RXFFLSH_Msk /*!< RxFIFO flush */
-#define USB_OTG_GRSTCTL_TXFFLSH_Pos (5U)
-#define USB_OTG_GRSTCTL_TXFFLSH_Msk (0x1UL << USB_OTG_GRSTCTL_TXFFLSH_Pos) /*!< 0x00000020 */
-#define USB_OTG_GRSTCTL_TXFFLSH USB_OTG_GRSTCTL_TXFFLSH_Msk /*!< TxFIFO flush */
-
-
-#define USB_OTG_GRSTCTL_TXFNUM_Pos (6U)
-#define USB_OTG_GRSTCTL_TXFNUM_Msk (0x1FUL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x000007C0 */
-#define USB_OTG_GRSTCTL_TXFNUM USB_OTG_GRSTCTL_TXFNUM_Msk /*!< TxFIFO number */
-#define USB_OTG_GRSTCTL_TXFNUM_0 (0x01UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000040 */
-#define USB_OTG_GRSTCTL_TXFNUM_1 (0x02UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000080 */
-#define USB_OTG_GRSTCTL_TXFNUM_2 (0x04UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000100 */
-#define USB_OTG_GRSTCTL_TXFNUM_3 (0x08UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000200 */
-#define USB_OTG_GRSTCTL_TXFNUM_4 (0x10UL << USB_OTG_GRSTCTL_TXFNUM_Pos) /*!< 0x00000400 */
-#define USB_OTG_GRSTCTL_DMAREQ_Pos (30U)
-#define USB_OTG_GRSTCTL_DMAREQ_Msk (0x1UL << USB_OTG_GRSTCTL_DMAREQ_Pos) /*!< 0x40000000 */
-#define USB_OTG_GRSTCTL_DMAREQ USB_OTG_GRSTCTL_DMAREQ_Msk /*!< DMA request signal */
-#define USB_OTG_GRSTCTL_AHBIDL_Pos (31U)
-#define USB_OTG_GRSTCTL_AHBIDL_Msk (0x1UL << USB_OTG_GRSTCTL_AHBIDL_Pos) /*!< 0x80000000 */
-#define USB_OTG_GRSTCTL_AHBIDL USB_OTG_GRSTCTL_AHBIDL_Msk /*!< AHB master idle */
-
-/******************** Bit definition for USB_OTG_DIEPMSK register ********************/
-#define USB_OTG_DIEPMSK_XFRCM_Pos (0U)
-#define USB_OTG_DIEPMSK_XFRCM_Msk (0x1UL << USB_OTG_DIEPMSK_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_DIEPMSK_XFRCM USB_OTG_DIEPMSK_XFRCM_Msk /*!< Transfer completed interrupt mask */
-#define USB_OTG_DIEPMSK_EPDM_Pos (1U)
-#define USB_OTG_DIEPMSK_EPDM_Msk (0x1UL << USB_OTG_DIEPMSK_EPDM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DIEPMSK_EPDM USB_OTG_DIEPMSK_EPDM_Msk /*!< Endpoint disabled interrupt mask */
-#define USB_OTG_DIEPMSK_TOM_Pos (3U)
-#define USB_OTG_DIEPMSK_TOM_Msk (0x1UL << USB_OTG_DIEPMSK_TOM_Pos) /*!< 0x00000008 */
-#define USB_OTG_DIEPMSK_TOM USB_OTG_DIEPMSK_TOM_Msk /*!< Timeout condition mask (nonisochronous endpoints) */
-#define USB_OTG_DIEPMSK_ITTXFEMSK_Pos (4U)
-#define USB_OTG_DIEPMSK_ITTXFEMSK_Msk (0x1UL << USB_OTG_DIEPMSK_ITTXFEMSK_Pos) /*!< 0x00000010 */
-#define USB_OTG_DIEPMSK_ITTXFEMSK USB_OTG_DIEPMSK_ITTXFEMSK_Msk /*!< IN token received when TxFIFO empty mask */
-#define USB_OTG_DIEPMSK_INEPNMM_Pos (5U)
-#define USB_OTG_DIEPMSK_INEPNMM_Msk (0x1UL << USB_OTG_DIEPMSK_INEPNMM_Pos) /*!< 0x00000020 */
-#define USB_OTG_DIEPMSK_INEPNMM USB_OTG_DIEPMSK_INEPNMM_Msk /*!< IN token received with EP mismatch mask */
-#define USB_OTG_DIEPMSK_INEPNEM_Pos (6U)
-#define USB_OTG_DIEPMSK_INEPNEM_Msk (0x1UL << USB_OTG_DIEPMSK_INEPNEM_Pos) /*!< 0x00000040 */
-#define USB_OTG_DIEPMSK_INEPNEM USB_OTG_DIEPMSK_INEPNEM_Msk /*!< IN endpoint NAK effective mask */
-#define USB_OTG_DIEPMSK_TXFURM_Pos (8U)
-#define USB_OTG_DIEPMSK_TXFURM_Msk (0x1UL << USB_OTG_DIEPMSK_TXFURM_Pos) /*!< 0x00000100 */
-#define USB_OTG_DIEPMSK_TXFURM USB_OTG_DIEPMSK_TXFURM_Msk /*!< FIFO underrun mask */
-#define USB_OTG_DIEPMSK_BIM_Pos (9U)
-#define USB_OTG_DIEPMSK_BIM_Msk (0x1UL << USB_OTG_DIEPMSK_BIM_Pos) /*!< 0x00000200 */
-#define USB_OTG_DIEPMSK_BIM USB_OTG_DIEPMSK_BIM_Msk /*!< BNA interrupt mask */
-
-/******************** Bit definition for USB_OTG_HPTXSTS register ********************/
-#define USB_OTG_HPTXSTS_PTXFSAVL_Pos (0U)
-#define USB_OTG_HPTXSTS_PTXFSAVL_Msk (0xFFFFUL << USB_OTG_HPTXSTS_PTXFSAVL_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HPTXSTS_PTXFSAVL USB_OTG_HPTXSTS_PTXFSAVL_Msk /*!< Periodic transmit data FIFO space available */
-#define USB_OTG_HPTXSTS_PTXQSAV_Pos (16U)
-#define USB_OTG_HPTXSTS_PTXQSAV_Msk (0xFFUL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00FF0000 */
-#define USB_OTG_HPTXSTS_PTXQSAV USB_OTG_HPTXSTS_PTXQSAV_Msk /*!< Periodic transmit request queue space available */
-#define USB_OTG_HPTXSTS_PTXQSAV_0 (0x01UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00010000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_1 (0x02UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00020000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_2 (0x04UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00040000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_3 (0x08UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00080000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_4 (0x10UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00100000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_5 (0x20UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00200000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_6 (0x40UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00400000 */
-#define USB_OTG_HPTXSTS_PTXQSAV_7 (0x80UL << USB_OTG_HPTXSTS_PTXQSAV_Pos) /*!< 0x00800000 */
-
-#define USB_OTG_HPTXSTS_PTXQTOP_Pos (24U)
-#define USB_OTG_HPTXSTS_PTXQTOP_Msk (0xFFUL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0xFF000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP USB_OTG_HPTXSTS_PTXQTOP_Msk /*!< Top of the periodic transmit request queue */
-#define USB_OTG_HPTXSTS_PTXQTOP_0 (0x01UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x01000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_1 (0x02UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x02000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_2 (0x04UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x04000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_3 (0x08UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x08000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_4 (0x10UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x10000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_5 (0x20UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x20000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_6 (0x40UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x40000000 */
-#define USB_OTG_HPTXSTS_PTXQTOP_7 (0x80UL << USB_OTG_HPTXSTS_PTXQTOP_Pos) /*!< 0x80000000 */
-
-/******************** Bit definition for USB_OTG_HAINT register ********************/
-#define USB_OTG_HAINT_HAINT_Pos (0U)
-#define USB_OTG_HAINT_HAINT_Msk (0xFFFFUL << USB_OTG_HAINT_HAINT_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HAINT_HAINT USB_OTG_HAINT_HAINT_Msk /*!< Channel interrupts */
-
-/******************** Bit definition for USB_OTG_DOEPMSK register ********************/
-#define USB_OTG_DOEPMSK_XFRCM_Pos (0U)
-#define USB_OTG_DOEPMSK_XFRCM_Msk (0x1UL << USB_OTG_DOEPMSK_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_DOEPMSK_XFRCM USB_OTG_DOEPMSK_XFRCM_Msk /*!< Transfer completed interrupt mask */
-#define USB_OTG_DOEPMSK_EPDM_Pos (1U)
-#define USB_OTG_DOEPMSK_EPDM_Msk (0x1UL << USB_OTG_DOEPMSK_EPDM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DOEPMSK_EPDM USB_OTG_DOEPMSK_EPDM_Msk /*!< Endpoint disabled interrupt mask */
-#define USB_OTG_DOEPMSK_AHBERRM_Pos (2U)
-#define USB_OTG_DOEPMSK_AHBERRM_Msk (0x1UL << USB_OTG_DOEPMSK_AHBERRM_Pos) /*!< 0x00000004 */
-#define USB_OTG_DOEPMSK_AHBERRM USB_OTG_DOEPMSK_AHBERRM_Msk /*!< OUT transaction AHB Error interrupt mask */
-#define USB_OTG_DOEPMSK_STUPM_Pos (3U)
-#define USB_OTG_DOEPMSK_STUPM_Msk (0x1UL << USB_OTG_DOEPMSK_STUPM_Pos) /*!< 0x00000008 */
-#define USB_OTG_DOEPMSK_STUPM USB_OTG_DOEPMSK_STUPM_Msk /*!< SETUP phase done mask */
-#define USB_OTG_DOEPMSK_OTEPDM_Pos (4U)
-#define USB_OTG_DOEPMSK_OTEPDM_Msk (0x1UL << USB_OTG_DOEPMSK_OTEPDM_Pos) /*!< 0x00000010 */
-#define USB_OTG_DOEPMSK_OTEPDM USB_OTG_DOEPMSK_OTEPDM_Msk /*!< OUT token received when endpoint disabled mask */
-#define USB_OTG_DOEPMSK_OTEPSPRM_Pos (5U)
-#define USB_OTG_DOEPMSK_OTEPSPRM_Msk (0x1UL << USB_OTG_DOEPMSK_OTEPSPRM_Pos) /*!< 0x00000020 */
-#define USB_OTG_DOEPMSK_OTEPSPRM USB_OTG_DOEPMSK_OTEPSPRM_Msk /*!< Status Phase Received mask */
-#define USB_OTG_DOEPMSK_B2BSTUP_Pos (6U)
-#define USB_OTG_DOEPMSK_B2BSTUP_Msk (0x1UL << USB_OTG_DOEPMSK_B2BSTUP_Pos) /*!< 0x00000040 */
-#define USB_OTG_DOEPMSK_B2BSTUP USB_OTG_DOEPMSK_B2BSTUP_Msk /*!< Back-to-back SETUP packets received mask */
-#define USB_OTG_DOEPMSK_OPEM_Pos (8U)
-#define USB_OTG_DOEPMSK_OPEM_Msk (0x1UL << USB_OTG_DOEPMSK_OPEM_Pos) /*!< 0x00000100 */
-#define USB_OTG_DOEPMSK_OPEM USB_OTG_DOEPMSK_OPEM_Msk /*!< OUT packet error mask */
-#define USB_OTG_DOEPMSK_BOIM_Pos (9U)
-#define USB_OTG_DOEPMSK_BOIM_Msk (0x1UL << USB_OTG_DOEPMSK_BOIM_Pos) /*!< 0x00000200 */
-#define USB_OTG_DOEPMSK_BOIM USB_OTG_DOEPMSK_BOIM_Msk /*!< BNA interrupt mask */
-#define USB_OTG_DOEPMSK_BERRM_Pos (12U)
-#define USB_OTG_DOEPMSK_BERRM_Msk (0x1UL << USB_OTG_DOEPMSK_BERRM_Pos) /*!< 0x00001000 */
-#define USB_OTG_DOEPMSK_BERRM USB_OTG_DOEPMSK_BERRM_Msk /*!< Babble error interrupt mask */
-#define USB_OTG_DOEPMSK_NAKM_Pos (13U)
-#define USB_OTG_DOEPMSK_NAKM_Msk (0x1UL << USB_OTG_DOEPMSK_NAKM_Pos) /*!< 0x00002000 */
-#define USB_OTG_DOEPMSK_NAKM USB_OTG_DOEPMSK_NAKM_Msk /*!< OUT Packet NAK interrupt mask */
-#define USB_OTG_DOEPMSK_NYETM_Pos (14U)
-#define USB_OTG_DOEPMSK_NYETM_Msk (0x1UL << USB_OTG_DOEPMSK_NYETM_Pos) /*!< 0x00004000 */
-#define USB_OTG_DOEPMSK_NYETM USB_OTG_DOEPMSK_NYETM_Msk /*!< NYET interrupt mask */
-/******************** Bit definition for USB_OTG_GINTSTS register ********************/
-#define USB_OTG_GINTSTS_CMOD_Pos (0U)
-#define USB_OTG_GINTSTS_CMOD_Msk (0x1UL << USB_OTG_GINTSTS_CMOD_Pos) /*!< 0x00000001 */
-#define USB_OTG_GINTSTS_CMOD USB_OTG_GINTSTS_CMOD_Msk /*!< Current mode of operation */
-#define USB_OTG_GINTSTS_MMIS_Pos (1U)
-#define USB_OTG_GINTSTS_MMIS_Msk (0x1UL << USB_OTG_GINTSTS_MMIS_Pos) /*!< 0x00000002 */
-#define USB_OTG_GINTSTS_MMIS USB_OTG_GINTSTS_MMIS_Msk /*!< Mode mismatch interrupt */
-#define USB_OTG_GINTSTS_OTGINT_Pos (2U)
-#define USB_OTG_GINTSTS_OTGINT_Msk (0x1UL << USB_OTG_GINTSTS_OTGINT_Pos) /*!< 0x00000004 */
-#define USB_OTG_GINTSTS_OTGINT USB_OTG_GINTSTS_OTGINT_Msk /*!< OTG interrupt */
-#define USB_OTG_GINTSTS_SOF_Pos (3U)
-#define USB_OTG_GINTSTS_SOF_Msk (0x1UL << USB_OTG_GINTSTS_SOF_Pos) /*!< 0x00000008 */
-#define USB_OTG_GINTSTS_SOF USB_OTG_GINTSTS_SOF_Msk /*!< Start of frame */
-#define USB_OTG_GINTSTS_RXFLVL_Pos (4U)
-#define USB_OTG_GINTSTS_RXFLVL_Msk (0x1UL << USB_OTG_GINTSTS_RXFLVL_Pos) /*!< 0x00000010 */
-#define USB_OTG_GINTSTS_RXFLVL USB_OTG_GINTSTS_RXFLVL_Msk /*!< RxFIFO nonempty */
-#define USB_OTG_GINTSTS_NPTXFE_Pos (5U)
-#define USB_OTG_GINTSTS_NPTXFE_Msk (0x1UL << USB_OTG_GINTSTS_NPTXFE_Pos) /*!< 0x00000020 */
-#define USB_OTG_GINTSTS_NPTXFE USB_OTG_GINTSTS_NPTXFE_Msk /*!< Nonperiodic TxFIFO empty */
-#define USB_OTG_GINTSTS_GINAKEFF_Pos (6U)
-#define USB_OTG_GINTSTS_GINAKEFF_Msk (0x1UL << USB_OTG_GINTSTS_GINAKEFF_Pos) /*!< 0x00000040 */
-#define USB_OTG_GINTSTS_GINAKEFF USB_OTG_GINTSTS_GINAKEFF_Msk /*!< Global IN nonperiodic NAK effective */
-#define USB_OTG_GINTSTS_BOUTNAKEFF_Pos (7U)
-#define USB_OTG_GINTSTS_BOUTNAKEFF_Msk (0x1UL << USB_OTG_GINTSTS_BOUTNAKEFF_Pos) /*!< 0x00000080 */
-#define USB_OTG_GINTSTS_BOUTNAKEFF USB_OTG_GINTSTS_BOUTNAKEFF_Msk /*!< Global OUT NAK effective */
-#define USB_OTG_GINTSTS_ESUSP_Pos (10U)
-#define USB_OTG_GINTSTS_ESUSP_Msk (0x1UL << USB_OTG_GINTSTS_ESUSP_Pos) /*!< 0x00000400 */
-#define USB_OTG_GINTSTS_ESUSP USB_OTG_GINTSTS_ESUSP_Msk /*!< Early suspend */
-#define USB_OTG_GINTSTS_USBSUSP_Pos (11U)
-#define USB_OTG_GINTSTS_USBSUSP_Msk (0x1UL << USB_OTG_GINTSTS_USBSUSP_Pos) /*!< 0x00000800 */
-#define USB_OTG_GINTSTS_USBSUSP USB_OTG_GINTSTS_USBSUSP_Msk /*!< USB suspend */
-#define USB_OTG_GINTSTS_USBRST_Pos (12U)
-#define USB_OTG_GINTSTS_USBRST_Msk (0x1UL << USB_OTG_GINTSTS_USBRST_Pos) /*!< 0x00001000 */
-#define USB_OTG_GINTSTS_USBRST USB_OTG_GINTSTS_USBRST_Msk /*!< USB reset */
-#define USB_OTG_GINTSTS_ENUMDNE_Pos (13U)
-#define USB_OTG_GINTSTS_ENUMDNE_Msk (0x1UL << USB_OTG_GINTSTS_ENUMDNE_Pos) /*!< 0x00002000 */
-#define USB_OTG_GINTSTS_ENUMDNE USB_OTG_GINTSTS_ENUMDNE_Msk /*!< Enumeration done */
-#define USB_OTG_GINTSTS_ISOODRP_Pos (14U)
-#define USB_OTG_GINTSTS_ISOODRP_Msk (0x1UL << USB_OTG_GINTSTS_ISOODRP_Pos) /*!< 0x00004000 */
-#define USB_OTG_GINTSTS_ISOODRP USB_OTG_GINTSTS_ISOODRP_Msk /*!< Isochronous OUT packet dropped interrupt */
-#define USB_OTG_GINTSTS_EOPF_Pos (15U)
-#define USB_OTG_GINTSTS_EOPF_Msk (0x1UL << USB_OTG_GINTSTS_EOPF_Pos) /*!< 0x00008000 */
-#define USB_OTG_GINTSTS_EOPF USB_OTG_GINTSTS_EOPF_Msk /*!< End of periodic frame interrupt */
-#define USB_OTG_GINTSTS_IEPINT_Pos (18U)
-#define USB_OTG_GINTSTS_IEPINT_Msk (0x1UL << USB_OTG_GINTSTS_IEPINT_Pos) /*!< 0x00040000 */
-#define USB_OTG_GINTSTS_IEPINT USB_OTG_GINTSTS_IEPINT_Msk /*!< IN endpoint interrupt */
-#define USB_OTG_GINTSTS_OEPINT_Pos (19U)
-#define USB_OTG_GINTSTS_OEPINT_Msk (0x1UL << USB_OTG_GINTSTS_OEPINT_Pos) /*!< 0x00080000 */
-#define USB_OTG_GINTSTS_OEPINT USB_OTG_GINTSTS_OEPINT_Msk /*!< OUT endpoint interrupt */
-#define USB_OTG_GINTSTS_IISOIXFR_Pos (20U)
-#define USB_OTG_GINTSTS_IISOIXFR_Msk (0x1UL << USB_OTG_GINTSTS_IISOIXFR_Pos) /*!< 0x00100000 */
-#define USB_OTG_GINTSTS_IISOIXFR USB_OTG_GINTSTS_IISOIXFR_Msk /*!< Incomplete isochronous IN transfer */
-#define USB_OTG_GINTSTS_PXFR_INCOMPISOOUT_Pos (21U)
-#define USB_OTG_GINTSTS_PXFR_INCOMPISOOUT_Msk (0x1UL << USB_OTG_GINTSTS_PXFR_INCOMPISOOUT_Pos) /*!< 0x00200000 */
-#define USB_OTG_GINTSTS_PXFR_INCOMPISOOUT USB_OTG_GINTSTS_PXFR_INCOMPISOOUT_Msk /*!< Incomplete periodic transfer */
-#define USB_OTG_GINTSTS_DATAFSUSP_Pos (22U)
-#define USB_OTG_GINTSTS_DATAFSUSP_Msk (0x1UL << USB_OTG_GINTSTS_DATAFSUSP_Pos) /*!< 0x00400000 */
-#define USB_OTG_GINTSTS_DATAFSUSP USB_OTG_GINTSTS_DATAFSUSP_Msk /*!< Data fetch suspended */
-#define USB_OTG_GINTSTS_HPRTINT_Pos (24U)
-#define USB_OTG_GINTSTS_HPRTINT_Msk (0x1UL << USB_OTG_GINTSTS_HPRTINT_Pos) /*!< 0x01000000 */
-#define USB_OTG_GINTSTS_HPRTINT USB_OTG_GINTSTS_HPRTINT_Msk /*!< Host port interrupt */
-#define USB_OTG_GINTSTS_HCINT_Pos (25U)
-#define USB_OTG_GINTSTS_HCINT_Msk (0x1UL << USB_OTG_GINTSTS_HCINT_Pos) /*!< 0x02000000 */
-#define USB_OTG_GINTSTS_HCINT USB_OTG_GINTSTS_HCINT_Msk /*!< Host channels interrupt */
-#define USB_OTG_GINTSTS_PTXFE_Pos (26U)
-#define USB_OTG_GINTSTS_PTXFE_Msk (0x1UL << USB_OTG_GINTSTS_PTXFE_Pos) /*!< 0x04000000 */
-#define USB_OTG_GINTSTS_PTXFE USB_OTG_GINTSTS_PTXFE_Msk /*!< Periodic TxFIFO empty */
-#define USB_OTG_GINTSTS_CIDSCHG_Pos (28U)
-#define USB_OTG_GINTSTS_CIDSCHG_Msk (0x1UL << USB_OTG_GINTSTS_CIDSCHG_Pos) /*!< 0x10000000 */
-#define USB_OTG_GINTSTS_CIDSCHG USB_OTG_GINTSTS_CIDSCHG_Msk /*!< Connector ID status change */
-#define USB_OTG_GINTSTS_DISCINT_Pos (29U)
-#define USB_OTG_GINTSTS_DISCINT_Msk (0x1UL << USB_OTG_GINTSTS_DISCINT_Pos) /*!< 0x20000000 */
-#define USB_OTG_GINTSTS_DISCINT USB_OTG_GINTSTS_DISCINT_Msk /*!< Disconnect detected interrupt */
-#define USB_OTG_GINTSTS_SRQINT_Pos (30U)
-#define USB_OTG_GINTSTS_SRQINT_Msk (0x1UL << USB_OTG_GINTSTS_SRQINT_Pos) /*!< 0x40000000 */
-#define USB_OTG_GINTSTS_SRQINT USB_OTG_GINTSTS_SRQINT_Msk /*!< Session request/new session detected interrupt */
-#define USB_OTG_GINTSTS_WKUINT_Pos (31U)
-#define USB_OTG_GINTSTS_WKUINT_Msk (0x1UL << USB_OTG_GINTSTS_WKUINT_Pos) /*!< 0x80000000 */
-#define USB_OTG_GINTSTS_WKUINT USB_OTG_GINTSTS_WKUINT_Msk /*!< Resume/remote wakeup detected interrupt */
-
-/******************** Bit definition for USB_OTG_GINTMSK register ********************/
-#define USB_OTG_GINTMSK_MMISM_Pos (1U)
-#define USB_OTG_GINTMSK_MMISM_Msk (0x1UL << USB_OTG_GINTMSK_MMISM_Pos) /*!< 0x00000002 */
-#define USB_OTG_GINTMSK_MMISM USB_OTG_GINTMSK_MMISM_Msk /*!< Mode mismatch interrupt mask */
-#define USB_OTG_GINTMSK_OTGINT_Pos (2U)
-#define USB_OTG_GINTMSK_OTGINT_Msk (0x1UL << USB_OTG_GINTMSK_OTGINT_Pos) /*!< 0x00000004 */
-#define USB_OTG_GINTMSK_OTGINT USB_OTG_GINTMSK_OTGINT_Msk /*!< OTG interrupt mask */
-#define USB_OTG_GINTMSK_SOFM_Pos (3U)
-#define USB_OTG_GINTMSK_SOFM_Msk (0x1UL << USB_OTG_GINTMSK_SOFM_Pos) /*!< 0x00000008 */
-#define USB_OTG_GINTMSK_SOFM USB_OTG_GINTMSK_SOFM_Msk /*!< Start of frame mask */
-#define USB_OTG_GINTMSK_RXFLVLM_Pos (4U)
-#define USB_OTG_GINTMSK_RXFLVLM_Msk (0x1UL << USB_OTG_GINTMSK_RXFLVLM_Pos) /*!< 0x00000010 */
-#define USB_OTG_GINTMSK_RXFLVLM USB_OTG_GINTMSK_RXFLVLM_Msk /*!< Receive FIFO nonempty mask */
-#define USB_OTG_GINTMSK_NPTXFEM_Pos (5U)
-#define USB_OTG_GINTMSK_NPTXFEM_Msk (0x1UL << USB_OTG_GINTMSK_NPTXFEM_Pos) /*!< 0x00000020 */
-#define USB_OTG_GINTMSK_NPTXFEM USB_OTG_GINTMSK_NPTXFEM_Msk /*!< Nonperiodic TxFIFO empty mask */
-#define USB_OTG_GINTMSK_GINAKEFFM_Pos (6U)
-#define USB_OTG_GINTMSK_GINAKEFFM_Msk (0x1UL << USB_OTG_GINTMSK_GINAKEFFM_Pos) /*!< 0x00000040 */
-#define USB_OTG_GINTMSK_GINAKEFFM USB_OTG_GINTMSK_GINAKEFFM_Msk /*!< Global nonperiodic IN NAK effective mask */
-#define USB_OTG_GINTMSK_GONAKEFFM_Pos (7U)
-#define USB_OTG_GINTMSK_GONAKEFFM_Msk (0x1UL << USB_OTG_GINTMSK_GONAKEFFM_Pos) /*!< 0x00000080 */
-#define USB_OTG_GINTMSK_GONAKEFFM USB_OTG_GINTMSK_GONAKEFFM_Msk /*!< Global OUT NAK effective mask */
-#define USB_OTG_GINTMSK_ESUSPM_Pos (10U)
-#define USB_OTG_GINTMSK_ESUSPM_Msk (0x1UL << USB_OTG_GINTMSK_ESUSPM_Pos) /*!< 0x00000400 */
-#define USB_OTG_GINTMSK_ESUSPM USB_OTG_GINTMSK_ESUSPM_Msk /*!< Early suspend mask */
-#define USB_OTG_GINTMSK_USBSUSPM_Pos (11U)
-#define USB_OTG_GINTMSK_USBSUSPM_Msk (0x1UL << USB_OTG_GINTMSK_USBSUSPM_Pos) /*!< 0x00000800 */
-#define USB_OTG_GINTMSK_USBSUSPM USB_OTG_GINTMSK_USBSUSPM_Msk /*!< USB suspend mask */
-#define USB_OTG_GINTMSK_USBRST_Pos (12U)
-#define USB_OTG_GINTMSK_USBRST_Msk (0x1UL << USB_OTG_GINTMSK_USBRST_Pos) /*!< 0x00001000 */
-#define USB_OTG_GINTMSK_USBRST USB_OTG_GINTMSK_USBRST_Msk /*!< USB reset mask */
-#define USB_OTG_GINTMSK_ENUMDNEM_Pos (13U)
-#define USB_OTG_GINTMSK_ENUMDNEM_Msk (0x1UL << USB_OTG_GINTMSK_ENUMDNEM_Pos) /*!< 0x00002000 */
-#define USB_OTG_GINTMSK_ENUMDNEM USB_OTG_GINTMSK_ENUMDNEM_Msk /*!< Enumeration done mask */
-#define USB_OTG_GINTMSK_ISOODRPM_Pos (14U)
-#define USB_OTG_GINTMSK_ISOODRPM_Msk (0x1UL << USB_OTG_GINTMSK_ISOODRPM_Pos) /*!< 0x00004000 */
-#define USB_OTG_GINTMSK_ISOODRPM USB_OTG_GINTMSK_ISOODRPM_Msk /*!< Isochronous OUT packet dropped interrupt mask */
-#define USB_OTG_GINTMSK_EOPFM_Pos (15U)
-#define USB_OTG_GINTMSK_EOPFM_Msk (0x1UL << USB_OTG_GINTMSK_EOPFM_Pos) /*!< 0x00008000 */
-#define USB_OTG_GINTMSK_EOPFM USB_OTG_GINTMSK_EOPFM_Msk /*!< End of periodic frame interrupt mask */
-#define USB_OTG_GINTMSK_EPMISM_Pos (17U)
-#define USB_OTG_GINTMSK_EPMISM_Msk (0x1UL << USB_OTG_GINTMSK_EPMISM_Pos) /*!< 0x00020000 */
-#define USB_OTG_GINTMSK_EPMISM USB_OTG_GINTMSK_EPMISM_Msk /*!< Endpoint mismatch interrupt mask */
-#define USB_OTG_GINTMSK_IEPINT_Pos (18U)
-#define USB_OTG_GINTMSK_IEPINT_Msk (0x1UL << USB_OTG_GINTMSK_IEPINT_Pos) /*!< 0x00040000 */
-#define USB_OTG_GINTMSK_IEPINT USB_OTG_GINTMSK_IEPINT_Msk /*!< IN endpoints interrupt mask */
-#define USB_OTG_GINTMSK_OEPINT_Pos (19U)
-#define USB_OTG_GINTMSK_OEPINT_Msk (0x1UL << USB_OTG_GINTMSK_OEPINT_Pos) /*!< 0x00080000 */
-#define USB_OTG_GINTMSK_OEPINT USB_OTG_GINTMSK_OEPINT_Msk /*!< OUT endpoints interrupt mask */
-#define USB_OTG_GINTMSK_IISOIXFRM_Pos (20U)
-#define USB_OTG_GINTMSK_IISOIXFRM_Msk (0x1UL << USB_OTG_GINTMSK_IISOIXFRM_Pos) /*!< 0x00100000 */
-#define USB_OTG_GINTMSK_IISOIXFRM USB_OTG_GINTMSK_IISOIXFRM_Msk /*!< Incomplete isochronous IN transfer mask */
-#define USB_OTG_GINTMSK_PXFRM_IISOOXFRM_Pos (21U)
-#define USB_OTG_GINTMSK_PXFRM_IISOOXFRM_Msk (0x1UL << USB_OTG_GINTMSK_PXFRM_IISOOXFRM_Pos) /*!< 0x00200000 */
-#define USB_OTG_GINTMSK_PXFRM_IISOOXFRM USB_OTG_GINTMSK_PXFRM_IISOOXFRM_Msk /*!< Incomplete periodic transfer mask */
-#define USB_OTG_GINTMSK_FSUSPM_Pos (22U)
-#define USB_OTG_GINTMSK_FSUSPM_Msk (0x1UL << USB_OTG_GINTMSK_FSUSPM_Pos) /*!< 0x00400000 */
-#define USB_OTG_GINTMSK_FSUSPM USB_OTG_GINTMSK_FSUSPM_Msk /*!< Data fetch suspended mask */
-#define USB_OTG_GINTMSK_PRTIM_Pos (24U)
-#define USB_OTG_GINTMSK_PRTIM_Msk (0x1UL << USB_OTG_GINTMSK_PRTIM_Pos) /*!< 0x01000000 */
-#define USB_OTG_GINTMSK_PRTIM USB_OTG_GINTMSK_PRTIM_Msk /*!< Host port interrupt mask */
-#define USB_OTG_GINTMSK_HCIM_Pos (25U)
-#define USB_OTG_GINTMSK_HCIM_Msk (0x1UL << USB_OTG_GINTMSK_HCIM_Pos) /*!< 0x02000000 */
-#define USB_OTG_GINTMSK_HCIM USB_OTG_GINTMSK_HCIM_Msk /*!< Host channels interrupt mask */
-#define USB_OTG_GINTMSK_PTXFEM_Pos (26U)
-#define USB_OTG_GINTMSK_PTXFEM_Msk (0x1UL << USB_OTG_GINTMSK_PTXFEM_Pos) /*!< 0x04000000 */
-#define USB_OTG_GINTMSK_PTXFEM USB_OTG_GINTMSK_PTXFEM_Msk /*!< Periodic TxFIFO empty mask */
-#define USB_OTG_GINTMSK_CIDSCHGM_Pos (28U)
-#define USB_OTG_GINTMSK_CIDSCHGM_Msk (0x1UL << USB_OTG_GINTMSK_CIDSCHGM_Pos) /*!< 0x10000000 */
-#define USB_OTG_GINTMSK_CIDSCHGM USB_OTG_GINTMSK_CIDSCHGM_Msk /*!< Connector ID status change mask */
-#define USB_OTG_GINTMSK_DISCINT_Pos (29U)
-#define USB_OTG_GINTMSK_DISCINT_Msk (0x1UL << USB_OTG_GINTMSK_DISCINT_Pos) /*!< 0x20000000 */
-#define USB_OTG_GINTMSK_DISCINT USB_OTG_GINTMSK_DISCINT_Msk /*!< Disconnect detected interrupt mask */
-#define USB_OTG_GINTMSK_SRQIM_Pos (30U)
-#define USB_OTG_GINTMSK_SRQIM_Msk (0x1UL << USB_OTG_GINTMSK_SRQIM_Pos) /*!< 0x40000000 */
-#define USB_OTG_GINTMSK_SRQIM USB_OTG_GINTMSK_SRQIM_Msk /*!< Session request/new session detected interrupt mask */
-#define USB_OTG_GINTMSK_WUIM_Pos (31U)
-#define USB_OTG_GINTMSK_WUIM_Msk (0x1UL << USB_OTG_GINTMSK_WUIM_Pos) /*!< 0x80000000 */
-#define USB_OTG_GINTMSK_WUIM USB_OTG_GINTMSK_WUIM_Msk /*!< Resume/remote wakeup detected interrupt mask */
-
-/******************** Bit definition for USB_OTG_DAINT register ********************/
-#define USB_OTG_DAINT_IEPINT_Pos (0U)
-#define USB_OTG_DAINT_IEPINT_Msk (0xFFFFUL << USB_OTG_DAINT_IEPINT_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DAINT_IEPINT USB_OTG_DAINT_IEPINT_Msk /*!< IN endpoint interrupt bits */
-#define USB_OTG_DAINT_OEPINT_Pos (16U)
-#define USB_OTG_DAINT_OEPINT_Msk (0xFFFFUL << USB_OTG_DAINT_OEPINT_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_DAINT_OEPINT USB_OTG_DAINT_OEPINT_Msk /*!< OUT endpoint interrupt bits */
-
-/******************** Bit definition for USB_OTG_HAINTMSK register ********************/
-#define USB_OTG_HAINTMSK_HAINTM_Pos (0U)
-#define USB_OTG_HAINTMSK_HAINTM_Msk (0xFFFFUL << USB_OTG_HAINTMSK_HAINTM_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HAINTMSK_HAINTM USB_OTG_HAINTMSK_HAINTM_Msk /*!< Channel interrupt mask */
-
-/******************** Bit definition for USB_OTG_GRXSTSP register ********************/
-#define USB_OTG_GRXSTSP_EPNUM_Pos (0U)
-#define USB_OTG_GRXSTSP_EPNUM_Msk (0xFUL << USB_OTG_GRXSTSP_EPNUM_Pos) /*!< 0x0000000F */
-#define USB_OTG_GRXSTSP_EPNUM USB_OTG_GRXSTSP_EPNUM_Msk /*!< IN EP interrupt mask bits */
-#define USB_OTG_GRXSTSP_BCNT_Pos (4U)
-#define USB_OTG_GRXSTSP_BCNT_Msk (0x7FFUL << USB_OTG_GRXSTSP_BCNT_Pos) /*!< 0x00007FF0 */
-#define USB_OTG_GRXSTSP_BCNT USB_OTG_GRXSTSP_BCNT_Msk /*!< OUT EP interrupt mask bits */
-#define USB_OTG_GRXSTSP_DPID_Pos (15U)
-#define USB_OTG_GRXSTSP_DPID_Msk (0x3UL << USB_OTG_GRXSTSP_DPID_Pos) /*!< 0x00018000 */
-#define USB_OTG_GRXSTSP_DPID USB_OTG_GRXSTSP_DPID_Msk /*!< OUT EP interrupt mask bits */
-#define USB_OTG_GRXSTSP_PKTSTS_Pos (17U)
-#define USB_OTG_GRXSTSP_PKTSTS_Msk (0xFUL << USB_OTG_GRXSTSP_PKTSTS_Pos) /*!< 0x001E0000 */
-#define USB_OTG_GRXSTSP_PKTSTS USB_OTG_GRXSTSP_PKTSTS_Msk /*!< OUT EP interrupt mask bits */
-
-/******************** Bit definition for USB_OTG_DAINTMSK register ********************/
-#define USB_OTG_DAINTMSK_IEPM_Pos (0U)
-#define USB_OTG_DAINTMSK_IEPM_Msk (0xFFFFUL << USB_OTG_DAINTMSK_IEPM_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DAINTMSK_IEPM USB_OTG_DAINTMSK_IEPM_Msk /*!< IN EP interrupt mask bits */
-#define USB_OTG_DAINTMSK_OEPM_Pos (16U)
-#define USB_OTG_DAINTMSK_OEPM_Msk (0xFFFFUL << USB_OTG_DAINTMSK_OEPM_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_DAINTMSK_OEPM USB_OTG_DAINTMSK_OEPM_Msk /*!< OUT EP interrupt mask bits */
-
-/******************** Bit definition for USB_OTG_GRXFSIZ register ********************/
-#define USB_OTG_GRXFSIZ_RXFD_Pos (0U)
-#define USB_OTG_GRXFSIZ_RXFD_Msk (0xFFFFUL << USB_OTG_GRXFSIZ_RXFD_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_GRXFSIZ_RXFD USB_OTG_GRXFSIZ_RXFD_Msk /*!< RxFIFO depth */
-
-/******************** Bit definition for USB_OTG_DVBUSDIS register ********************/
-#define USB_OTG_DVBUSDIS_VBUSDT_Pos (0U)
-#define USB_OTG_DVBUSDIS_VBUSDT_Msk (0xFFFFUL << USB_OTG_DVBUSDIS_VBUSDT_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DVBUSDIS_VBUSDT USB_OTG_DVBUSDIS_VBUSDT_Msk /*!< Device VBUS discharge time */
-
-/******************** Bit definition for OTG register ********************/
-#define USB_OTG_NPTXFSA_Pos (0U)
-#define USB_OTG_NPTXFSA_Msk (0xFFFFUL << USB_OTG_NPTXFSA_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_NPTXFSA USB_OTG_NPTXFSA_Msk /*!< Nonperiodic transmit RAM start address */
-#define USB_OTG_NPTXFD_Pos (16U)
-#define USB_OTG_NPTXFD_Msk (0xFFFFUL << USB_OTG_NPTXFD_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_NPTXFD USB_OTG_NPTXFD_Msk /*!< Nonperiodic TxFIFO depth */
-#define USB_OTG_TX0FSA_Pos (0U)
-#define USB_OTG_TX0FSA_Msk (0xFFFFUL << USB_OTG_TX0FSA_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_TX0FSA USB_OTG_TX0FSA_Msk /*!< Endpoint 0 transmit RAM start address */
-#define USB_OTG_TX0FD_Pos (16U)
-#define USB_OTG_TX0FD_Msk (0xFFFFUL << USB_OTG_TX0FD_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_TX0FD USB_OTG_TX0FD_Msk /*!< Endpoint 0 TxFIFO depth */
-
-/******************** Bit definition for USB_OTG_DVBUSPULSE register ********************/
-#define USB_OTG_DVBUSPULSE_DVBUSP_Pos (0U)
-#define USB_OTG_DVBUSPULSE_DVBUSP_Msk (0xFFFUL << USB_OTG_DVBUSPULSE_DVBUSP_Pos) /*!< 0x00000FFF */
-#define USB_OTG_DVBUSPULSE_DVBUSP USB_OTG_DVBUSPULSE_DVBUSP_Msk /*!< Device VBUS pulsing time */
-
-/******************** Bit definition for USB_OTG_GNPTXSTS register ********************/
-#define USB_OTG_GNPTXSTS_NPTXFSAV_Pos (0U)
-#define USB_OTG_GNPTXSTS_NPTXFSAV_Msk (0xFFFFUL << USB_OTG_GNPTXSTS_NPTXFSAV_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_GNPTXSTS_NPTXFSAV USB_OTG_GNPTXSTS_NPTXFSAV_Msk /*!< Nonperiodic TxFIFO space available */
-
-#define USB_OTG_GNPTXSTS_NPTQXSAV_Pos (16U)
-#define USB_OTG_GNPTXSTS_NPTQXSAV_Msk (0xFFUL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00FF0000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV USB_OTG_GNPTXSTS_NPTQXSAV_Msk /*!< Nonperiodic transmit request queue space available */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_0 (0x01UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00010000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_1 (0x02UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00020000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_2 (0x04UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00040000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_3 (0x08UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00080000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_4 (0x10UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00100000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_5 (0x20UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00200000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_6 (0x40UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00400000 */
-#define USB_OTG_GNPTXSTS_NPTQXSAV_7 (0x80UL << USB_OTG_GNPTXSTS_NPTQXSAV_Pos) /*!< 0x00800000 */
-
-#define USB_OTG_GNPTXSTS_NPTXQTOP_Pos (24U)
-#define USB_OTG_GNPTXSTS_NPTXQTOP_Msk (0x7FUL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x7F000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP USB_OTG_GNPTXSTS_NPTXQTOP_Msk /*!< Top of the nonperiodic transmit request queue */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_0 (0x01UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x01000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_1 (0x02UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x02000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_2 (0x04UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x04000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_3 (0x08UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x08000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_4 (0x10UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x10000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_5 (0x20UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x20000000 */
-#define USB_OTG_GNPTXSTS_NPTXQTOP_6 (0x40UL << USB_OTG_GNPTXSTS_NPTXQTOP_Pos) /*!< 0x40000000 */
-
-/******************** Bit definition for USB_OTG_DTHRCTL register ********************/
-#define USB_OTG_DTHRCTL_NONISOTHREN_Pos (0U)
-#define USB_OTG_DTHRCTL_NONISOTHREN_Msk (0x1UL << USB_OTG_DTHRCTL_NONISOTHREN_Pos) /*!< 0x00000001 */
-#define USB_OTG_DTHRCTL_NONISOTHREN USB_OTG_DTHRCTL_NONISOTHREN_Msk /*!< Nonisochronous IN endpoints threshold enable */
-#define USB_OTG_DTHRCTL_ISOTHREN_Pos (1U)
-#define USB_OTG_DTHRCTL_ISOTHREN_Msk (0x1UL << USB_OTG_DTHRCTL_ISOTHREN_Pos) /*!< 0x00000002 */
-#define USB_OTG_DTHRCTL_ISOTHREN USB_OTG_DTHRCTL_ISOTHREN_Msk /*!< ISO IN endpoint threshold enable */
-
-#define USB_OTG_DTHRCTL_TXTHRLEN_Pos (2U)
-#define USB_OTG_DTHRCTL_TXTHRLEN_Msk (0x1FFUL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x000007FC */
-#define USB_OTG_DTHRCTL_TXTHRLEN USB_OTG_DTHRCTL_TXTHRLEN_Msk /*!< Transmit threshold length */
-#define USB_OTG_DTHRCTL_TXTHRLEN_0 (0x001UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000004 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_1 (0x002UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000008 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_2 (0x004UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000010 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_3 (0x008UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000020 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_4 (0x010UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000040 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_5 (0x020UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000080 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_6 (0x040UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000100 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_7 (0x080UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000200 */
-#define USB_OTG_DTHRCTL_TXTHRLEN_8 (0x100UL << USB_OTG_DTHRCTL_TXTHRLEN_Pos) /*!< 0x00000400 */
-#define USB_OTG_DTHRCTL_RXTHREN_Pos (16U)
-#define USB_OTG_DTHRCTL_RXTHREN_Msk (0x1UL << USB_OTG_DTHRCTL_RXTHREN_Pos) /*!< 0x00010000 */
-#define USB_OTG_DTHRCTL_RXTHREN USB_OTG_DTHRCTL_RXTHREN_Msk /*!< Receive threshold enable */
-
-#define USB_OTG_DTHRCTL_RXTHRLEN_Pos (17U)
-#define USB_OTG_DTHRCTL_RXTHRLEN_Msk (0x1FFUL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x03FE0000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN USB_OTG_DTHRCTL_RXTHRLEN_Msk /*!< Receive threshold length */
-#define USB_OTG_DTHRCTL_RXTHRLEN_0 (0x001UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00020000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_1 (0x002UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00040000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_2 (0x004UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00080000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_3 (0x008UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00100000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_4 (0x010UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00200000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_5 (0x020UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00400000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_6 (0x040UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x00800000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_7 (0x080UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x01000000 */
-#define USB_OTG_DTHRCTL_RXTHRLEN_8 (0x100UL << USB_OTG_DTHRCTL_RXTHRLEN_Pos) /*!< 0x02000000 */
-#define USB_OTG_DTHRCTL_ARPEN_Pos (27U)
-#define USB_OTG_DTHRCTL_ARPEN_Msk (0x1UL << USB_OTG_DTHRCTL_ARPEN_Pos) /*!< 0x08000000 */
-#define USB_OTG_DTHRCTL_ARPEN USB_OTG_DTHRCTL_ARPEN_Msk /*!< Arbiter parking enable */
-
-/******************** Bit definition for USB_OTG_DIEPEMPMSK register ********************/
-#define USB_OTG_DIEPEMPMSK_INEPTXFEM_Pos (0U)
-#define USB_OTG_DIEPEMPMSK_INEPTXFEM_Msk (0xFFFFUL << USB_OTG_DIEPEMPMSK_INEPTXFEM_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DIEPEMPMSK_INEPTXFEM USB_OTG_DIEPEMPMSK_INEPTXFEM_Msk /*!< IN EP Tx FIFO empty interrupt mask bits */
-
-/******************** Bit definition for USB_OTG_DEACHINT register ********************/
-#define USB_OTG_DEACHINT_IEP1INT_Pos (1U)
-#define USB_OTG_DEACHINT_IEP1INT_Msk (0x1UL << USB_OTG_DEACHINT_IEP1INT_Pos) /*!< 0x00000002 */
-#define USB_OTG_DEACHINT_IEP1INT USB_OTG_DEACHINT_IEP1INT_Msk /*!< IN endpoint 1interrupt bit */
-#define USB_OTG_DEACHINT_OEP1INT_Pos (17U)
-#define USB_OTG_DEACHINT_OEP1INT_Msk (0x1UL << USB_OTG_DEACHINT_OEP1INT_Pos) /*!< 0x00020000 */
-#define USB_OTG_DEACHINT_OEP1INT USB_OTG_DEACHINT_OEP1INT_Msk /*!< OUT endpoint 1 interrupt bit */
-
-/******************** Bit definition for USB_OTG_GCCFG register ********************/
-#define USB_OTG_GCCFG_PWRDWN_Pos (16U)
-#define USB_OTG_GCCFG_PWRDWN_Msk (0x1UL << USB_OTG_GCCFG_PWRDWN_Pos) /*!< 0x00010000 */
-#define USB_OTG_GCCFG_PWRDWN USB_OTG_GCCFG_PWRDWN_Msk /*!< Power down */
-#define USB_OTG_GCCFG_VBUSASEN_Pos (18U)
-#define USB_OTG_GCCFG_VBUSASEN_Msk (0x1UL << USB_OTG_GCCFG_VBUSASEN_Pos) /*!< 0x00040000 */
-#define USB_OTG_GCCFG_VBUSASEN USB_OTG_GCCFG_VBUSASEN_Msk /*!< Enable the VBUS sensing device */
-#define USB_OTG_GCCFG_VBUSBSEN_Pos (19U)
-#define USB_OTG_GCCFG_VBUSBSEN_Msk (0x1UL << USB_OTG_GCCFG_VBUSBSEN_Pos) /*!< 0x00080000 */
-#define USB_OTG_GCCFG_VBUSBSEN USB_OTG_GCCFG_VBUSBSEN_Msk /*!< Enable the VBUS sensing device */
-#define USB_OTG_GCCFG_SOFOUTEN_Pos (20U)
-#define USB_OTG_GCCFG_SOFOUTEN_Msk (0x1UL << USB_OTG_GCCFG_SOFOUTEN_Pos) /*!< 0x00100000 */
-#define USB_OTG_GCCFG_SOFOUTEN USB_OTG_GCCFG_SOFOUTEN_Msk /*!< SOF output enable */
-
-/******************** Bit definition for USB_OTG_DEACHINTMSK register ********************/
-#define USB_OTG_DEACHINTMSK_IEP1INTM_Pos (1U)
-#define USB_OTG_DEACHINTMSK_IEP1INTM_Msk (0x1UL << USB_OTG_DEACHINTMSK_IEP1INTM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DEACHINTMSK_IEP1INTM USB_OTG_DEACHINTMSK_IEP1INTM_Msk /*!< IN Endpoint 1 interrupt mask bit */
-#define USB_OTG_DEACHINTMSK_OEP1INTM_Pos (17U)
-#define USB_OTG_DEACHINTMSK_OEP1INTM_Msk (0x1UL << USB_OTG_DEACHINTMSK_OEP1INTM_Pos) /*!< 0x00020000 */
-#define USB_OTG_DEACHINTMSK_OEP1INTM USB_OTG_DEACHINTMSK_OEP1INTM_Msk /*!< OUT Endpoint 1 interrupt mask bit */
-
-/******************** Bit definition for USB_OTG_CID register ********************/
-#define USB_OTG_CID_PRODUCT_ID_Pos (0U)
-#define USB_OTG_CID_PRODUCT_ID_Msk (0xFFFFFFFFUL << USB_OTG_CID_PRODUCT_ID_Pos) /*!< 0xFFFFFFFF */
-#define USB_OTG_CID_PRODUCT_ID USB_OTG_CID_PRODUCT_ID_Msk /*!< Product ID field */
-
-/******************** Bit definition for USB_OTG_DIEPEACHMSK1 register ********************/
-#define USB_OTG_DIEPEACHMSK1_XFRCM_Pos (0U)
-#define USB_OTG_DIEPEACHMSK1_XFRCM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_DIEPEACHMSK1_XFRCM USB_OTG_DIEPEACHMSK1_XFRCM_Msk /*!< Transfer completed interrupt mask */
-#define USB_OTG_DIEPEACHMSK1_EPDM_Pos (1U)
-#define USB_OTG_DIEPEACHMSK1_EPDM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_EPDM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DIEPEACHMSK1_EPDM USB_OTG_DIEPEACHMSK1_EPDM_Msk /*!< Endpoint disabled interrupt mask */
-#define USB_OTG_DIEPEACHMSK1_TOM_Pos (3U)
-#define USB_OTG_DIEPEACHMSK1_TOM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_TOM_Pos) /*!< 0x00000008 */
-#define USB_OTG_DIEPEACHMSK1_TOM USB_OTG_DIEPEACHMSK1_TOM_Msk /*!< Timeout condition mask (nonisochronous endpoints) */
-#define USB_OTG_DIEPEACHMSK1_ITTXFEMSK_Pos (4U)
-#define USB_OTG_DIEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_ITTXFEMSK_Pos) /*!< 0x00000010 */
-#define USB_OTG_DIEPEACHMSK1_ITTXFEMSK USB_OTG_DIEPEACHMSK1_ITTXFEMSK_Msk /*!< IN token received when TxFIFO empty mask */
-#define USB_OTG_DIEPEACHMSK1_INEPNMM_Pos (5U)
-#define USB_OTG_DIEPEACHMSK1_INEPNMM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_INEPNMM_Pos) /*!< 0x00000020 */
-#define USB_OTG_DIEPEACHMSK1_INEPNMM USB_OTG_DIEPEACHMSK1_INEPNMM_Msk /*!< IN token received with EP mismatch mask */
-#define USB_OTG_DIEPEACHMSK1_INEPNEM_Pos (6U)
-#define USB_OTG_DIEPEACHMSK1_INEPNEM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_INEPNEM_Pos) /*!< 0x00000040 */
-#define USB_OTG_DIEPEACHMSK1_INEPNEM USB_OTG_DIEPEACHMSK1_INEPNEM_Msk /*!< IN endpoint NAK effective mask */
-#define USB_OTG_DIEPEACHMSK1_TXFURM_Pos (8U)
-#define USB_OTG_DIEPEACHMSK1_TXFURM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_TXFURM_Pos) /*!< 0x00000100 */
-#define USB_OTG_DIEPEACHMSK1_TXFURM USB_OTG_DIEPEACHMSK1_TXFURM_Msk /*!< FIFO underrun mask */
-#define USB_OTG_DIEPEACHMSK1_BIM_Pos (9U)
-#define USB_OTG_DIEPEACHMSK1_BIM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_BIM_Pos) /*!< 0x00000200 */
-#define USB_OTG_DIEPEACHMSK1_BIM USB_OTG_DIEPEACHMSK1_BIM_Msk /*!< BNA interrupt mask */
-#define USB_OTG_DIEPEACHMSK1_NAKM_Pos (13U)
-#define USB_OTG_DIEPEACHMSK1_NAKM_Msk (0x1UL << USB_OTG_DIEPEACHMSK1_NAKM_Pos) /*!< 0x00002000 */
-#define USB_OTG_DIEPEACHMSK1_NAKM USB_OTG_DIEPEACHMSK1_NAKM_Msk /*!< NAK interrupt mask */
-
-/******************** Bit definition for USB_OTG_HPRT register ********************/
-#define USB_OTG_HPRT_PCSTS_Pos (0U)
-#define USB_OTG_HPRT_PCSTS_Msk (0x1UL << USB_OTG_HPRT_PCSTS_Pos) /*!< 0x00000001 */
-#define USB_OTG_HPRT_PCSTS USB_OTG_HPRT_PCSTS_Msk /*!< Port connect status */
-#define USB_OTG_HPRT_PCDET_Pos (1U)
-#define USB_OTG_HPRT_PCDET_Msk (0x1UL << USB_OTG_HPRT_PCDET_Pos) /*!< 0x00000002 */
-#define USB_OTG_HPRT_PCDET USB_OTG_HPRT_PCDET_Msk /*!< Port connect detected */
-#define USB_OTG_HPRT_PENA_Pos (2U)
-#define USB_OTG_HPRT_PENA_Msk (0x1UL << USB_OTG_HPRT_PENA_Pos) /*!< 0x00000004 */
-#define USB_OTG_HPRT_PENA USB_OTG_HPRT_PENA_Msk /*!< Port enable */
-#define USB_OTG_HPRT_PENCHNG_Pos (3U)
-#define USB_OTG_HPRT_PENCHNG_Msk (0x1UL << USB_OTG_HPRT_PENCHNG_Pos) /*!< 0x00000008 */
-#define USB_OTG_HPRT_PENCHNG USB_OTG_HPRT_PENCHNG_Msk /*!< Port enable/disable change */
-#define USB_OTG_HPRT_POCA_Pos (4U)
-#define USB_OTG_HPRT_POCA_Msk (0x1UL << USB_OTG_HPRT_POCA_Pos) /*!< 0x00000010 */
-#define USB_OTG_HPRT_POCA USB_OTG_HPRT_POCA_Msk /*!< Port overcurrent active */
-#define USB_OTG_HPRT_POCCHNG_Pos (5U)
-#define USB_OTG_HPRT_POCCHNG_Msk (0x1UL << USB_OTG_HPRT_POCCHNG_Pos) /*!< 0x00000020 */
-#define USB_OTG_HPRT_POCCHNG USB_OTG_HPRT_POCCHNG_Msk /*!< Port overcurrent change */
-#define USB_OTG_HPRT_PRES_Pos (6U)
-#define USB_OTG_HPRT_PRES_Msk (0x1UL << USB_OTG_HPRT_PRES_Pos) /*!< 0x00000040 */
-#define USB_OTG_HPRT_PRES USB_OTG_HPRT_PRES_Msk /*!< Port resume */
-#define USB_OTG_HPRT_PSUSP_Pos (7U)
-#define USB_OTG_HPRT_PSUSP_Msk (0x1UL << USB_OTG_HPRT_PSUSP_Pos) /*!< 0x00000080 */
-#define USB_OTG_HPRT_PSUSP USB_OTG_HPRT_PSUSP_Msk /*!< Port suspend */
-#define USB_OTG_HPRT_PRST_Pos (8U)
-#define USB_OTG_HPRT_PRST_Msk (0x1UL << USB_OTG_HPRT_PRST_Pos) /*!< 0x00000100 */
-#define USB_OTG_HPRT_PRST USB_OTG_HPRT_PRST_Msk /*!< Port reset */
-
-#define USB_OTG_HPRT_PLSTS_Pos (10U)
-#define USB_OTG_HPRT_PLSTS_Msk (0x3UL << USB_OTG_HPRT_PLSTS_Pos) /*!< 0x00000C00 */
-#define USB_OTG_HPRT_PLSTS USB_OTG_HPRT_PLSTS_Msk /*!< Port line status */
-#define USB_OTG_HPRT_PLSTS_0 (0x1UL << USB_OTG_HPRT_PLSTS_Pos) /*!< 0x00000400 */
-#define USB_OTG_HPRT_PLSTS_1 (0x2UL << USB_OTG_HPRT_PLSTS_Pos) /*!< 0x00000800 */
-#define USB_OTG_HPRT_PPWR_Pos (12U)
-#define USB_OTG_HPRT_PPWR_Msk (0x1UL << USB_OTG_HPRT_PPWR_Pos) /*!< 0x00001000 */
-#define USB_OTG_HPRT_PPWR USB_OTG_HPRT_PPWR_Msk /*!< Port power */
-
-#define USB_OTG_HPRT_PTCTL_Pos (13U)
-#define USB_OTG_HPRT_PTCTL_Msk (0xFUL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x0001E000 */
-#define USB_OTG_HPRT_PTCTL USB_OTG_HPRT_PTCTL_Msk /*!< Port test control */
-#define USB_OTG_HPRT_PTCTL_0 (0x1UL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x00002000 */
-#define USB_OTG_HPRT_PTCTL_1 (0x2UL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x00004000 */
-#define USB_OTG_HPRT_PTCTL_2 (0x4UL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x00008000 */
-#define USB_OTG_HPRT_PTCTL_3 (0x8UL << USB_OTG_HPRT_PTCTL_Pos) /*!< 0x00010000 */
-
-#define USB_OTG_HPRT_PSPD_Pos (17U)
-#define USB_OTG_HPRT_PSPD_Msk (0x3UL << USB_OTG_HPRT_PSPD_Pos) /*!< 0x00060000 */
-#define USB_OTG_HPRT_PSPD USB_OTG_HPRT_PSPD_Msk /*!< Port speed */
-#define USB_OTG_HPRT_PSPD_0 (0x1UL << USB_OTG_HPRT_PSPD_Pos) /*!< 0x00020000 */
-#define USB_OTG_HPRT_PSPD_1 (0x2UL << USB_OTG_HPRT_PSPD_Pos) /*!< 0x00040000 */
-
-/******************** Bit definition for USB_OTG_DOEPEACHMSK1 register ********************/
-#define USB_OTG_DOEPEACHMSK1_XFRCM_Pos (0U)
-#define USB_OTG_DOEPEACHMSK1_XFRCM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_DOEPEACHMSK1_XFRCM USB_OTG_DOEPEACHMSK1_XFRCM_Msk /*!< Transfer completed interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_EPDM_Pos (1U)
-#define USB_OTG_DOEPEACHMSK1_EPDM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_EPDM_Pos) /*!< 0x00000002 */
-#define USB_OTG_DOEPEACHMSK1_EPDM USB_OTG_DOEPEACHMSK1_EPDM_Msk /*!< Endpoint disabled interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_TOM_Pos (3U)
-#define USB_OTG_DOEPEACHMSK1_TOM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_TOM_Pos) /*!< 0x00000008 */
-#define USB_OTG_DOEPEACHMSK1_TOM USB_OTG_DOEPEACHMSK1_TOM_Msk /*!< Timeout condition mask */
-#define USB_OTG_DOEPEACHMSK1_ITTXFEMSK_Pos (4U)
-#define USB_OTG_DOEPEACHMSK1_ITTXFEMSK_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_ITTXFEMSK_Pos) /*!< 0x00000010 */
-#define USB_OTG_DOEPEACHMSK1_ITTXFEMSK USB_OTG_DOEPEACHMSK1_ITTXFEMSK_Msk /*!< IN token received when TxFIFO empty mask */
-#define USB_OTG_DOEPEACHMSK1_INEPNMM_Pos (5U)
-#define USB_OTG_DOEPEACHMSK1_INEPNMM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_INEPNMM_Pos) /*!< 0x00000020 */
-#define USB_OTG_DOEPEACHMSK1_INEPNMM USB_OTG_DOEPEACHMSK1_INEPNMM_Msk /*!< IN token received with EP mismatch mask */
-#define USB_OTG_DOEPEACHMSK1_INEPNEM_Pos (6U)
-#define USB_OTG_DOEPEACHMSK1_INEPNEM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_INEPNEM_Pos) /*!< 0x00000040 */
-#define USB_OTG_DOEPEACHMSK1_INEPNEM USB_OTG_DOEPEACHMSK1_INEPNEM_Msk /*!< IN endpoint NAK effective mask */
-#define USB_OTG_DOEPEACHMSK1_TXFURM_Pos (8U)
-#define USB_OTG_DOEPEACHMSK1_TXFURM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_TXFURM_Pos) /*!< 0x00000100 */
-#define USB_OTG_DOEPEACHMSK1_TXFURM USB_OTG_DOEPEACHMSK1_TXFURM_Msk /*!< OUT packet error mask */
-#define USB_OTG_DOEPEACHMSK1_BIM_Pos (9U)
-#define USB_OTG_DOEPEACHMSK1_BIM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_BIM_Pos) /*!< 0x00000200 */
-#define USB_OTG_DOEPEACHMSK1_BIM USB_OTG_DOEPEACHMSK1_BIM_Msk /*!< BNA interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_BERRM_Pos (12U)
-#define USB_OTG_DOEPEACHMSK1_BERRM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_BERRM_Pos) /*!< 0x00001000 */
-#define USB_OTG_DOEPEACHMSK1_BERRM USB_OTG_DOEPEACHMSK1_BERRM_Msk /*!< Bubble error interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_NAKM_Pos (13U)
-#define USB_OTG_DOEPEACHMSK1_NAKM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_NAKM_Pos) /*!< 0x00002000 */
-#define USB_OTG_DOEPEACHMSK1_NAKM USB_OTG_DOEPEACHMSK1_NAKM_Msk /*!< NAK interrupt mask */
-#define USB_OTG_DOEPEACHMSK1_NYETM_Pos (14U)
-#define USB_OTG_DOEPEACHMSK1_NYETM_Msk (0x1UL << USB_OTG_DOEPEACHMSK1_NYETM_Pos) /*!< 0x00004000 */
-#define USB_OTG_DOEPEACHMSK1_NYETM USB_OTG_DOEPEACHMSK1_NYETM_Msk /*!< NYET interrupt mask */
-
-/******************** Bit definition for USB_OTG_HPTXFSIZ register ********************/
-#define USB_OTG_HPTXFSIZ_PTXSA_Pos (0U)
-#define USB_OTG_HPTXFSIZ_PTXSA_Msk (0xFFFFUL << USB_OTG_HPTXFSIZ_PTXSA_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_HPTXFSIZ_PTXSA USB_OTG_HPTXFSIZ_PTXSA_Msk /*!< Host periodic TxFIFO start address */
-#define USB_OTG_HPTXFSIZ_PTXFD_Pos (16U)
-#define USB_OTG_HPTXFSIZ_PTXFD_Msk (0xFFFFUL << USB_OTG_HPTXFSIZ_PTXFD_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_HPTXFSIZ_PTXFD USB_OTG_HPTXFSIZ_PTXFD_Msk /*!< Host periodic TxFIFO depth */
-
-/******************** Bit definition for USB_OTG_DIEPCTL register ********************/
-#define USB_OTG_DIEPCTL_MPSIZ_Pos (0U)
-#define USB_OTG_DIEPCTL_MPSIZ_Msk (0x7FFUL << USB_OTG_DIEPCTL_MPSIZ_Pos) /*!< 0x000007FF */
-#define USB_OTG_DIEPCTL_MPSIZ USB_OTG_DIEPCTL_MPSIZ_Msk /*!< Maximum packet size */
-#define USB_OTG_DIEPCTL_USBAEP_Pos (15U)
-#define USB_OTG_DIEPCTL_USBAEP_Msk (0x1UL << USB_OTG_DIEPCTL_USBAEP_Pos) /*!< 0x00008000 */
-#define USB_OTG_DIEPCTL_USBAEP USB_OTG_DIEPCTL_USBAEP_Msk /*!< USB active endpoint */
-#define USB_OTG_DIEPCTL_EONUM_DPID_Pos (16U)
-#define USB_OTG_DIEPCTL_EONUM_DPID_Msk (0x1UL << USB_OTG_DIEPCTL_EONUM_DPID_Pos) /*!< 0x00010000 */
-#define USB_OTG_DIEPCTL_EONUM_DPID USB_OTG_DIEPCTL_EONUM_DPID_Msk /*!< Even/odd frame */
-#define USB_OTG_DIEPCTL_NAKSTS_Pos (17U)
-#define USB_OTG_DIEPCTL_NAKSTS_Msk (0x1UL << USB_OTG_DIEPCTL_NAKSTS_Pos) /*!< 0x00020000 */
-#define USB_OTG_DIEPCTL_NAKSTS USB_OTG_DIEPCTL_NAKSTS_Msk /*!< NAK status */
-
-#define USB_OTG_DIEPCTL_EPTYP_Pos (18U)
-#define USB_OTG_DIEPCTL_EPTYP_Msk (0x3UL << USB_OTG_DIEPCTL_EPTYP_Pos) /*!< 0x000C0000 */
-#define USB_OTG_DIEPCTL_EPTYP USB_OTG_DIEPCTL_EPTYP_Msk /*!< Endpoint type */
-#define USB_OTG_DIEPCTL_EPTYP_0 (0x1UL << USB_OTG_DIEPCTL_EPTYP_Pos) /*!< 0x00040000 */
-#define USB_OTG_DIEPCTL_EPTYP_1 (0x2UL << USB_OTG_DIEPCTL_EPTYP_Pos) /*!< 0x00080000 */
-#define USB_OTG_DIEPCTL_STALL_Pos (21U)
-#define USB_OTG_DIEPCTL_STALL_Msk (0x1UL << USB_OTG_DIEPCTL_STALL_Pos) /*!< 0x00200000 */
-#define USB_OTG_DIEPCTL_STALL USB_OTG_DIEPCTL_STALL_Msk /*!< STALL handshake */
-
-#define USB_OTG_DIEPCTL_TXFNUM_Pos (22U)
-#define USB_OTG_DIEPCTL_TXFNUM_Msk (0xFUL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x03C00000 */
-#define USB_OTG_DIEPCTL_TXFNUM USB_OTG_DIEPCTL_TXFNUM_Msk /*!< TxFIFO number */
-#define USB_OTG_DIEPCTL_TXFNUM_0 (0x1UL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x00400000 */
-#define USB_OTG_DIEPCTL_TXFNUM_1 (0x2UL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x00800000 */
-#define USB_OTG_DIEPCTL_TXFNUM_2 (0x4UL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x01000000 */
-#define USB_OTG_DIEPCTL_TXFNUM_3 (0x8UL << USB_OTG_DIEPCTL_TXFNUM_Pos) /*!< 0x02000000 */
-#define USB_OTG_DIEPCTL_CNAK_Pos (26U)
-#define USB_OTG_DIEPCTL_CNAK_Msk (0x1UL << USB_OTG_DIEPCTL_CNAK_Pos) /*!< 0x04000000 */
-#define USB_OTG_DIEPCTL_CNAK USB_OTG_DIEPCTL_CNAK_Msk /*!< Clear NAK */
-#define USB_OTG_DIEPCTL_SNAK_Pos (27U)
-#define USB_OTG_DIEPCTL_SNAK_Msk (0x1UL << USB_OTG_DIEPCTL_SNAK_Pos) /*!< 0x08000000 */
-#define USB_OTG_DIEPCTL_SNAK USB_OTG_DIEPCTL_SNAK_Msk /*!< Set NAK */
-#define USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Pos (28U)
-#define USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Pos) /*!< 0x10000000 */
-#define USB_OTG_DIEPCTL_SD0PID_SEVNFRM USB_OTG_DIEPCTL_SD0PID_SEVNFRM_Msk /*!< Set DATA0 PID */
-#define USB_OTG_DIEPCTL_SODDFRM_Pos (29U)
-#define USB_OTG_DIEPCTL_SODDFRM_Msk (0x1UL << USB_OTG_DIEPCTL_SODDFRM_Pos) /*!< 0x20000000 */
-#define USB_OTG_DIEPCTL_SODDFRM USB_OTG_DIEPCTL_SODDFRM_Msk /*!< Set odd frame */
-#define USB_OTG_DIEPCTL_EPDIS_Pos (30U)
-#define USB_OTG_DIEPCTL_EPDIS_Msk (0x1UL << USB_OTG_DIEPCTL_EPDIS_Pos) /*!< 0x40000000 */
-#define USB_OTG_DIEPCTL_EPDIS USB_OTG_DIEPCTL_EPDIS_Msk /*!< Endpoint disable */
-#define USB_OTG_DIEPCTL_EPENA_Pos (31U)
-#define USB_OTG_DIEPCTL_EPENA_Msk (0x1UL << USB_OTG_DIEPCTL_EPENA_Pos) /*!< 0x80000000 */
-#define USB_OTG_DIEPCTL_EPENA USB_OTG_DIEPCTL_EPENA_Msk /*!< Endpoint enable */
-
-/******************** Bit definition for USB_OTG_HCCHAR register ********************/
-#define USB_OTG_HCCHAR_MPSIZ_Pos (0U)
-#define USB_OTG_HCCHAR_MPSIZ_Msk (0x7FFUL << USB_OTG_HCCHAR_MPSIZ_Pos) /*!< 0x000007FF */
-#define USB_OTG_HCCHAR_MPSIZ USB_OTG_HCCHAR_MPSIZ_Msk /*!< Maximum packet size */
-
-#define USB_OTG_HCCHAR_EPNUM_Pos (11U)
-#define USB_OTG_HCCHAR_EPNUM_Msk (0xFUL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00007800 */
-#define USB_OTG_HCCHAR_EPNUM USB_OTG_HCCHAR_EPNUM_Msk /*!< Endpoint number */
-#define USB_OTG_HCCHAR_EPNUM_0 (0x1UL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00000800 */
-#define USB_OTG_HCCHAR_EPNUM_1 (0x2UL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00001000 */
-#define USB_OTG_HCCHAR_EPNUM_2 (0x4UL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00002000 */
-#define USB_OTG_HCCHAR_EPNUM_3 (0x8UL << USB_OTG_HCCHAR_EPNUM_Pos) /*!< 0x00004000 */
-#define USB_OTG_HCCHAR_EPDIR_Pos (15U)
-#define USB_OTG_HCCHAR_EPDIR_Msk (0x1UL << USB_OTG_HCCHAR_EPDIR_Pos) /*!< 0x00008000 */
-#define USB_OTG_HCCHAR_EPDIR USB_OTG_HCCHAR_EPDIR_Msk /*!< Endpoint direction */
-#define USB_OTG_HCCHAR_LSDEV_Pos (17U)
-#define USB_OTG_HCCHAR_LSDEV_Msk (0x1UL << USB_OTG_HCCHAR_LSDEV_Pos) /*!< 0x00020000 */
-#define USB_OTG_HCCHAR_LSDEV USB_OTG_HCCHAR_LSDEV_Msk /*!< Low-speed device */
-
-#define USB_OTG_HCCHAR_EPTYP_Pos (18U)
-#define USB_OTG_HCCHAR_EPTYP_Msk (0x3UL << USB_OTG_HCCHAR_EPTYP_Pos) /*!< 0x000C0000 */
-#define USB_OTG_HCCHAR_EPTYP USB_OTG_HCCHAR_EPTYP_Msk /*!< Endpoint type */
-#define USB_OTG_HCCHAR_EPTYP_0 (0x1UL << USB_OTG_HCCHAR_EPTYP_Pos) /*!< 0x00040000 */
-#define USB_OTG_HCCHAR_EPTYP_1 (0x2UL << USB_OTG_HCCHAR_EPTYP_Pos) /*!< 0x00080000 */
-
-#define USB_OTG_HCCHAR_MC_Pos (20U)
-#define USB_OTG_HCCHAR_MC_Msk (0x3UL << USB_OTG_HCCHAR_MC_Pos) /*!< 0x00300000 */
-#define USB_OTG_HCCHAR_MC USB_OTG_HCCHAR_MC_Msk /*!< Multi Count (MC) / Error Count (EC) */
-#define USB_OTG_HCCHAR_MC_0 (0x1UL << USB_OTG_HCCHAR_MC_Pos) /*!< 0x00100000 */
-#define USB_OTG_HCCHAR_MC_1 (0x2UL << USB_OTG_HCCHAR_MC_Pos) /*!< 0x00200000 */
-
-#define USB_OTG_HCCHAR_DAD_Pos (22U)
-#define USB_OTG_HCCHAR_DAD_Msk (0x7FUL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x1FC00000 */
-#define USB_OTG_HCCHAR_DAD USB_OTG_HCCHAR_DAD_Msk /*!< Device address */
-#define USB_OTG_HCCHAR_DAD_0 (0x01UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x00400000 */
-#define USB_OTG_HCCHAR_DAD_1 (0x02UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x00800000 */
-#define USB_OTG_HCCHAR_DAD_2 (0x04UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x01000000 */
-#define USB_OTG_HCCHAR_DAD_3 (0x08UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x02000000 */
-#define USB_OTG_HCCHAR_DAD_4 (0x10UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x04000000 */
-#define USB_OTG_HCCHAR_DAD_5 (0x20UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x08000000 */
-#define USB_OTG_HCCHAR_DAD_6 (0x40UL << USB_OTG_HCCHAR_DAD_Pos) /*!< 0x10000000 */
-#define USB_OTG_HCCHAR_ODDFRM_Pos (29U)
-#define USB_OTG_HCCHAR_ODDFRM_Msk (0x1UL << USB_OTG_HCCHAR_ODDFRM_Pos) /*!< 0x20000000 */
-#define USB_OTG_HCCHAR_ODDFRM USB_OTG_HCCHAR_ODDFRM_Msk /*!< Odd frame */
-#define USB_OTG_HCCHAR_CHDIS_Pos (30U)
-#define USB_OTG_HCCHAR_CHDIS_Msk (0x1UL << USB_OTG_HCCHAR_CHDIS_Pos) /*!< 0x40000000 */
-#define USB_OTG_HCCHAR_CHDIS USB_OTG_HCCHAR_CHDIS_Msk /*!< Channel disable */
-#define USB_OTG_HCCHAR_CHENA_Pos (31U)
-#define USB_OTG_HCCHAR_CHENA_Msk (0x1UL << USB_OTG_HCCHAR_CHENA_Pos) /*!< 0x80000000 */
-#define USB_OTG_HCCHAR_CHENA USB_OTG_HCCHAR_CHENA_Msk /*!< Channel enable */
-
-/******************** Bit definition for USB_OTG_HCSPLT register ********************/
-
-#define USB_OTG_HCSPLT_PRTADDR_Pos (0U)
-#define USB_OTG_HCSPLT_PRTADDR_Msk (0x7FUL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x0000007F */
-#define USB_OTG_HCSPLT_PRTADDR USB_OTG_HCSPLT_PRTADDR_Msk /*!< Port address */
-#define USB_OTG_HCSPLT_PRTADDR_0 (0x01UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000001 */
-#define USB_OTG_HCSPLT_PRTADDR_1 (0x02UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000002 */
-#define USB_OTG_HCSPLT_PRTADDR_2 (0x04UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000004 */
-#define USB_OTG_HCSPLT_PRTADDR_3 (0x08UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000008 */
-#define USB_OTG_HCSPLT_PRTADDR_4 (0x10UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000010 */
-#define USB_OTG_HCSPLT_PRTADDR_5 (0x20UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000020 */
-#define USB_OTG_HCSPLT_PRTADDR_6 (0x40UL << USB_OTG_HCSPLT_PRTADDR_Pos) /*!< 0x00000040 */
-
-#define USB_OTG_HCSPLT_HUBADDR_Pos (7U)
-#define USB_OTG_HCSPLT_HUBADDR_Msk (0x7FUL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00003F80 */
-#define USB_OTG_HCSPLT_HUBADDR USB_OTG_HCSPLT_HUBADDR_Msk /*!< Hub address */
-#define USB_OTG_HCSPLT_HUBADDR_0 (0x01UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000080 */
-#define USB_OTG_HCSPLT_HUBADDR_1 (0x02UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000100 */
-#define USB_OTG_HCSPLT_HUBADDR_2 (0x04UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000200 */
-#define USB_OTG_HCSPLT_HUBADDR_3 (0x08UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000400 */
-#define USB_OTG_HCSPLT_HUBADDR_4 (0x10UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00000800 */
-#define USB_OTG_HCSPLT_HUBADDR_5 (0x20UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00001000 */
-#define USB_OTG_HCSPLT_HUBADDR_6 (0x40UL << USB_OTG_HCSPLT_HUBADDR_Pos) /*!< 0x00002000 */
-
-#define USB_OTG_HCSPLT_XACTPOS_Pos (14U)
-#define USB_OTG_HCSPLT_XACTPOS_Msk (0x3UL << USB_OTG_HCSPLT_XACTPOS_Pos) /*!< 0x0000C000 */
-#define USB_OTG_HCSPLT_XACTPOS USB_OTG_HCSPLT_XACTPOS_Msk /*!< XACTPOS */
-#define USB_OTG_HCSPLT_XACTPOS_0 (0x1UL << USB_OTG_HCSPLT_XACTPOS_Pos) /*!< 0x00004000 */
-#define USB_OTG_HCSPLT_XACTPOS_1 (0x2UL << USB_OTG_HCSPLT_XACTPOS_Pos) /*!< 0x00008000 */
-#define USB_OTG_HCSPLT_COMPLSPLT_Pos (16U)
-#define USB_OTG_HCSPLT_COMPLSPLT_Msk (0x1UL << USB_OTG_HCSPLT_COMPLSPLT_Pos) /*!< 0x00010000 */
-#define USB_OTG_HCSPLT_COMPLSPLT USB_OTG_HCSPLT_COMPLSPLT_Msk /*!< Do complete split */
-#define USB_OTG_HCSPLT_SPLITEN_Pos (31U)
-#define USB_OTG_HCSPLT_SPLITEN_Msk (0x1UL << USB_OTG_HCSPLT_SPLITEN_Pos) /*!< 0x80000000 */
-#define USB_OTG_HCSPLT_SPLITEN USB_OTG_HCSPLT_SPLITEN_Msk /*!< Split enable */
-
-/******************** Bit definition for USB_OTG_HCINT register ********************/
-#define USB_OTG_HCINT_XFRC_Pos (0U)
-#define USB_OTG_HCINT_XFRC_Msk (0x1UL << USB_OTG_HCINT_XFRC_Pos) /*!< 0x00000001 */
-#define USB_OTG_HCINT_XFRC USB_OTG_HCINT_XFRC_Msk /*!< Transfer completed */
-#define USB_OTG_HCINT_CHH_Pos (1U)
-#define USB_OTG_HCINT_CHH_Msk (0x1UL << USB_OTG_HCINT_CHH_Pos) /*!< 0x00000002 */
-#define USB_OTG_HCINT_CHH USB_OTG_HCINT_CHH_Msk /*!< Channel halted */
-#define USB_OTG_HCINT_AHBERR_Pos (2U)
-#define USB_OTG_HCINT_AHBERR_Msk (0x1UL << USB_OTG_HCINT_AHBERR_Pos) /*!< 0x00000004 */
-#define USB_OTG_HCINT_AHBERR USB_OTG_HCINT_AHBERR_Msk /*!< AHB error */
-#define USB_OTG_HCINT_STALL_Pos (3U)
-#define USB_OTG_HCINT_STALL_Msk (0x1UL << USB_OTG_HCINT_STALL_Pos) /*!< 0x00000008 */
-#define USB_OTG_HCINT_STALL USB_OTG_HCINT_STALL_Msk /*!< STALL response received interrupt */
-#define USB_OTG_HCINT_NAK_Pos (4U)
-#define USB_OTG_HCINT_NAK_Msk (0x1UL << USB_OTG_HCINT_NAK_Pos) /*!< 0x00000010 */
-#define USB_OTG_HCINT_NAK USB_OTG_HCINT_NAK_Msk /*!< NAK response received interrupt */
-#define USB_OTG_HCINT_ACK_Pos (5U)
-#define USB_OTG_HCINT_ACK_Msk (0x1UL << USB_OTG_HCINT_ACK_Pos) /*!< 0x00000020 */
-#define USB_OTG_HCINT_ACK USB_OTG_HCINT_ACK_Msk /*!< ACK response received/transmitted interrupt */
-#define USB_OTG_HCINT_NYET_Pos (6U)
-#define USB_OTG_HCINT_NYET_Msk (0x1UL << USB_OTG_HCINT_NYET_Pos) /*!< 0x00000040 */
-#define USB_OTG_HCINT_NYET USB_OTG_HCINT_NYET_Msk /*!< Response received interrupt */
-#define USB_OTG_HCINT_TXERR_Pos (7U)
-#define USB_OTG_HCINT_TXERR_Msk (0x1UL << USB_OTG_HCINT_TXERR_Pos) /*!< 0x00000080 */
-#define USB_OTG_HCINT_TXERR USB_OTG_HCINT_TXERR_Msk /*!< Transaction error */
-#define USB_OTG_HCINT_BBERR_Pos (8U)
-#define USB_OTG_HCINT_BBERR_Msk (0x1UL << USB_OTG_HCINT_BBERR_Pos) /*!< 0x00000100 */
-#define USB_OTG_HCINT_BBERR USB_OTG_HCINT_BBERR_Msk /*!< Babble error */
-#define USB_OTG_HCINT_FRMOR_Pos (9U)
-#define USB_OTG_HCINT_FRMOR_Msk (0x1UL << USB_OTG_HCINT_FRMOR_Pos) /*!< 0x00000200 */
-#define USB_OTG_HCINT_FRMOR USB_OTG_HCINT_FRMOR_Msk /*!< Frame overrun */
-#define USB_OTG_HCINT_DTERR_Pos (10U)
-#define USB_OTG_HCINT_DTERR_Msk (0x1UL << USB_OTG_HCINT_DTERR_Pos) /*!< 0x00000400 */
-#define USB_OTG_HCINT_DTERR USB_OTG_HCINT_DTERR_Msk /*!< Data toggle error */
-
-/******************** Bit definition for USB_OTG_DIEPINT register ********************/
-#define USB_OTG_DIEPINT_XFRC_Pos (0U)
-#define USB_OTG_DIEPINT_XFRC_Msk (0x1UL << USB_OTG_DIEPINT_XFRC_Pos) /*!< 0x00000001 */
-#define USB_OTG_DIEPINT_XFRC USB_OTG_DIEPINT_XFRC_Msk /*!< Transfer completed interrupt */
-#define USB_OTG_DIEPINT_EPDISD_Pos (1U)
-#define USB_OTG_DIEPINT_EPDISD_Msk (0x1UL << USB_OTG_DIEPINT_EPDISD_Pos) /*!< 0x00000002 */
-#define USB_OTG_DIEPINT_EPDISD USB_OTG_DIEPINT_EPDISD_Msk /*!< Endpoint disabled interrupt */
-#define USB_OTG_DIEPINT_AHBERR_Pos (2U)
-#define USB_OTG_DIEPINT_AHBERR_Msk (0x1UL << USB_OTG_DIEPINT_AHBERR_Pos) /*!< 0x00000004 */
-#define USB_OTG_DIEPINT_AHBERR USB_OTG_DIEPINT_AHBERR_Msk /*!< AHB Error (AHBErr) during an IN transaction */
-#define USB_OTG_DIEPINT_TOC_Pos (3U)
-#define USB_OTG_DIEPINT_TOC_Msk (0x1UL << USB_OTG_DIEPINT_TOC_Pos) /*!< 0x00000008 */
-#define USB_OTG_DIEPINT_TOC USB_OTG_DIEPINT_TOC_Msk /*!< Timeout condition */
-#define USB_OTG_DIEPINT_ITTXFE_Pos (4U)
-#define USB_OTG_DIEPINT_ITTXFE_Msk (0x1UL << USB_OTG_DIEPINT_ITTXFE_Pos) /*!< 0x00000010 */
-#define USB_OTG_DIEPINT_ITTXFE USB_OTG_DIEPINT_ITTXFE_Msk /*!< IN token received when TxFIFO is empty */
-#define USB_OTG_DIEPINT_INEPNM_Pos (5U)
-#define USB_OTG_DIEPINT_INEPNM_Msk (0x1UL << USB_OTG_DIEPINT_INEPNM_Pos) /*!< 0x00000004 */
-#define USB_OTG_DIEPINT_INEPNM USB_OTG_DIEPINT_INEPNM_Msk /*!< IN token received with EP mismatch */
-#define USB_OTG_DIEPINT_INEPNE_Pos (6U)
-#define USB_OTG_DIEPINT_INEPNE_Msk (0x1UL << USB_OTG_DIEPINT_INEPNE_Pos) /*!< 0x00000040 */
-#define USB_OTG_DIEPINT_INEPNE USB_OTG_DIEPINT_INEPNE_Msk /*!< IN endpoint NAK effective */
-#define USB_OTG_DIEPINT_TXFE_Pos (7U)
-#define USB_OTG_DIEPINT_TXFE_Msk (0x1UL << USB_OTG_DIEPINT_TXFE_Pos) /*!< 0x00000080 */
-#define USB_OTG_DIEPINT_TXFE USB_OTG_DIEPINT_TXFE_Msk /*!< Transmit FIFO empty */
-#define USB_OTG_DIEPINT_TXFIFOUDRN_Pos (8U)
-#define USB_OTG_DIEPINT_TXFIFOUDRN_Msk (0x1UL << USB_OTG_DIEPINT_TXFIFOUDRN_Pos) /*!< 0x00000100 */
-#define USB_OTG_DIEPINT_TXFIFOUDRN USB_OTG_DIEPINT_TXFIFOUDRN_Msk /*!< Transmit Fifo Underrun */
-#define USB_OTG_DIEPINT_BNA_Pos (9U)
-#define USB_OTG_DIEPINT_BNA_Msk (0x1UL << USB_OTG_DIEPINT_BNA_Pos) /*!< 0x00000200 */
-#define USB_OTG_DIEPINT_BNA USB_OTG_DIEPINT_BNA_Msk /*!< Buffer not available interrupt */
-#define USB_OTG_DIEPINT_PKTDRPSTS_Pos (11U)
-#define USB_OTG_DIEPINT_PKTDRPSTS_Msk (0x1UL << USB_OTG_DIEPINT_PKTDRPSTS_Pos) /*!< 0x00000800 */
-#define USB_OTG_DIEPINT_PKTDRPSTS USB_OTG_DIEPINT_PKTDRPSTS_Msk /*!< Packet dropped status */
-#define USB_OTG_DIEPINT_BERR_Pos (12U)
-#define USB_OTG_DIEPINT_BERR_Msk (0x1UL << USB_OTG_DIEPINT_BERR_Pos) /*!< 0x00001000 */
-#define USB_OTG_DIEPINT_BERR USB_OTG_DIEPINT_BERR_Msk /*!< Babble error interrupt */
-#define USB_OTG_DIEPINT_NAK_Pos (13U)
-#define USB_OTG_DIEPINT_NAK_Msk (0x1UL << USB_OTG_DIEPINT_NAK_Pos) /*!< 0x00002000 */
-#define USB_OTG_DIEPINT_NAK USB_OTG_DIEPINT_NAK_Msk /*!< NAK interrupt */
-
-/******************** Bit definition for USB_OTG_HCINTMSK register ********************/
-#define USB_OTG_HCINTMSK_XFRCM_Pos (0U)
-#define USB_OTG_HCINTMSK_XFRCM_Msk (0x1UL << USB_OTG_HCINTMSK_XFRCM_Pos) /*!< 0x00000001 */
-#define USB_OTG_HCINTMSK_XFRCM USB_OTG_HCINTMSK_XFRCM_Msk /*!< Transfer completed mask */
-#define USB_OTG_HCINTMSK_CHHM_Pos (1U)
-#define USB_OTG_HCINTMSK_CHHM_Msk (0x1UL << USB_OTG_HCINTMSK_CHHM_Pos) /*!< 0x00000002 */
-#define USB_OTG_HCINTMSK_CHHM USB_OTG_HCINTMSK_CHHM_Msk /*!< Channel halted mask */
-#define USB_OTG_HCINTMSK_AHBERR_Pos (2U)
-#define USB_OTG_HCINTMSK_AHBERR_Msk (0x1UL << USB_OTG_HCINTMSK_AHBERR_Pos) /*!< 0x00000004 */
-#define USB_OTG_HCINTMSK_AHBERR USB_OTG_HCINTMSK_AHBERR_Msk /*!< AHB error */
-#define USB_OTG_HCINTMSK_STALLM_Pos (3U)
-#define USB_OTG_HCINTMSK_STALLM_Msk (0x1UL << USB_OTG_HCINTMSK_STALLM_Pos) /*!< 0x00000008 */
-#define USB_OTG_HCINTMSK_STALLM USB_OTG_HCINTMSK_STALLM_Msk /*!< STALL response received interrupt mask */
-#define USB_OTG_HCINTMSK_NAKM_Pos (4U)
-#define USB_OTG_HCINTMSK_NAKM_Msk (0x1UL << USB_OTG_HCINTMSK_NAKM_Pos) /*!< 0x00000010 */
-#define USB_OTG_HCINTMSK_NAKM USB_OTG_HCINTMSK_NAKM_Msk /*!< NAK response received interrupt mask */
-#define USB_OTG_HCINTMSK_ACKM_Pos (5U)
-#define USB_OTG_HCINTMSK_ACKM_Msk (0x1UL << USB_OTG_HCINTMSK_ACKM_Pos) /*!< 0x00000020 */
-#define USB_OTG_HCINTMSK_ACKM USB_OTG_HCINTMSK_ACKM_Msk /*!< ACK response received/transmitted interrupt mask */
-#define USB_OTG_HCINTMSK_NYET_Pos (6U)
-#define USB_OTG_HCINTMSK_NYET_Msk (0x1UL << USB_OTG_HCINTMSK_NYET_Pos) /*!< 0x00000040 */
-#define USB_OTG_HCINTMSK_NYET USB_OTG_HCINTMSK_NYET_Msk /*!< response received interrupt mask */
-#define USB_OTG_HCINTMSK_TXERRM_Pos (7U)
-#define USB_OTG_HCINTMSK_TXERRM_Msk (0x1UL << USB_OTG_HCINTMSK_TXERRM_Pos) /*!< 0x00000080 */
-#define USB_OTG_HCINTMSK_TXERRM USB_OTG_HCINTMSK_TXERRM_Msk /*!< Transaction error mask */
-#define USB_OTG_HCINTMSK_BBERRM_Pos (8U)
-#define USB_OTG_HCINTMSK_BBERRM_Msk (0x1UL << USB_OTG_HCINTMSK_BBERRM_Pos) /*!< 0x00000100 */
-#define USB_OTG_HCINTMSK_BBERRM USB_OTG_HCINTMSK_BBERRM_Msk /*!< Babble error mask */
-#define USB_OTG_HCINTMSK_FRMORM_Pos (9U)
-#define USB_OTG_HCINTMSK_FRMORM_Msk (0x1UL << USB_OTG_HCINTMSK_FRMORM_Pos) /*!< 0x00000200 */
-#define USB_OTG_HCINTMSK_FRMORM USB_OTG_HCINTMSK_FRMORM_Msk /*!< Frame overrun mask */
-#define USB_OTG_HCINTMSK_DTERRM_Pos (10U)
-#define USB_OTG_HCINTMSK_DTERRM_Msk (0x1UL << USB_OTG_HCINTMSK_DTERRM_Pos) /*!< 0x00000400 */
-#define USB_OTG_HCINTMSK_DTERRM USB_OTG_HCINTMSK_DTERRM_Msk /*!< Data toggle error mask */
-
-/******************** Bit definition for USB_OTG_DIEPTSIZ register ********************/
-
-#define USB_OTG_DIEPTSIZ_XFRSIZ_Pos (0U)
-#define USB_OTG_DIEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << USB_OTG_DIEPTSIZ_XFRSIZ_Pos) /*!< 0x0007FFFF */
-#define USB_OTG_DIEPTSIZ_XFRSIZ USB_OTG_DIEPTSIZ_XFRSIZ_Msk /*!< Transfer size */
-#define USB_OTG_DIEPTSIZ_PKTCNT_Pos (19U)
-#define USB_OTG_DIEPTSIZ_PKTCNT_Msk (0x3FFUL << USB_OTG_DIEPTSIZ_PKTCNT_Pos) /*!< 0x1FF80000 */
-#define USB_OTG_DIEPTSIZ_PKTCNT USB_OTG_DIEPTSIZ_PKTCNT_Msk /*!< Packet count */
-#define USB_OTG_DIEPTSIZ_MULCNT_Pos (29U)
-#define USB_OTG_DIEPTSIZ_MULCNT_Msk (0x3UL << USB_OTG_DIEPTSIZ_MULCNT_Pos) /*!< 0x60000000 */
-#define USB_OTG_DIEPTSIZ_MULCNT USB_OTG_DIEPTSIZ_MULCNT_Msk /*!< Packet count */
-/******************** Bit definition for USB_OTG_HCTSIZ register ********************/
-#define USB_OTG_HCTSIZ_XFRSIZ_Pos (0U)
-#define USB_OTG_HCTSIZ_XFRSIZ_Msk (0x7FFFFUL << USB_OTG_HCTSIZ_XFRSIZ_Pos) /*!< 0x0007FFFF */
-#define USB_OTG_HCTSIZ_XFRSIZ USB_OTG_HCTSIZ_XFRSIZ_Msk /*!< Transfer size */
-#define USB_OTG_HCTSIZ_PKTCNT_Pos (19U)
-#define USB_OTG_HCTSIZ_PKTCNT_Msk (0x3FFUL << USB_OTG_HCTSIZ_PKTCNT_Pos) /*!< 0x1FF80000 */
-#define USB_OTG_HCTSIZ_PKTCNT USB_OTG_HCTSIZ_PKTCNT_Msk /*!< Packet count */
-#define USB_OTG_HCTSIZ_DOPING_Pos (31U)
-#define USB_OTG_HCTSIZ_DOPING_Msk (0x1UL << USB_OTG_HCTSIZ_DOPING_Pos) /*!< 0x80000000 */
-#define USB_OTG_HCTSIZ_DOPING USB_OTG_HCTSIZ_DOPING_Msk /*!< Do PING */
-#define USB_OTG_HCTSIZ_DPID_Pos (29U)
-#define USB_OTG_HCTSIZ_DPID_Msk (0x3UL << USB_OTG_HCTSIZ_DPID_Pos) /*!< 0x60000000 */
-#define USB_OTG_HCTSIZ_DPID USB_OTG_HCTSIZ_DPID_Msk /*!< Data PID */
-#define USB_OTG_HCTSIZ_DPID_0 (0x1UL << USB_OTG_HCTSIZ_DPID_Pos) /*!< 0x20000000 */
-#define USB_OTG_HCTSIZ_DPID_1 (0x2UL << USB_OTG_HCTSIZ_DPID_Pos) /*!< 0x40000000 */
-
-/******************** Bit definition for USB_OTG_DIEPDMA register ********************/
-#define USB_OTG_DIEPDMA_DMAADDR_Pos (0U)
-#define USB_OTG_DIEPDMA_DMAADDR_Msk (0xFFFFFFFFUL << USB_OTG_DIEPDMA_DMAADDR_Pos) /*!< 0xFFFFFFFF */
-#define USB_OTG_DIEPDMA_DMAADDR USB_OTG_DIEPDMA_DMAADDR_Msk /*!< DMA address */
-
-/******************** Bit definition for USB_OTG_HCDMA register ********************/
-#define USB_OTG_HCDMA_DMAADDR_Pos (0U)
-#define USB_OTG_HCDMA_DMAADDR_Msk (0xFFFFFFFFUL << USB_OTG_HCDMA_DMAADDR_Pos) /*!< 0xFFFFFFFF */
-#define USB_OTG_HCDMA_DMAADDR USB_OTG_HCDMA_DMAADDR_Msk /*!< DMA address */
-
-/******************** Bit definition for USB_OTG_DTXFSTS register ********************/
-#define USB_OTG_DTXFSTS_INEPTFSAV_Pos (0U)
-#define USB_OTG_DTXFSTS_INEPTFSAV_Msk (0xFFFFUL << USB_OTG_DTXFSTS_INEPTFSAV_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DTXFSTS_INEPTFSAV USB_OTG_DTXFSTS_INEPTFSAV_Msk /*!< IN endpoint TxFIFO space available */
-
-/******************** Bit definition for USB_OTG_DIEPTXF register ********************/
-#define USB_OTG_DIEPTXF_INEPTXSA_Pos (0U)
-#define USB_OTG_DIEPTXF_INEPTXSA_Msk (0xFFFFUL << USB_OTG_DIEPTXF_INEPTXSA_Pos) /*!< 0x0000FFFF */
-#define USB_OTG_DIEPTXF_INEPTXSA USB_OTG_DIEPTXF_INEPTXSA_Msk /*!< IN endpoint FIFOx transmit RAM start address */
-#define USB_OTG_DIEPTXF_INEPTXFD_Pos (16U)
-#define USB_OTG_DIEPTXF_INEPTXFD_Msk (0xFFFFUL << USB_OTG_DIEPTXF_INEPTXFD_Pos) /*!< 0xFFFF0000 */
-#define USB_OTG_DIEPTXF_INEPTXFD USB_OTG_DIEPTXF_INEPTXFD_Msk /*!< IN endpoint TxFIFO depth */
-
-/******************** Bit definition for USB_OTG_DOEPCTL register ********************/
-
-#define USB_OTG_DOEPCTL_MPSIZ_Pos (0U)
-#define USB_OTG_DOEPCTL_MPSIZ_Msk (0x7FFUL << USB_OTG_DOEPCTL_MPSIZ_Pos) /*!< 0x000007FF */
-#define USB_OTG_DOEPCTL_MPSIZ USB_OTG_DOEPCTL_MPSIZ_Msk /*!< Maximum packet size */ /*!<Bit 1 */
-#define USB_OTG_DOEPCTL_USBAEP_Pos (15U)
-#define USB_OTG_DOEPCTL_USBAEP_Msk (0x1UL << USB_OTG_DOEPCTL_USBAEP_Pos) /*!< 0x00008000 */
-#define USB_OTG_DOEPCTL_USBAEP USB_OTG_DOEPCTL_USBAEP_Msk /*!< USB active endpoint */
-#define USB_OTG_DOEPCTL_NAKSTS_Pos (17U)
-#define USB_OTG_DOEPCTL_NAKSTS_Msk (0x1UL << USB_OTG_DOEPCTL_NAKSTS_Pos) /*!< 0x00020000 */
-#define USB_OTG_DOEPCTL_NAKSTS USB_OTG_DOEPCTL_NAKSTS_Msk /*!< NAK status */
-#define USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Pos (28U)
-#define USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Msk (0x1UL << USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Pos) /*!< 0x10000000 */
-#define USB_OTG_DOEPCTL_SD0PID_SEVNFRM USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Msk /*!< Set DATA0 PID */
-#define USB_OTG_DOEPCTL_SODDFRM_Pos (29U)
-#define USB_OTG_DOEPCTL_SODDFRM_Msk (0x1UL << USB_OTG_DOEPCTL_SODDFRM_Pos) /*!< 0x20000000 */
-#define USB_OTG_DOEPCTL_SODDFRM USB_OTG_DOEPCTL_SODDFRM_Msk /*!< Set odd frame */
-#define USB_OTG_DOEPCTL_EPTYP_Pos (18U)
-#define USB_OTG_DOEPCTL_EPTYP_Msk (0x3UL << USB_OTG_DOEPCTL_EPTYP_Pos) /*!< 0x000C0000 */
-#define USB_OTG_DOEPCTL_EPTYP USB_OTG_DOEPCTL_EPTYP_Msk /*!< Endpoint type */
-#define USB_OTG_DOEPCTL_EPTYP_0 (0x1UL << USB_OTG_DOEPCTL_EPTYP_Pos) /*!< 0x00040000 */
-#define USB_OTG_DOEPCTL_EPTYP_1 (0x2UL << USB_OTG_DOEPCTL_EPTYP_Pos) /*!< 0x00080000 */
-#define USB_OTG_DOEPCTL_SNPM_Pos (20U)
-#define USB_OTG_DOEPCTL_SNPM_Msk (0x1UL << USB_OTG_DOEPCTL_SNPM_Pos) /*!< 0x00100000 */
-#define USB_OTG_DOEPCTL_SNPM USB_OTG_DOEPCTL_SNPM_Msk /*!< Snoop mode */
-#define USB_OTG_DOEPCTL_STALL_Pos (21U)
-#define USB_OTG_DOEPCTL_STALL_Msk (0x1UL << USB_OTG_DOEPCTL_STALL_Pos) /*!< 0x00200000 */
-#define USB_OTG_DOEPCTL_STALL USB_OTG_DOEPCTL_STALL_Msk /*!< STALL handshake */
-#define USB_OTG_DOEPCTL_CNAK_Pos (26U)
-#define USB_OTG_DOEPCTL_CNAK_Msk (0x1UL << USB_OTG_DOEPCTL_CNAK_Pos) /*!< 0x04000000 */
-#define USB_OTG_DOEPCTL_CNAK USB_OTG_DOEPCTL_CNAK_Msk /*!< Clear NAK */
-#define USB_OTG_DOEPCTL_SNAK_Pos (27U)
-#define USB_OTG_DOEPCTL_SNAK_Msk (0x1UL << USB_OTG_DOEPCTL_SNAK_Pos) /*!< 0x08000000 */
-#define USB_OTG_DOEPCTL_SNAK USB_OTG_DOEPCTL_SNAK_Msk /*!< Set NAK */
-#define USB_OTG_DOEPCTL_EPDIS_Pos (30U)
-#define USB_OTG_DOEPCTL_EPDIS_Msk (0x1UL << USB_OTG_DOEPCTL_EPDIS_Pos) /*!< 0x40000000 */
-#define USB_OTG_DOEPCTL_EPDIS USB_OTG_DOEPCTL_EPDIS_Msk /*!< Endpoint disable */
-#define USB_OTG_DOEPCTL_EPENA_Pos (31U)
-#define USB_OTG_DOEPCTL_EPENA_Msk (0x1UL << USB_OTG_DOEPCTL_EPENA_Pos) /*!< 0x80000000 */
-#define USB_OTG_DOEPCTL_EPENA USB_OTG_DOEPCTL_EPENA_Msk /*!< Endpoint enable */
-
-/******************** Bit definition for USB_OTG_DOEPINT register ********************/
-#define USB_OTG_DOEPINT_XFRC_Pos (0U)
-#define USB_OTG_DOEPINT_XFRC_Msk (0x1UL << USB_OTG_DOEPINT_XFRC_Pos) /*!< 0x00000001 */
-#define USB_OTG_DOEPINT_XFRC USB_OTG_DOEPINT_XFRC_Msk /*!< Transfer completed interrupt */
-#define USB_OTG_DOEPINT_EPDISD_Pos (1U)
-#define USB_OTG_DOEPINT_EPDISD_Msk (0x1UL << USB_OTG_DOEPINT_EPDISD_Pos) /*!< 0x00000002 */
-#define USB_OTG_DOEPINT_EPDISD USB_OTG_DOEPINT_EPDISD_Msk /*!< Endpoint disabled interrupt */
-#define USB_OTG_DOEPINT_AHBERR_Pos (2U)
-#define USB_OTG_DOEPINT_AHBERR_Msk (0x1UL << USB_OTG_DOEPINT_AHBERR_Pos) /*!< 0x00000004 */
-#define USB_OTG_DOEPINT_AHBERR USB_OTG_DOEPINT_AHBERR_Msk /*!< AHB Error (AHBErr) during an OUT transaction */
-#define USB_OTG_DOEPINT_STUP_Pos (3U)
-#define USB_OTG_DOEPINT_STUP_Msk (0x1UL << USB_OTG_DOEPINT_STUP_Pos) /*!< 0x00000008 */
-#define USB_OTG_DOEPINT_STUP USB_OTG_DOEPINT_STUP_Msk /*!< SETUP phase done */
-#define USB_OTG_DOEPINT_OTEPDIS_Pos (4U)
-#define USB_OTG_DOEPINT_OTEPDIS_Msk (0x1UL << USB_OTG_DOEPINT_OTEPDIS_Pos) /*!< 0x00000010 */
-#define USB_OTG_DOEPINT_OTEPDIS USB_OTG_DOEPINT_OTEPDIS_Msk /*!< OUT token received when endpoint disabled */
-#define USB_OTG_DOEPINT_OTEPSPR_Pos (5U)
-#define USB_OTG_DOEPINT_OTEPSPR_Msk (0x1UL << USB_OTG_DOEPINT_OTEPSPR_Pos) /*!< 0x00000020 */
-#define USB_OTG_DOEPINT_OTEPSPR USB_OTG_DOEPINT_OTEPSPR_Msk /*!< Status Phase Received For Control Write */
-#define USB_OTG_DOEPINT_B2BSTUP_Pos (6U)
-#define USB_OTG_DOEPINT_B2BSTUP_Msk (0x1UL << USB_OTG_DOEPINT_B2BSTUP_Pos) /*!< 0x00000040 */
-#define USB_OTG_DOEPINT_B2BSTUP USB_OTG_DOEPINT_B2BSTUP_Msk /*!< Back-to-back SETUP packets received */
-#define USB_OTG_DOEPINT_OUTPKTERR_Pos (8U)
-#define USB_OTG_DOEPINT_OUTPKTERR_Msk (0x1UL << USB_OTG_DOEPINT_OUTPKTERR_Pos) /*!< 0x00000100 */
-#define USB_OTG_DOEPINT_OUTPKTERR USB_OTG_DOEPINT_OUTPKTERR_Msk /*!< OUT packet error */
-#define USB_OTG_DOEPINT_NAK_Pos (13U)
-#define USB_OTG_DOEPINT_NAK_Msk (0x1UL << USB_OTG_DOEPINT_NAK_Pos) /*!< 0x00002000 */
-#define USB_OTG_DOEPINT_NAK USB_OTG_DOEPINT_NAK_Msk /*!< NAK Packet is transmitted by the device */
-#define USB_OTG_DOEPINT_NYET_Pos (14U)
-#define USB_OTG_DOEPINT_NYET_Msk (0x1UL << USB_OTG_DOEPINT_NYET_Pos) /*!< 0x00004000 */
-#define USB_OTG_DOEPINT_NYET USB_OTG_DOEPINT_NYET_Msk /*!< NYET interrupt */
-#define USB_OTG_DOEPINT_STPKTRX_Pos (15U)
-#define USB_OTG_DOEPINT_STPKTRX_Msk (0x1UL << USB_OTG_DOEPINT_STPKTRX_Pos) /*!< 0x00008000 */
-#define USB_OTG_DOEPINT_STPKTRX USB_OTG_DOEPINT_STPKTRX_Msk /*!< Setup Packet Received */
-/******************** Bit definition for USB_OTG_DOEPTSIZ register ********************/
-
-#define USB_OTG_DOEPTSIZ_XFRSIZ_Pos (0U)
-#define USB_OTG_DOEPTSIZ_XFRSIZ_Msk (0x7FFFFUL << USB_OTG_DOEPTSIZ_XFRSIZ_Pos) /*!< 0x0007FFFF */
-#define USB_OTG_DOEPTSIZ_XFRSIZ USB_OTG_DOEPTSIZ_XFRSIZ_Msk /*!< Transfer size */
-#define USB_OTG_DOEPTSIZ_PKTCNT_Pos (19U)
-#define USB_OTG_DOEPTSIZ_PKTCNT_Msk (0x3FFUL << USB_OTG_DOEPTSIZ_PKTCNT_Pos) /*!< 0x1FF80000 */
-#define USB_OTG_DOEPTSIZ_PKTCNT USB_OTG_DOEPTSIZ_PKTCNT_Msk /*!< Packet count */
-
-#define USB_OTG_DOEPTSIZ_STUPCNT_Pos (29U)
-#define USB_OTG_DOEPTSIZ_STUPCNT_Msk (0x3UL << USB_OTG_DOEPTSIZ_STUPCNT_Pos) /*!< 0x60000000 */
-#define USB_OTG_DOEPTSIZ_STUPCNT USB_OTG_DOEPTSIZ_STUPCNT_Msk /*!< SETUP packet count */
-#define USB_OTG_DOEPTSIZ_STUPCNT_0 (0x1UL << USB_OTG_DOEPTSIZ_STUPCNT_Pos) /*!< 0x20000000 */
-#define USB_OTG_DOEPTSIZ_STUPCNT_1 (0x2UL << USB_OTG_DOEPTSIZ_STUPCNT_Pos) /*!< 0x40000000 */
-
-/******************** Bit definition for PCGCCTL register ********************/
-#define USB_OTG_PCGCCTL_STOPCLK_Pos (0U)
-#define USB_OTG_PCGCCTL_STOPCLK_Msk (0x1UL << USB_OTG_PCGCCTL_STOPCLK_Pos) /*!< 0x00000001 */
-#define USB_OTG_PCGCCTL_STOPCLK USB_OTG_PCGCCTL_STOPCLK_Msk /*!< SETUP packet count */
-#define USB_OTG_PCGCCTL_GATECLK_Pos (1U)
-#define USB_OTG_PCGCCTL_GATECLK_Msk (0x1UL << USB_OTG_PCGCCTL_GATECLK_Pos) /*!< 0x00000002 */
-#define USB_OTG_PCGCCTL_GATECLK USB_OTG_PCGCCTL_GATECLK_Msk /*!<Bit 0 */
-#define USB_OTG_PCGCCTL_PHYSUSP_Pos (4U)
-#define USB_OTG_PCGCCTL_PHYSUSP_Msk (0x1UL << USB_OTG_PCGCCTL_PHYSUSP_Pos) /*!< 0x00000010 */
-#define USB_OTG_PCGCCTL_PHYSUSP USB_OTG_PCGCCTL_PHYSUSP_Msk /*!<Bit 1 */
-
-/* Legacy define */
-/******************** Bit definition for OTG register ********************/
-#define USB_OTG_CHNUM_Pos (0U)
-#define USB_OTG_CHNUM_Msk (0xFUL << USB_OTG_CHNUM_Pos) /*!< 0x0000000F */
-#define USB_OTG_CHNUM USB_OTG_CHNUM_Msk /*!< Channel number */
-#define USB_OTG_CHNUM_0 (0x1UL << USB_OTG_CHNUM_Pos) /*!< 0x00000001 */
-#define USB_OTG_CHNUM_1 (0x2UL << USB_OTG_CHNUM_Pos) /*!< 0x00000002 */
-#define USB_OTG_CHNUM_2 (0x4UL << USB_OTG_CHNUM_Pos) /*!< 0x00000004 */
-#define USB_OTG_CHNUM_3 (0x8UL << USB_OTG_CHNUM_Pos) /*!< 0x00000008 */
-#define USB_OTG_BCNT_Pos (4U)
-#define USB_OTG_BCNT_Msk (0x7FFUL << USB_OTG_BCNT_Pos) /*!< 0x00007FF0 */
-#define USB_OTG_BCNT USB_OTG_BCNT_Msk /*!< Byte count */
-
-#define USB_OTG_DPID_Pos (15U)
-#define USB_OTG_DPID_Msk (0x3UL << USB_OTG_DPID_Pos) /*!< 0x00018000 */
-#define USB_OTG_DPID USB_OTG_DPID_Msk /*!< Data PID */
-#define USB_OTG_DPID_0 (0x1UL << USB_OTG_DPID_Pos) /*!< 0x00008000 */
-#define USB_OTG_DPID_1 (0x2UL << USB_OTG_DPID_Pos) /*!< 0x00010000 */
-
-#define USB_OTG_PKTSTS_Pos (17U)
-#define USB_OTG_PKTSTS_Msk (0xFUL << USB_OTG_PKTSTS_Pos) /*!< 0x001E0000 */
-#define USB_OTG_PKTSTS USB_OTG_PKTSTS_Msk /*!< Packet status */
-#define USB_OTG_PKTSTS_0 (0x1UL << USB_OTG_PKTSTS_Pos) /*!< 0x00020000 */
-#define USB_OTG_PKTSTS_1 (0x2UL << USB_OTG_PKTSTS_Pos) /*!< 0x00040000 */
-#define USB_OTG_PKTSTS_2 (0x4UL << USB_OTG_PKTSTS_Pos) /*!< 0x00080000 */
-#define USB_OTG_PKTSTS_3 (0x8UL << USB_OTG_PKTSTS_Pos) /*!< 0x00100000 */
-
-#define USB_OTG_EPNUM_Pos (0U)
-#define USB_OTG_EPNUM_Msk (0xFUL << USB_OTG_EPNUM_Pos) /*!< 0x0000000F */
-#define USB_OTG_EPNUM USB_OTG_EPNUM_Msk /*!< Endpoint number */
-#define USB_OTG_EPNUM_0 (0x1UL << USB_OTG_EPNUM_Pos) /*!< 0x00000001 */
-#define USB_OTG_EPNUM_1 (0x2UL << USB_OTG_EPNUM_Pos) /*!< 0x00000002 */
-#define USB_OTG_EPNUM_2 (0x4UL << USB_OTG_EPNUM_Pos) /*!< 0x00000004 */
-#define USB_OTG_EPNUM_3 (0x8UL << USB_OTG_EPNUM_Pos) /*!< 0x00000008 */
-
-#define USB_OTG_FRMNUM_Pos (21U)
-#define USB_OTG_FRMNUM_Msk (0xFUL << USB_OTG_FRMNUM_Pos) /*!< 0x01E00000 */
-#define USB_OTG_FRMNUM USB_OTG_FRMNUM_Msk /*!< Frame number */
-#define USB_OTG_FRMNUM_0 (0x1UL << USB_OTG_FRMNUM_Pos) /*!< 0x00200000 */
-#define USB_OTG_FRMNUM_1 (0x2UL << USB_OTG_FRMNUM_Pos) /*!< 0x00400000 */
-#define USB_OTG_FRMNUM_2 (0x4UL << USB_OTG_FRMNUM_Pos) /*!< 0x00800000 */
-#define USB_OTG_FRMNUM_3 (0x8UL << USB_OTG_FRMNUM_Pos) /*!< 0x01000000 */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
new file mode 100644
index 000000000..2de0d9cb4
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
@@ -0,0 +1,58 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_IMXRT_H_
+#define _CI_HS_IMXRT_H_
+
+#include "fsl_device_registers.h"
+
+#if !defined(USB1_BASE) && defined(USB_OTG1_BASE)
+#define USB1_BASE USB_OTG1_BASE
+#endif
+
+#if !defined(USB2_BASE) && defined(USB_OTG2_BASE)
+#define USB2_BASE USB_OTG2_BASE
+#endif
+
+static const ci_hs_controller_t _ci_controller[] =
+{
+ // RT1010 and RT1020 only has 1 USB controller
+ #if FSL_FEATURE_SOC_USBHS_COUNT == 1
+ { .reg_base = USB_BASE , .irqnum = USB_OTG1_IRQn, .ep_count = 8 }
+ #else
+ { .reg_base = USB1_BASE, .irqnum = USB_OTG1_IRQn, .ep_count = 8 },
+ { .reg_base = USB2_BASE, .irqnum = USB_OTG2_IRQn, .ep_count = 8 }
+ #endif
+};
+
+#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h
new file mode 100644
index 000000000..8c2e7dfa6
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h
@@ -0,0 +1,45 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_LPC18_43_H_
+#define _CI_HS_LPC18_43_H_
+
+// LPCOpen for 18xx & 43xx
+#include "chip.h"
+
+static const ci_hs_controller_t _ci_controller[] =
+{
+ { .reg_base = LPC_USB0_BASE, .irqnum = USB0_IRQn, .ep_count = 6 },
+ { .reg_base = LPC_USB1_BASE, .irqnum = USB1_IRQn, .ep_count = 4 }
+};
+
+#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_type.h b/src/portable/chipidea/ci_hs/ci_hs_type.h
new file mode 100644
index 000000000..728a86b86
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_type.h
@@ -0,0 +1,144 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef CI_HS_TYPE_H_
+#define CI_HS_TYPE_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// USBCMD
+enum {
+ USBCMD_RUN_STOP = TU_BIT(0),
+ USBCMD_RESET = TU_BIT(1),
+ USBCMD_SETUP_TRIPWIRE = TU_BIT(13),
+ USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoint’s linked list. This bit is set and cleared by software during the process of adding a new dTD
+// Interrupt Threshold bit 23:16
+};
+
+// PORTSC1
+#define PORTSC1_PORT_SPEED_POS 26
+
+enum {
+ PORTSC1_CURRENT_CONNECT_STATUS = TU_BIT(0),
+ PORTSC1_FORCE_PORT_RESUME = TU_BIT(6),
+ PORTSC1_SUSPEND = TU_BIT(7),
+ PORTSC1_FORCE_FULL_SPEED = TU_BIT(24),
+ PORTSC1_PORT_SPEED = TU_BIT(26) | TU_BIT(27)
+};
+
+// OTGSC
+enum {
+ OTGSC_VBUS_DISCHARGE = TU_BIT(0),
+ OTGSC_VBUS_CHARGE = TU_BIT(1),
+// OTGSC_HWASSIST_AUTORESET = TU_BIT(2),
+ OTGSC_OTG_TERMINATION = TU_BIT(3), ///< Must set to 1 when OTG go to device mode
+ OTGSC_DATA_PULSING = TU_BIT(4),
+ OTGSC_ID_PULLUP = TU_BIT(5),
+// OTGSC_HWASSIT_DATA_PULSE = TU_BIT(6),
+// OTGSC_HWASSIT_BDIS_ACONN = TU_BIT(7),
+ OTGSC_ID = TU_BIT(8), ///< 0 = A device, 1 = B Device
+ OTGSC_A_VBUS_VALID = TU_BIT(9),
+ OTGSC_A_SESSION_VALID = TU_BIT(10),
+ OTGSC_B_SESSION_VALID = TU_BIT(11),
+ OTGSC_B_SESSION_END = TU_BIT(12),
+ OTGSC_1MS_TOGGLE = TU_BIT(13),
+ OTGSC_DATA_BUS_PULSING_STATUS = TU_BIT(14),
+};
+
+// USBMode
+enum {
+ USBMODE_CM_DEVICE = 2,
+ USBMODE_CM_HOST = 3,
+
+ USBMODE_SLOM = TU_BIT(3),
+ USBMODE_SDIS = TU_BIT(4),
+
+ USBMODE_VBUS_POWER_SELECT = TU_BIT(5), // Need to be enabled for LPC18XX/43XX in host mode
+};
+
+// Device Registers
+typedef struct
+{
+ //------------- ID + HW Parameter Registers-------------//
+ volatile uint32_t TU_RESERVED[64]; ///< For iMX RT10xx, but not used by LPC18XX/LPC43XX
+
+ //------------- Capability Registers-------------//
+ volatile uint8_t CAPLENGTH; ///< Capability Registers Length
+ volatile uint8_t TU_RESERVED[1];
+ volatile uint16_t HCIVERSION; ///< Host Controller Interface Version
+
+ volatile uint32_t HCSPARAMS; ///< Host Controller Structural Parameters
+ volatile uint32_t HCCPARAMS; ///< Host Controller Capability Parameters
+ volatile uint32_t TU_RESERVED[5];
+
+ volatile uint16_t DCIVERSION; ///< Device Controller Interface Version
+ volatile uint8_t TU_RESERVED[2];
+
+ volatile uint32_t DCCPARAMS; ///< Device Controller Capability Parameters
+ volatile uint32_t TU_RESERVED[6];
+
+ //------------- Operational Registers -------------//
+ volatile uint32_t USBCMD; ///< USB Command Register
+ volatile uint32_t USBSTS; ///< USB Status Register
+ volatile uint32_t USBINTR; ///< Interrupt Enable Register
+ volatile uint32_t FRINDEX; ///< USB Frame Index
+ volatile uint32_t TU_RESERVED;
+ volatile uint32_t DEVICEADDR; ///< Device Address
+ volatile uint32_t ENDPTLISTADDR; ///< Endpoint List Address
+ volatile uint32_t TU_RESERVED;
+ volatile uint32_t BURSTSIZE; ///< Programmable Burst Size
+ volatile uint32_t TXFILLTUNING; ///< TX FIFO Fill Tuning
+ uint32_t TU_RESERVED[4];
+ volatile uint32_t ENDPTNAK; ///< Endpoint NAK
+ volatile uint32_t ENDPTNAKEN; ///< Endpoint NAK Enable
+ volatile uint32_t TU_RESERVED;
+ volatile uint32_t PORTSC1; ///< Port Status & Control
+ volatile uint32_t TU_RESERVED[7];
+ volatile uint32_t OTGSC; ///< On-The-Go Status & control
+ volatile uint32_t USBMODE; ///< USB Device Mode
+ volatile uint32_t ENDPTSETUPSTAT; ///< Endpoint Setup Status
+ volatile uint32_t ENDPTPRIME; ///< Endpoint Prime
+ volatile uint32_t ENDPTFLUSH; ///< Endpoint Flush
+ volatile uint32_t ENDPTSTAT; ///< Endpoint Status
+ volatile uint32_t ENDPTCOMPLETE; ///< Endpoint Complete
+ volatile uint32_t ENDPTCTRL[8]; ///< Endpoint Control 0 - 7
+} ci_hs_regs_t;
+
+
+typedef struct
+{
+ uint32_t reg_base;
+ uint32_t irqnum;
+ uint8_t ep_count; // Max bi-directional Endpoints
+}ci_hs_controller_t;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* CI_HS_TYPE_H_ */
diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
new file mode 100644
index 000000000..c7cc3e0e8
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -0,0 +1,644 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_CHIPIDEA_HS)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "device/dcd.h"
+#include "ci_hs_type.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
+ #include "ci_hs_imxrt.h"
+#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+ #include "ci_hs_lpc18_43.h"
+#else
+ #error "Unsupported MCUs"
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
+
+#if defined(__CORTEX_M) && __CORTEX_M == 7 && __DCACHE_PRESENT == 1
+ #define CleanInvalidateDCache_by_Addr SCB_CleanInvalidateDCache_by_Addr
+#else
+ #define CleanInvalidateDCache_by_Addr(_addr, _dsize)
+#endif
+
+
+// ENDPTCTRL
+enum {
+ ENDPTCTRL_STALL = TU_BIT(0),
+ ENDPTCTRL_TOGGLE_INHIBIT = TU_BIT(5), // used for test only
+ ENDPTCTRL_TOGGLE_RESET = TU_BIT(6),
+ ENDPTCTRL_ENABLE = TU_BIT(7)
+};
+
+enum {
+ ENDPTCTRL_TYPE_POS = 2, // Endpoint type is 2-bit field
+};
+
+// USBSTS, USBINTR
+enum {
+ INTR_USB = TU_BIT(0),
+ INTR_ERROR = TU_BIT(1),
+ INTR_PORT_CHANGE = TU_BIT(2),
+ INTR_RESET = TU_BIT(6),
+ INTR_SOF = TU_BIT(7),
+ INTR_SUSPEND = TU_BIT(8),
+ INTR_NAK = TU_BIT(16)
+};
+
+// Queue Transfer Descriptor
+typedef struct
+{
+ // Word 0: Next QTD Pointer
+ uint32_t next; ///< Next link pointer This field contains the physical memory address of the next dTD to be processed
+
+ // Word 1: qTQ Token
+ uint32_t : 3 ;
+ volatile uint32_t xact_err : 1 ;
+ uint32_t : 1 ;
+ volatile uint32_t buffer_err : 1 ;
+ volatile uint32_t halted : 1 ;
+ volatile uint32_t active : 1 ;
+ uint32_t : 2 ;
+ uint32_t iso_mult_override : 2 ; ///< This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO.
+ uint32_t : 3 ;
+ uint32_t int_on_complete : 1 ;
+ volatile uint32_t total_bytes : 15 ;
+ uint32_t : 1 ;
+
+ // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
+ uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous
+
+ //--------------------------------------------------------------------+
+ // TD is 32 bytes aligned but occupies only 28 bytes
+ // Therefore there are 4 bytes padding that we can use.
+ //--------------------------------------------------------------------+
+ uint16_t expected_bytes;
+ uint8_t reserved[2];
+} dcd_qtd_t;
+
+TU_VERIFY_STATIC( sizeof(dcd_qtd_t) == 32, "size is not correct");
+
+// Queue Head
+typedef struct
+{
+ // Word 0: Capabilities and Characteristics
+ uint32_t : 15 ; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed.
+ uint32_t int_on_setup : 1 ; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received.
+ uint32_t max_packet_size : 11 ; ///< Endpoint's wMaxPacketSize
+ uint32_t : 2 ;
+ uint32_t zero_length_termination : 1 ; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length.
+ uint32_t iso_mult : 2 ; ///<
+
+ // Word 1: Current qTD Pointer
+ volatile uint32_t qtd_addr;
+
+ // Word 2-9: Transfer Overlay
+ volatile dcd_qtd_t qtd_overlay;
+
+ // Word 10-11: Setup request (control OUT only)
+ volatile tusb_control_request_t setup_request;
+
+ //--------------------------------------------------------------------+
+ // QHD is 64 bytes aligned but occupies only 48 bytes
+ // Therefore there are 16 bytes padding that we can use.
+ //--------------------------------------------------------------------+
+ tu_fifo_t * ff;
+ uint8_t reserved[12];
+} dcd_qhd_t;
+
+TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
+
+//--------------------------------------------------------------------+
+// Variables
+//--------------------------------------------------------------------+
+
+#define QTD_NEXT_INVALID 0x01
+
+typedef struct {
+ // Must be at 2K alignment
+ // Each endpoint with direction (IN/OUT) occupies a queue head
+ // for portability, TinyUSB only queue 1 TD for each Qhd
+ dcd_qhd_t qhd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
+ dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
+}dcd_data_t;
+
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
+static dcd_data_t _dcd_data;
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+/// follows LPC43xx User Manual 23.10.3
+static void bus_reset(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ // The reset value for all endpoint types is the control endpoint. If one endpoint
+ // direction is enabled and the paired endpoint of opposite direction is disabled, then the
+ // endpoint type of the unused direction must be changed from the control type to any other
+ // type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
+ // for the data PID tracking on the active endpoint.
+ for( uint8_t i=1; i < _ci_controller[rhport].ep_count; i++)
+ {
+ dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
+ }
+
+ //------------- Clear All Registers -------------//
+ dcd_reg->ENDPTNAK = dcd_reg->ENDPTNAK;
+ dcd_reg->ENDPTNAKEN = 0;
+ dcd_reg->USBSTS = dcd_reg->USBSTS;
+ dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
+ dcd_reg->ENDPTCOMPLETE = dcd_reg->ENDPTCOMPLETE;
+
+ while (dcd_reg->ENDPTPRIME) {}
+ dcd_reg->ENDPTFLUSH = 0xFFFFFFFF;
+ while (dcd_reg->ENDPTFLUSH) {}
+
+ // read reset bit in portsc
+
+ //------------- Queue Head & Queue TD -------------//
+ tu_memclr(&_dcd_data, sizeof(dcd_data_t));
+
+ //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------//
+ _dcd_data.qhd[0][0].zero_length_termination = _dcd_data.qhd[0][1].zero_length_termination = 1;
+ _dcd_data.qhd[0][0].max_packet_size = _dcd_data.qhd[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
+ _dcd_data.qhd[0][0].qtd_overlay.next = _dcd_data.qhd[0][1].qtd_overlay.next = QTD_NEXT_INVALID;
+
+ _dcd_data.qhd[0][0].int_on_setup = 1; // OUT only
+}
+
+void dcd_init(uint8_t rhport)
+{
+ tu_memclr(&_dcd_data, sizeof(dcd_data_t));
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ // Reset controller
+ dcd_reg->USBCMD |= USBCMD_RESET;
+ while( dcd_reg->USBCMD & USBCMD_RESET ) {}
+
+ // Set mode to device, must be set immediately after reset
+ dcd_reg->USBMODE = USBMODE_CM_DEVICE;
+ dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
+
+#if !TUD_OPT_HIGH_SPEED
+ dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
+#endif
+
+ CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+
+ dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment
+ dcd_reg->USBSTS = dcd_reg->USBSTS;
+ dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND;
+
+ dcd_reg->USBCMD &= ~0x00FF0000; // Interrupt Threshold Interval = 0
+ dcd_reg->USBCMD |= USBCMD_RUN_STOP; // Connect
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ CI_DCD_INT_ENABLE(rhport);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ CI_DCD_INT_DISABLE(rhport);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ // Response with status first before changing device address
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->PORTSC1 |= PORTSC1_FORCE_PORT_RESUME;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->USBCMD |= USBCMD_RUN_STOP;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->USBCMD &= ~USBCMD_RUN_STOP;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// HELPER
+//--------------------------------------------------------------------+
+
+static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
+{
+ // Force the CPU to flush the buffer. We increase the size by 31 because the call aligns the
+ // address to 32-byte boundaries. Buffer must be word aligned
+ CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31);
+
+ tu_memclr(p_qtd, sizeof(dcd_qtd_t));
+
+ p_qtd->next = QTD_NEXT_INVALID;
+ p_qtd->active = 1;
+ p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
+ p_qtd->int_on_complete = true;
+
+ if (data_ptr != NULL)
+ {
+ p_qtd->buffer[0] = (uint32_t) data_ptr;
+
+ uint32_t const bufend = p_qtd->buffer[0] + total_bytes;
+ for(uint8_t i=1; i<5; i++)
+ {
+ uint32_t const next_page = tu_align4k( p_qtd->buffer[i-1] ) + 4096;
+ if ( bufend <= next_page ) break;
+
+ p_qtd->buffer[i] = next_page;
+
+ // TODO page[1] FRAME_N for ISO transfer
+ }
+ }
+}
+
+//--------------------------------------------------------------------+
+// DCD Endpoint Port
+//--------------------------------------------------------------------+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
+
+ // flush to abort any primed buffer
+ dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ // data toggle also need to be reset
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << ( dir ? 16 : 0 );
+ dcd_reg->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << ( dir ? 16 : 0));
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+ uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+
+ // Must not exceed max endpoint number
+ TU_ASSERT( epnum < _ci_controller[rhport].ep_count );
+
+ //------------- Prepare Queue Head -------------//
+ dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
+ tu_memclr(p_qhd, sizeof(dcd_qhd_t));
+
+ p_qhd->zero_length_termination = 1;
+ p_qhd->max_packet_size = tu_edpt_packet_size(p_endpoint_desc);
+ if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
+ {
+ p_qhd->iso_mult = 1;
+ }
+
+ p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
+
+ CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+
+ // Enable EP Control
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ uint32_t const epctrl = (p_endpoint_desc->bmAttributes.xfer << ENDPTCTRL_TYPE_POS) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET;
+
+ if ( dir == TUSB_DIR_OUT )
+ {
+ dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0xFFFF0000u) | epctrl;
+ }else
+ {
+ dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0x0000FFFFu) | (epctrl << 16);
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ // Disable all non-control endpoints
+ for( uint8_t epnum=1; epnum < _ci_controller[rhport].ep_count; epnum++)
+ {
+ _dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1;
+ _dcd_data.qhd[epnum][TUSB_DIR_IN ].qtd_overlay.halted = 1;
+
+ dcd_reg->ENDPTFLUSH = TU_BIT(epnum) | TU_BIT(epnum+16);
+ dcd_reg->ENDPTCTRL[epnum] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ _dcd_data.qhd[epnum][dir].qtd_overlay.halted = 1;
+
+ // Flush EP
+ uint32_t const flush_mask = TU_BIT(epnum + (dir ? 16 : 0));
+ dcd_reg->ENDPTFLUSH = flush_mask;
+ while(dcd_reg->ENDPTFLUSH & flush_mask);
+
+ // Clear EP enable
+ dcd_reg->ENDPTCTRL[epnum] &=~(ENDPTCTRL_ENABLE << (dir ? 16 : 0));
+}
+
+static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ p_qhd->qtd_overlay.halted = false; // clear any previous error
+ p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd
+
+ // flush cache
+ CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+
+ if ( epnum == 0 )
+ {
+ // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
+ // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
+ while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
+ }
+
+ // start transfer
+ dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0));
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ // Prepare qtd
+ qtd_init(p_qtd, buffer, total_bytes);
+
+ // Start qhd transfer
+ p_qhd->ff = NULL;
+ qhd_start_xfer(rhport, epnum, dir);
+
+ return true;
+}
+
+// fifo has to be aligned to 4k boundary
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ tu_fifo_buffer_info_t fifo_info;
+
+ if (dir)
+ {
+ tu_fifo_get_read_info(ff, &fifo_info);
+ } else
+ {
+ tu_fifo_get_write_info(ff, &fifo_info);
+ }
+
+ if ( fifo_info.len_lin >= total_bytes )
+ {
+ // Linear length is enough for this transfer
+ qtd_init(p_qtd, fifo_info.ptr_lin, total_bytes);
+ }
+ else
+ {
+ // linear part is not enough
+
+ // prepare TD up to linear length
+ qtd_init(p_qtd, fifo_info.ptr_lin, fifo_info.len_lin);
+
+ if ( !tu_offset4k((uint32_t) fifo_info.ptr_wrap) && !tu_offset4k(tu_fifo_depth(ff)) )
+ {
+ // If buffer is aligned to 4K & buffer size is multiple of 4K
+ // We can make use of buffer page array to also combine the linear + wrapped length
+ p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
+
+ for(uint8_t i = 1, page = 0; i < 5; i++)
+ {
+ // pick up buffer array where linear ends
+ if (p_qtd->buffer[i] == 0)
+ {
+ p_qtd->buffer[i] = (uint32_t) fifo_info.ptr_wrap + 4096 * page;
+ page++;
+ }
+ }
+
+ CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
+ }
+ else
+ {
+ // TODO we may need to carry the wrapped length after the linear part complete
+ // for now only transfer up to linear part
+ }
+ }
+
+ // Start qhd transfer
+ p_qhd->ff = ff;
+ qhd_start_xfer(rhport, epnum, dir);
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+
+static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir)
+{
+ dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
+ dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
+
+ uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
+ ( p_qtd->xact_err || p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS;
+
+ if ( result != XFER_RESULT_SUCCESS )
+ {
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ // flush to abort error buffer
+ dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
+ }
+
+ uint16_t const xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes;
+
+ if (p_qhd->ff)
+ {
+ if (dir == TUSB_DIR_IN)
+ {
+ tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes);
+ } else
+ {
+ tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes);
+ }
+ }
+
+ // only number of bytes in the IOC qtd
+ dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true);
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
+ uint32_t const int_enable = dcd_reg->USBINTR;
+ uint32_t const int_status = dcd_reg->USBSTS & int_enable;
+ dcd_reg->USBSTS = int_status; // Acknowledge handled interrupt
+
+ // disabled interrupt sources
+ if (int_status == 0) return;
+
+ // Set if the port controller enters the full or high-speed operational state.
+ // either from Bus Reset or Suspended state
+ if (int_status & INTR_PORT_CHANGE)
+ {
+ // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1);
+
+ // Reset interrupt is not enabled, we manually check if Port Change is due
+ // to connection / disconnection
+ if ( dcd_reg->USBSTS & INTR_RESET )
+ {
+ dcd_reg->USBSTS = INTR_RESET;
+
+ if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS)
+ {
+ uint32_t const speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS;
+ bus_reset(rhport);
+ dcd_event_bus_reset(rhport, (tusb_speed_t) speed, true);
+ }else
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+ }
+ else
+ {
+ // Triggered by resuming from suspended state
+ if ( !(dcd_reg->PORTSC1 & PORTSC1_SUSPEND) )
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+ }
+ }
+
+ if (int_status & INTR_SUSPEND)
+ {
+ // TU_LOG2("Suspend %08lx\r\n", dcd_reg->PORTSC1);
+
+ if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND)
+ {
+ // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
+ // Skip suspend event if we are not addressed
+ if ((dcd_reg->DEVICEADDR >> 25) & 0x0f)
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+ }
+ }
+ }
+
+ if (int_status & INTR_USB)
+ {
+ // Make sure we read the latest version of _dcd_data.
+ CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+
+ uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE;
+ dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge
+
+ if (dcd_reg->ENDPTSETUPSTAT)
+ {
+ //------------- Set up Received -------------//
+ // 23.10.10.2 Operational model for setup transfers
+ dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
+
+ dcd_event_setup_received(rhport, (uint8_t*)(uintptr_t) &_dcd_data.qhd[0][0].setup_request, true);
+ }
+
+ // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set
+ // nothing to do, we will submit xfer as error to usbd
+ // if (int_status & INTR_ERROR) { }
+
+ if ( edpt_complete )
+ {
+ for(uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++)
+ {
+ if ( tu_bit_test(edpt_complete, epnum) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT);
+ if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN);
+ }
+ }
+ }
+
+ if (int_status & INTR_SOF)
+ {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
new file mode 100644
index 000000000..d0396daea
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -0,0 +1,94 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+// Chipidea Highspeed USB IP implement EHCI for host functionality
+
+#if CFG_TUH_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "common/tusb_common.h"
+#include "host/hcd.h"
+#include "portable/ehci/ehci_api.h"
+#include "ci_hs_type.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
+ #include "ci_hs_imxrt.h"
+#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+ #include "ci_hs_lpc18_43.h"
+#else
+ #error "Unsupported MCUs"
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+bool hcd_init(uint8_t rhport)
+{
+ ci_hs_regs_t* hcd_reg = CI_HS_REG(rhport);
+
+ // Reset controller
+ hcd_reg->USBCMD |= USBCMD_RESET;
+ while( hcd_reg->USBCMD & USBCMD_RESET ) {}
+
+ // Set mode to device, must be set immediately after reset
+#if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX
+ // LPC18XX/43XX need to set VBUS Power Select to HIGH
+ // RHPORT1 is fullspeed only (need external PHY for Highspeed)
+ hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
+ if (rhport == 1) hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
+#else
+ hcd_reg->USBMODE = USBMODE_CM_HOST;
+#endif
+
+ // FIXME force full speed, still have issue with Highspeed enumeration
+ hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
+
+ return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD);
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ CI_HCD_INT_ENABLE(rhport);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ CI_HCD_INT_DISABLE(rhport);
+}
+
+#endif
diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c
index 311119747..0bb8b6e41 100644
--- a/src/portable/dialog/da146xx/dcd_da146xx.c
+++ b/src/portable/dialog/da146xx/dcd_da146xx.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_DA1469X
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_DA1469X
#include "mcu/mcu.h"
@@ -733,6 +733,15 @@ static void handle_alt_ev(void)
set_nfsr(NFSR_NODE_OPERATIONAL);
USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
USB_USB_ALTMSK_REG_USB_M_SD3_Msk;
+ // Re-enable reception of endpoint with pending transfer
+ for (int epnum = 1; epnum <= 3; ++epnum)
+ {
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
+ if (xfer->total_len > xfer->transferred)
+ {
+ start_rx_packet(xfer);
+ }
+ }
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
}
@@ -873,6 +882,14 @@ void dcd_disconnect(uint8_t rhport)
REG_CLR_BIT(USB_MCTRL_REG, USB_NAT);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
{
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
@@ -935,13 +952,13 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
if (dir == TUSB_DIR_OUT)
{
regs->epc_out = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
- USB->USB_RXMSK_REG |= 0x101 << (epnum - 1);
+ USB->USB_RXMSK_REG |= 0x11 << (epnum - 1);
REG_SET_BIT(USB_MAMSK_REG, USB_M_RX_EV);
}
else
{
regs->epc_in = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
- USB->USB_TXMSK_REG |= 0x101 << (epnum - 1);
+ USB->USB_TXMSK_REG |= 0x11 << (epnum - 1);
REG_SET_BIT(USB_MAMSK_REG, USB_M_TX_EV);
}
}
@@ -982,7 +999,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
regs->rxc = USB_USB_RXC1_REG_USB_FLUSH_Msk;
regs->epc_out = 0;
- USB->USB_RXMSK_REG &= ~(0x101 << (epnum - 1));
+ USB->USB_RXMSK_REG &= ~(0x11 << (epnum - 1));
// Release DMA if needed
if (_dcd.dma_ep[TUSB_DIR_OUT] == epnum)
{
@@ -994,7 +1011,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
regs->epc_in = 0;
- USB->USB_TXMSK_REG &= ~(0x101 << (epnum - 1));
+ USB->USB_TXMSK_REG &= ~(0x11 << (epnum - 1));
// Release DMA if needed
if (_dcd.dma_ep[TUSB_DIR_IN] == epnum)
{
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index e92f8a951..76ba2a921 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -24,9 +24,9 @@
* This file is part of the TinyUSB stack.
*/
-#include "host/hcd_attr.h"
+#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && defined(HCD_ATTR_EHCI_TRANSDIMENSION)
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_EHCI)
//--------------------------------------------------------------------+
// INCLUDE
@@ -45,7 +45,7 @@
#define EHCI_DBG 2
// Framelist size as small as possible to save SRAM
-#ifdef HCD_ATTR_EHCI_TRANSDIMENSION
+#ifdef TUP_USBIP_CHIPIDEA_HS
// NXP Transdimension: 8 elements
#define FRAMELIST_SIZE_BIT_VALUE 7u
#define FRAMELIST_SIZE_USBCMD_VALUE (((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_POS_FRAMELIST_SIZE) | \
@@ -58,6 +58,9 @@
#define FRAMELIST_SIZE (1024 >> FRAMELIST_SIZE_BIT_VALUE)
+#define QHD_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
+#define QTD_MAX QHD_MAX
+
typedef struct
{
ehci_link_t period_framelist[FRAMELIST_SIZE];
@@ -73,8 +76,8 @@ typedef struct
ehci_qtd_t qtd;
}control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
- ehci_qhd_t qhd_pool[HCD_MAX_ENDPOINT];
- ehci_qtd_t qtd_pool[HCD_MAX_XFER] TU_ATTR_ALIGNED(32);
+ ehci_qhd_t qhd_pool[QHD_MAX];
+ ehci_qtd_t qtd_pool[QTD_MAX] TU_ATTR_ALIGNED(32);
ehci_registers_t* regs;
@@ -160,15 +163,15 @@ void hcd_port_reset(uint8_t rhport)
regs->portsc = portsc;
}
-#if 0
void hcd_port_reset_end(uint8_t rhport)
{
(void) rhport;
+#if 0
ehci_registers_t* regs = ehci_data.regs;
regs->portsc_bm.port_reset = 0;
-}
#endif
+}
bool hcd_port_connect_status(uint8_t rhport)
{
@@ -189,7 +192,11 @@ static void list_remove_qhd_by_addr(ehci_link_t* list_head, uint8_t dev_addr)
prev = list_next(prev) )
{
// TODO check type for ISO iTD and siTD
+ // TODO Suppress cast-align warning
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wcast-align"
ehci_qhd_t* qhd = (ehci_qhd_t*) list_next(prev);
+ #pragma GCC diagnostic pop
if ( qhd->dev_addr == dev_addr )
{
// TODO deactive all TD, wait for QHD to inactive before removal
@@ -474,7 +481,7 @@ static void async_advance_isr(uint8_t rhport)
(void) rhport;
ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
- for(uint32_t i = 0; i < HCD_MAX_ENDPOINT; i++)
+ for(uint32_t i = 0; i < QHD_MAX; i++)
{
if ( qhd_pool[i].removing )
{
@@ -542,7 +549,7 @@ static void period_list_xfer_complete_isr(uint8_t hostid, uint32_t interval_ms)
// TODO abstract max loop guard for period
while( !next_item.terminate &&
!(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) &&
- max_loop < (HCD_MAX_ENDPOINT + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX)
+ max_loop < (QHD_MAX + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX)
{
switch ( next_item.type )
{
@@ -649,6 +656,26 @@ static void xfer_error_isr(uint8_t hostid)
}
}
+#if CFG_TUSB_DEBUG >= EHCI_DBG
+
+static inline void print_portsc(ehci_registers_t* regs)
+{
+ TU_LOG_HEX(EHCI_DBG, regs->portsc);
+ TU_LOG(EHCI_DBG, " Current Connect Status: %u\r\n", regs->portsc_bm.current_connect_status);
+ TU_LOG(EHCI_DBG, " Connect Status Change : %u\r\n", regs->portsc_bm.connect_status_change);
+ TU_LOG(EHCI_DBG, " Port Enabled : %u\r\n", regs->portsc_bm.port_enabled);
+ TU_LOG(EHCI_DBG, " Port Enabled Change : %u\r\n", regs->portsc_bm.port_enable_change);
+
+ TU_LOG(EHCI_DBG, " Port Reset : %u\r\n", regs->portsc_bm.port_reset);
+ TU_LOG(EHCI_DBG, " Port Power : %u\r\n", regs->portsc_bm.port_power);
+}
+
+#else
+
+#define print_portsc(_reg)
+
+#endif
+
//------------- Host Controller Driver's Interrupt Handler -------------//
void hcd_int_handler(uint8_t rhport)
{
@@ -657,7 +684,7 @@ void hcd_int_handler(uint8_t rhport)
uint32_t int_status = regs->status;
int_status &= regs->inten;
- regs->status |= int_status; // Acknowledge handled interrupt
+ regs->status = int_status; // Acknowledge handled interrupt
if (int_status == 0) return;
@@ -668,9 +695,8 @@ void hcd_int_handler(uint8_t rhport)
if (int_status & EHCI_INT_MASK_PORT_CHANGE)
{
- uint32_t port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
-
- TU_LOG_HEX(EHCI_DBG, regs->portsc);
+ uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
+ print_portsc(regs);
if (regs->portsc_bm.connect_status_change)
{
@@ -714,7 +740,7 @@ void hcd_int_handler(uint8_t rhport)
//------------- queue head helper -------------//
static inline ehci_qhd_t* qhd_find_free (void)
{
- for (uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+ for (uint32_t i=0; i<QHD_MAX; i++)
{
if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
}
@@ -731,7 +757,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
{
ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
- for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+ for(uint32_t i=0; i<QHD_MAX; i++)
{
if ( (qhd_pool[i].dev_addr == dev_addr) &&
ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) )
@@ -746,7 +772,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
//------------- TD helper -------------//
static inline ehci_qtd_t* qtd_find_free(void)
{
- for (uint32_t i=0; i<HCD_MAX_XFER; i++)
+ for (uint32_t i=0; i<QTD_MAX; i++)
{
if ( !ehci_data.qtd_pool[i].used ) return &ehci_data.qtd_pool[i];
}
diff --git a/src/portable/ehci/ehci.h b/src/portable/ehci/ehci.h
index c2bee67a5..ff9ae12e7 100644
--- a/src/portable/ehci/ehci.h
+++ b/src/portable/ehci/ehci.h
@@ -101,8 +101,8 @@ typedef struct
// Word 2: qTQ Token
volatile uint32_t ping_err : 1 ; ///< For Highspeed: 0 Out, 1 Ping. Full/Slow used as error indicator
- volatile uint32_t non_hs_split_state : 1 ; ///< Used by HC to track the state of slipt transaction
- volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete slip transaction
+ volatile uint32_t non_hs_split_state : 1 ; ///< Used by HC to track the state of split transaction
+ volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete split transaction
volatile uint32_t xact_err : 1 ; ///< Error (Timeout, CRC, Bad PID ... )
volatile uint32_t babble_err : 1 ; ///< Babble detected, also set Halted bit to 1
volatile uint32_t buffer_err : 1 ; ///< Data overrun/underrun error
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
index a9c311324..0b75af627 100644
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -28,13 +28,12 @@
#include "tusb_option.h"
-#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && TUSB_OPT_DEVICE_ENABLED)
+#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED)
// Espressif
#include "freertos/xtensa_api.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
-#include "driver/gpio.h"
#include "soc/dport_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/usb_periph.h"
@@ -60,6 +59,7 @@ typedef struct {
uint16_t queued_len;
uint16_t max_size;
bool short_packet;
+ uint8_t interval;
} xfer_ctl_t;
static const char *TAG = "TUSB:DCD";
@@ -241,6 +241,14 @@ void dcd_disconnect(uint8_t rhport)
USB0.dctl |= USB_SFTDISCON_M;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -260,6 +268,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
xfer->max_size = tu_edpt_packet_size(desc_edpt);
+ xfer->interval = desc_edpt->bInterval;
if (dir == TUSB_DIR_OUT) {
out_ep[epnum].doepctl |= USB_USBACTEP1_M |
@@ -372,6 +381,13 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes;
USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK
+ // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
+ if ((USB0.in_ep_reg[epnum].diepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
+ // Take odd/even bit from frame counter.
+ uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
+ USB0.in_ep_reg[epnum].diepctl |= (odd_frame_now ? USB_DI_SETD0PID1 : USB_DI_SETD1PID1);
+ }
+
// Enable fifo empty interrupt only if there are something to put in the fifo.
if(total_bytes != 0) {
USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
@@ -380,6 +396,13 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
// Each complete packet for OUT xfers triggers XFRC.
USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
+
+ // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
+ if ((USB0.out_ep_reg[epnum].doepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
+ // Take odd/even bit from frame counter.
+ uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
+ USB0.out_ep_reg[epnum].doepctl |= (odd_frame_now ? USB_DO_SETD0PID1 : USB_DO_SETD1PID1);
+ }
}
return true;
}
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
index 4b4c2f9b2..0ba53d4d0 100644
--- a/src/portable/mentor/musb/dcd_musb.c
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -26,7 +26,8 @@
#include "tusb_option.h"
-#if TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+#if CFG_TUD_ENABLED && \
+ TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
/* GCC warns that an address may be unaligned, even though
@@ -169,13 +170,13 @@ static inline void print_block_list(free_block_t const *blk, unsigned num)
static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
{
- free_block_t free_blocks[2 * (DCD_ATTR_ENDPOINT_MAX - 1)];
+ free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)];
unsigned num_blocks = 1;
/* Initialize free memory block list */
free_blocks[0].beg = 64 / 8;
free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */
- for (int i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+ for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
uint_fast16_t addr;
int num;
USB0->EPIDX = i;
@@ -250,12 +251,12 @@ static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
len -= 4;
}
if (len >= 2) {
- *(uint32_t *)addr = reg->u16;
+ *(uint16_t *)addr = reg->u16;
addr += 2;
len -= 2;
}
if (len) {
- *(uint32_t *)addr = reg->u8;
+ *(uint8_t *)addr = reg->u8;
}
}
@@ -574,7 +575,7 @@ static void process_bus_reset(uint8_t rhport)
USB0->RXIE = 0;
/* Clear FIFO settings */
- for (unsigned i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
USB0->EPIDX = i;
USB0->TXFIFOSZ = 0;
USB0->TXFIFOADD = 0;
@@ -647,6 +648,14 @@ void dcd_disconnect(uint8_t rhport)
USB0->POWER &= ~USB_POWER_SOFTCONN;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -662,7 +671,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
const unsigned xfer = ep_desc->bmAttributes.xfer;
const unsigned mps = tu_edpt_packet_size(ep_desc);
- TU_ASSERT(epn < DCD_ATTR_ENDPOINT_MAX);
+ TU_ASSERT(epn < TUP_DCD_ENDPOINT_MAX);
pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
pipe->buf = NULL;
@@ -714,7 +723,7 @@ void dcd_edpt_close_all(uint8_t rhport)
NVIC_DisableIRQ(USB0_IRQn);
USB0->TXIE = 1; /* Enable only EP0 */
USB0->RXIE = 0;
- for (unsigned i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
regs->TXMAXP = 0;
regs->TXCSRH = 0;
if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c
new file mode 100644
index 000000000..85e18e3aa
--- /dev/null
+++ b/src/portable/mentor/musb/hcd_musb.c
@@ -0,0 +1,881 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && \
+ TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+
+#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
+/* GCC warns that an address may be unaligned, even though
+ * the target CPU has the capability for unaligned memory access. */
+_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
+#endif
+
+#include "host/hcd.h"
+
+#if TU_CHECK_MCU(OPT_MCU_MSP432E4)
+ #include "musb_msp432e.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #include "musb_tm4c.h"
+
+ // HACK generalize later
+ #include "musb_type.h"
+ #define FIFO0_WORD FIFO0
+
+#else
+ #error "Unsupported MCUs"
+#endif
+
+#ifndef HCD_ATTR_ENDPOINT_MAX
+# define HCD_ATTR_ENDPOINT_MAX 8
+#endif
+
+/*------------------------------------------------------------------
+ * MACRO TYPEDEF CONSTANT ENUM DECLARATION
+ *------------------------------------------------------------------*/
+#define REQUEST_TYPE_INVALID (0xFFu)
+
+typedef struct {
+ uint_fast16_t beg; /* offset of including first element */
+ uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t TXFUNCADDR;
+ uint8_t RESERVED0;
+ uint8_t TXHUBADDR;
+ uint8_t TXHUBPORT;
+ uint8_t RXFUNCADDR;
+ uint8_t RESERVED1;
+ uint8_t RXHUBADDR;
+ uint8_t RXHUBPORT;
+} hw_addr_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t TXMAXP;
+ uint8_t TXCSRL;
+ uint8_t TXCSRH;
+ uint16_t RXMAXP;
+ uint8_t RXCSRL;
+ uint8_t RXCSRH;
+ uint16_t RXCOUNT;
+ uint8_t TXTYPE;
+ uint8_t TXINTERVAL;
+ uint8_t RXTYPE;
+ uint8_t RXINTERVAL;
+ uint16_t RESERVED;
+} hw_endpoint_t;
+
+typedef union {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+} hw_fifo_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+} pipe_state_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ uint8_t dev;
+ uint8_t ep;
+} pipe_addr_t;
+
+typedef struct
+{
+ bool need_reset; /* The device has not been reset after connection. */
+ uint8_t bmRequestType;
+ uint8_t ctl_mps[7]; /* EP0 max packet size for each device */
+ pipe_state_t pipe0;
+ pipe_state_t pipe[7][2]; /* pipe[pipe number - 1][direction 0:RX 1:TX] */
+ pipe_addr_t addr[7][2]; /* addr[pipe number - 1][direction 0:RX 1:TX] */
+} hcd_data_t;
+
+/*------------------------------------------------------------------
+ * INTERNAL OBJECT & FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+static hcd_data_t _hcd;
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+ free_block_t *cur = beg;
+ for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+ return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+ free_block_t *p = find_containing_block(blks, blks + num, addr);
+ TU_ASSERT(p != blks + num, -2);
+ if (p->beg == addr) {
+ /* Shrink block */
+ p->beg = addr + size;
+ if (p->beg != p->end) return 0;
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ } else {
+ /* Split into 2 blocks */
+ free_block_t tmp = {
+ .beg = addr + size,
+ .end = p->end
+ };
+ p->end = addr;
+ if (p->beg == p->end) {
+ if (tmp.beg != tmp.end) {
+ *p = tmp;
+ return 0;
+ }
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ }
+ if (tmp.beg == tmp.end) return 0;
+ blks[num] = tmp;
+ return 1;
+ }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+ return blk->end - blk->beg;
+}
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+ free_block_t free_blocks[2 * (HCD_ATTR_ENDPOINT_MAX - 1)];
+ unsigned num_blocks = 1;
+
+ /* Initialize free memory block list */
+ free_blocks[0].beg = 64 / 8;
+ free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */
+ for (int i = 1; i < HCD_ATTR_ENDPOINT_MAX; ++i) {
+ uint_fast16_t addr;
+ int num;
+ USB0->EPIDX = i;
+ addr = USB0->TXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->TXFIFOSZ;
+ unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ }
+ addr = USB0->RXFIFOADD;
+ if (addr) {
+ unsigned sz = USB0->RXFIFOSZ;
+ unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ }
+ }
+
+ /* Find the best fit memory block */
+ uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+ free_block_t const *min = NULL;
+ uint_fast16_t min_sz = 0xFFFFu;
+ free_block_t const *end = &free_blocks[num_blocks];
+ for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+ uint_fast16_t sz = free_block_size(cur);
+ if (sz < size_in_8byte_unit) continue;
+ if (size_in_8byte_unit == sz) return cur->beg;
+ if (sz < min_sz) min = cur;
+ }
+ TU_ASSERT(min, 0);
+ return min->beg;
+}
+
+static inline volatile hw_endpoint_t* edpt_regs(unsigned epnum_minus1)
+{
+ volatile hw_endpoint_t *regs = (volatile hw_endpoint_t*)((uintptr_t)&USB0->TXMAXP1);
+ return regs + epnum_minus1;
+}
+
+static unsigned find_pipe(uint_fast8_t dev_addr, uint_fast8_t ep_addr)
+{
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ pipe_addr_t const *p = &_hcd.addr[0][dir_tx];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i, p += 2) {
+ if ((dev_addr == p->dev) && (ep_addr == p->ep))
+ return i + 1;
+ }
+ return 0;
+}
+
+static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ reg->u32 = *(uint32_t const *)addr;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ reg->u16 = *(uint16_t const *)addr;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ reg->u8 = *(uint8_t const *)addr;
+ }
+}
+
+static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 4) {
+ *(uint32_t *)addr = reg->u32;
+ addr += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ *(uint16_t *)addr = reg->u16;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ *(uint8_t *)addr = reg->u8;
+ }
+}
+
+static bool edpt0_xfer_out(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe0;
+ unsigned const rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const mps = _hcd.ctl_mps[dev_addr];
+ unsigned const len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, &USB0->FIFO0_WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ USB0->CSRL0 = USB_CSRL0_TXRDY;
+ return false;
+}
+
+static bool edpt0_xfer_in(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe0;
+ unsigned const rem = pipe->remaining;
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const mps = _hcd.ctl_mps[dev_addr];
+ unsigned const vld = USB0->COUNT0;
+ unsigned const len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, &USB0->FIFO0_WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return true;
+ }
+ USB0->CSRL0 = USB_CSRL0_REQPKT;
+ return false;
+}
+
+static bool edpt0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+
+ unsigned const req = _hcd.bmRequestType;
+ TU_ASSERT(req != REQUEST_TYPE_INVALID);
+ TU_ASSERT(dev_addr < sizeof(_hcd.ctl_mps));
+
+ USB0->TXFUNCADDR0 = dev_addr;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
+ TU_ASSERT(buffer);
+ _hcd.pipe0.buf = buffer;
+ _hcd.pipe0.length = buflen;
+ _hcd.pipe0.remaining = buflen;
+ if (dir_in)
+ USB0->CSRL0 = USB_CSRL0_REQPKT;
+ else
+ edpt0_xfer_out();
+ } else { /* STATUS stage */
+ _hcd.pipe0.buf = NULL;
+ _hcd.pipe0.length = 0;
+ _hcd.pipe0.remaining = 0;
+ USB0->CSRL0 = USB_CSRL0_STATUS | (dir_in ? USB_CSRL0_REQPKT: USB_CSRL0_TXRDY);
+ }
+ return true;
+}
+
+static bool pipe_xfer_out(uint_fast8_t pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][1];
+ unsigned const rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ unsigned const mps = regs->TXMAXP;
+ unsigned const len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, &USB0->FIFO0_WORD + pipenum, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ pipe->remaining = rem - len;
+ regs->TXCSRL = USB_TXCSRL1_TXRDY;
+ return false;
+}
+
+static bool pipe_xfer_in(uint_fast8_t pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][0];
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+
+ TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY);
+
+ const unsigned mps = regs->RXMAXP;
+ const unsigned rem = pipe->remaining;
+ const unsigned vld = regs->RXCOUNT;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, &USB0->FIFO0_WORD + pipenum, len);
+ pipe->buf = buf + len;
+ pipe->remaining = rem - len;
+ }
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ regs->RXCSRL = USB_RXCSRL1_REQPKT;
+ return false;
+}
+
+static bool edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+ unsigned const pipenum = find_pipe(dev_addr, ep_addr);
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][dir_tx];
+ pipe->buf = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (dir_tx) {
+ pipe_xfer_out(pipenum);
+ } else {
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ regs->RXCSRL = USB_RXCSRL1_REQPKT;
+ }
+ return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+ (void)rhport;
+
+ uint_fast8_t csrl = USB0->CSRL0;
+ // TU_LOG1(" EP0 CSRL = %x\n", csrl);
+
+ unsigned const dev_addr = USB0->TXFUNCADDR0;
+ unsigned const req = _hcd.bmRequestType;
+ if (csrl & (USB_CSRL0_ERROR | USB_CSRL0_NAKTO | USB_CSRL0_STALLED)) {
+ /* No response / NAK timed out / Stall received */
+ if (csrl & (USB_CSRL0_RXRDY | USB_CSRL0_TXRDY))
+ USB0->CSRH0 = USB_CSRH0_FLUSH;
+ USB0->CSRL0 = 0;
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ uint8_t result = (csrl & USB_CSRL0_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ if (REQUEST_TYPE_INVALID == req) { /* SETUP */
+ uint8_t const ep_addr = tu_edpt_addr(0, TUSB_DIR_OUT);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ } else if (csrl & USB_CSRL0_STATUS) { /* STATUS */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_OUT): tu_edpt_addr(0, TUSB_DIR_IN);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ } else { /* DATA */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_IN): tu_edpt_addr(0, TUSB_DIR_OUT);
+ hcd_event_xfer_complete(dev_addr, ep_addr,
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ result, true);
+ }
+ return;
+ }
+ if (csrl & USB_CSRL0_STATUS) {
+ /* STATUS IN */
+ TU_ASSERT(USB_CSRL0_RXRDY == (csrl & USB_CSRL0_RXRDY),);
+ TU_ASSERT(0 == USB0->COUNT0,);
+ USB0->CSRH0 = USB_CSRH0_FLUSH;
+ USB0->CSRL0 = 0;
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_IN),
+ 0, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (csrl & USB_CSRL0_RXRDY) {
+ /* DATA IN */
+ TU_ASSERT(REQUEST_TYPE_INVALID != req,);
+ TU_ASSERT(_hcd.pipe0.buf,);
+ if (edpt0_xfer_in()) {
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_IN),
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ return;
+ }
+
+ /* When CSRL0 is zero, it means that completion of sending a any length packet. */
+ if (!_hcd.pipe0.buf) {
+ /* STATUS OUT */
+ TU_ASSERT(REQUEST_TYPE_INVALID != req,);
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ /* EP address is the reverse direction of DATA stage */
+ uint8_t const ep_addr = tu_edpt_dir(req) ?
+ tu_edpt_addr(0, TUSB_DIR_OUT): tu_edpt_addr(0, TUSB_DIR_IN);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (REQUEST_TYPE_INVALID == req) {
+ /* SETUP */
+ _hcd.bmRequestType = *(uint8_t*)_hcd.pipe0.buf;
+ _hcd.pipe0.buf = NULL;
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_OUT),
+ 8, XFER_RESULT_SUCCESS, true);
+ return;
+ }
+
+ /* DATA OUT */
+ if (edpt0_xfer_out()) {
+ hcd_event_xfer_complete(dev_addr, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _hcd.pipe0.length - _hcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_pipe_tx(uint8_t rhport, uint_fast8_t pipenum)
+{
+ (void)rhport;
+ bool completed;
+ uint8_t result;
+
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ unsigned const csrl = regs->TXCSRL;
+ // TU_LOG1(" TXCSRL%d = %x\n", pipenum, csrl);
+ if (csrl & (USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) {
+ if (csrl & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = (csrl & ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = csrl & ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR);
+ completed = true;
+ result = (csrl & USB_TXCSRL1_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ } else {
+ completed = pipe_xfer_out(pipenum);
+ result = XFER_RESULT_SUCCESS;
+ }
+ if (completed) {
+ pipe_addr_t *addr = &_hcd.addr[pipenum - 1][1];
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][1];
+ hcd_event_xfer_complete(addr->dev, addr->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+ }
+}
+
+static void process_pipe_rx(uint8_t rhport, uint_fast8_t pipenum)
+{
+ (void)rhport;
+ bool completed;
+ uint8_t result;
+
+ volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1);
+ unsigned const csrl = regs->RXCSRL;
+ // TU_LOG1(" RXCSRL%d = %x\n", pipenum, csrl);
+ if (csrl & (USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) {
+ if (csrl & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = (csrl & ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = csrl & ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR);
+ completed = true;
+ result = (csrl & USB_RXCSRL1_STALLED) ? XFER_RESULT_STALLED: XFER_RESULT_FAILED;
+ } else {
+ completed = pipe_xfer_in(pipenum);
+ result = XFER_RESULT_SUCCESS;
+ }
+ if (completed) {
+ pipe_addr_t *addr = &_hcd.addr[pipenum - 1][0];
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][0];
+ hcd_event_xfer_complete(addr->dev, addr->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+ }
+}
+
+/*------------------------------------------------------------------
+ * Host API
+ *------------------------------------------------------------------*/
+
+bool hcd_init(uint8_t rhport)
+{
+ (void)rhport;
+
+ NVIC_ClearPendingIRQ(USB0_IRQn);
+ _hcd.bmRequestType = REQUEST_TYPE_INVALID;
+ USB0->DEVCTL |= USB_DEVCTL_SESSION;
+ USB0->IE = USB_IE_DISCON | USB_IE_CONN | USB_IE_BABBLE | USB_IE_RESUME;
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void)rhport;
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ return USB0->FRAME;
+}
+
+//--------------------------------------------------------------------+
+// Port API
+//--------------------------------------------------------------------+
+
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ (void)rhport;
+ unsigned devctl = USB0->DEVCTL;
+ if (!(devctl & USB_DEVCTL_HOST)) return false;
+ if (devctl & (USB_DEVCTL_LSDEV | USB_DEVCTL_FSDEV)) return true;
+ return false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ (void)rhport;
+ USB0->POWER |= USB_POWER_HSENAB | USB_POWER_RESET;
+ unsigned cnt = SystemCoreClock / 1000 * 20;
+ while (cnt--) __NOP();
+ USB0->POWER &= ~USB_POWER_RESET;
+ _hcd.need_reset = false;
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ (void)rhport;
+ unsigned devctl = USB0->DEVCTL;
+ if (devctl & USB_DEVCTL_LSDEV) return TUSB_SPEED_LOW;
+ if (!(devctl & USB_DEVCTL_FSDEV)) return TUSB_SPEED_INVALID;
+ if (USB0->POWER & USB_POWER_HSMODE) return TUSB_SPEED_HIGH;
+ return TUSB_SPEED_FULL;
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ if (sizeof(_hcd.ctl_mps) <= dev_addr) return;
+
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ _hcd.ctl_mps[dev_addr] = 0;
+ if (!dev_addr) return;
+
+ pipe_addr_t *p = &_hcd.addr[0][0];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i) {
+ for (unsigned j = 0; j < 2; ++j, ++p) {
+ if (dev_addr != p->dev) continue;
+ hw_addr_t volatile *fadr = (hw_addr_t volatile*)&USB0->TXFUNCADDR0 + i + 1;
+ hw_endpoint_t volatile *regs = edpt_regs(i);
+ USB0->EPIDX = i + 1;
+ if (j) {
+ USB0->TXIE &= ~TU_BIT(i + 1);
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ regs->TXMAXP = 0;
+ regs->TXTYPE = 0;
+ regs->TXINTERVAL = 0;
+ fadr->TXFUNCADDR = 0;
+ fadr->TXHUBADDR = 0;
+ fadr->TXHUBPORT = 0;
+ USB0->TXFIFOADD = 0;
+ USB0->TXFIFOSZ = 0;
+ } else {
+ USB0->RXIE &= ~TU_BIT(i + 1);
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ regs->RXMAXP = 0;
+ regs->RXTYPE = 0;
+ regs->RXINTERVAL = 0;
+ fadr->RXFUNCADDR = 0;
+ fadr->RXHUBADDR = 0;
+ fadr->RXHUBPORT = 0;
+ USB0->RXFIFOADD = 0;
+ USB0->RXFIFOSZ = 0;
+ }
+ p->dev = 0;
+ p->ep = 0;
+ pipe_state_t *pipe = &_hcd.pipe[i][j];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+ }
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ (void)rhport;
+ pipe_write_packet((void*)(uintptr_t)setup_packet, &USB0->FIFO0_WORD, 8);
+ _hcd.pipe0.buf = (void*)(uintptr_t)setup_packet;
+ _hcd.pipe0.length = 8;
+ _hcd.pipe0.remaining = 0;
+
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ switch (devtree.speed) {
+ default: return false;
+ case TUSB_SPEED_LOW: USB0->TYPE0 = USB_TYPE0_SPEED_LOW; break;
+ case TUSB_SPEED_FULL: USB0->TYPE0 = USB_TYPE0_SPEED_FULL; break;
+ case TUSB_SPEED_HIGH: USB0->TYPE0 = USB_TYPE0_SPEED_HIGH; break;
+ }
+ USB0->TXHUBADDR0 = devtree.hub_addr;
+ USB0->TXHUBPORT0 = devtree.hub_port;
+ USB0->TXFUNCADDR0 = dev_addr;
+ USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_SETUP;
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+ if (sizeof(_hcd.ctl_mps) <= dev_addr) return false;
+ unsigned const ep_addr = ep_desc->bEndpointAddress;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ if (0 == epn) {
+ _hcd.ctl_mps[dev_addr] = ep_desc->wMaxPacketSize;
+ return true;
+ }
+
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ /* Find a free pipe */
+ unsigned pipenum = 0;
+ pipe_addr_t *p = &_hcd.addr[0][dir_tx];
+ for (unsigned i = 0; i < sizeof(_hcd.addr)/sizeof(_hcd.addr[0]); ++i, p += 2) {
+ if (0 == p->ep) {
+ p->dev = dev_addr;
+ p->ep = ep_addr;
+ pipenum = i + 1;
+ break;
+ }
+ }
+ if (!pipenum) return false;
+
+ unsigned const xfer = ep_desc->bmAttributes.xfer;
+ unsigned const mps = tu_edpt_packet_size(ep_desc);
+
+ pipe_state_t *pipe = &_hcd.pipe[pipenum - 1][dir_tx];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+
+ uint8_t pipe_type = 0;
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ switch (devtree.speed) {
+ default: return false;
+ case TUSB_SPEED_LOW: pipe_type |= USB_TXTYPE1_SPEED_LOW; break;
+ case TUSB_SPEED_FULL: pipe_type |= USB_TXTYPE1_SPEED_FULL; break;
+ case TUSB_SPEED_HIGH: pipe_type |= USB_TXTYPE1_SPEED_HIGH; break;
+ }
+ switch (xfer) {
+ default: return false;
+ case TUSB_XFER_BULK: pipe_type |= USB_TXTYPE1_PROTO_BULK; break;
+ case TUSB_XFER_INTERRUPT: pipe_type |= USB_TXTYPE1_PROTO_INT; break;
+ case TUSB_XFER_ISOCHRONOUS: pipe_type |= USB_TXTYPE1_PROTO_ISOC; break;
+ }
+
+ hw_addr_t volatile *fadr = (hw_addr_t volatile*)&USB0->TXFUNCADDR0 + pipenum;
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ if (dir_tx) {
+ fadr->TXFUNCADDR = dev_addr;
+ fadr->TXHUBADDR = devtree.hub_addr;
+ fadr->TXHUBPORT = devtree.hub_port;
+ regs->TXMAXP = mps;
+ regs->TXTYPE = pipe_type | epn;
+ regs->TXINTERVAL = ep_desc->bInterval;
+ if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+ else
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ USB0->TXIE |= TU_BIT(pipenum);
+ } else {
+ fadr->RXFUNCADDR = dev_addr;
+ fadr->RXHUBADDR = devtree.hub_addr;
+ fadr->RXHUBPORT = devtree.hub_port;
+ regs->RXMAXP = mps;
+ regs->RXTYPE = pipe_type | epn;
+ regs->RXINTERVAL = ep_desc->bInterval;
+ if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+ regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ USB0->RXIE |= TU_BIT(pipenum);
+ }
+
+ /* Setup FIFO */
+ int size_in_log2_minus3 = 28 - TU_MIN(28, __CLZ((uint32_t)mps));
+ if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+ unsigned addr = find_free_memory(size_in_log2_minus3);
+ TU_ASSERT(addr);
+
+ USB0->EPIDX = pipenum;
+ if (dir_tx) {
+ USB0->TXFIFOADD = addr;
+ USB0->TXFIFOSZ = size_in_log2_minus3;
+ } else {
+ USB0->RXFIFOADD = addr;
+ USB0->RXFIFOSZ = size_in_log2_minus3;
+ }
+ return true;
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ (void)rhport;
+ bool ret = false;
+ if (0 == tu_edpt_number(ep_addr)) {
+ ret = edpt0_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ } else {
+ ret = edpt_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
+ }
+ return ret;
+}
+
+// clear stall, data toggle is also reset to DATA0
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ unsigned const pipenum = find_pipe(dev_addr, ep_addr);
+ if (!pipenum) return false;
+ hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
+ unsigned const dir_tx = tu_edpt_dir(ep_addr) ? 0: 1;
+ if (dir_tx)
+ regs->TXCSRL = USB_TXCSRL1_CLRDT;
+ else
+ regs->RXCSRL = USB_RXCSRL1_CLRDT;
+ return true;
+}
+
+/*-------------------------------------------------------------------
+ * ISR
+ *-------------------------------------------------------------------*/
+void hcd_int_handler(uint8_t rhport)
+{
+ uint_fast8_t is, txis, rxis;
+
+ is = USB0->IS; /* read and clear interrupt status */
+ txis = USB0->TXIS; /* read and clear interrupt status */
+ rxis = USB0->RXIS; /* read and clear interrupt status */
+ // TU_LOG1("D%2x T%2x R%2x\n", is, txis, rxis);
+
+ is &= USB0->IE; /* Clear disabled interrupts */
+ if (is & USB_IS_RESUME) {
+ }
+ if (is & USB_IS_CONN) {
+ _hcd.need_reset = true;
+ hcd_event_device_attach(rhport, true);
+ }
+ if (is & USB_IS_DISCON) {
+ hcd_event_device_remove(rhport, true);
+ }
+ if (is & USB_IS_BABBLE) {
+ }
+ txis &= USB0->TXIE; /* Clear disabled interrupts */
+ if (txis & USB_TXIE_EP0) {
+ process_ep0(rhport);
+ txis &= ~TU_BIT(0);
+ }
+ while (txis) {
+ unsigned const num = __builtin_ctz(txis);
+ process_pipe_tx(rhport, num);
+ txis &= ~TU_BIT(num);
+ }
+ rxis &= USB0->RXIE; /* Clear disabled interrupts */
+ while (rxis) {
+ unsigned const num = __builtin_ctz(rxis);
+ process_pipe_rx(rhport, num);
+ rxis &= ~TU_BIT(num);
+ }
+}
+
+#endif
diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c
new file mode 100644
index 000000000..6cf0e6285
--- /dev/null
+++ b/src/portable/microchip/pic/dcd_pic.c
@@ -0,0 +1,786 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Koji Kitayama
+ * Copyright (c) 2022 Reimu NotMoe <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_PIC32MX || CFG_TUSB_MCU == OPT_MCU_PIC32MM || \
+ CFG_TUSB_MCU == OPT_MCU_PIC32MK || CFG_TUSB_MCU == OPT_MCU_PIC24 || \
+ CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+
+#include <xc.h>
+
+#include "device/dcd.h"
+
+
+#if (CFG_TUSB_MCU == OPT_MCU_PIC32MX || CFG_TUSB_MCU == OPT_MCU_PIC32MM || CFG_TUSB_MCU == OPT_MCU_PIC32MK)
+
+#define TU_PIC_INT_SIZE 4
+
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24 || CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+
+#define TU_PIC_INT_SIZE 2
+
+#else
+
+#error Unsupportd PIC MCU
+
+#endif
+
+
+#if TU_PIC_INT_SIZE == 4
+
+#ifndef KVA_TO_PA
+#define KVA_TO_PA(kva) ((uint32_t)(kva) & 0x1fffffff)
+#endif
+
+#ifndef PA_TO_KVA1
+#define PA_TO_KVA1(pa) ((uint32_t)(pa) | 0xA0000000)
+#endif
+
+#else
+
+#ifndef KVA_TO_PA
+#define KVA_TO_PA(kva) (kva)
+#endif
+
+#ifndef PA_TO_KVA1
+#define PA_TO_KVA1(pa) (pa)
+#endif
+
+#endif
+
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+ TOK_PID_OUT = 0x1u,
+ TOK_PID_IN = 0x9u,
+ TOK_PID_SETUP = 0xDu,
+};
+
+// The BDT is 8 bytes on 32bit PICs and 4 bytes on 8/16bit PICs
+#if TU_PIC_INT_SIZE == 4
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t head;
+ struct {
+ union {
+ struct {
+ uint16_t : 2;
+ uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ uint16_t own : 1;
+ uint16_t : 8;
+ };
+ struct {
+ uint16_t : 2;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
+ };
+ };
+ uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+} buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+#else
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint16_t head;
+
+ struct {
+ uint16_t : 10;
+ uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ uint16_t own : 1;
+ };
+ struct {
+ uint16_t : 10;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ };
+
+ struct {
+ uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+} buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 4, "size is not correct" );
+#endif
+
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t state;
+ struct {
+ uint32_t max_packet_size :11;
+ uint32_t : 5;
+ uint32_t odd : 1;
+ uint32_t :15;
+ };
+ };
+ uint16_t length;
+ uint16_t remaining;
+} endpoint_state_t;
+
+TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" );
+
+typedef struct
+{
+ union {
+ /* [#EP][OUT,IN][EVEN,ODD] */
+ buffer_descriptor_t bdt[16][2][2];
+#if TU_PIC_INT_SIZE == 4
+ uint16_t bda[256];
+#else
+ uint8_t bda[256];
+#endif
+ };
+ TU_ATTR_ALIGNED(4) union {
+ endpoint_state_t endpoint[16][2];
+ endpoint_state_t endpoint_unified[16 * 2];
+ };
+ uint8_t setup_packet[8];
+ uint8_t addr;
+} dcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) volatile static dcd_data_t _dcd;
+
+#if TU_PIC_INT_SIZE == 4
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
+#else
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 256, "size is not correct" );
+#endif
+
+#if TU_PIC_INT_SIZE == 4
+typedef uint32_t ep_reg_t;
+#elif TU_PIC_INT_SIZE == 2
+typedef uint16_t ep_reg_t;
+#endif
+
+static inline volatile void *ep_addr(uint8_t rhport, uint8_t ep_num) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ volatile void *ep_reg_base = rhport ? (&U2EP0) : (&U1EP0);
+#else
+ volatile void *ep_reg_base = &U1EP0;
+#endif
+#if TU_PIC_INT_SIZE == 4
+ const size_t offset = 0x10;
+#else
+ const size_t offset = 0x2;
+#endif
+ return ep_reg_base + offset * ep_num;
+}
+
+static inline ep_reg_t ep_read(uint8_t rhport, uint8_t ep_num) {
+ volatile ep_reg_t *ep = ep_addr(rhport, ep_num);
+ return *ep;
+}
+
+static inline void ep_write(uint8_t rhport, uint8_t ep_num, ep_reg_t val) {
+ volatile ep_reg_t *ep = ep_addr(rhport, ep_num);
+ *ep = val;
+}
+
+static inline void ep_clear(uint8_t rhport, uint8_t ep_num, ep_reg_t val) {
+#if TU_PIC_INT_SIZE == 4
+ volatile ep_reg_t *ep_clr = (ep_addr(rhport, ep_num) + 0x4);
+ *ep_clr = val;
+#else
+ ep_reg_t v = ep_read(rhport, ep_num);
+ v &= ~val;
+ ep_write(rhport, ep_num, v);
+#endif
+}
+
+static inline void ep_set(uint8_t rhport, uint8_t ep_num, ep_reg_t val) {
+#if TU_PIC_INT_SIZE == 4
+ volatile ep_reg_t *ep_s = (ep_addr(rhport, ep_num) + 0x8);
+ *ep_s = val;
+#else
+ ep_reg_t v = ep_read(rhport, ep_num);
+ v |= val;
+ ep_write(rhport, ep_num, v);
+#endif
+}
+
+static inline void intr_enable(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ IEC0SET = _IEC0_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ IEC1SET = _IEC1_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ IEC1SET = _IEC1_USB1IE_MASK;
+ else
+ IEC7SET = _IEC7_USB2IE_MASK;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ IEC5bits.USB1IE = 1;
+#endif
+}
+
+static inline void intr_disable(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ IEC0CLR = _IEC0_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ IEC1CLR = _IEC1_USBIE_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ IEC1CLR = _IEC1_USB1IE_MASK;
+ else
+ IEC7CLR = _IEC7_USB2IE_MASK;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ IEC5bits.USB1IE = 0;
+#endif
+}
+
+static inline int intr_is_enabled(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ return IEC0bits.USBIE;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ return IEC1bits.USBIE;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ return IEC1bits.USB1IE;
+ else
+ return IEC7bits.USB2IE;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ return IEC5bits.USB1IE;
+#endif
+}
+
+static inline void intr_clear(uint8_t rhport) {
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ IFS0CLR = _IFS0_USBIF_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX
+ IFS1CLR = _IFS1_USBIF_MASK;
+#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK
+ if (rhport == 0)
+ IFS1CLR = _IFS1_USB1IF_MASK;
+ else
+ IFS7CLR = _IFS7_USB2IF_MASK;
+#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33)
+ IFS5bits.USB1IF = 0;
+#endif
+}
+
+static void prepare_next_setup_packet(uint8_t rhport)
+{
+ const unsigned out_odd = _dcd.endpoint[0][0].odd;
+ const unsigned in_odd = _dcd.endpoint[0][1].odd;
+ TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, );
+
+ _dcd.bdt[0][0][out_odd].data = 0;
+ _dcd.bdt[0][0][out_odd ^ 1].data = 1;
+ _dcd.bdt[0][1][in_odd].data = 1;
+ _dcd.bdt[0][1][in_odd ^ 1].data = 0;
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.setup_packet, sizeof(_dcd.setup_packet));
+}
+
+static void process_stall(uint8_t rhport)
+{
+ for (int i = 0; i < 16; ++i) {
+ unsigned const endpt = ep_read(rhport, i);
+
+ if (endpt & _U1EP0_EPSTALL_MASK) {
+ // prepare next setup if endpoint0
+ if ( i == 0 ) prepare_next_setup_packet(rhport);
+
+ // clear stall bit
+ ep_clear(rhport, i, _U1EP0_EPSTALL_MASK);
+ }
+ }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+ ep_reg_t s = U1STAT;
+
+ U1IR = _U1IR_TRNIF_MASK;
+
+ uint8_t epnum = (s >> _U1STAT_ENDPT0_POSITION);
+ uint8_t dir = (s & _U1STAT_DIR_MASK) >> _U1STAT_DIR_POSITION;
+ unsigned odd = (s & _U1STAT_PPBI_MASK) ? 1 : 0;
+
+ buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
+ endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3];
+
+ /* fetch pid before discarded by the next steps */
+ const unsigned pid = bd->tok_pid;
+
+ /* reset values for a next transfer */
+ bd->bdt_stall = 0;
+ bd->dts = 1;
+ bd->ninc = 0;
+ bd->keep = 0;
+ /* update the odd variable to prepare for the next transfer */
+ ep->odd = odd ^ 1;
+ if (pid == TOK_PID_SETUP) {
+ dcd_event_setup_received(rhport, (uint8_t *)PA_TO_KVA1(bd->addr), true);
+#if TU_PIC_INT_SIZE == 4
+ U1CONCLR = _U1CON_PKTDIS_TOKBUSY_MASK;
+#else
+ U1CONbits.PKTDIS = 0;
+#endif
+ return;
+ }
+
+ const unsigned bc = bd->bc;
+ const unsigned remaining = ep->remaining - bc;
+ if (remaining && bc == ep->max_packet_size) {
+ /* continue the transferring consecutive data */
+ ep->remaining = remaining;
+ const int next_remaining = remaining - ep->max_packet_size;
+ if (next_remaining > 0) {
+ /* prepare to the after next transfer */
+ bd->addr += ep->max_packet_size * 2;
+ bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining;
+ bd->own = 1; /* the own bit must set after addr */
+ }
+ return;
+ }
+ const unsigned length = ep->length;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(epnum, dir),
+ length - remaining, XFER_RESULT_SUCCESS, true);
+ if (0 == epnum && 0 == length) {
+ /* After completion a ZLP of control transfer,
+ * it prepares for the next steup transfer. */
+ if (_dcd.addr) {
+ /* When the transfer was the SetAddress,
+ * the device address should be updated here. */
+ U1ADDR = _dcd.addr;
+ _dcd.addr = 0;
+ }
+ prepare_next_setup_packet(rhport);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCCLR = _U1PWRC_USUSPEND_MASK;
+ U1CONSET = _U1CON_PPBRST_MASK;
+#else
+ U1PWRCbits.USUSPND = 0;
+ U1CONbits.PPBRST = 1;
+#endif
+ U1ADDR = 0;
+
+ U1IE = _U1IE_URSTIE_MASK | _U1IE_TRNIE_MASK | _U1IE_IDLEIE_MASK |
+ _U1IE_UERRIE_MASK | _U1IE_STALLIE_MASK;
+
+ U1EP0 = _U1EP0_EPHSHK_MASK | _U1EP0_EPRXEN_MASK | _U1EP0_EPTXEN_MASK;
+
+ for (unsigned i = 1; i < 16; ++i) {
+ ep_write(rhport, i, 0);
+ }
+
+ buffer_descriptor_t *bd = _dcd.bdt[0][0];
+ for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ const endpoint_state_t ep0 = {
+ .max_packet_size = CFG_TUD_ENDPOINT0_SIZE,
+ .odd = 0,
+ .length = 0,
+ .remaining = 0,
+ };
+ _dcd.endpoint[0][0] = ep0;
+ _dcd.endpoint[0][1] = ep0;
+ tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0]));
+ _dcd.addr = 0;
+ prepare_next_setup_packet(rhport);
+#if TU_PIC_INT_SIZE == 4
+ U1CONCLR = _U1CON_PPBRST_MASK;
+#else
+ U1CONbits.PPBRST = 0;
+#endif
+ dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_bus_sleep(uint8_t rhport)
+{
+ // Enable resume & disable suspend interrupt
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+}
+
+static void process_bus_resume(uint8_t rhport)
+{
+ // Enable suspend & disable resume interrupt
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCCLR = _U1PWRC_USUSPEND_MASK;
+ U1IECLR = _U1IE_RESUMEIE_MASK;
+ U1IESET = _U1IE_IDLEIE_MASK;
+#else
+ U1PWRCbits.USUSPND = 0;
+ U1IEbits.RESUMEIE = 0;
+ U1IEbits.IDLEIE = 1;
+#endif
+
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+ intr_disable(rhport);
+ intr_clear(rhport);
+
+#if CFG_TUSB_MCU == OPT_MCU_PIC32MM
+ TRISBbits.TRISB6 = 1;
+#endif
+
+ tu_memclr(&_dcd, sizeof(_dcd));
+
+#if TU_PIC_INT_SIZE == 4
+ U1PWRCSET = _U1PWRC_USBPWR_MASK;
+#else
+ U1PWRCbits.USBPWR = 1;
+#endif
+
+#if TU_PIC_INT_SIZE == 4
+ uint32_t bdt_phys = KVA_TO_PA((uintptr_t)_dcd.bdt);
+
+ U1BDTP1 = (uint8_t)(bdt_phys >> 8);
+ U1BDTP2 = (uint8_t)(bdt_phys >> 16);
+ U1BDTP3 = (uint8_t)(bdt_phys >> 24);
+#else
+ U1BDTP1 = (uint8_t)((uint16_t)(void *)_dcd.bdt >> 8);
+
+ U1CNFG1bits.PPB = 2;
+#endif
+
+ U1IE = _U1IE_URSTIE_MASK;
+
+ dcd_connect(rhport);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ intr_enable(rhport);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ intr_disable(rhport);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ _dcd.addr = dev_addr & 0x7F;
+ /* Response with status first before changing device address */
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+#if TU_PIC_INT_SIZE == 4
+ U1CONSET = _U1CON_RESUME_MASK;
+#else
+ U1CONbits.RESUME = 1;
+#endif
+ unsigned cnt = 25000000 / 1000;
+ while (cnt--) asm volatile("nop");
+
+#if TU_PIC_INT_SIZE == 4
+ U1CONCLR = _U1CON_RESUME_MASK;
+#else
+ U1CONbits.RESUME = 0;
+#endif
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ while (!U1CONbits.USBEN) {
+#if TU_PIC_INT_SIZE == 4
+ U1CONSET = _U1CON_USBEN_SOFEN_MASK;
+#else
+ U1CONbits.USBEN = 1;
+#endif
+ }
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ U1CON = 0;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ const unsigned odd = ep->odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+
+ /* No support for control transfer */
+ TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
+
+ ep->max_packet_size = tu_edpt_packet_size(ep_desc);
+
+
+ unsigned val = _U1EP0_EPCONDIS_MASK;
+ val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? _U1EP0_EPHSHK_MASK : 0;
+ val |= dir ? _U1EP0_EPTXEN_MASK : _U1EP0_EPRXEN_MASK;
+
+ ep_reg_t tmp = ep_read(rhport, epn);
+ tmp |= val;
+ ep_write(rhport, epn, tmp);
+
+ if (xfer != TUSB_XFER_ISOCHRONOUS) {
+ bd[odd].dts = 1;
+ bd[odd].data = 0;
+ bd[odd ^ 1].dts = 1;
+ bd[odd ^ 1].data = 1;
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ const unsigned ie = intr_is_enabled(rhport);
+ intr_disable(rhport);
+
+ for (unsigned i = 1; i < 16; ++i) {
+ ep_write(rhport, i, 0);
+ }
+
+ if (ie) intr_enable(rhport);
+
+ buffer_descriptor_t *bd = _dcd.bdt[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ endpoint_state_t *ep = &_dcd.endpoint[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.endpoint)/sizeof(*ep); ++i, ++ep) {
+ /* Clear except the odd */
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ const unsigned msk = dir ? _U1EP0_EPTXEN_MASK : _U1EP0_EPRXEN_MASK;
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ ep_clear(rhport, epn, msk);
+
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ bd[0].head = 0;
+ bd[1].head = 0;
+
+ if (ie) intr_enable(rhport);
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
+ TU_ASSERT(0 == bd->own);
+
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ ep->length = total_bytes;
+ ep->remaining = total_bytes;
+
+ const unsigned mps = ep->max_packet_size;
+ if (total_bytes > mps) {
+ buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1;
+ /* When total_bytes is greater than the max packet size,
+ * it prepares to the next transfer to avoid NAK in advance. */
+ next->bc = total_bytes >= 2 * mps ? mps: total_bytes - mps;
+ next->addr = (uint8_t *)KVA_TO_PA(buffer + mps);
+ next->own = 1;
+ }
+ bd->bc = total_bytes >= mps ? mps: total_bytes;
+ bd->addr = (uint8_t *)KVA_TO_PA(buffer);
+ bd->own = 1; /* This bit must be set last */
+
+ if (ie) intr_enable(rhport);
+
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ if (0 == epn) {
+ ep_set(rhport, epn, _U1EP0_EPSTALL_MASK);
+ } else {
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][odd];
+ TU_ASSERT(0 == bd->own,);
+
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ bd->bdt_stall = 1;
+ bd->own = 1; /* This bit must be set last */
+
+ if (ie) intr_enable(rhport);
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ TU_VERIFY(epn,);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ TU_VERIFY(bd[odd].own,);
+
+ const unsigned ie = intr_is_enabled(rhport);
+
+ intr_disable(rhport);
+
+ bd[odd].own = 0;
+
+ // clear stall
+ bd[odd].bdt_stall = 0;
+
+ // Reset data toggle
+ bd[odd ].data = 0;
+ bd[odd ^ 1].data = 1;
+
+ // We already cleared this in ISR, but just clear it here to be safe
+ const unsigned endpt = ep_read(rhport, epn);
+ if (endpt & _U1EP0_EPSTALL_MASK) {
+ ep_clear(rhport, endpt, _U1EP0_EPSTALL_MASK);
+ }
+
+ if (ie) intr_enable(rhport);
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+ uint32_t is = U1IR;
+ uint32_t msk = U1IE;
+
+ U1IR = is & ~msk;
+ is &= msk;
+
+ if (is & _U1IR_UERRIF_MASK) {
+ uint32_t es = U1EIR;
+ U1EIR = es;
+ U1IR = is; /* discard any pending events */
+ }
+
+ if (is & _U1IR_URSTIF_MASK) {
+ U1IR = is; /* discard any pending events */
+ process_bus_reset(rhport);
+ }
+
+ if (is & _U1IR_IDLEIF_MASK) {
+ // Note Host usually has extra delay after bus reset (without SOF), which could falsely
+ // detected as Sleep event. Though usbd has debouncing logic so we are good
+ U1IR = _U1IR_IDLEIF_MASK;
+ process_bus_sleep(rhport);
+ }
+
+ if (is & _U1IR_RESUMEIF_MASK) {
+ U1IR = _U1IR_RESUMEIF_MASK;
+ process_bus_resume(rhport);
+ }
+
+ if (is & _U1IR_SOFIF_MASK) {
+ U1IR = _U1IR_SOFIF_MASK;
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+
+ if (is & _U1IR_STALLIF_MASK) {
+ U1IR = _U1IR_STALLIF_MASK;
+ process_stall(rhport);
+ }
+
+ if (is & _U1IR_TRNIF_MASK) {
+ process_tokdne(rhport);
+ }
+
+ intr_clear(rhport);
+}
+
+#endif
diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c
new file mode 100644
index 000000000..9ad755670
--- /dev/null
+++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c
@@ -0,0 +1,753 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Jerzy Kasenberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_PIC32MZ
+
+#include <common/tusb_common.h>
+#include <device/dcd.h>
+
+#include <xc.h>
+#include "usbhs_registers.h"
+
+#define USB_REGS ((usbhs_registers_t *) (_USB_BASE_ADDRESS))
+
+// Maximum number of endpoints, could be trimmed down in tusb_config to reduce RAM usage.
+#ifndef EP_MAX
+#define EP_MAX 8
+#endif
+
+
+typedef enum {
+ EP0_STAGE_NONE,
+ EP0_STAGE_SETUP_IN_DATA,
+ EP0_STAGE_SETUP_OUT_NO_DATA,
+ EP0_STAGE_SETUP_OUT_DATA,
+ EP0_STAGE_DATA_IN,
+ EP0_STAGE_DATA_IN_LAST_PACKET_FILLED,
+ EP0_STAGE_DATA_IN_SENT,
+ EP0_STAGE_DATA_OUT,
+ EP0_STAGE_DATA_OUT_COMPLETE,
+ EP0_STAGE_STATUS_IN,
+ EP0_STAGE_ADDRESS_CHANGE,
+} ep0_stage_t;
+
+typedef struct {
+ uint8_t * buffer;
+ // Total length of current transfer
+ uint16_t total_len;
+ // Bytes transferred so far
+ uint16_t transferred;
+ uint16_t max_packet_size;
+ uint16_t fifo_size;
+ // Packet size sent or received so far. It is used to modify transferred field
+ // after ACK is received or when filling ISO endpoint with size larger then
+ // FIFO size.
+ uint16_t last_packet_size;
+ uint8_t ep_addr;
+} xfer_ctl_t;
+
+static struct
+{
+ // Current FIFO RAM address used for FIFO allocation
+ uint16_t fifo_addr_top;
+ // EP0 transfer stage
+ ep0_stage_t ep0_stage;
+ // Device address
+ uint8_t dev_addr;
+ xfer_ctl_t xfer_status[EP_MAX][2];
+} _dcd;
+
+// Two endpoint 0 descriptor definition for unified dcd_edpt_open()
+static tusb_desc_endpoint_t const ep0OUT_desc =
+{
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+
+ .bEndpointAddress = 0x00,
+ .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
+};
+
+static tusb_desc_endpoint_t const ep0IN_desc =
+{
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+
+ .bEndpointAddress = 0x80,
+ .bmAttributes = { .xfer = TUSB_XFER_CONTROL },
+ .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
+ .bInterval = 0
+};
+
+#define XFER_CTL_BASE(_ep, _dir) &_dcd.xfer_status[_ep][_dir]
+
+static void ep0_set_stage(ep0_stage_t stage)
+{
+ _dcd.ep0_stage = stage;
+}
+
+static ep0_stage_t ep0_get_stage(void)
+{
+ return _dcd.ep0_stage;
+}
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+ // Disable endpoint interrupts for now
+ USB_REGS->INTRRXEbits.w = 0;
+ USB_REGS->INTRTXEbits.w = 0;
+ // Enable Reset/Suspend/Resume interrupts only
+ USB_REGS->INTRUSBEbits.w = 7;
+
+ dcd_connect(rhport);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+
+ USBCRCONbits.USBIE = 1;
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+
+ USBCRCONbits.USBIE = 0;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void) rhport;
+
+ ep0_set_stage(EP0_STAGE_ADDRESS_CHANGE);
+ // Store address it will be used later after status stage is done
+ _dcd.dev_addr = dev_addr;
+ // Confirm packet now, address will be set when status stage is detected
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void) rhport;
+
+ USB_REGS->POWERbits.RESUME = 1;
+#if CFG_TUSB_OS != OPT_OS_NONE
+ osal_task_delay(10);
+#else
+ // TODO: Wait in non blocking mode
+ unsigned cnt = 2000;
+ while (cnt--) __asm__("nop");
+#endif
+ USB_REGS->POWERbits.RESUME = 0;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+
+ USB_REGS->POWERbits.HSEN = TUD_OPT_HIGH_SPEED ? 1 : 0;
+ USB_REGS->POWERbits.SOFTCONN = 1;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+
+ USB_REGS->POWERbits.SOFTCONN = 1;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
+{
+ return (_CP0_GET_STATUS() & (_CP0_STATUS_EXL_MASK | _CP0_STATUS_IPL_MASK)) != 0;
+}
+
+static void epn_rx_configure(uint8_t endpoint, uint16_t endpointSize,
+ uint16_t fifoAddress, uint8_t fifoSize,
+ uint32_t transferType)
+{
+ uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
+
+ // Select endpoint register set (same register address is used for all endpoints.
+ USB_REGS->INDEXbits.ENDPOINT = endpoint;
+
+ // Configure the Endpoint size
+ USB_REGS->INDEXED_EPCSR.RXMAXPbits.RXMAXP = endpointSize;
+
+ // Set up the fifo address.
+ USB_REGS->RXFIFOADDbits.RXFIFOAD = fifoAddress;
+
+ // Resets the endpoint data toggle to 0
+ USB_REGS->INDEXED_EPCSR.RXCSRL_DEVICEbits.CLRDT = 1;
+
+ // Set up the FIFO size
+ USB_REGS->RXFIFOSZbits.RXFIFOSZ = fifoSize;
+
+ USB_REGS->INDEXED_EPCSR.RXCSRH_DEVICEbits.ISO = transferType == 1 ? 1 : 0;
+ // Disable NYET Handshakes for interrupt endpoints
+ USB_REGS->INDEXED_EPCSR.RXCSRH_DEVICEbits.DISNYET = transferType == 3 ? 1 : 0;
+
+ // Restore the index register.
+ USB_REGS->INDEXbits.ENDPOINT = old_index;
+
+ // Enable the endpoint interrupt.
+ USB_REGS->INTRRXEbits.w |= (1 << endpoint);
+}
+
+static void epn_tx_configure(uint8_t endpoint, uint16_t endpointSize,
+ uint16_t fifoAddress, uint8_t fifoSize,
+ uint32_t transferType)
+{
+ uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
+
+ // Select endpoint register set (same register address is used for all endpoints.
+ USB_REGS->INDEXbits.ENDPOINT = endpoint;
+
+ // Configure the Endpoint size
+ USB_REGS->INDEXED_EPCSR.TXMAXPbits.TXMAXP = endpointSize;
+
+ // Set up the fifo address
+ USB_REGS->TXFIFOADDbits.TXFIFOAD = fifoAddress;
+
+ // Resets the endpoint data toggle to 0
+ USB_REGS->INDEXED_EPCSR.TXCSRL_DEVICEbits.CLRDT = 1;
+
+ // Set up the FIFO size
+ USB_REGS->TXFIFOSZbits.TXFIFOSZ = fifoSize;
+
+ USB_REGS->INDEXED_EPCSR.TXCSRH_DEVICEbits.ISO = 1 == transferType ? 1 : 0;
+
+ // Restore the index register
+ USB_REGS->INDEXbits.ENDPOINT = old_index;
+
+ // Enable the interrupt
+ USB_REGS->INTRTXEbits.w |= (1 << endpoint);
+}
+
+static void tx_fifo_write(uint8_t endpoint, uint8_t const * buffer, size_t count)
+{
+ size_t i;
+ volatile uint8_t * fifo_reg;
+
+ fifo_reg = (volatile uint8_t *) (&USB_REGS->FIFO[endpoint]);
+
+ for (i = 0; i < count; i++)
+ {
+ *fifo_reg = buffer[i];
+ }
+}
+
+static int rx_fifo_read(uint8_t epnum, uint8_t * buffer)
+{
+ uint32_t i;
+ uint32_t count;
+ volatile uint8_t * fifo_reg;
+
+ fifo_reg = (volatile uint8_t *) (&USB_REGS->FIFO[epnum]);
+
+ count = USB_REGS->EPCSR[epnum].RXCOUNTbits.RXCNT;
+
+ for (i = 0; i < count; i++)
+ {
+ buffer[i] = fifo_reg[i & 3];
+ }
+
+ return count;
+}
+
+static void xfer_complete(xfer_ctl_t * xfer, uint8_t result, bool in_isr)
+{
+ dcd_event_xfer_complete(0, xfer->ep_addr, xfer->transferred, result, in_isr);
+}
+
+static void ep0_fill_tx(xfer_ctl_t * xfer_in)
+{
+ uint16_t left = xfer_in->total_len - xfer_in->transferred;
+
+ if (left)
+ {
+ xfer_in->last_packet_size = tu_min16(xfer_in->max_packet_size, left);
+ tx_fifo_write(0, xfer_in->buffer + xfer_in->transferred, xfer_in->last_packet_size);
+ xfer_in->transferred += xfer_in->last_packet_size;
+ left = xfer_in->total_len - xfer_in->transferred;
+ }
+
+ if (xfer_in->last_packet_size < xfer_in->max_packet_size || left == 0)
+ {
+ switch (ep0_get_stage())
+ {
+ case EP0_STAGE_SETUP_IN_DATA:
+ case EP0_STAGE_DATA_IN:
+ case EP0_STAGE_DATA_IN_SENT:
+ ep0_set_stage(EP0_STAGE_DATA_IN_LAST_PACKET_FILLED);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.TXPKTRDY = 1;
+ break;
+ case EP0_STAGE_SETUP_OUT_NO_DATA:
+ ep0_set_stage(EP0_STAGE_STATUS_IN);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
+ break;
+ case EP0_STAGE_DATA_OUT_COMPLETE:
+ ep0_set_stage(EP0_STAGE_STATUS_IN);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (ep0_get_stage())
+ {
+ case EP0_STAGE_SETUP_IN_DATA:
+ ep0_set_stage(EP0_STAGE_DATA_IN);
+ // fall through
+ case EP0_STAGE_DATA_IN:
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.TXPKTRDY = 1;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void epn_fill_tx(xfer_ctl_t * xfer_in, uint8_t epnum)
+{
+ uint16_t left = xfer_in->total_len - xfer_in->transferred;
+ if (left)
+ {
+ xfer_in->last_packet_size = tu_min16(xfer_in->max_packet_size, left);
+ tx_fifo_write(epnum, xfer_in->buffer + xfer_in->transferred, xfer_in->last_packet_size);
+ }
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.TXPKTRDY = 1;
+}
+
+static bool ep0_xfer(xfer_ctl_t * xfer, int dir)
+{
+ if (dir == TUSB_DIR_OUT)
+ {
+ if (xfer->total_len)
+ {
+ switch (_dcd.ep0_stage)
+ {
+ case EP0_STAGE_DATA_OUT_COMPLETE:
+ case EP0_STAGE_SETUP_OUT_DATA:
+ ep0_set_stage(EP0_STAGE_DATA_OUT);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
+ break;
+ default:
+ TU_ASSERT(0);
+ }
+ }
+ else
+ {
+ switch (_dcd.ep0_stage)
+ {
+ case EP0_STAGE_DATA_IN_SENT:
+ ep0_set_stage(EP0_STAGE_NONE);
+ // fall through
+ case EP0_STAGE_NONE:
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else // IN
+ {
+ ep0_fill_tx(xfer);
+ }
+
+ return true;
+}
+
+/*------------------------------------------------------------------*/
+/* DCD Endpoint port
+ *------------------------------------------------------------------*/
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
+{
+ (void) rhport;
+ uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+
+ TU_ASSERT(epnum < EP_MAX);
+
+ xfer->max_packet_size = tu_edpt_packet_size(desc_edpt);
+ xfer->fifo_size = xfer->max_packet_size;
+ xfer->ep_addr = desc_edpt->bEndpointAddress;
+
+ if (epnum != 0)
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ epn_rx_configure(epnum, xfer->max_packet_size, _dcd.fifo_addr_top, __builtin_ctz(xfer->fifo_size) - 3, desc_edpt->bmAttributes.xfer);
+ _dcd.fifo_addr_top += (xfer->fifo_size + 7) >> 3;
+ }
+ else
+ {
+ epn_tx_configure(epnum, xfer->max_packet_size, _dcd.fifo_addr_top, __builtin_ctz(xfer->fifo_size) - 3, desc_edpt->bmAttributes.xfer);
+ _dcd.fifo_addr_top += (xfer->fifo_size + 7) >> 3;
+ }
+ }
+ return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+
+ // Reserve EP0 FIFO address
+ _dcd.fifo_addr_top = 64 >> 3;
+ for (int i = 1; i < EP_MAX; ++i)
+ {
+ tu_memclr(&_dcd.xfer_status[i], sizeof(_dcd.xfer_status[i]));
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ (void) ep_addr;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+ (void) rhport;
+
+ xfer->buffer = buffer;
+ xfer->total_len = total_bytes;
+ xfer->last_packet_size = 0;
+ xfer->transferred = 0;
+
+ if (epnum == 0)
+ {
+ return ep0_xfer(xfer, dir);
+ }
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REGS->INTRRXEbits.w |= (1u << epnum);
+ }
+ else // IN
+ {
+ epn_fill_tx(xfer, epnum);
+ }
+
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ (void) rhport;
+
+ if (epnum == 0)
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENDSTALL = 1;
+ }
+ else
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.SENDSTALL = 1;
+ }
+ else
+ {
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.SENDSTALL = 1;
+ }
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+ (void) rhport;
+
+ if (epnum == 0)
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENDSTALL = 0;
+ }
+ else
+ {
+ if (dir == TUSB_DIR_OUT)
+ {
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w &= ~(USBHS_EP_DEVICE_RX_SENT_STALL | USBHS_EP_DEVICE_RX_SEND_STALL);
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.CLRDT = 1;
+ }
+ else
+ {
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w &= ~(USBHS_EP_DEVICE_TX_SENT_STALL | USBHS_EP_DEVICE_TX_SEND_STALL);
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.CLRDT = 1;
+ }
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Interrupt Handler
+ *------------------------------------------------------------------*/
+
+static void ep0_handle_rx(void)
+{
+ int transferred;
+ xfer_ctl_t * xfer = XFER_CTL_BASE(0, TUSB_DIR_OUT);
+
+ TU_ASSERT(xfer->buffer,);
+
+ transferred = rx_fifo_read(0, xfer->buffer + xfer->transferred);
+ xfer->transferred += transferred;
+ TU_ASSERT(xfer->transferred <= xfer->total_len,);
+ if (transferred < xfer->max_packet_size || xfer->transferred == xfer->total_len)
+ {
+ ep0_set_stage(EP0_STAGE_DATA_OUT_COMPLETE);
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ }
+ else
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
+ }
+}
+
+static void epn_handle_rx_int(uint8_t epnum)
+{
+ uint8_t ep_status;
+ int transferred;
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
+
+ ep_status = USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w;
+ if (ep_status & USBHS_EP_DEVICE_RX_SENT_STALL)
+ {
+ USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w &= ~USBHS_EP_DEVICE_RX_SENT_STALL;
+ }
+
+ if (ep_status & USBHS_EP0_HOST_RXPKTRDY)
+ {
+ TU_ASSERT(xfer->buffer != NULL,);
+
+ transferred = rx_fifo_read(epnum, xfer->buffer + xfer->transferred);
+ USB_REGS->EPCSR[epnum].RXCSRL_HOSTbits.RXPKTRDY = 0;
+ xfer->transferred += transferred;
+ TU_ASSERT(xfer->transferred <= xfer->total_len,);
+ if (transferred < xfer->max_packet_size || xfer->transferred == xfer->total_len)
+ {
+ USB_REGS->INTRRXEbits.w &= ~(1u << epnum);
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ }
+ }
+}
+
+static void epn_handle_tx_int(uint8_t epnum)
+{
+ uint8_t ep_status = USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w;
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
+
+ if (ep_status & USBHS_EP_DEVICE_TX_SENT_STALL)
+ {
+ USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w &= ~USBHS_EP_DEVICE_TX_SENT_STALL;
+ }
+ else
+ {
+ xfer->transferred += xfer->last_packet_size;
+ TU_ASSERT(xfer->transferred <= xfer->total_len,);
+ if (xfer->last_packet_size < xfer->max_packet_size || xfer->transferred == xfer->total_len)
+ {
+ xfer->last_packet_size = 0;
+ xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
+ }
+ else
+ {
+ epn_fill_tx(xfer, epnum);
+ }
+ }
+}
+
+static void ep0_handle_int(void)
+{
+ __USBHS_CSR0L_DEVICE_t ep0_status;
+ union {
+ tusb_control_request_t request;
+ uint32_t setup_buffer[2];
+ } setup_packet;
+ xfer_ctl_t * xfer_in = XFER_CTL_BASE(0, TUSB_DIR_IN);
+ uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
+
+ // Select EP0 registers
+ USB_REGS->INDEXbits.ENDPOINT = 0;
+
+ ep0_status = USB_REGS->EPCSR[0].CSR0L_DEVICEbits;
+
+ if (ep0_status.SENTSTALL)
+ {
+ // Stall was sent. Reset the endpoint 0 state.
+ // Clear the sent stall bit.
+ ep0_set_stage(EP0_STAGE_NONE);
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENTSTALL = 0;
+ }
+
+ if (ep0_status.SETUPEND)
+ {
+ // This means the current control transfer end prematurely. We don't
+ // need to end any transfers. The device layer will manage the
+ // premature transfer end. We clear the SetupEnd bit and reset the
+ // driver control transfer state machine to waiting for next setup
+ // packet from host.
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVSSETEND = 1;
+ ep0_set_stage(EP0_STAGE_NONE);
+ }
+
+ if (ep0_status.RXPKTRDY)
+ {
+ switch (ep0_get_stage())
+ {
+ default:
+ // Data arrived at unexpected state, this must be setup stage packet after all.
+ // Fall through
+ case EP0_STAGE_NONE:
+ // This means we were expecting a SETUP packet and we got one.
+ setup_packet.setup_buffer[0] = USB_REGS->FIFO[0];
+ setup_packet.setup_buffer[1] = USB_REGS->FIFO[0];
+ if (setup_packet.request.bmRequestType_bit.direction == TUSB_DIR_OUT)
+ {
+ // SVCRPR is not set yet, it will be set later when out xfer is started
+ // Till then NAKs will hold incommint data
+ ep0_set_stage(setup_packet.request.wLength == 0 ? EP0_STAGE_SETUP_OUT_NO_DATA : EP0_STAGE_SETUP_OUT_DATA);
+ }
+ else
+ {
+ USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
+ ep0_set_stage(EP0_STAGE_SETUP_IN_DATA);
+ }
+ dcd_event_setup_received(0, &setup_packet.request.bmRequestType, true);
+ break;
+ case EP0_STAGE_DATA_OUT:
+ ep0_handle_rx();
+ break;
+ }
+ }
+ else
+ {
+ switch (ep0_get_stage())
+ {
+ case EP0_STAGE_STATUS_IN:
+ // Status was just sent, this concludes request, notify client
+ ep0_set_stage(EP0_STAGE_NONE);
+ xfer_complete(xfer_in, XFER_RESULT_SUCCESS, true);
+ break;
+ case EP0_STAGE_DATA_IN:
+ // Packet sent, fill more data
+ ep0_fill_tx(xfer_in);
+ break;
+ case EP0_STAGE_DATA_IN_LAST_PACKET_FILLED:
+ ep0_set_stage(EP0_STAGE_DATA_IN_SENT);
+ xfer_complete(xfer_in, XFER_RESULT_SUCCESS, true);
+ break;
+ case EP0_STAGE_ADDRESS_CHANGE:
+ // Status stage after set address request finished, address can be changed
+ USB_REGS->FADDRbits.FUNC = _dcd.dev_addr;
+ ep0_set_stage(EP0_STAGE_NONE);
+ break;
+ default:
+ break;
+ }
+ }
+ // Restore register index
+ USB_REGS->INDEXbits.ENDPOINT = old_index;
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+ int i;
+ uint8_t mask;
+ __USBCSR2bits_t csr2_bits;
+ uint16_t rxints = USB_REGS->INTRRX & USB_REGS->INTRRXEbits.w;
+ uint16_t txints = USB_REGS->INTRTX;
+ csr2_bits = USBCSR2bits;
+ (void) rhport;
+
+ IFS4CLR = _IFS4_USBIF_MASK;
+
+ if (csr2_bits.SOFIF && csr2_bits.SOFIE)
+ {
+ dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+ }
+ if (csr2_bits.RESETIF)
+ {
+ dcd_edpt_open(0, &ep0OUT_desc);
+ dcd_edpt_open(0, &ep0IN_desc);
+ dcd_event_bus_reset(0, USB_REGS->POWERbits.HSMODE ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true);
+ }
+ if (csr2_bits.SUSPIF)
+ {
+ dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+ }
+ if (csr2_bits.RESUMEIF)
+ {
+ dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+ }
+ // INTRTX has bit for EP0
+ if (txints & 1)
+ {
+ txints ^= 1;
+ ep0_handle_int();
+ }
+ for (mask = 0x02, i = 1; rxints != 0 && mask != 0; mask <<= 1, ++i)
+ {
+ if (rxints & mask)
+ {
+ rxints ^= mask;
+ epn_handle_rx_int(i);
+ }
+ }
+ for (mask = 0x02, i = 1; txints != 0 && mask != 0; mask <<= 1, ++i)
+ {
+ if (txints & mask)
+ {
+ txints ^= mask;
+ epn_handle_tx_int(i);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/microchip/pic32mz/usbhs_registers.h b/src/portable/microchip/pic32mz/usbhs_registers.h
new file mode 100644
index 000000000..757e3f083
--- /dev/null
+++ b/src/portable/microchip/pic32mz/usbhs_registers.h
@@ -0,0 +1,931 @@
+/*******************************************************************************
+* Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries.
+*
+* Subject to your compliance with these terms, you may use Microchip software
+* and any derivatives exclusively with Microchip products. It is your
+* responsibility to comply with third party license terms applicable to your
+* use of third party software (including open source software) that may
+* accompany Microchip software.
+*
+* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
+* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
+* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
+* PARTICULAR PURPOSE.
+*
+* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
+* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
+* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
+* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
+* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
+* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+*******************************************************************************/
+/*******************************************************************************
+ USBHS Peripheral Library Register Defintions
+
+ File Name:
+ usbhs_registers.h
+
+ Summary:
+ USBHS PLIB Register Defintions
+
+ Description:
+ This file contains the constants and defintions which are required by the
+ the USBHS library.
+*******************************************************************************/
+
+#ifndef __USBHS_REGISTERS_H__
+#define __USBHS_REGISTERS_H__
+
+#include <p32xxxx.h>
+#include <stdint.h>
+
+/*****************************************
+ * Module Register Offsets.
+ *****************************************/
+
+#define USBHS_REG_FADDR 0x000
+#define USBHS_REG_POWER 0x001
+#define USBHS_REG_INTRTX 0x002
+#define USBHS_REG_INTRRX 0x004
+#define USBHS_REG_INTRTXE 0x006
+#define USBHS_REG_INTRRXE 0x008
+#define USBHS_REG_INTRUSB 0x00A
+#define USBHS_REG_INTRUSBE 0x00B
+#define USBHS_REG_FRAME 0x00C
+#define USBHS_REG_INDEX 0x00E
+#define USBHS_REG_TESTMODE 0x00F
+
+/*******************************************************
+ * Endpoint Control Status Registers (CSR). These values
+ * should be added to either the 0x10 to access the
+ * register through Indexed CSR. To access the actual
+ * CSR, see ahead in this header file.
+ ******************************************************/
+
+#define USBHS_REG_EP_TXMAXP 0x000
+#define USBHS_REG_EP_CSR0L 0x002
+#define USBHS_REG_EP_CSR0H 0x003
+#define USBHS_REG_EP_TXCSRL 0x002
+#define USBHS_REG_EP_TXCSRH 0x003
+#define USBHS_REG_EP_RXMAXP 0x004
+#define USBHS_REG_EP_RXCSRL 0x006
+#define USBHS_REG_EP_RXCSRH 0x007
+#define USBHS_REG_EP_COUNT0 0x008
+#define USBHS_REG_EP_RXCOUNT 0x008
+#define USBHS_REG_EP_TYPE0 0x01A
+#define USBHS_REG_EP_TXTYPE 0x01A
+#define USBHS_REG_EP_NAKLIMIT0 0x01B
+#define USBHS_REG_EP_TXINTERVAL 0x01B
+#define USBHS_REG_EP_RXTYPE 0x01C
+#define USBHS_REG_EP_RXINTERVAL 0x01D
+#define USBHS_REG_EP_CONFIGDATA 0x01F
+#define USBHS_REG_EP_FIFOSIZE 0x01F
+
+#define USBHS_HOST_EP0_SETUPKT_SET 0x8
+#define USBHS_HOST_EP0_TXPKTRDY_SET 0x2
+#define USBHS_SOFT_RST_NRST_SET 0x1
+#define USBHS_SOFT_RST_NRSTX_SET 0x2
+#define USBHS_EP0_DEVICE_SERVICED_RXPKTRDY 0x40
+#define USBHS_EP0_DEVICE_DATAEND 0x08
+#define USBHS_EP0_DEVICE_TXPKTRDY 0x02
+#define USBHS_EP0_HOST_STATUS_STAGE_START 0x40
+#define USBHS_EP0_HOST_REQPKT 0x20
+#define USBHS_EP0_HOST_TXPKTRDY 0x02
+#define USBHS_EP0_HOST_RXPKTRDY 0x01
+#define USBHS_EP_DEVICE_TX_SENT_STALL 0x20
+#define USBHS_EP_DEVICE_TX_SEND_STALL 0x10
+#define USBHS_EP_DEVICE_RX_SENT_STALL 0x40
+#define USBHS_EP_DEVICE_RX_SEND_STALL 0x20
+
+/* FADDR - Device Function Address */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned FUNC:7;
+ unsigned :1;
+ };
+
+ uint8_t w;
+
+} __USBHS_FADDR_t;
+
+/* POWER - Control Resume and Suspend signalling */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned SUSPEN:1;
+ unsigned SUSPMODE:1;
+ unsigned RESUME:1;
+ unsigned RESET:1;
+ unsigned HSMODE:1;
+ unsigned HSEN:1;
+ unsigned SOFTCONN:1;
+ unsigned ISOUPD:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_POWER_t;
+
+/* INTRTXE - Transmit endpoint interrupt enable */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned EP0IE:1;
+ unsigned EP1TXIE:1;
+ unsigned EP2TXIE:1;
+ unsigned EP3TXIE:1;
+ unsigned EP4TXIE:1;
+ unsigned EP5TXIE:1;
+ unsigned EP6TXIE:1;
+ unsigned EP7TXIE:1;
+ unsigned :8;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_INTRTXE_t;
+
+/* INTRRXE - Receive endpoint interrupt enable */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned :1;
+ unsigned EP1RXIE:1;
+ unsigned EP2RXIE:1;
+ unsigned EP3RXIE:1;
+ unsigned EP4RXIE:1;
+ unsigned EP5RXIE:1;
+ unsigned EP6RXIE:1;
+ unsigned EP7RXIE:1;
+ unsigned :8;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_INTRRXE_t;
+
+/* INTRUSBE - General USB Interrupt enable */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned SUSPIE:1;
+ unsigned RESUMEIE:1;
+ unsigned RESETIE:1;
+ unsigned SOFIE:1;
+ unsigned CONNIE:1;
+ unsigned DISCONIE:1;
+ unsigned SESSRQIE:1;
+ unsigned VBUSERRIE:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_INTRUSBE_t;
+
+/* FRAME - Frame number */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RFRMNUM:11;
+ unsigned :5;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_FRAME_t;
+
+/* INDEX - Endpoint index */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned ENDPOINT:4;
+ unsigned :4;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_INDEX_t;
+
+/* TESTMODE - Test mode register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned NAK:1;
+ unsigned TESTJ:1;
+ unsigned TESTK:1;
+ unsigned PACKET:1;
+ unsigned FORCEHS:1;
+ unsigned FORCEFS:1;
+ unsigned FIFOACC:1;
+ unsigned FORCEHST:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TESTMODE_t;
+
+/* COUNT0 - Indicates the amount of data received in endpoint 0 */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXCNT:7;
+ unsigned :1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_COUNT0_t;
+
+/* TYPE0 - Operating speed of target device */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned :6;
+ unsigned SPEED:2;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TYPE0_t;
+
+/* DEVCTL - Module control register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned SESSION:1;
+ unsigned HOSTREQ:1;
+ unsigned HOSTMODE:1;
+ unsigned VBUS:2;
+ unsigned LSDEV:1;
+ unsigned FSDEV:1;
+ unsigned BDEV:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_DEVCTL_t;
+
+/* CSR0L Device - Endpoint Device Mode Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned TXPKTRDY:1;
+ unsigned SENTSTALL:1;
+ unsigned DATAEND:1;
+ unsigned SETUPEND:1;
+ unsigned SENDSTALL:1;
+ unsigned SVCRPR:1;
+ unsigned SVSSETEND:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0L_DEVICE_t;
+
+/* CSR0L Host - Endpoint Host Mode Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned TXPKTRDY:1;
+ unsigned RXSTALL:1;
+ unsigned SETUPPKT:1;
+ unsigned ERROR:1;
+ unsigned REQPKT:1;
+ unsigned STATPKT:1;
+ unsigned NAKTMOUT:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0L_HOST_t;
+
+/* TXCSRL Device - Endpoint Transmit Control Status Register Low */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXPKTRDY:1;
+ unsigned FIFOONE:1;
+ unsigned UNDERRUN:1;
+ unsigned FLUSH:1;
+ unsigned SENDSTALL:1;
+ unsigned SENTSTALL:1;
+ unsigned CLRDT:1;
+ unsigned INCOMPTX:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRL_DEVICE_t;
+
+/* TXCSRL Host - Endpoint Transmit Control Status Register Low */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXPKTRDY:1;
+ unsigned FIFONE:1;
+ unsigned ERROR:1;
+ unsigned FLUSH:1;
+ unsigned SETUPPKT:1;
+ unsigned RXSTALL:1;
+ unsigned CLRDT:1;
+ unsigned INCOMPTX:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRL_HOST_t;
+
+/* TXCSRH Device - Endpoint Transmit Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned :2;
+ unsigned DMAREQMD:1;
+ unsigned FRCDATTG:1;
+ unsigned DMAREQENL:1;
+ unsigned MODE:1;
+ unsigned ISO:1;
+ unsigned AUTOSET:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRH_DEVICE_t;
+
+/* TXCSRH Host - Endpoint Transmit Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned DATATGGL:1;
+ unsigned DTWREN:1;
+ unsigned DMAREQMD:1;
+ unsigned FRCDATTG:1;
+ unsigned DMAREQEN:1;
+ unsigned MODE:1;
+ unsigned :1;
+ unsigned AUOTSET:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXCSRH_HOST_t;
+
+/* CSR0H Device - Endpoint 0 Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned FLSHFIFO:1;
+ unsigned :7;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0H_DEVICE_t;
+
+/* CSR0H Host - Endpoint 0 Control Status Register High */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned FLSHFIFO:1;
+ unsigned DATATGGL:1;
+ unsigned DTWREN:1;
+ unsigned DISPING:1;
+ unsigned :4;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_CSR0H_HOST_t;
+
+/* RXMAXP - Receive Endpoint Max packet size. */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXMAXP:11;
+ unsigned MULT:5;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_RXMAXP_t;
+
+/* RXCSRL Device - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned FIFOFULL:1;
+ unsigned OVERRUN:1;
+ unsigned DATAERR:1;
+ unsigned FLUSH:1;
+ unsigned SENDSTALL:1;
+ unsigned SENTSTALL:1;
+ unsigned CLRDT:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRL_DEVICE_t;
+
+/* RXCSRL Host - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXPKTRDY:1;
+ unsigned FIFOFULL:1;
+ unsigned ERROR:1;
+ unsigned DERRNAKT:1;
+ unsigned FLUSH:1;
+ unsigned REQPKT:1;
+ unsigned RXSTALL:1;
+ unsigned CLRDT:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRL_HOST_t;
+
+/* RXCSRH Device - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned INCOMPRX:1;
+ unsigned :2;
+ unsigned DMAREQMODE:1;
+ unsigned DISNYET:1;
+ unsigned DMAREQEN:1;
+ unsigned ISO:1;
+ unsigned AUTOCLR:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRH_DEVICE_t;
+
+/* RXCSRH Host - Receive endpoint Control Status Register */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned INCOMPRX:1;
+ unsigned DATATGGL:1;
+ unsigned DATATWEN:1;
+ unsigned DMAREQMD:1;
+ unsigned PIDERR:1;
+ unsigned DMAREQEN:1;
+ unsigned AUTORQ:1;
+ unsigned AUOTCLR:1;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXCSRH_HOST_t;
+
+/* RXCOUNT - Amount of data pending in RX FIFO */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXCNT:14;
+ unsigned :2;
+ };
+ struct
+ {
+ uint16_t w;
+ };
+
+} __USBHS_RXCOUNT_t;
+
+/* TXTYPE - Specifies the target transmit endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TEP:4;
+ unsigned PROTOCOL:2;
+ unsigned SPEED:2;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_TXTYPE_t;
+
+/* RXTYPE - Specifies the target receive endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TEP:4;
+ unsigned PROTOCOL:2;
+ unsigned SPEED:2;
+ };
+ struct
+ {
+ uint8_t w;
+ };
+
+} __USBHS_RXTYPE_t;
+
+/* TXINTERVAL - Defines the polling interval */
+typedef struct
+{
+ uint8_t TXINTERV;
+
+} __USBHS_TXINTERVAL_t;
+
+/* RXINTERVAL - Defines the polling interval */
+typedef struct
+{
+ uint8_t RXINTERV;
+
+} __USBHS_RXINTERVAL_t;
+
+/* TXMAXP - Maximum amount of data that can be transferred through a TX endpoint
+ * */
+
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXMAXP:11;
+ unsigned MULT:5;
+ };
+ uint16_t w;
+
+} __USBHS_TXMAXP_t;
+
+/* TXFIFOSZ - Size of the transmit endpoint FIFO */
+typedef struct __attribute__((packed))
+{
+ unsigned TXFIFOSZ:4;
+ unsigned TXDPB:1;
+ unsigned :3;
+
+} __USBHS_TXFIFOSZ_t;
+
+/* RXFIFOSZ - Size of the receive endpoint FIFO */
+typedef struct __attribute__((packed))
+{
+ unsigned RXFIFOSZ:4;
+ unsigned RXDPB:1;
+ unsigned :3;
+
+} __USBHS_RXFIFOSZ_t;
+
+/* TXFIFOADD - Start address of the transmit endpoint FIFO */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXFIFOAD:13;
+ unsigned :3;
+ };
+ uint16_t w;
+
+} __USBHS_TXFIFOADD_t;
+
+/* RXFIFOADD - Start address of the receive endpoint FIFO */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXFIFOAD:13;
+ unsigned :3;
+ };
+ uint16_t w;
+
+} __USBHS_RXFIFOADD_t;
+
+/* SOFTRST - Asserts NRSTO and NRSTOX */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned NRST:1;
+ unsigned NRSTX:1;
+ unsigned :6;
+ };
+ uint8_t w;
+
+} __USBHS_SOFTRST_t;
+
+/* TXFUNCADDR - Target address of transmit endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXFADDR:7;
+ unsigned :1;
+ };
+ uint8_t w;
+
+} __USBHS_TXFUNCADDR_t;
+
+/* RXFUNCADDR - Target address of receive endpoint */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXFADDR:7;
+ unsigned :1;
+ };
+ uint8_t w;
+
+} __USBHS_RXFUNCADDR_t;
+
+/* TXHUBADDR - Address of the hub to which the target transmit device endpoint
+ * is connected */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXHUBADDR:7;
+ unsigned MULTTRAN:1;
+ };
+ uint8_t w;
+
+} __USBHS_TXHUBADDR_t;
+
+/* RXHUBADDR - Address of the hub to which the target receive device endpoint is
+ * connected */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXHUBADDR:7;
+ unsigned MULTTRAN:1;
+ };
+ uint8_t w;
+
+} __USBHS_RXHUBADDR_t;
+
+/* TXHUBPORT - Address of the hub to which the target transmit device endpoint
+ * is connected. */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned TXHUBPRT:7;
+ unsigned :1;
+ };
+
+ uint8_t w;
+
+} __USBHS_TXHUBPORT_t;
+
+/* RXHUBPORT - Address of the hub to which the target receive device endpoint
+ * is connected. */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned RXHUBPRT:7;
+ unsigned :1;
+ };
+
+ uint8_t w;
+
+} __USBHS_RXHUBPORT_t;
+
+/* DMACONTROL - Configures a DMA channel */
+typedef union
+{
+ struct __attribute__((packed))
+ {
+ unsigned DMAEN:1;
+ unsigned DMADIR:1;
+ unsigned DMAMODE:1;
+ unsigned DMAIE:1;
+ unsigned DMAEP:4;
+ unsigned DMAERR:1;
+ unsigned DMABRSTM:2;
+ unsigned:21;
+ };
+
+ uint32_t w;
+
+} __USBHS_DMACNTL_t;
+
+/* Endpoint Control and Status Register Set */
+typedef struct __attribute__((packed))
+{
+ volatile __USBHS_TXMAXP_t TXMAXPbits;
+ union
+ {
+ struct
+ {
+ union
+ {
+ volatile __USBHS_CSR0L_DEVICE_t CSR0L_DEVICEbits;
+ volatile __USBHS_CSR0L_HOST_t CSR0L_HOSTbits;
+ };
+ union
+ {
+ volatile __USBHS_CSR0H_DEVICE_t CSR0H_DEVICEbits;
+ volatile __USBHS_CSR0H_HOST_t CSR0H_HOSTbits;
+ };
+ };
+
+ struct
+ {
+ union
+ {
+ volatile __USBHS_TXCSRL_DEVICE_t TXCSRL_DEVICEbits;
+ volatile __USBHS_TXCSRL_HOST_t TXCSRL_HOSTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_TXCSRH_DEVICE_t TXCSRH_DEVICEbits;
+ volatile __USBHS_TXCSRH_HOST_t TXCSRH_HOSTbits;
+ };
+ };
+ };
+
+ volatile __USBHS_RXMAXP_t RXMAXPbits;
+
+ union
+ {
+ volatile __USBHS_RXCSRL_DEVICE_t RXCSRL_DEVICEbits;
+ volatile __USBHS_RXCSRL_HOST_t RXCSRL_HOSTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_RXCSRH_DEVICE_t RXCSRH_DEVICEbits;
+ volatile __USBHS_RXCSRH_HOST_t RXCSRH_HOSTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_COUNT0_t COUNT0bits;
+ volatile __USBHS_RXCOUNT_t RXCOUNTbits;
+ };
+
+ union
+ {
+ volatile __USBHS_TYPE0_t TYPE0bits;
+ volatile __USBHS_TXTYPE_t TXTYPEbits;
+ };
+
+ union
+ {
+ volatile uint8_t NAKLIMIT0;
+ volatile __USBHS_TXINTERVAL_t TXINTERVALbits;
+ };
+
+ volatile __USBHS_RXTYPE_t RXTYPEbits;
+ volatile __USBHS_RXINTERVAL_t RXINTERVALbits;
+ unsigned :8;
+ union
+ {
+ volatile uint8_t CONFIGDATA;
+ volatile uint8_t FIFOSIZE;
+ };
+
+} __USBHS_EPCSR_t;
+
+/* Set of registers that configure the multi-point option */
+typedef struct __attribute__((packed))
+{
+ volatile __USBHS_TXFUNCADDR_t TXFUNCADDRbits;
+ unsigned :8;
+ volatile __USBHS_TXHUBADDR_t TXHUBADDRbits;
+ volatile __USBHS_TXHUBPORT_t TXHUBPORTbits;
+ volatile __USBHS_RXFUNCADDR_t RXFUNCADDRbits;
+ unsigned :8;
+ volatile __USBHS_RXHUBADDR_t RXHUBADDRbits;
+ volatile __USBHS_RXHUBPORT_t RXHUBPORTbits;
+
+} __USBHS_TARGET_ADDR_t;
+
+/* Set of registers that configure the DMA channel */
+typedef struct __attribute__((packed))
+{
+ volatile __USBHS_DMACNTL_t DMACNTLbits;
+ volatile uint32_t DMAADDR;
+ volatile uint32_t DMACOUNT;
+ volatile uint32_t pad;
+} __USBHS_DMA_CHANNEL_t;
+
+/* USBHS module register set */
+typedef struct __attribute__((aligned(4),packed))
+{
+ volatile __USBHS_FADDR_t FADDRbits;
+ volatile __USBHS_POWER_t POWERbits;
+ volatile uint16_t INTRTX;
+ volatile uint16_t INTRRX;
+ volatile __USBHS_INTRTXE_t INTRTXEbits;
+ volatile __USBHS_INTRRXE_t INTRRXEbits;
+ volatile uint8_t INTRUSB;
+ volatile __USBHS_INTRUSBE_t INTRUSBEbits;
+ volatile __USBHS_FRAME_t FRAMEbits;
+ volatile __USBHS_INDEX_t INDEXbits;
+ volatile __USBHS_TESTMODE_t TESTMODEbits;
+ volatile __USBHS_EPCSR_t INDEXED_EPCSR;
+ volatile uint32_t FIFO[16];
+ volatile __USBHS_DEVCTL_t DEVCTLbits;
+ volatile uint8_t MISC;
+ volatile __USBHS_TXFIFOSZ_t TXFIFOSZbits;
+ volatile __USBHS_RXFIFOSZ_t RXFIFOSZbits;
+
+ volatile __USBHS_TXFIFOADD_t TXFIFOADDbits;
+ volatile __USBHS_RXFIFOADD_t RXFIFOADDbits;
+
+ volatile uint32_t VCONTROL;
+ volatile uint16_t HWVERS;
+ volatile uint8_t padding1[10];
+ volatile uint8_t EPINFO;
+ volatile uint8_t RAMINFO;
+ volatile uint8_t LINKINFO;
+ volatile uint8_t VPLEN;
+ volatile uint8_t HS_EOF1;
+ volatile uint8_t FS_EOF1;
+ volatile uint8_t LS_EOF1;
+
+ volatile __USBHS_SOFTRST_t SOFTRSTbits;
+
+ volatile __USBHS_TARGET_ADDR_t TADDR[16];
+ volatile __USBHS_EPCSR_t EPCSR[16];
+ volatile uint32_t DMA_INTR;
+ volatile __USBHS_DMA_CHANNEL_t DMA_CHANNEL[8];
+ volatile uint32_t RQPKTXOUNT[16];
+
+} usbhs_registers_t;
+
+#endif
diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c
index 46aabc5aa..976d3dfd0 100644
--- a/src/portable/microchip/samd/dcd_samd.c
+++ b/src/portable/microchip/samd/dcd_samd.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
+#if CFG_TUD_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_SAML21)
@@ -180,6 +180,14 @@ void dcd_connect(uint8_t rhport)
USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -214,14 +222,14 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
uint32_t size_value = 0;
while (size_value < 7) {
- if (1 << (size_value + 3) == tu_edpt_packet_size(desc_edpt)) {
+ if (1 << (size_value + 3) >= tu_edpt_packet_size(desc_edpt)) {
break;
}
size_value++;
}
// unsupported endpoint size
- if ( size_value == 7 && tu_edpt_packet_size(desc_edpt) != 1023 ) return false;
+ if ( size_value == 7 && tu_edpt_packet_size(desc_edpt) > 1023 ) return false;
bank->PCKSIZE.bit.SIZE = size_value;
@@ -242,6 +250,13 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
return true;
}
+void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ (void) ep_addr;
+
+ // TODO: implement if necessary?
+}
+
void dcd_edpt_close_all (uint8_t rhport)
{
(void) rhport;
@@ -271,14 +286,14 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
{
bank->PCKSIZE.bit.MULTI_PACKET_SIZE = total_bytes;
bank->PCKSIZE.bit.BYTE_COUNT = 0;
- ep->EPSTATUSCLR.reg |= USB_DEVICE_EPSTATUSCLR_BK0RDY;
- ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL0;
+ ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY;
+ ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL0;
} else
{
bank->PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
bank->PCKSIZE.bit.BYTE_COUNT = total_bytes;
- ep->EPSTATUSSET.reg |= USB_DEVICE_EPSTATUSSET_BK1RDY;
- ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL1;
+ ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK1RDY;
+ ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL1;
}
return true;
diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c
index 2e9854153..814e680fb 100644
--- a/src/portable/microchip/samg/dcd_samg.c
+++ b/src/portable/microchip/samg/dcd_samg.c
@@ -210,6 +210,14 @@ void dcd_disconnect(uint8_t rhport)
UDP->UDP_TXVC = UDP_TXVC_TXVDIS_Msk;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c
index 9e3b43840..7507c0f69 100644
--- a/src/portable/microchip/samx7x/dcd_samx7x.c
+++ b/src/portable/microchip/samx7x/dcd_samx7x.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMX7X
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMX7X
#include "device/dcd.h"
#include "sam.h"
@@ -191,6 +191,14 @@ void dcd_disconnect(uint8_t rhport)
USB_REG->DEVCTRL &=~(DEVCTRL_ADDEN | DEVCTRL_UADD);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
static tusb_speed_t get_speed(void)
{
switch (USB_REG->SR & SR_SPEED) {
diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
index a3b69b987..39b09db68 100644
--- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
+++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MM32F327X )
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MM32F327X )
#include "reg_usb_otg_fs.h"
#include "mm32_device.h"
@@ -305,6 +305,14 @@ void dcd_disconnect(uint8_t rhport)
USB_OTG_FS->CTL = 0;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 9d7db11b2..ca37d799f 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -26,8 +26,9 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
+#include <stdatomic.h>
#include "nrf.h"
#include "nrf_clock.h"
#include "nrf_power.h"
@@ -38,6 +39,10 @@
#include "device/usbd.h"
#include "device/usbd_pvt.h" // to use defer function helper
+#if CFG_TUSB_OS == OPT_OS_MYNEWT
+#include "mcu/mcu.h"
+#endif
+
/*------------------------------------------------------------------*/
/* MACRO TYPEDEF CONSTANT ENUM
*------------------------------------------------------------------*/
@@ -63,11 +68,12 @@ typedef struct
uint8_t* buffer;
uint16_t total_len;
volatile uint16_t actual_len;
- uint16_t mps; // max packet size
+ uint16_t mps; // max packet size
// nRF will auto accept OUT packet after DMA is done
// indicate packet is already ACK
volatile bool data_received;
+ volatile bool started;
// Set to true when data was transferred from RAM to ISO IN output buffer.
// New data can be put in ISO IN output buffer after SOF.
@@ -82,11 +88,8 @@ static struct
// +1 for ISO endpoints
xfer_td_t xfer[EP_CBI_COUNT + 1][2];
- // Number of pending DMA that is started but not handled yet by dcd_int_handler().
- // Since nRF can only carry one DMA can run at a time, this value is normally be either 0 or 1.
- // However, in critical section with interrupt disabled, the DMA can be finished and added up
- // until handled by dcd_int_handler() when exiting critical section.
- volatile uint8_t dma_pending;
+ // nRF can only carry one DMA at a time, this is used to guard the access to EasyDMA
+ atomic_bool dma_running;
}_dcd;
/*------------------------------------------------------------------*/
@@ -115,67 +118,36 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
}
// 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)
+static void start_dma(volatile uint32_t* reg_startep)
{
- // Only one dma can be active
- if ( _dcd.dma_pending )
- {
- if (is_in_isr())
- {
- // Called within ISR, use usbd task to defer later
- usbd_defer_func((osal_task_func_t) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
- return;
- }
- else
- {
- if ( __get_PRIMASK() || !NVIC_GetEnableIRQ(USBD_IRQn) )
- {
- // Called in critical section with interrupt disabled. We have to manually check
- // for the DMA complete by comparing current pending DMA with number of ENDED Events
- uint32_t ended = 0;
-
- while ( _dcd.dma_pending > ((uint8_t) ended) )
- {
- ended = NRF_USBD->EVENTS_ENDISOIN + NRF_USBD->EVENTS_ENDISOOUT;
-
- for (uint8_t i=0; i<EP_CBI_COUNT; i++)
- {
- ended += NRF_USBD->EVENTS_ENDEPIN[i] + NRF_USBD->EVENTS_ENDEPOUT[i];
- }
- }
- }else
- {
- // Called in non-critical thread-mode, should be 99% of the time.
- // Should be safe to blocking wait until previous DMA transfer complete
- while ( _dcd.dma_pending ) { }
- }
- }
- }
-
- _dcd.dma_pending++;
-
(*reg_startep) = 1;
__ISB(); __DSB();
+
+ // TASKS_EP0STATUS, TASKS_EP0RCVOUT seem to need EasyDMA to be available
+ // However these don't trigger any DMA transfer and got ENDED event subsequently
+ // Therefore dma_pending is corrected right away
+ if ( (reg_startep == &NRF_USBD->TASKS_EP0STATUS) || (reg_startep == &NRF_USBD->TASKS_EP0RCVOUT) )
+ {
+ atomic_flag_clear(&_dcd.dma_running);
+ }
}
-// DMA is complete
-static void edpt_dma_end(void)
+static void edpt_dma_start(volatile uint32_t* reg_startep)
{
- TU_ASSERT(_dcd.dma_pending, );
- _dcd.dma_pending = 0;
+ if ( atomic_flag_test_and_set(&_dcd.dma_running) )
+ {
+ usbd_defer_func((osal_task_func_t) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
+ }else
+ {
+ start_dma(reg_startep);
+ }
}
-// 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)
+// DMA is complete
+static void edpt_dma_end(void)
{
- edpt_dma_start(reg_task);
-
- // correct the dma_running++ in dma start
- if (_dcd.dma_pending) _dcd.dma_pending--;
+ TU_ASSERT(_dcd.dma_running, );
+ atomic_flag_clear(&_dcd.dma_running);
}
// helper getting td
@@ -184,24 +156,42 @@ static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir)
return &_dcd.xfer[epnum][dir];
}
+static void xact_out_dma(uint8_t epnum);
+// Function wraps xact_out_dma which wants uint8_t while usbd_defer_func wants void (*)(void *)
+static void xact_out_dma_wrapper(void *epnum)
+{
+ xact_out_dma((uint8_t)((uintptr_t)epnum));
+}
+
// Start DMA to move data from Endpoint -> RAM
static void xact_out_dma(uint8_t epnum)
{
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
uint32_t xact_len;
+ // DMA can't be active during read of SIZE.EPOUT or SIZE.ISOOUT, so try to lock,
+ // If already running deffer call regardless if it was called from ISR or task,
+ if ( atomic_flag_test_and_set(&_dcd.dma_running) )
+ {
+ usbd_defer_func((osal_task_func_t)xact_out_dma_wrapper, (void *)(uint32_t)epnum, is_in_isr());
+ return;
+ }
if (epnum == EP_ISO_NUM)
{
xact_len = NRF_USBD->SIZE.ISOOUT;
// If ZERO bit is set, ignore ISOOUT length
- if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk) xact_len = 0;
+ if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk)
+ {
+ xact_len = 0;
+ atomic_flag_clear(&_dcd.dma_running);
+ }
else
{
// Trigger DMA move data from Endpoint -> SRAM
NRF_USBD->ISOOUT.PTR = (uint32_t) xfer->buffer;
NRF_USBD->ISOOUT.MAXCNT = xact_len;
- edpt_dma_start(&NRF_USBD->TASKS_STARTISOOUT);
+ start_dma(&NRF_USBD->TASKS_STARTISOOUT);
}
}
else
@@ -213,11 +203,8 @@ static void xact_out_dma(uint8_t epnum)
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
- edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
+ start_dma(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
}
-
- xfer->buffer += xact_len;
- xfer->actual_len += xact_len;
}
// Prepare for a CBI transaction IN, call at the start
@@ -232,8 +219,6 @@ static void xact_in_dma(uint8_t epnum)
NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
- xfer->buffer += xact_len;
-
edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
}
@@ -242,6 +227,7 @@ static void xact_in_dma(uint8_t epnum)
//--------------------------------------------------------------------+
void dcd_init (uint8_t rhport)
{
+ TU_LOG1("dcd init\r\n");
(void) rhport;
}
@@ -300,6 +286,14 @@ void dcd_connect(uint8_t rhport)
NRF_USBD->USBPULLUP = 1;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -444,6 +438,7 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
// When both ISO endpoint are close there is no need for SOF any more.
if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0) NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
}
+ _dcd.xfer[epnum][dir].started = false;
__ISB(); __DSB();
}
@@ -456,6 +451,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
xfer_td_t* xfer = get_td(epnum, dir);
+ TU_ASSERT(!xfer->started);
xfer->buffer = buffer;
xfer->total_len = total_bytes;
xfer->actual_len = 0;
@@ -466,20 +462,27 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
if ( control_status )
{
// Status Phase also requires EasyDMA has to be available as well !!!!
- start_ep0_task(&NRF_USBD->TASKS_EP0STATUS);
+ edpt_dma_start(&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, is_in_isr());
}
else if ( dir == TUSB_DIR_OUT )
{
+ xfer->started = true;
if ( epnum == 0 )
{
// Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
- start_ep0_task(&NRF_USBD->TASKS_EP0RCVOUT);
+ edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
}else
{
- if ( xfer->data_received )
+ // started just set, it could start DMA transfer if interrupt was trigger after this line
+ // code only needs to start transfer (from Endpoint to RAM) when data_received was set
+ // before started was set. If started is NOT set but data_received is, it means that
+ // current transfer was already finished and next data is already present in endpoint and
+ // can be consumed by future transfer
+ __ISB(); __DSB();
+ if ( xfer->data_received && xfer->started )
{
// Data is already received previously
// start DMA to copy to SRAM
@@ -522,7 +525,6 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
// There maybe data in endpoint fifo already, we need to pull it out
if ( (dir == TUSB_DIR_OUT) && xfer->data_received )
{
- TU_LOG_LOCATION();
xfer->data_received = false;
xact_out_dma(epnum);
}
@@ -717,7 +719,8 @@ void dcd_int_handler(uint8_t rhport)
if ( int_status & EDPT_END_ALL_MASK )
{
- // DMA complete move data from SRAM -> Endpoint
+ // DMA complete move data from SRAM <-> Endpoint
+ // Must before endpoint transfer handling
edpt_dma_end();
}
@@ -732,7 +735,7 @@ void dcd_int_handler(uint8_t rhport)
* - Host -> Endpoint
* EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPOUT[i]
* to start DMA. For Bulk/Interrupt, this step can occur automatically (without sw),
- * which means data may or may not be ready (data_received flag).
+ * which means data may or may not be ready (out_received flag).
* - Endpoint -> RAM
* ENDEPOUT[i] interrupted, transaction complete, sw prepare next transaction
*
@@ -762,7 +765,10 @@ void dcd_int_handler(uint8_t rhport)
if ( tu_bit_test(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum))
{
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
- uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
+ uint16_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
+
+ xfer->buffer += xact_len;
+ xfer->actual_len += xact_len;
// Transfer complete if transaction len < Max Packet Size or total len is transferred
if ( (epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
@@ -770,14 +776,7 @@ void dcd_int_handler(uint8_t rhport)
if ( epnum == 0 )
{
// 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*) (uintptr_t) &NRF_USBD->TASKS_EP0RCVOUT, true);
- }else
- {
- start_ep0_task(&NRF_USBD->TASKS_EP0RCVOUT);
- }
+ edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
}else
{
// nRF auto accept next Bulk/Interrupt OUT packet
@@ -785,7 +784,9 @@ void dcd_int_handler(uint8_t rhport)
}
}else
{
+ TU_ASSERT(xfer->started,);
xfer->total_len = xfer->actual_len;
+ xfer->started = false;
// CBI OUT complete
dcd_event_xfer_complete(0, epnum, xfer->actual_len, XFER_RESULT_SUCCESS, true);
@@ -814,8 +815,10 @@ void dcd_int_handler(uint8_t rhport)
if ( tu_bit_test(data_status, epnum) || (epnum == 0 && is_control_in) )
{
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
+ uint8_t const xact_len = NRF_USBD->EPIN[epnum].AMOUNT;
- xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT;
+ xfer->buffer += xact_len;
+ xfer->actual_len += xact_len;
if ( xfer->actual_len < xfer->total_len )
{
@@ -836,7 +839,7 @@ void dcd_int_handler(uint8_t rhport)
{
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
- if (xfer->actual_len < xfer->total_len)
+ if ( xfer->started && xfer->actual_len < xfer->total_len )
{
xact_out_dma(epnum);
}else
@@ -896,6 +899,11 @@ static bool hfclk_running(void)
static void hfclk_enable(void)
{
+#if CFG_TUSB_OS == OPT_OS_MYNEWT
+ usb_clock_request();
+ return;
+#else
+
// already running, nothing to do
if ( hfclk_running() ) return;
@@ -909,10 +917,16 @@ static void hfclk_enable(void)
nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
+#endif
}
static void hfclk_disable(void)
{
+#if CFG_TUSB_OS == OPT_OS_MYNEWT
+ usb_clock_release();
+ return;
+#else
+
#ifdef SOFTDEVICE_PRESENT
if ( is_sd_enabled() )
{
@@ -922,6 +936,7 @@ static void hfclk_disable(void)
#endif
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
+#endif
}
// Power & Clock Peripheral on nRF5x to manage USB
@@ -1064,7 +1079,13 @@ void tusb_hal_nrf_power_event (uint32_t event)
// Enable interrupt, priorities should be set by application
NVIC_ClearPendingIRQ(USBD_IRQn);
- NVIC_EnableIRQ(USBD_IRQn);
+ // Don't enable USBD interrupt yet, if dcd_init() did not finish yet
+ // Interrupt will be enabled by tud_init(), when USB stack is ready
+ // to handle interrupts.
+ if (tud_inited())
+ {
+ NVIC_EnableIRQ(USBD_IRQn);
+ }
// Wait for HFCLK
while ( !hfclk_running() ) { }
diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c
index 0d45090d1..2fdc05f36 100644
--- a/src/portable/nuvoton/nuc120/dcd_nuc120.c
+++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c
@@ -35,7 +35,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC120)
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC120)
#include "device/dcd.h"
#include "NUC100Series.h"
@@ -497,4 +497,12 @@ void dcd_connect(uint8_t rhport)
usb_attach();
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
#endif
diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c
index fc7150508..a56b5f8e8 100644
--- a/src/portable/nuvoton/nuc121/dcd_nuc121.c
+++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c
@@ -35,7 +35,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) )
+#if CFG_TUD_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) )
#include "device/dcd.h"
#include "NuMicro.h"
@@ -551,4 +551,12 @@ void dcd_connect(uint8_t rhport)
usb_attach();
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
#endif
diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c
index aefb09f4e..886720e33 100644
--- a/src/portable/nuvoton/nuc505/dcd_nuc505.c
+++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c
@@ -35,7 +35,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC505)
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC505)
#include "device/dcd.h"
#include "NUC505Series.h"
@@ -720,4 +720,12 @@ void dcd_connect(uint8_t rhport)
usb_attach();
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
#endif
diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c
index 8de924f90..13eb105cd 100644
--- a/src/portable/nxp/khci/dcd_khci.c
+++ b/src/portable/nxp/khci/dcd_khci.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( \
+#if CFG_TUD_ENABLED && ( \
( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX ) || ( CFG_TUSB_MCU == OPT_MCU_K32L2BXX ) \
)
@@ -328,6 +328,14 @@ void dcd_disconnect(uint8_t rhport)
KHCI->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/nxp/khci/hcd_khci.c
new file mode 100644
index 000000000..0f5fa6275
--- /dev/null
+++ b/src/portable/nxp/khci/hcd_khci.c
@@ -0,0 +1,626 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji Kitayama
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && ( \
+ ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX ) || ( CFG_TUSB_MCU == OPT_MCU_K32L2BXX ) \
+ )
+
+#include "fsl_device_registers.h"
+#define KHCI USB0
+
+#include "host/hcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+ TOK_PID_OUT = 0x1u,
+ TOK_PID_IN = 0x9u,
+ TOK_PID_SETUP = 0xDu,
+ TOK_PID_DATA0 = 0x3u,
+ TOK_PID_DATA1 = 0xbu,
+ TOK_PID_ACK = 0x2u,
+ TOK_PID_STALL = 0xeu,
+ TOK_PID_NAK = 0xau,
+ TOK_PID_BUSTO = 0x0u,
+ TOK_PID_ERR = 0xfu,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t head;
+ struct {
+ union {
+ struct {
+ uint16_t : 2;
+ __IO uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ __IO uint16_t own : 1;
+ uint16_t : 8;
+ };
+ struct {
+ uint16_t : 2;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
+ };
+ };
+ __IO uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+}buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t state;
+ struct {
+ uint32_t pipenum:16;
+ uint32_t odd : 1;
+ uint32_t : 0;
+ };
+ };
+ uint8_t *buffer;
+ uint16_t length;
+ uint16_t remaining;
+} endpoint_state_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ uint8_t dev_addr;
+ uint8_t ep_addr;
+ uint16_t max_packet_size;
+ union {
+ uint8_t flags;
+ struct {
+ uint8_t data : 1;
+ uint8_t xfer : 2;
+ uint8_t : 0;
+ };
+ };
+ uint8_t *buffer;
+ uint16_t length;
+ uint16_t remaining;
+} pipe_state_t;
+
+
+typedef struct
+{
+ union {
+ /* [OUT,IN][EVEN,ODD] */
+ buffer_descriptor_t bdt[2][2];
+ uint16_t bda[2*2];
+ };
+ endpoint_state_t endpoint[2];
+ pipe_state_t pipe[CFG_TUH_ENDPOINT_MAX * 2];
+ uint32_t in_progress; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe is in progress */
+ uint32_t pending; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe will be resume the next frame */
+ bool need_reset; /* The device has not been reset after connection. */
+} hcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static hcd_data_t _hcd;
+//CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _rx_buf[1024];
+
+int find_pipe(uint8_t dev_addr, uint8_t ep_addr)
+{
+ /* Find the target pipe */
+ int num;
+ for (num = 0; num < CFG_TUH_ENDPOINT_MAX * 2; ++num) {
+ pipe_state_t *p = &_hcd.pipe[num];
+ if ((p->dev_addr == dev_addr) && (p->ep_addr == ep_addr))
+ return num;
+ }
+ return -1;
+}
+
+static int prepare_packets(int pipenum)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ unsigned const dir_tx = tu_edpt_dir(pipe->ep_addr) ? 0 : 1;
+ endpoint_state_t *ep = &_hcd.endpoint[dir_tx];
+ unsigned const odd = ep->odd;
+ buffer_descriptor_t *bd = _hcd.bdt[dir_tx];
+ TU_ASSERT(0 == bd[odd].own, -1);
+
+ // TU_LOG1(" %p dir %d odd %d data %d\n", &bd[odd], dir_tx, odd, pipe->data);
+
+ ep->pipenum = pipenum;
+
+ bd[odd ].data = pipe->data;
+ bd[odd ^ 1].data = pipe->data ^ 1;
+ bd[odd ^ 1].own = 0;
+ /* reset values for a next transfer */
+
+ int num_tokens = 0; /* The number of prepared packets */
+ unsigned const mps = pipe->max_packet_size;
+ unsigned const rem = pipe->remaining;
+ if (rem > mps) {
+ /* When total_bytes is greater than the max packet size,
+ * it prepares to the next transfer to avoid NAK in advance. */
+ bd[odd ^ 1].bc = rem >= 2 * mps ? mps: rem - mps;
+ bd[odd ^ 1].addr = pipe->buffer + mps;
+ bd[odd ^ 1].own = 1;
+ if (dir_tx) ++num_tokens;
+ }
+ bd[odd].bc = rem >= mps ? mps: rem;
+ bd[odd].addr = pipe->buffer;
+ __DSB();
+ bd[odd].own = 1; /* This bit must be set last */
+ ++num_tokens;
+ return num_tokens;
+}
+
+static int select_next_pipenum(int pipenum)
+{
+ unsigned wip = _hcd.in_progress & ~_hcd.pending;
+ if (!wip) return -1;
+ unsigned msk = TU_GENMASK(31, pipenum);
+ int next = __builtin_ctz(wip & msk);
+ if (next) return next;
+ msk = TU_GENMASK(pipenum, 0);
+ next = __builtin_ctz(wip & msk);
+ return next;
+}
+
+/* When transfer is completed, return true. */
+static bool continue_transfer(int pipenum, buffer_descriptor_t *bd)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ unsigned const bc = bd->bc;
+ unsigned const rem = pipe->remaining - bc;
+
+ pipe->remaining = rem;
+ if (rem && bc == pipe->max_packet_size) {
+ int const next_rem = rem - pipe->max_packet_size;
+ if (next_rem > 0) {
+ /* Prepare to the after next transfer */
+ bd->addr += pipe->max_packet_size * 2;
+ bd->bc = next_rem > pipe->max_packet_size ? pipe->max_packet_size: next_rem;
+ __DSB();
+ bd->own = 1; /* This bit must be set last */
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = KHCI->TOKEN; /* Queue the same token as the last */
+ } else if (TUSB_DIR_IN == tu_edpt_dir(pipe->ep_addr)) { /* IN */
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = KHCI->TOKEN;
+ }
+ return true;
+ }
+ pipe->data = bd->data ^ 1;
+ return false;
+}
+
+static bool resume_transfer(int pipenum)
+{
+ int num_tokens = prepare_packets(pipenum);
+ TU_ASSERT(0 <= num_tokens);
+
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+
+ unsigned flags = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
+ flags |= USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+ switch (pipe->xfer) {
+ case TUSB_XFER_CONTROL:
+ flags |= USB_ENDPT_EPHSHK_MASK;
+ break;
+ case TUSB_XFER_ISOCHRONOUS:
+ flags |= USB_ENDPT_EPCTLDIS_MASK | USB_ENDPT_RETRYDIS_MASK;
+ break;
+ default:
+ flags |= USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPCTLDIS_MASK | USB_ENDPT_RETRYDIS_MASK;
+ break;
+ }
+ // TU_LOG1(" resume pipenum %d flags %x\n", pipenum, flags);
+
+ KHCI->ENDPOINT[0].ENDPT = flags;
+ KHCI->ADDR = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | pipe->dev_addr;
+
+ unsigned const token = tu_edpt_number(pipe->ep_addr) |
+ ((tu_edpt_dir(pipe->ep_addr) ? TOK_PID_IN: TOK_PID_OUT) << USB_TOKEN_TOKENPID_SHIFT);
+ do {
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = token;
+ } while (--num_tokens);
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return true;
+}
+
+static void suspend_transfer(int pipenum, buffer_descriptor_t *bd)
+{
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ pipe->buffer = bd->addr;
+ pipe->data = bd->data ^ 1;
+ if ((TUSB_XFER_INTERRUPT == pipe->xfer) ||
+ (TUSB_XFER_BULK == pipe->xfer)) {
+ _hcd.pending |= TU_BIT(pipenum);
+ KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK;
+ }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+ (void)rhport;
+ const unsigned s = KHCI->STAT;
+ KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+ uint8_t const dir_in = (s & USB_STAT_TX_MASK) ? TUSB_DIR_OUT: TUSB_DIR_IN;
+ unsigned const odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
+ buffer_descriptor_t *bd = (buffer_descriptor_t *)&_hcd.bda[s];
+ endpoint_state_t *ep = &_hcd.endpoint[s >> 3];
+
+ /* fetch status before discarded by the next steps */
+ const unsigned pid = bd->tok_pid;
+
+ /* reset values for a next transfer */
+ bd->bdt_stall = 0;
+ bd->dts = 1;
+ bd->ninc = 0;
+ bd->keep = 0;
+ /* Update the odd variable to prepare for the next transfer */
+ ep->odd = odd ^ 1;
+
+ int pipenum = ep->pipenum;
+ int next_pipenum;
+ // TU_LOG1("TOKDNE %x PID %x pipe %d\n", s, pid, pipenum);
+
+ xfer_result_t result;
+ switch (pid) {
+ default:
+ if (continue_transfer(pipenum, bd))
+ return;
+ result = XFER_RESULT_SUCCESS;
+ break;
+ case TOK_PID_NAK:
+ suspend_transfer(pipenum, bd);
+ next_pipenum = select_next_pipenum(pipenum);
+ if (0 <= next_pipenum)
+ resume_transfer(next_pipenum);
+ return;
+ case TOK_PID_STALL:
+ result = XFER_RESULT_STALLED;
+ break;
+ case TOK_PID_ERR: /* mismatch toggle bit */
+ case TOK_PID_BUSTO:
+ result = XFER_RESULT_FAILED;
+ break;
+ }
+ _hcd.in_progress &= ~TU_BIT(pipenum);
+ pipe_state_t *pipe = &_hcd.pipe[ep->pipenum];
+ hcd_event_xfer_complete(pipe->dev_addr,
+ tu_edpt_addr(KHCI->TOKEN & USB_TOKEN_TOKENENDPT_MASK, dir_in),
+ pipe->length - pipe->remaining,
+ result, true);
+ next_pipenum = select_next_pipenum(pipenum);
+ if (0 <= next_pipenum)
+ resume_transfer(next_pipenum);
+}
+
+static void process_attach(uint8_t rhport)
+{
+ unsigned ctl = KHCI->CTL;
+ if (!(ctl & USB_CTL_JSTATE_MASK)) {
+ /* The attached device is a low speed device. */
+ KHCI->ADDR = USB_ADDR_LSEN_MASK;
+ KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_HOSTWOHUB_MASK;
+ }
+ hcd_event_device_attach(rhport, true);
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK;
+ KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+ KHCI->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+ KHCI->ADDR = 0;
+ KHCI->ENDPOINT[0].ENDPT = 0;
+
+ hcd_event_device_remove(rhport, true);
+
+ _hcd.in_progress = 0;
+ _hcd.pending = 0;
+ buffer_descriptor_t *bd = &_hcd.bdt[0][0];
+ for (unsigned i = 0; i < 2; ++i, ++bd) {
+ bd->head = 0;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* Host API
+ *------------------------------------------------------------------*/
+bool hcd_init(uint8_t rhport)
+{
+ (void)rhport;
+
+ KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+ while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+ tu_memclr(&_hcd, sizeof(_hcd));
+ KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
+ KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_hcd.bdt >> 8);
+ KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_hcd.bdt >> 16);
+ KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_hcd.bdt >> 24);
+
+ KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+ KHCI->CTL |= USB_CTL_ODDRST_MASK;
+ for (unsigned i = 0; i < 16; ++i) {
+ KHCI->ENDPOINT[i].ENDPT = 0;
+ }
+ KHCI->CTL &= ~USB_CTL_ODDRST_MASK;
+
+ KHCI->SOFTHLD = 74; /* for 64-byte packets */
+ // KHCI->SOFTHLD = 144; /* for low speed 8-byte packets */
+ KHCI->CTL = USB_CTL_HOSTMODEEN_MASK | USB_CTL_SE0_MASK;
+ KHCI->USBCTRL = USB_USBCTRL_PDE_MASK;
+
+ NVIC_ClearPendingIRQ(USB0_IRQn);
+ KHCI->INTEN = USB_INTEN_ATTACHEN_MASK | USB_INTEN_TOKDNEEN_MASK |
+ USB_INTEN_USBRSTEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
+ KHCI->ERREN = 0xff;
+
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void)rhport;
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ uint32_t frmnum = KHCI->FRMNUML;
+ frmnum |= KHCI->FRMNUMH << 8u;
+ return frmnum;
+}
+
+/*--------------------------------------------------------------------+
+ * Port API
+ *--------------------------------------------------------------------+ */
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ (void)rhport;
+ if (KHCI->ISTAT & USB_ISTAT_ATTACH_MASK)
+ return true;
+ return false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ (void)rhport;
+ KHCI->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+ KHCI->CTL |= USB_CTL_RESET_MASK;
+ unsigned cnt = SystemCoreClock / 100;
+ while (cnt--) __NOP();
+ KHCI->CTL &= ~USB_CTL_RESET_MASK;
+ KHCI->CTL |= USB_CTL_USBENSOFEN_MASK;
+ _hcd.need_reset = false;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ (void)rhport;
+ tusb_speed_t speed = TUSB_SPEED_FULL;
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ if (KHCI->ADDR & USB_ADDR_LSEN_MASK)
+ speed = TUSB_SPEED_LOW;
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return speed;
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ pipe_state_t *p = &_hcd.pipe[0];
+ pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
+ for (;p != end; ++p) {
+ if (p->dev_addr == dev_addr)
+ tu_memclr(p, sizeof(*p));
+ }
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ (void)rhport;
+ // TU_LOG1("SETUP %u\n", dev_addr);
+ TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(0)));
+
+ int pipenum = find_pipe(dev_addr, 0);
+ if (pipenum < 0) return false;
+
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ pipe[0].data = 0;
+ pipe[0].buffer = (uint8_t*)(uintptr_t)setup_packet;
+ pipe[0].length = 8;
+ pipe[0].remaining = 8;
+ pipe[1].data = 1;
+
+ if (1 != prepare_packets(pipenum))
+ return false;
+
+ _hcd.in_progress |= TU_BIT(pipenum);
+
+ unsigned hostwohub = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
+ KHCI->ENDPOINT[0].ENDPT = hostwohub |
+ USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+ KHCI->ADDR = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | dev_addr;
+ while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+ KHCI->TOKEN = (TOK_PID_SETUP << USB_TOKEN_TOKENPID_SHIFT);
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+ uint8_t const ep_addr = ep_desc->bEndpointAddress;
+ // TU_LOG1("O %u %x\n", dev_addr, ep_addr);
+ /* Find a free pipe */
+ pipe_state_t *p = &_hcd.pipe[0];
+ pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
+ if (dev_addr || ep_addr) {
+ p += 2;
+ for (; p < end && (p->dev_addr || p->ep_addr); ++p) ;
+ if (p == end) return false;
+ }
+ p->dev_addr = dev_addr;
+ p->ep_addr = ep_addr;
+ p->max_packet_size = ep_desc->wMaxPacketSize;
+ p->xfer = ep_desc->bmAttributes.xfer;
+ p->data = 0;
+ if (!ep_addr) {
+ /* Open one more pipe for Control IN transfer */
+ TU_ASSERT(TUSB_XFER_CONTROL == p->xfer);
+ pipe_state_t *q = p + 1;
+ TU_ASSERT(!q->dev_addr && !q->ep_addr);
+ q->dev_addr = dev_addr;
+ q->ep_addr = tu_edpt_addr(0, TUSB_DIR_IN);
+ q->max_packet_size = ep_desc->wMaxPacketSize;
+ q->xfer = ep_desc->bmAttributes.xfer;
+ q->data = 1;
+ }
+ return true;
+}
+
+/* The address of buffer must be aligned to 4 byte boundary. And it must be at least 4 bytes long.
+ * DMA writes data in 4 byte unit */
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
+{
+ (void)rhport;
+ // TU_LOG1("X %u %x %x %d\n", dev_addr, ep_addr, (uintptr_t)buffer, buflen);
+
+ int pipenum = find_pipe(dev_addr, ep_addr);
+ TU_ASSERT(0 <= pipenum);
+
+ TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(pipenum)));
+ unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+ NVIC_DisableIRQ(USB0_IRQn);
+ pipe_state_t *pipe = &_hcd.pipe[pipenum];
+ pipe->buffer = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ _hcd.in_progress |= TU_BIT(pipenum);
+ _hcd.pending |= TU_BIT(pipenum); /* Send at the next Frame */
+ KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK;
+ if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ return true;
+}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ if (!tu_edpt_number(ep_addr)) return true;
+ int num = find_pipe(dev_addr, ep_addr);
+ if (num < 0) return false;
+ pipe_state_t *p = &_hcd.pipe[num];
+ p->data = 0; /* Reset data toggle */
+ return true;
+}
+
+/*--------------------------------------------------------------------+
+ * ISR
+ *--------------------------------------------------------------------+*/
+void hcd_int_handler(uint8_t rhport)
+{
+ uint32_t is = KHCI->ISTAT;
+ uint32_t msk = KHCI->INTEN;
+
+ // TU_LOG1("S %lx\n", is);
+
+ /* clear disabled interrupts */
+ KHCI->ISTAT = (is & ~msk & ~USB_ISTAT_TOKDNE_MASK) | USB_ISTAT_SOFTOK_MASK;
+ is &= msk;
+
+ if (is & USB_ISTAT_ERROR_MASK) {
+ unsigned err = KHCI->ERRSTAT;
+ if (err) {
+ TU_LOG1(" ERR %x\n", err);
+ KHCI->ERRSTAT = err;
+ } else {
+ KHCI->INTEN &= ~USB_ISTAT_ERROR_MASK;
+ }
+ }
+
+ if (is & USB_ISTAT_USBRST_MASK) {
+ KHCI->INTEN = (msk & ~USB_INTEN_USBRSTEN_MASK) | USB_INTEN_ATTACHEN_MASK;
+ process_bus_reset(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_ATTACH_MASK) {
+ KHCI->INTEN = (msk & ~USB_INTEN_ATTACHEN_MASK) | USB_INTEN_USBRSTEN_MASK;
+ _hcd.need_reset = true;
+ process_attach(rhport);
+ return;
+ }
+ if (is & USB_ISTAT_STALL_MASK) {
+ KHCI->ISTAT = USB_ISTAT_STALL_MASK;
+ }
+ if (is & USB_ISTAT_SOFTOK_MASK) {
+ msk &= ~USB_ISTAT_SOFTOK_MASK;
+ KHCI->INTEN = msk;
+ if (_hcd.pending) {
+ int pipenum = __builtin_ctz(_hcd.pending);
+ _hcd.pending = 0;
+ if (!(is & USB_ISTAT_TOKDNE_MASK))
+ resume_transfer(pipenum);
+ }
+ }
+ if (is & USB_ISTAT_TOKDNE_MASK) {
+ process_tokdne(rhport);
+ }
+}
+
+#endif
diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
index 0f500a88f..0894a5eeb 100644
--- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
+#if CFG_TUD_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
#include "device/dcd.h"
@@ -228,6 +228,14 @@ void dcd_disconnect(uint8_t rhport)
sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 0);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// CONTROL HELPER
//--------------------------------------------------------------------+
diff --git a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
index 1c1faed94..ad9ed59b4 100644
--- a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && \
+#if CFG_TUH_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
#include "chip.h"
diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
index 1bdf72d6d..9b490c48c 100644
--- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -34,7 +34,7 @@
* - LPC54114
* - LPC55s69
*/
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_LPC11UXX || \
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_LPC11UXX || \
CFG_TUSB_MCU == OPT_MCU_LPC13XX || \
CFG_TUSB_MCU == OPT_MCU_LPC15XX || \
CFG_TUSB_MCU == OPT_MCU_LPC51UXX || \
@@ -78,8 +78,10 @@ typedef struct {
// Max nbytes for each control/bulk/interrupt transfer
enum {
- NBYTES_CBI_FULLSPEED_MAX = 64,
- NBYTES_CBI_HIGHSPEED_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
+ NBYTES_ISO_FS_MAX = 1023, // FS ISO
+ NBYTES_ISO_HS_MAX = 1024, // HS ISO
+ NBYTES_CBI_FS_MAX = 64, // FS control/bulk/interrupt
+ NBYTES_CBI_HS_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
};
enum {
@@ -112,6 +114,8 @@ enum {
typedef union TU_ATTR_PACKED
{
// Full and High speed has different bit layout for buffer_offset and nbytes
+ // TODO FS/HS layout depends on the max speed of controller e.g
+ // lpc55s69 PORT0 is only FS but actually has the same layout as HS on port1
// Buffer (aligned 64) = DATABUFSTART [31:22] | buffer_offset [21:6]
volatile struct {
@@ -175,6 +179,9 @@ typedef struct
// Use CFG_TUSB_MEM_SECTION to place it accordingly.
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
+// Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug)
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
+
//--------------------------------------------------------------------+
// Multiple Controllers
//--------------------------------------------------------------------+
@@ -225,8 +232,36 @@ static inline uint8_t ep_addr2id(uint8_t ep_addr)
//--------------------------------------------------------------------+
// CONTROLLER API
//--------------------------------------------------------------------+
+
+static void prepare_setup_packet(uint8_t rhport)
+{
+ if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
+ {
+ _dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet);
+ }else
+ {
+ _dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet);
+ }
+}
+
+static void edpt_reset(uint8_t rhport, uint8_t ep_id)
+{
+ (void) rhport;
+ tu_memclr(&_dcd.ep[ep_id], sizeof(_dcd.ep[ep_id]));
+}
+
+static void edpt_reset_all(uint8_t rhport)
+{
+ for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id)
+ {
+ edpt_reset(rhport, ep_id);
+ }
+ prepare_setup_packet(rhport);
+}
void dcd_init(uint8_t rhport)
{
+ edpt_reset_all(rhport);
+
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
dcd_reg->EPLISTSTART = (uint32_t) _dcd.ep;
@@ -277,6 +312,14 @@ void dcd_disconnect(uint8_t rhport)
dcd_reg->DEVCMDSTAT &= ~CMDSTAT_DEVICE_CONNECT_MASK;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// DCD Endpoint Port
//--------------------------------------------------------------------+
@@ -302,18 +345,13 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
{
- (void) rhport;
-
- // TODO not support ISO yet
- TU_VERIFY(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
-
//------------- Prepare Queue Head -------------//
uint8_t ep_id = ep_addr2id(p_endpoint_desc->bEndpointAddress);
// Check if endpoint is available
TU_ASSERT( _dcd.ep[ep_id][0].disable && _dcd.ep[ep_id][1].disable );
- tu_memclr(_dcd.ep[ep_id], 2*sizeof(ep_cmd_sts_t));
+ edpt_reset(rhport, ep_id);
_dcd.ep[ep_id][0].is_iso = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
// Enable EP interrupt
@@ -325,19 +363,20 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
void dcd_edpt_close_all (uint8_t rhport)
{
- (void) rhport;
- // TODO implement dcd_edpt_close_all()
+ for (uint8_t ep_id = 0; ep_id < 2*_dcd_controller[rhport].ep_pairs; ++ep_id)
+ {
+ _dcd.ep[ep_id][0].active = _dcd.ep[ep_id][0].active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
+ _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
+ }
}
-static void prepare_setup_packet(uint8_t rhport)
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
- if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
- {
- _dcd.ep[0][1].buffer_fs.offset = get_buf_offset(_dcd.setup_packet);;
- }else
- {
- _dcd.ep[0][1].buffer_hs.offset = get_buf_offset(_dcd.setup_packet);;
- }
+ (void) rhport;
+
+ uint8_t ep_id = ep_addr2id(ep_addr);
+ _dcd.ep[ep_id][0].active = _dcd.ep[ep_id][0].active = 0; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
+ _dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
}
static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes)
@@ -346,13 +385,12 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset,
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
{
- // TODO ISO FullSpeed can have up to 1023 bytes
- nbytes = tu_min16(total_bytes, NBYTES_CBI_FULLSPEED_MAX);
+ nbytes = tu_min16(total_bytes, _dcd.ep[ep_id][0].is_iso ? NBYTES_ISO_FS_MAX : NBYTES_CBI_FS_MAX);
_dcd.ep[ep_id][0].buffer_fs.offset = buf_offset;
_dcd.ep[ep_id][0].buffer_fs.nbytes = nbytes;
}else
{
- nbytes = tu_min16(total_bytes, NBYTES_CBI_HIGHSPEED_MAX);
+ nbytes = tu_min16(total_bytes, NBYTES_CBI_HS_MAX);
_dcd.ep[ep_id][0].buffer_hs.offset = buf_offset;
_dcd.ep[ep_id][0].buffer_hs.nbytes = nbytes;
}
@@ -364,13 +402,19 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset,
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
{
- (void) rhport;
-
uint8_t const ep_id = ep_addr2id(ep_addr);
tu_memclr(&_dcd.dma[ep_id], sizeof(xfer_dma_t));
_dcd.dma[ep_id].total_bytes = total_bytes;
+ if (!buffer)
+ {
+ // Although having no data, ZLPs can cause buffer overwritten to zeroes.
+ // Probably due to USB/DMA controller side effect/bug.
+ // Assigned buffer offset to (valid) dummy to prevent overwriting to DATABUFSTART
+ buffer = (uint8_t*)(uint32_t)dummy;
+ }
+
prepare_ep_xfer(rhport, ep_id, get_buf_offset(buffer), total_bytes);
return true;
@@ -382,15 +426,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
static void bus_reset(uint8_t rhport)
{
tu_memclr(&_dcd, sizeof(dcd_data_t));
+ edpt_reset_all(rhport);
- // disable all non-control endpoints on bus reset
- for(uint8_t ep_id = 2; ep_id < 2*MAX_EP_PAIRS; ep_id++)
+ // disable all endpoints as specified by LPC55S69 UM Table 778
+ for(uint8_t ep_id = 0; ep_id < 2*MAX_EP_PAIRS; ep_id++)
{
_dcd.ep[ep_id][0].disable = _dcd.ep[ep_id][1].disable = 1;
}
- prepare_setup_packet(rhport);
-
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
dcd_reg->EPINUSE = 0;
@@ -498,23 +541,15 @@ void dcd_int_handler(uint8_t rhport)
}
}
- // TODO support suspend & resume
if (cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK)
{
- if (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK)
- { // suspend signal, bus idle for more than 3ms
- // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
- if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
+ // suspend signal, bus idle for more than 3ms
+ // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
+ if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
+ {
+ dcd_event_bus_signal(rhport, (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, true);
}
}
-// else
-// { // resume signal
-// dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
-// }
-// }
}
// Setup Receive
diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c
index 5ac041fbf..1f27a6872 100644
--- a/src/portable/nxp/transdimension/dcd_transdimension.c
+++ b/src/portable/nxp/transdimension/dcd_transdimension.c
@@ -26,13 +26,15 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
+#if CFG_TUD_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT)
+
+#warning "transdimenion is renamed to chipidea (portable/chipidea/ci_hs) to match other opensource naming convention such as linux. This file will be removed in the future, please update your makefile accordingly"
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
#include "fsl_device_registers.h"
#define INCLUDE_FSL_DEVICE_REGISTERS
#else
@@ -151,7 +153,7 @@ typedef struct
const uint8_t ep_count; // Max bi-directional Endpoints
}dcd_controller_t;
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
static const dcd_controller_t _dcd_controller[] =
{
// RT1010 and RT1020 only has 1 USB controller
@@ -177,8 +179,8 @@ typedef struct {
// Must be at 2K alignment
// Each endpoint with direction (IN/OUT) occupies a queue head
// for portability, TinyUSB only queue 1 TD for each Qhd
- dcd_qhd_t qhd[DCD_ATTR_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
- dcd_qtd_t qtd[DCD_ATTR_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
+ dcd_qhd_t qhd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
+ dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
}dcd_data_t;
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
@@ -292,6 +294,14 @@ void dcd_disconnect(uint8_t rhport)
dcd_reg->USBCMD &= ~USBCMD_RUN_STOP;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// HELPER
//--------------------------------------------------------------------+
@@ -645,7 +655,7 @@ void dcd_int_handler(uint8_t rhport)
if ( edpt_complete )
{
- for(uint8_t epnum = 0; epnum < DCD_ATTR_ENDPOINT_MAX; epnum++)
+ for(uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++)
{
if ( tu_bit_test(edpt_complete, epnum) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT);
if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN);
diff --git a/src/portable/nxp/transdimension/hcd_transdimension.c b/src/portable/nxp/transdimension/hcd_transdimension.c
index d216f0728..392764ff6 100644
--- a/src/portable/nxp/transdimension/hcd_transdimension.c
+++ b/src/portable/nxp/transdimension/hcd_transdimension.c
@@ -28,13 +28,15 @@
// NXP Trans-Dimension USB IP implement EHCI for host functionality
-#if TUSB_OPT_HOST_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
+#if CFG_TUH_ENABLED && \
+ (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT)
+
+#warning "transdimenion is renamed to chipidea (portable/chipidea/ci_hs) to match other opensource naming convention such as linux. This file will be removed in the future, please update your makefile accordingly"
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
#include "fsl_device_registers.h"
#else
// LPCOpen for 18xx & 43xx
@@ -56,7 +58,7 @@ typedef struct
const IRQn_Type irqnum; // IRQ number
}hcd_controller_t;
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
static const hcd_controller_t _hcd_controller[] =
{
// RT1010 and RT1020 only has 1 USB controller
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
index daa8075b7..3e523ebc2 100644
--- a/src/portable/ohci/ohci.c
+++ b/src/portable/ohci/ohci.c
@@ -24,9 +24,9 @@
* This file is part of the TinyUSB stack.
*/
-#include "host/hcd_attr.h"
+#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && defined(HCD_ATTR_OHCI)
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_OHCI)
//--------------------------------------------------------------------+
// INCLUDE
@@ -216,6 +216,11 @@ void hcd_port_reset(uint8_t hostid)
OHCI_REG->rhport_status[0] = RHPORT_PORT_RESET_STATUS_MASK;
}
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
+}
+
bool hcd_port_connect_status(uint8_t hostid)
{
(void) hostid;
@@ -313,7 +318,7 @@ static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
ohci_ed_t* ed_pool = ohci_data.ed_pool;
- for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+ for(uint32_t i=0; i<ED_MAX; i++)
{
if ( (ed_pool[i].dev_addr == dev_addr) &&
ep_addr == tu_edpt_addr(ed_pool[i].ep_number, ed_pool[i].pid == PID_IN) )
@@ -329,7 +334,7 @@ static ohci_ed_t * ed_find_free(void)
{
ohci_ed_t* ed_pool = ohci_data.ed_pool;
- for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; i++)
+ for(uint8_t i = 0; i < ED_MAX; i++)
{
if ( !ed_pool[i].used ) return &ed_pool[i];
}
@@ -368,7 +373,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr)
static ohci_gtd_t * gtd_find_free(void)
{
- for(uint8_t i=0; i < HCD_MAX_XFER; i++)
+ for(uint8_t i=0; i < GTD_MAX; i++)
{
if ( !ohci_data.gtd_pool[i].used ) return &ohci_data.gtd_pool[i];
}
diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h
index cd90aa45a..9fc954c8f 100644
--- a/src/portable/ohci/ohci.h
+++ b/src/portable/ohci/ohci.h
@@ -42,6 +42,9 @@ enum {
OHCI_MAX_ITD = 4
};
+#define ED_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
+#define GTD_MAX ED_MAX
+
//--------------------------------------------------------------------+
// OHCI Data Structure
//--------------------------------------------------------------------+
@@ -159,11 +162,11 @@ typedef struct TU_ATTR_ALIGNED(256)
struct {
ohci_ed_t ed;
ohci_gtd_t gtd;
- }control[CFG_TUH_DEVICE_MAX+1];
+ }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
// ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
- ohci_ed_t ed_pool[HCD_MAX_ENDPOINT];
- ohci_gtd_t gtd_pool[HCD_MAX_XFER];
+ ohci_ed_t ed_pool[ED_MAX];
+ ohci_gtd_t gtd_pool[GTD_MAX];
volatile uint16_t frame_number_hi;
diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
new file mode 100644
index 000000000..1bc5594d8
--- /dev/null
+++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
@@ -0,0 +1,210 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUD_RPI_PIO_USB
+
+#include "pico.h"
+#include "pio_usb.h"
+#include "pio_usb_ll.h"
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+#define RHPORT_OFFSET 1
+#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET)
+
+//------------- -------------//
+static usb_device_t *usb_device = NULL;
+static usb_descriptor_buffers_t desc;
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+// Initialize controller to device mode
+void dcd_init (uint8_t rhport)
+{
+ (void) rhport;
+
+ static pio_usb_configuration_t config = PIO_USB_DEFAULT_CONFIG;
+ usb_device = pio_usb_device_init(&config, &desc);
+}
+
+// Enable device interrupt
+void dcd_int_enable (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Disable device interrupt
+void dcd_int_disable (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+ // must be called before queuing status
+ pio_usb_device_set_address(dev_addr);
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+}
+
+// Wake up host
+void dcd_remote_wakeup (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
+{
+ (void) rhport;
+ return pio_usb_device_endpoint_open((uint8_t const*) desc_ep);
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ return pio_usb_ll_transfer_start(ep, buffer, total_bytes);
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+//bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+//{
+// (void) rhport;
+// (void) ep_addr;
+// (void) ff;
+// (void) total_bytes;
+// return false;
+//}
+
+// Stall endpoint
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ ep->has_transfer = false;
+ ep->stalled = true;
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ ep->data_id = 0;
+ ep->stalled = false;
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+static void __no_inline_not_in_flash_func(handle_endpoint_irq)(uint8_t tu_rhport, xfer_result_t result, volatile uint32_t* ep_reg)
+{
+ const uint32_t ep_all = *ep_reg;
+
+ for(uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++)
+ {
+ uint32_t const mask = (1u << ep_idx);
+
+ if (ep_all & mask)
+ {
+ endpoint_t* ep = PIO_USB_ENDPOINT(ep_idx);
+ dcd_event_xfer_complete(tu_rhport, ep->ep_num, ep->actual_len, result, true);
+ }
+ }
+
+ // clear all
+ (*ep_reg) &= ~ep_all;
+}
+
+// IRQ Handler
+void __no_inline_not_in_flash_func(pio_usb_device_irq_handler)(uint8_t root_id)
+{
+ uint8_t const tu_rhport = root_id + 1;
+ root_port_t* rport = PIO_USB_ROOT_PORT(root_id);
+ uint32_t const ints = rport->ints;
+
+ if (ints & PIO_USB_INTS_RESET_END_BITS)
+ {
+ dcd_event_bus_reset(tu_rhport, TUSB_SPEED_FULL, true);
+ }
+
+ if (ints & PIO_USB_INTS_SETUP_REQ_BITS)
+ {
+ dcd_event_setup_received(tu_rhport, rport->setup_packet, true);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_SUCCESS, &rport->ep_complete);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_STALLED, &rport->ep_stalled);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_FAILED, &rport->ep_error);
+ }
+
+ // clear all
+ rport->ints &= ~ints;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
new file mode 100644
index 000000000..58b153ac3
--- /dev/null
+++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
@@ -0,0 +1,225 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUH_RPI_PIO_USB
+
+#include "pico.h"
+#include "pio_usb.h"
+#include "pio_usb_ll.h"
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "osal/osal.h"
+
+#include "host/hcd.h"
+#include "host/usbh.h"
+
+#define RHPORT_OFFSET 1
+#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET)
+
+static pio_usb_configuration_t pio_host_cfg = PIO_USB_DEFAULT_CONFIG;
+
+//--------------------------------------------------------------------+
+// HCD API
+//--------------------------------------------------------------------+
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param)
+{
+ (void) rhport;
+ TU_VERIFY(cfg_id == TUH_CFGID_RPI_PIO_USB_CONFIGURATION);
+ memcpy(&pio_host_cfg, cfg_param, sizeof(pio_usb_configuration_t));
+ return true;
+}
+
+bool hcd_init(uint8_t rhport)
+{
+ (void) rhport;
+
+ // To run USB SOF interrupt in core1, call this init in core1
+ pio_usb_host_init(&pio_host_cfg);
+
+ return true;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_port_reset_start(pio_rhport);
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_port_reset_end(pio_rhport);
+}
+
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+
+ root_port_t *root = PIO_USB_ROOT_PORT(pio_rhport);
+ port_pin_status_t line_state = pio_usb_bus_get_line_state(root);
+
+ return line_state != PORT_PIN_SE0;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ // TODO determine link speed
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return PIO_USB_ROOT_PORT(pio_rhport)->is_fullspeed ? TUSB_SPEED_FULL : TUSB_SPEED_LOW;
+}
+
+// Close all opened endpoint belong to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_close_device(pio_rhport, dev_addr);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void) rhport;
+ return 0;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
+{
+ hcd_devtree_info_t dev_tree;
+ hcd_devtree_get_info(dev_addr, &dev_tree);
+ bool const need_pre = (dev_tree.hub_addr && dev_tree.speed == TUSB_SPEED_LOW);
+
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const*) desc_ep, need_pre);
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_transfer(pio_rhport, dev_addr, ep_addr, buffer, buflen);
+}
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_send_setup(pio_rhport, dev_addr, setup_packet);
+}
+
+//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
+//{
+// // EPX is shared, so multiple device addresses and endpoint addresses share that
+// // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
+// // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
+// // on that device
+// pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
+// struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
+// assert(ep);
+// bool busy = ep->active;
+// pico_trace("busy == %d\n", busy);
+// return busy;
+//}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ (void) dev_addr;
+ (void) ep_addr;
+
+ return true;
+}
+
+static void __no_inline_not_in_flash_func(handle_endpoint_irq)(root_port_t* rport, xfer_result_t result, volatile uint32_t* ep_reg)
+{
+ (void) rport;
+ const uint32_t ep_all = *ep_reg;
+
+ for(uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++)
+ {
+ uint32_t const mask = (1u << ep_idx);
+
+ if (ep_all & mask)
+ {
+ endpoint_t* ep = PIO_USB_ENDPOINT(ep_idx);
+ hcd_event_xfer_complete(ep->dev_addr, ep->ep_num, ep->actual_len, result, true);
+ }
+ }
+
+ // clear all
+ (*ep_reg) &= ~ep_all;
+}
+
+// IRQ Handler
+void __no_inline_not_in_flash_func(pio_usb_host_irq_handler)(uint8_t root_id)
+{
+ uint8_t const tu_rhport = root_id + 1;
+ root_port_t* rport = PIO_USB_ROOT_PORT(root_id);
+ uint32_t const ints = rport->ints;
+
+ if ( ints & PIO_USB_INTS_CONNECT_BITS )
+ {
+ hcd_event_device_attach(tu_rhport, true);
+ }
+
+ if ( ints & PIO_USB_INTS_DISCONNECT_BITS )
+ {
+ hcd_event_device_remove(tu_rhport, true);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS )
+ {
+ handle_endpoint_irq(rport, XFER_RESULT_SUCCESS, &rport->ep_complete);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS )
+ {
+ handle_endpoint_irq(rport, XFER_RESULT_STALLED, &rport->ep_stalled);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS )
+ {
+ handle_endpoint_irq(rport, XFER_RESULT_FAILED, &rport->ep_error);
+ }
+
+ // clear all
+ rport->ints &= ~ints;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index e084478e0..4952d29b1 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUD_RPI_PIO_USB
#include "pico.h"
#include "rp2040_usb.h"
@@ -55,7 +55,10 @@ static uint8_t *next_buffer_ptr;
// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
-static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
+// SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd
+static bool _sof_enable = false;
+
+TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
{
return &hw_endpoints[num][dir];
}
@@ -83,9 +86,9 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
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);
+ hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
- pico_info(" Alloced %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
+ pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
// Fill in endpoint control register with buffer offset
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
@@ -93,7 +96,6 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
*ep->endpoint_control = reg;
}
-#if 0 // todo unused
static void _hw_endpoint_close(struct hw_endpoint *ep)
{
// Clear hardware registers and then zero the struct
@@ -103,6 +105,21 @@ static void _hw_endpoint_close(struct hw_endpoint *ep)
*ep->buffer_control = 0;
// Clear any endpoint state
memset(ep, 0, sizeof(struct hw_endpoint));
+
+ // Reclaim buffer space if all endpoints are closed
+ bool reclaim_buffers = true;
+ for ( uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++ )
+ {
+ if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL || hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL)
+ {
+ reclaim_buffers = false;
+ break;
+ }
+ }
+ if (reclaim_buffers)
+ {
+ next_buffer_ptr = &usb_dpram->epx_data[0];
+ }
}
static void hw_endpoint_close(uint8_t ep_addr)
@@ -110,7 +127,6 @@ static void hw_endpoint_close(uint8_t ep_addr)
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_close(ep);
}
-#endif
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
{
@@ -172,7 +188,7 @@ static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_by
hw_endpoint_xfer_start(ep, buffer, total_bytes);
}
-static void hw_handle_buff_status(void)
+static void __tusb_irq_path_func(hw_handle_buff_status)(void)
{
uint32_t remaining_buffers = usb_hw->buf_status;
pico_trace("buf_status = 0x%08x\n", remaining_buffers);
@@ -201,7 +217,7 @@ static void hw_handle_buff_status(void)
}
}
-static void reset_ep0_pid(void)
+TU_ATTR_ALWAYS_INLINE static inline void reset_ep0_pid(void)
{
// If we have finished this transfer on EP0 set pid back to 1 for next
// setup transfer. Also clear a stall in case
@@ -213,7 +229,7 @@ static void reset_ep0_pid(void)
}
}
-static void reset_non_control_endpoints(void)
+static void __tusb_irq_path_func(reset_non_control_endpoints)(void)
{
// Disable all non-control
for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS-1; i++ )
@@ -224,14 +240,34 @@ static void reset_non_control_endpoints(void)
// clear non-control hw endpoints
tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2*sizeof(hw_endpoint_t));
+
+ // reclaim buffer space
next_buffer_ptr = &usb_dpram->epx_data[0];
}
-static void dcd_rp2040_irq(void)
+static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
{
uint32_t const status = usb_hw->ints;
uint32_t handled = 0;
+ if (status & USB_INTF_DEV_SOF_BITS)
+ {
+ handled |= USB_INTF_DEV_SOF_BITS;
+
+ // disable SOF interrupt if it is used for RESUME in remote wakeup
+ if (!_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+
+ dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
+ }
+
+ // xfer events are handled before setup req. So if a transfer completes immediately
+ // before closing the EP, the events will be delivered in same order.
+ if (status & USB_INTS_BUFF_STATUS_BITS)
+ {
+ handled |= USB_INTS_BUFF_STATUS_BITS;
+ hw_handle_buff_status();
+ }
+
if (status & USB_INTS_SETUP_REQ_BITS)
{
handled |= USB_INTS_SETUP_REQ_BITS;
@@ -245,12 +281,6 @@ static void dcd_rp2040_irq(void)
usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
}
- if (status & USB_INTS_BUFF_STATUS_BITS)
- {
- handled |= USB_INTS_BUFF_STATUS_BITS;
- hw_handle_buff_status();
- }
-
#if FORCE_VBUS_DETECT == 0
// Since we force VBUS detect On, device will always think it is connected and
// couldn't distinguish between disconnect and suspend
@@ -340,7 +370,7 @@ void dcd_init (uint8_t rhport)
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
#endif
- irq_set_exclusive_handler(USBCTRL_IRQ, dcd_rp2040_irq);
+ irq_add_shared_handler(USBCTRL_IRQ, dcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
// Init control endpoints
tu_memclr(hw_endpoints[0], 2*sizeof(hw_endpoint_t));
@@ -388,9 +418,13 @@ void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr)
void dcd_remote_wakeup(__unused uint8_t rhport)
{
- pico_info("dcd_remote_wakeup %d\n", rhport);
- assert(rhport == 0);
- usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS;
+ pico_info("dcd_remote_wakeup %d\n", rhport);
+ assert(rhport == 0);
+
+ // since RESUME interrupt is not triggered if we are the one initiate
+ // briefly enable SOF to notify usbd when bus is ready
+ usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
+ usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS;
}
// disconnect by disabling internal pull-up resistor on D+/D-
@@ -407,6 +441,21 @@ void dcd_connect(__unused uint8_t rhport)
usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+
+ _sof_enable = en;
+
+ if (en)
+ {
+ usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
+ }else
+ {
+ usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+ }
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -479,13 +528,12 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
void dcd_edpt_close (uint8_t rhport, uint8_t 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);
+ hw_endpoint_close(ep_addr);
}
-void dcd_int_handler(uint8_t rhport)
+void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport)
{
(void) rhport;
dcd_rp2040_irq();
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 768cccc86..10237d1f9 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040
+#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUH_RPI_PIO_USB
#include "pico.h"
#include "rp2040_usb.h"
@@ -40,7 +40,8 @@
#include "host/hcd.h"
#include "host/usbh.h"
-#define ROOT_PORT 0
+// port 0 is native USB port, other is counted as software PIO
+#define RHPORT_NATIVE 0
//--------------------------------------------------------------------+
// Low level rp2040 controller functions
@@ -78,7 +79,7 @@ static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
return NULL;
}
-static inline uint8_t dev_speed(void)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void)
{
return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
}
@@ -90,7 +91,7 @@ static bool need_pre(uint8_t dev_addr)
return hcd_port_speed_get(0) != tuh_speed_get(dev_addr);
}
-static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result)
+static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result)
{
// Mark transfer as done before we tell the tinyusb stack
uint8_t dev_addr = ep->dev_addr;
@@ -100,9 +101,11 @@ static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result)
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)
+static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_endpoint *ep)
{
usb_hw_clear->buf_status = bit;
+ // EP may have been stalled?
+ assert(ep->active);
bool done = hw_endpoint_xfer_continue(ep);
if (done)
{
@@ -110,7 +113,7 @@ static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep)
}
}
-static void hw_handle_buff_status(void)
+static void __tusb_irq_path_func(hw_handle_buff_status)(void)
{
uint32_t remaining_buffers = usb_hw->buf_status;
pico_trace("buf_status 0x%08x\n", remaining_buffers);
@@ -135,20 +138,25 @@ static void hw_handle_buff_status(void)
_handle_buff_status_bit(bit, ep);
}
- // Check interrupt endpoints
+ // Check "interrupt" (asynchronous) endpoints for both IN and OUT
for (uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && remaining_buffers; i++)
{
- // EPX is bit 0
- // IEP1 is bit 2
- // IEP2 is bit 4
- // IEP3 is bit 6
+ // EPX is bit 0 & 1
+ // IEP1 IN is bit 2
+ // IEP1 OUT is bit 3
+ // IEP2 IN is bit 4
+ // IEP2 OUT is bit 5
+ // IEP3 IN is bit 6
+ // IEP3 OUT is bit 7
// etc
- bit = 1 << (i*2);
-
- if (remaining_buffers & bit)
+ for(uint j = 0; j < 2; j++)
{
- remaining_buffers &= ~bit;
- _handle_buff_status_bit(bit, &ep_pool[i]);
+ bit = 1 << (i*2+j);
+ if (remaining_buffers & bit)
+ {
+ remaining_buffers &= ~bit;
+ _handle_buff_status_bit(bit, &ep_pool[i]);
+ }
}
}
@@ -158,13 +166,15 @@ static void hw_handle_buff_status(void)
}
}
-static void hw_trans_complete(void)
+static void __tusb_irq_path_func(hw_trans_complete)(void)
{
if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS)
{
pico_trace("Sent setup packet\n");
struct hw_endpoint *ep = &epx;
assert(ep->active);
+ // Set transferred length to 8 for a setup packet
+ ep->xferred_len = 8;
hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
}
else
@@ -174,7 +184,7 @@ static void hw_trans_complete(void)
}
}
-static void hcd_rp2040_irq(void)
+static void __tusb_irq_path_func(hcd_rp2040_irq)(void)
{
uint32_t status = usb_hw->ints;
uint32_t handled = 0;
@@ -185,17 +195,29 @@ static void hcd_rp2040_irq(void)
if (dev_speed())
{
- hcd_event_device_attach(ROOT_PORT, true);
+ hcd_event_device_attach(RHPORT_NATIVE, true);
}
else
{
- hcd_event_device_remove(ROOT_PORT, true);
+ hcd_event_device_remove(RHPORT_NATIVE, true);
}
// Clear speed change interrupt
usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS;
}
+ if (status & USB_INTS_STALL_BITS)
+ {
+ // We have rx'd a stall from the device
+ // NOTE THIS SHOULD HAVE PRIORITY OVER BUFF_STATUS
+ // AND TRANS_COMPLETE as the stall is an alternative response
+ // to one of those events
+ pico_trace("Stall REC\n");
+ handled |= USB_INTS_STALL_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
+ hw_xfer_complete(&epx, XFER_RESULT_STALLED);
+ }
+
if (status & USB_INTS_BUFF_STATUS_BITS)
{
handled |= USB_INTS_BUFF_STATUS_BITS;
@@ -211,15 +233,6 @@ static void hcd_rp2040_irq(void)
hw_trans_complete();
}
- if (status & USB_INTS_STALL_BITS)
- {
- // We have rx'd a stall from the device
- pico_trace("Stall REC\n");
- handled |= USB_INTS_STALL_BITS;
- usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
- hw_xfer_complete(&epx, XFER_RESULT_STALLED);
- }
-
if (status & USB_INTS_ERROR_RX_TIMEOUT_BITS)
{
handled |= USB_INTS_ERROR_RX_TIMEOUT_BITS;
@@ -239,6 +252,12 @@ static void hcd_rp2040_irq(void)
}
}
+void __tusb_irq_path_func(hcd_int_handler)(uint8_t rhport)
+{
+ (void) rhport;
+ hcd_rp2040_irq();
+}
+
static struct hw_endpoint *_next_free_interrupt_ep(void)
{
struct hw_endpoint *ep = NULL;
@@ -248,7 +267,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void)
if (!ep->configured)
{
// Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
- ep->interrupt_num = i - 1;
+ ep->interrupt_num = (uint8_t) (i - 1);
return ep;
}
}
@@ -259,10 +278,12 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
{
struct hw_endpoint *ep = NULL;
- if (transfer_type == TUSB_XFER_INTERRUPT)
+ if (transfer_type != TUSB_XFER_CONTROL)
{
+ // Note: even though datasheet name these "Interrupt" endpoints. These are actually
+ // "Asynchronous" endpoints and can be used for other type such as: Bulk (ISO need confirmation)
ep = _next_free_interrupt_ep();
- pico_info("Allocate interrupt ep %d\n", ep->interrupt_num);
+ pico_info("Allocate %s ep %d\n", tu_edpt_type_str(transfer_type), ep->interrupt_num);
assert(ep);
ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
@@ -283,7 +304,7 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
return ep;
}
-static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
+static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
{
// Already has data buffer, endpoint control, and buffer control allocated at this point
assert(ep->endpoint_control);
@@ -315,22 +336,27 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
| EP_CTRL_INTERRUPT_PER_BUFFER
| (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
| dpram_offset;
- ep_reg |= bmInterval ? (bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB : 0;
+ if (bmInterval)
+ {
+ ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
+ }
*ep->endpoint_control = ep_reg;
pico_trace("endpoint control (0x%p) <- 0x%x\n", ep->endpoint_control, ep_reg);
ep->configured = true;
- if (bmInterval)
+ if (ep != &epx)
{
- // This is an interrupt endpoint
- // so need to set up interrupt endpoint address control register with:
- // device address
- // endpoint number / direction
- // 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);
+ // Endpoint has its own addr_endp and interrupt bits to be setup!
+ // This is an interrupt/async endpoint. so need to set up ADDR_ENDP register with:
+ // - device address
+ // - endpoint number / direction
+ // - preamble
+ uint32_t reg = (uint32_t) (dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB));
+
+ if (dir == TUSB_DIR_OUT)
+ {
+ reg |= USB_ADDR_ENDP1_INTEP_DIR_BITS;
+ }
if (need_pre(dev_addr))
{
@@ -351,71 +377,101 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
//--------------------------------------------------------------------+
bool hcd_init(uint8_t rhport)
{
- pico_trace("hcd_init %d\n", rhport);
- assert(rhport == 0);
+ (void) rhport;
+ pico_trace("hcd_init %d\n", rhport);
+ assert(rhport == 0);
- // Reset any previous state
- rp2040_usb_init();
+ // Reset any previous state
+ rp2040_usb_init();
- // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
- usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
+ // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
+ usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
- irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
+ // Remove shared irq if it was previously added so as not to fill up shared irq slots
+ irq_remove_handler(USBCTRL_IRQ, hcd_rp2040_irq);
- // clear epx and interrupt eps
- memset(&ep_pool, 0, sizeof(ep_pool));
+ irq_add_shared_handler(USBCTRL_IRQ, hcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
- // 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->inte = USB_INTE_BUFF_STATUS_BITS |
- USB_INTE_HOST_CONN_DIS_BITS |
- USB_INTE_HOST_RESUME_BITS |
- USB_INTE_STALL_BITS |
- USB_INTE_TRANS_COMPLETE_BITS |
- USB_INTE_ERROR_RX_TIMEOUT_BITS |
- USB_INTE_ERROR_DATA_SEQ_BITS ;
+ // clear epx and interrupt eps
+ memset(&ep_pool, 0, sizeof(ep_pool));
- return true;
+ // 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->inte = USB_INTE_BUFF_STATUS_BITS |
+ USB_INTE_HOST_CONN_DIS_BITS |
+ USB_INTE_HOST_RESUME_BITS |
+ USB_INTE_STALL_BITS |
+ USB_INTE_TRANS_COMPLETE_BITS |
+ USB_INTE_ERROR_RX_TIMEOUT_BITS |
+ USB_INTE_ERROR_DATA_SEQ_BITS ;
+
+ return true;
}
void hcd_port_reset(uint8_t rhport)
{
- pico_trace("hcd_port_reset\n");
- assert(rhport == 0);
- // TODO: Nothing to do here yet. Perhaps need to reset some state?
+ (void) rhport;
+ pico_trace("hcd_port_reset\n");
+ assert(rhport == 0);
+ // TODO: Nothing to do here yet. Perhaps need to reset some state?
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
}
bool hcd_port_connect_status(uint8_t rhport)
{
- pico_trace("hcd_port_connect_status\n");
- assert(rhport == 0);
- return usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS;
+ (void) rhport;
+ pico_trace("hcd_port_connect_status\n");
+ assert(rhport == 0);
+ return usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS;
}
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
{
- assert(rhport == 0);
- // TODO: Should enumval this register
- switch (dev_speed())
- {
- case 1:
- return TUSB_SPEED_LOW;
- case 2:
- return TUSB_SPEED_FULL;
- default:
- panic("Invalid speed\n");
- return TUSB_SPEED_INVALID;
- }
+ (void) rhport;
+ assert(rhport == 0);
+ // TODO: Should enumval this register
+ switch (dev_speed())
+ {
+ case 1:
+ return TUSB_SPEED_LOW;
+ case 2:
+ 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);
+ (void) rhport;
+
+ if (dev_addr == 0) return;
- pico_trace("hcd_device_close %d\n", dev_addr);
+ for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++)
+ {
+ hw_endpoint_t* ep = &ep_pool[i];
+
+ if (ep->dev_addr == dev_addr && ep->configured)
+ {
+ // in case it is an interrupt endpoint, disable it
+ usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1));
+ usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0;
+
+ // unconfigure the endpoint
+ ep->configured = false;
+ *ep->endpoint_control = 0;
+ *ep->buffer_control = 0;
+ hw_endpoint_reset_transfer(ep);
+ }
+ }
}
uint32_t hcd_frame_number(uint8_t rhport)
@@ -426,15 +482,17 @@ uint32_t hcd_frame_number(uint8_t rhport)
void hcd_int_enable(uint8_t rhport)
{
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, true);
+ (void) rhport;
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, true);
}
void hcd_int_disable(uint8_t rhport)
{
- // todo we should check this is disabling from the correct core; note currently this is never called
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, false);
+ (void) rhport;
+ // todo we should check this is disabling from the correct core; note currently this is never called
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, false);
}
//--------------------------------------------------------------------+
@@ -449,6 +507,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
// Allocated differently based on if it's an interrupt endpoint or not
struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
+ TU_ASSERT(ep);
_hw_endpoint_init(ep,
dev_addr,
@@ -471,7 +530,11 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
// Get appropriate ep. Either EPX or interrupt endpoint
struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
- assert(ep);
+
+ TU_ASSERT(ep);
+
+ // EP should be inactive
+ assert(!ep->active);
// Control endpoint can change direction 0x00 <-> 0x80
if ( ep_addr != ep->ep_addr )
@@ -490,7 +553,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
// That has set up buffer control, endpoint control etc
// for host we have to initiate the transfer
- usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB);
+ usb_hw->dev_addr_ctrl = (uint32_t) (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);
@@ -511,10 +574,17 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
(void) rhport;
// Copy data into setup packet buffer
- memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8);
+ for(uint8_t i=0; i<8; i++)
+ {
+ usbh_dpram->setup_packet[i] = setup_packet[i];
+ }
// Configure EP0 struct with setup info for the trans complete
struct hw_endpoint *ep = _hw_endpoint_allocate(0);
+ TU_ASSERT(ep);
+
+ // EPX should be inactive
+ assert(!ep->active);
// EP0 out
_hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
@@ -535,21 +605,6 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
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
-// // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
-// // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
-// // on that device
-// pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
-// struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
-// assert(ep);
-// bool busy = ep->active;
-// pico_trace("busy == %d\n", busy);
-// return busy;
-//}
-
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
{
(void) dev_addr;
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index c9e2f6b26..25c013bd2 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -38,7 +38,7 @@ const char *ep_dir_string[] = {
"in",
};
-static inline void _hw_endpoint_lock_update(__unused struct hw_endpoint * ep, __unused int delta) {
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_lock_update(__unused struct hw_endpoint * ep, __unused int delta) {
// todo add critsec as necessary to prevent issues between worker and IRQ...
// note that this is perhaps as simple as disabling IRQs because it would make
// sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
@@ -58,14 +58,20 @@ void rp2040_usb_init(void)
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
// Clear any previous state just in case
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#if __GNUC__ > 6
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+#endif
memset(usb_hw, 0, sizeof(*usb_hw));
memset(usb_dpram, 0, sizeof(*usb_dpram));
+#pragma GCC diagnostic pop
// Mux the controller to the onboard usb phy
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
}
-void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
+void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint *ep)
{
ep->active = false;
ep->remaining_len = 0;
@@ -73,7 +79,7 @@ void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
ep->user_buf = 0;
}
-void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
+void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
uint32_t value = 0;
if (and_mask) {
value = *ep->buffer_control & and_mask;
@@ -87,7 +93,7 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
*ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
// 12 cycle delay.. (should be good for 48*12Mhz = 576Mhz)
// Don't need delay in host mode as host is in charge
-#if !TUSB_OPT_HOST_ENABLED
+#if !CFG_TUH_ENABLED
__asm volatile (
"b 1f\n"
"1: b 1f\n"
@@ -104,7 +110,7 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
}
// prepare buffer, return buffer control
-static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
+static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id)
{
uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
ep->remaining_len = (uint16_t)(ep->remaining_len - buflen);
@@ -139,7 +145,7 @@ static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
}
// Prepare buffer control register value
-static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
+static void __tusb_irq_path_func(_hw_endpoint_start_next_buffer)(struct hw_endpoint *ep)
{
uint32_t ep_ctrl = *ep->endpoint_control;
@@ -170,7 +176,7 @@ static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
*ep->endpoint_control = ep_ctrl;
- TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
// Finally, write to buffer_control which will trigger the transfer
// the next time the controller polls this dpram address
@@ -201,7 +207,7 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to
}
// sync endpoint buffer and return transferred bytes
-static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
+static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id)
{
uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
if (buf_id) buf_ctrl = buf_ctrl >> 16;
@@ -237,13 +243,13 @@ static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
return xferred_bytes;
}
-static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
+static void __tusb_irq_path_func(_hw_endpoint_xfer_sync) (struct hw_endpoint *ep)
{
// Update hw endpoint struct with info from hardware
// after a buff status interrupt
uint32_t __unused buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
- TU_LOG(3, " Sync BufCtrl: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
// always sync buffer 0
uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
@@ -281,20 +287,20 @@ static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
usb_hw->abort &= ~TU_BIT(ep_id);
TU_LOG(3, "----SHORT PACKET buffer0 on EP %02X:\r\n", ep->ep_addr);
- TU_LOG(3, " BufCtrl: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ TU_LOG(3, " BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
#endif
}
}
}
// Returns true if transfer is complete
-bool hw_endpoint_xfer_continue(struct hw_endpoint *ep)
+bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
{
_hw_endpoint_lock_update(ep, 1);
// Part way through a transfer
if (!ep->active)
{
- panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
+ panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
}
// Update EP struct from hardware state
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index a9cf1dd07..c72dae64c 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -16,6 +16,15 @@
#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
#endif
+#ifndef PICO_RP2040_USB_FAST_IRQ
+#define PICO_RP2040_USB_FAST_IRQ 0
+#endif
+
+#if PICO_RP2040_USB_FAST_IRQ
+#define __tusb_irq_path_func(x) __no_inline_not_in_flash_func(x)
+#else
+#define __tusb_irq_path_func(x) x
+#endif
#define pico_info(...) TU_LOG(2, __VA_ARGS__)
#define pico_trace(...) TU_LOG(3, __VA_ARGS__)
@@ -56,7 +65,7 @@ typedef struct hw_endpoint
// Interrupt, bulk, etc
uint8_t transfer_type;
-#if TUSB_OPT_HOST_ENABLED
+#if CFG_TUH_ENABLED
// Only needed for host
uint8_t dev_addr;
@@ -72,16 +81,20 @@ bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
void hw_endpoint_reset_transfer(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) {
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) {
return *ep->buffer_control;
}
-static inline void _hw_endpoint_buffer_control_set_value32(struct hw_endpoint *ep, uint32_t value) {
+
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_value32(struct hw_endpoint *ep, uint32_t value) {
return _hw_endpoint_buffer_control_update32(ep, 0, value);
}
-static inline void _hw_endpoint_buffer_control_set_mask32(struct hw_endpoint *ep, uint32_t value) {
+
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_mask32(struct hw_endpoint *ep, uint32_t value) {
return _hw_endpoint_buffer_control_update32(ep, ~value, value);
}
-static inline void _hw_endpoint_buffer_control_clear_mask32(struct hw_endpoint *ep, uint32_t value) {
+
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_clear_mask32(struct hw_endpoint *ep, uint32_t value) {
return _hw_endpoint_buffer_control_update32(ep, ~value, 0);
}
diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c
index ae7d2fd0c..fa87c9f4d 100644
--- a/src/portable/renesas/usba/dcd_usba.c
+++ b/src/portable/renesas/usba/dcd_usba.c
@@ -31,7 +31,7 @@
// We disable SOF for now until needed later on
#define USE_SOF 0
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
CFG_TUSB_MCU == OPT_MCU_RX65X || \
CFG_TUSB_MCU == OPT_MCU_RX72N )
#include "device/dcd.h"
@@ -494,7 +494,11 @@ static bool process_pipe_xfer(int buffer_type, uint8_t ep_addr, void* buffer, ui
while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
}
} else {
+#if defined(__CCRX__)
+ __evenaccess volatile reg_pipetre_t *pt = get_pipetre(num);
+#else
volatile reg_pipetre_t *pt = get_pipetre(num);
+#endif
if (pt) {
const unsigned mps = edpt_max_packet_size(num);
volatile uint16_t *ctr = get_pipectr(num);
@@ -683,6 +687,14 @@ void dcd_disconnect(uint8_t rhport)
USB0.SYSCFG.BIT.DPRPU = 0;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -715,11 +727,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
*ctr = 0;
unsigned cfg = (dir << 4) | epn;
if (xfer == TUSB_XFER_BULK) {
- cfg |= USB_PIPECFG_BULK | USB_PIPECFG_SHTNAK | USB_PIPECFG_DBLB;
+ cfg |= (USB_PIPECFG_BULK | USB_PIPECFG_SHTNAK | USB_PIPECFG_DBLB);
} else if (xfer == TUSB_XFER_INTERRUPT) {
cfg |= USB_PIPECFG_INT;
} else {
- cfg |= USB_PIPECFG_ISO | USB_PIPECFG_DBLB;
+ cfg |= (USB_PIPECFG_ISO | USB_PIPECFG_DBLB);
}
USB0.PIPECFG.WORD = cfg;
USB0.BRDYSTS.WORD = 0x1FFu ^ TU_BIT(num);
diff --git a/src/portable/renesas/usba/hcd_usba.c b/src/portable/renesas/usba/hcd_usba.c
new file mode 100644
index 000000000..5246ecb94
--- /dev/null
+++ b/src/portable/renesas/usba/hcd_usba.c
@@ -0,0 +1,875 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji Kitayama
+ * Portions copyrighted (c) 2021 Roland Winistoerfer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
+ CFG_TUSB_MCU == OPT_MCU_RX65X || \
+ CFG_TUSB_MCU == OPT_MCU_RX72N )
+#include "host/hcd.h"
+#include "iodefine.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+#define SYSTEM_PRCR_PRC1 (1<<1)
+#define SYSTEM_PRCR_PRKEY (0xA5u<<8)
+
+#define USB_DVSTCTR0_LOW (1u)
+#define USB_DVSTCTR0_FULL (2u)
+
+#define USB_FIFOSEL_TX ((uint16_t)(1u<<5))
+#define USB_FIFOSEL_BIGEND ((uint16_t)(1u<<8))
+#define USB_FIFOSEL_MBW_8 ((uint16_t)(0u<<10))
+#define USB_FIFOSEL_MBW_16 ((uint16_t)(1u<<10))
+#define USB_IS0_CTSQ ((uint16_t)(7u))
+#define USB_IS0_DVSQ ((uint16_t)(7u<<4))
+#define USB_IS0_VALID ((uint16_t)(1u<<3))
+#define USB_IS0_BRDY ((uint16_t)(1u<<8))
+#define USB_IS0_NRDY ((uint16_t)(1u<<9))
+#define USB_IS0_BEMP ((uint16_t)(1u<<10))
+#define USB_IS0_CTRT ((uint16_t)(1u<<11))
+#define USB_IS0_DVST ((uint16_t)(1u<<12))
+#define USB_IS0_SOFR ((uint16_t)(1u<<13))
+#define USB_IS0_RESM ((uint16_t)(1u<<14))
+#define USB_IS0_VBINT ((uint16_t)(1u<<15))
+#define USB_IS1_SACK ((uint16_t)(1u<<4))
+#define USB_IS1_SIGN ((uint16_t)(1u<<5))
+#define USB_IS1_EOFERR ((uint16_t)(1u<<6))
+#define USB_IS1_ATTCH ((uint16_t)(1u<<11))
+#define USB_IS1_DTCH ((uint16_t)(1u<<12))
+#define USB_IS1_BCHG ((uint16_t)(1u<<14))
+#define USB_IS1_OVRCR ((uint16_t)(1u<<15))
+
+#define USB_IS0_CTSQ_MSK (7u)
+#define USB_IS0_CTSQ_SETUP (1u)
+#define USB_IS0_DVSQ_DEF (1u<<4)
+#define USB_IS0_DVSQ_ADDR (2u<<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_MSK (3u)
+#define USB_PIPECTR_PID_NAK (0u)
+#define USB_PIPECTR_PID_BUF (1u)
+#define USB_PIPECTR_PID_STALL (2u)
+#define USB_PIPECTR_CCPL (1u<<2)
+#define USB_PIPECTR_SQMON (1u<<6)
+#define USB_PIPECTR_SQCLR (1u<<8)
+#define USB_PIPECTR_ACLRM (1u<<9)
+#define USB_PIPECTR_INBUFM (1u<<14)
+#define USB_PIPECTR_BSTS (1u<<15)
+
+#define USB_FIFOCTR_DTLN (0x1FF)
+#define USB_FIFOCTR_FRDY (1u<<13)
+#define USB_FIFOCTR_BCLR (1u<<14)
+#define USB_FIFOCTR_BVAL (1u<<15)
+
+#define USB_PIPECFG_SHTNAK (1u<<7)
+#define USB_PIPECFG_DBLB (1u<<9)
+#define USB_PIPECFG_BULK (1u<<14)
+#define USB_PIPECFG_ISO (3u<<14)
+#define USB_PIPECFG_INT (2u<<14)
+
+#define USB_DEVADD_LOW (1u<<6)
+#define USB_DEVADD_FULL (2u<<6)
+
+#define FIFO_REQ_CLR (1u)
+#define FIFO_COMPLETE (1u<<1)
+
+// Start of definition of packed structs (used by the CCRX toolchain)
+TU_ATTR_PACKED_BEGIN
+TU_ATTR_BIT_FIELD_ORDER_BEGIN
+
+typedef struct {
+ union {
+ struct {
+ uint16_t : 8;
+ uint16_t TRCLR: 1;
+ uint16_t TRENB: 1;
+ uint16_t : 0;
+ };
+ uint16_t TRE;
+ };
+ uint16_t TRN;
+} reg_pipetre_t;
+
+typedef union {
+ struct {
+ volatile uint16_t u8: 8;
+ volatile uint16_t : 0;
+ };
+ volatile uint16_t u16;
+} hw_fifo_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+ struct {
+ uint32_t ep : 8; /* an assigned endpoint address */
+ uint32_t dev : 8; /* an assigned device address */
+ uint32_t ff : 1; /* `buf` is TU_FUFO or POD */
+ uint32_t : 0;
+ };
+} pipe_state_t;
+
+TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain)
+TU_ATTR_BIT_FIELD_ORDER_END
+
+typedef struct
+{
+ bool need_reset; /* The device has not been reset after connection. */
+ pipe_state_t pipe[10];
+ uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
+ uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
+} hcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+static hcd_data_t _hcd;
+
+static uint32_t disable_interrupt(void)
+{
+ uint32_t pswi;
+#if defined(__CCRX__)
+ pswi = get_psw() & 0x010000;
+ clrpsw_i();
+#else
+ pswi = __builtin_rx_mvfc(0) & 0x010000;
+ __builtin_rx_clrpsw('I');
+#endif
+ return pswi;
+}
+
+static void enable_interrupt(uint32_t pswi)
+{
+#if defined(__CCRX__)
+ set_psw(get_psw() | pswi);
+#else
+ __builtin_rx_mvtc(0, __builtin_rx_mvfc(0) | pswi);
+#endif
+}
+
+static unsigned find_pipe(unsigned xfer)
+{
+ switch (xfer) {
+ case TUSB_XFER_ISOCHRONOUS:
+ for (int i = 1; i <= 2; ++i) {
+ if (0 == _hcd.pipe[i].ep) return i;
+ }
+ break;
+ case TUSB_XFER_BULK:
+ for (int i = 3; i <= 5; ++i) {
+ if (0 == _hcd.pipe[i].ep) return i;
+ }
+ for (int i = 1; i <= 1; ++i) {
+ if (0 == _hcd.pipe[i].ep) return i;
+ }
+ break;
+ case TUSB_XFER_INTERRUPT:
+ for (int i = 6; i <= 9; ++i) {
+ if (0 == _hcd.pipe[i].ep) return i;
+ }
+ break;
+ default:
+ /* No support for control transfer */
+ break;
+ }
+ return 0;
+}
+
+static volatile uint16_t* get_pipectr(unsigned num)
+{
+ volatile uint16_t *ctr = NULL;
+ if (num) {
+ ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD;
+ ctr += num - 1;
+ } else {
+ ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD;
+ }
+ return ctr;
+}
+
+static volatile reg_pipetre_t* get_pipetre(unsigned num)
+{
+ volatile reg_pipetre_t* tre = NULL;
+ if ((1 <= num) && (num <= 5)) {
+ tre = (volatile reg_pipetre_t*)&USB0.PIPE1TRE.WORD;
+ tre += num - 1;
+ }
+ return tre;
+}
+
+static volatile uint16_t* addr_to_pipectr(uint8_t dev_addr, unsigned ep_addr)
+{
+ volatile uint16_t *ctr = NULL;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ if (epn) {
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned num = _hcd.ep[dev_addr][dir_in][epn - 1];
+ if (num) {
+ ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD;
+ ctr += num - 1;
+ }
+ } else {
+ ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD;
+ }
+ return ctr;
+}
+
+static unsigned edpt0_max_packet_size(void)
+{
+ return USB0.DCPMAXP.BIT.MXPS;
+}
+
+static unsigned edpt_max_packet_size(unsigned num)
+{
+ USB0.PIPESEL.WORD = num;
+ return USB0.PIPEMAXP.BIT.MXPS;
+}
+
+static inline void pipe_wait_for_ready(unsigned num)
+{
+ while (USB0.D0FIFOSEL.BIT.CURPIPE != num) ;
+ while (!USB0.D0FIFOCTR.BIT.FRDY) ;
+}
+
+static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
+ uintptr_t addr = (uintptr_t)buf;
+ while (len >= 2) {
+ reg->u16 = *(const uint16_t *)addr;
+ addr += 2;
+ len -= 2;
+ }
+ if (len) {
+ reg->u8 = *(const uint8_t *)addr;
+ ++addr;
+ }
+}
+
+static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
+{
+ uint8_t *p = (uint8_t*)buf;
+ volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
+ while (len--) *p++ = *reg;
+}
+
+static bool pipe0_xfer_in(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ const unsigned rem = pipe->remaining;
+
+ const unsigned mps = edpt0_max_packet_size();
+ const unsigned vld = USB0.CFIFOCTR.BIT.DTLN;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
+ pipe_read_packet(buf, (volatile void*)&USB0.CFIFO.WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR;
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return true;
+ }
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF;
+ return false;
+}
+
+static bool pipe0_xfer_out(void)
+{
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ const unsigned rem = pipe->remaining;
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+ const unsigned mps = edpt0_max_packet_size();
+ const unsigned len = TU_MIN(mps, rem);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, (volatile void*)&USB0.CFIFO.WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL;
+ pipe->remaining = rem - len;
+ return false;
+}
+
+static bool pipe_xfer_in(unsigned num)
+{
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ const unsigned rem = pipe->remaining;
+
+ USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_8;
+ const unsigned mps = edpt_max_packet_size(num);
+ pipe_wait_for_ready(num);
+ const unsigned vld = USB0.D0FIFOCTR.BIT.DTLN;
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_read_packet(buf, (volatile void*)&USB0.D0FIFO.WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BCLR;
+ USB0.D0FIFOSEL.WORD = 0;
+ while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+ pipe->remaining = rem - len;
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ return false;
+}
+
+static bool pipe_xfer_out(unsigned num)
+{
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ const unsigned rem = pipe->remaining;
+
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16 | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? USB_FIFOSEL_BIGEND : 0);
+ const unsigned mps = edpt_max_packet_size(num);
+ pipe_wait_for_ready(num);
+ const unsigned len = TU_MIN(rem, mps);
+ void *buf = pipe->buf;
+ if (len) {
+ pipe_write_packet(buf, (volatile void*)&USB0.D0FIFO.WORD, len);
+ pipe->buf = (uint8_t*)buf + len;
+ }
+ if (len < mps) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL;
+ USB0.D0FIFOSEL.WORD = 0;
+ while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+ pipe->remaining = rem - len;
+ return false;
+}
+
+static bool process_pipe0_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
+{
+ (void)dev_addr;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+
+ /* configure fifo direction and access unit settings */
+ if (dir_in) { /* IN, a byte */
+ USB0.CFIFOSEL.WORD = USB_FIFOSEL_MBW_8;
+ while (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) ;
+ } else { /* OUT, 2 bytes */
+ USB0.CFIFOSEL.WORD = USB_FIFOSEL_TX | USB_FIFOSEL_MBW_16 | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? USB_FIFOSEL_BIGEND : 0);
+ while (!(USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX)) ;
+ }
+
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ pipe->ep = ep_addr;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (buflen) {
+ pipe->buf = buffer;
+ if (!dir_in) { /* OUT */
+ TU_ASSERT(USB0.DCPCTR.BIT.BSTS && (USB0.USBREQ.WORD & 0x80));
+ pipe0_xfer_out();
+ }
+ } else { /* ZLP */
+ pipe->buf = NULL;
+ if (!dir_in) { /* OUT */
+ USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL;
+ }
+ if (dir_in == USB0.DCPCFG.BIT.DIR) {
+ TU_ASSERT(USB_PIPECTR_PID_NAK == USB0.DCPCTR.BIT.PID);
+ USB0.DCPCTR.BIT.SQSET = 1;
+ USB0.DCPCFG.BIT.DIR = dir_in ^ 1;
+ }
+ }
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF;
+ return true;
+}
+
+static bool process_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned num = _hcd.ep[dev_addr - 1][dir_in][epn - 1];
+
+ TU_ASSERT(num);
+
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ pipe->buf = buffer;
+ pipe->length = buflen;
+ pipe->remaining = buflen;
+ if (!dir_in) { /* OUT */
+ if (buflen) {
+ pipe_xfer_out(num);
+ } else { /* ZLP */
+ USB0.D0FIFOSEL.WORD = num;
+ pipe_wait_for_ready(num);
+ USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL;
+ USB0.D0FIFOSEL.WORD = 0;
+ while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+ }
+ } else {
+ volatile uint16_t *ctr = get_pipectr(num);
+ volatile reg_pipetre_t *pt = get_pipetre(num);
+ if (pt) {
+ const unsigned mps = edpt_max_packet_size(num);
+ if (*ctr & 0x3) *ctr = USB_PIPECTR_PID_NAK;
+ pt->TRE = TU_BIT(8);
+ pt->TRN = (buflen + mps - 1) / mps;
+ pt->TRENB = 1;
+ }
+ *ctr = USB_PIPECTR_PID_BUF;
+ }
+ return true;
+}
+
+static bool process_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ if (0 == epn) {
+ return process_pipe0_xfer(dev_addr, ep_addr, buffer, buflen);
+ } else {
+ return process_pipe_xfer(dev_addr, ep_addr, buffer, buflen);
+ }
+}
+
+static void process_pipe0_bemp(uint8_t rhport)
+{
+ (void)rhport;
+ bool completed = pipe0_xfer_out();
+ if (completed) {
+ pipe_state_t *pipe = &_hcd.pipe[0];
+ hcd_event_xfer_complete(pipe->dev,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_pipe_nrdy(uint8_t rhport, unsigned num)
+{
+ (void)rhport;
+ unsigned result;
+ uint16_t volatile *ctr = get_pipectr(num);
+ // TU_LOG1("NRDY %d %x\n", num, *ctr);
+ switch (*ctr & USB_PIPECTR_PID_MSK) {
+ default: return;
+ case USB_PIPECTR_PID_STALL: result = XFER_RESULT_STALLED; break;
+ case USB_PIPECTR_PID_NAK: result = XFER_RESULT_FAILED; break;
+ }
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ hcd_event_xfer_complete(pipe->dev, pipe->ep,
+ pipe->length - pipe->remaining,
+ result, true);
+}
+
+static void process_pipe_brdy(uint8_t rhport, unsigned num)
+{
+ (void)rhport;
+ pipe_state_t *pipe = &_hcd.pipe[num];
+ const unsigned dir_in = tu_edpt_dir(pipe->ep);
+ bool completed;
+
+ if (dir_in) { /* IN */
+ if (num) {
+ completed = pipe_xfer_in(num);
+ } else {
+ completed = pipe0_xfer_in();
+ }
+ } else {
+ completed = pipe_xfer_out(num);
+ }
+ if (completed) {
+ hcd_event_xfer_complete(pipe->dev, pipe->ep,
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ // TU_LOG1("C %d %d\r\n", num, pipe->length - pipe->remaining);
+ }
+}
+
+
+/*------------------------------------------------------------------*/
+/* Host API
+ *------------------------------------------------------------------*/
+bool hcd_init(uint8_t rhport)
+{
+ (void)rhport;
+ /* Enable USB0 */
+ uint32_t pswi = disable_interrupt();
+ SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1;
+ MSTP(USB0) = 0;
+ SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY;
+ enable_interrupt(pswi);
+ USB0.SYSCFG.BIT.SCKE = 1;
+ while (!USB0.SYSCFG.BIT.SCKE) ;
+ USB0.SYSCFG.BIT.DPRPU = 0;
+ USB0.SYSCFG.BIT.DRPD = 0;
+ USB0.SYSCFG.BIT.DCFM = 1;
+
+ USB0.DVSTCTR0.BIT.VBUSEN = 1;
+
+ USB0.SYSCFG.BIT.DRPD = 1;
+ for (volatile int i = 0; i < 30000; ++i) ;
+ USB0.SYSCFG.BIT.USBE = 1;
+
+ USB.DPUSR0R.BIT.FIXPHY0 = 0u; /* USB0 Transceiver Output fixed */
+#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
+ USB0.PHYSLEW.LONG = 0x5;
+ IR(PERIB, INTB185) = 0;
+#else
+ IR(USB0, USBI0) = 0;
+#endif
+
+ /* Setup default control pipe */
+ USB0.DCPCFG.WORD = USB_PIPECFG_SHTNAK;
+ USB0.DCPMAXP.WORD = 64;
+ USB0.INTENB0.WORD = USB_IS0_BRDY | USB_IS0_NRDY | USB_IS0_BEMP;
+ USB0.INTENB1.WORD = USB_IS1_SACK | USB_IS1_SIGN |
+ USB_IS1_ATTCH | USB_IS1_DTCH;
+ USB0.BEMPENB.WORD = 1;
+ USB0.NRDYENB.WORD = 1;
+ USB0.BRDYENB.WORD = 1;
+ return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
+ IEN(PERIB, INTB185) = 1;
+#else
+ IEN(USB0, USBI0) = 1;
+#endif
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
+ IEN(PERIB, INTB185) = 0;
+#else
+ IEN(USB0, USBI0) = 0;
+#endif
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void)rhport;
+ /* The device must be reset at least once after connection
+ * in order to start the frame counter. */
+ if (_hcd.need_reset) hcd_port_reset(rhport);
+ return USB0.FRMNUM.BIT.FRNM;
+}
+
+/*--------------------------------------------------------------------+
+ * Port API
+ *--------------------------------------------------------------------+*/
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ (void)rhport;
+ return USB0.INTSTS1.BIT.ATTCH ? true: false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
+ while (USB0.DCPCTR.BIT.PBUSY) ;
+ hcd_int_disable(rhport);
+ USB0.DVSTCTR0.BIT.UACT = 0;
+ if (USB0.DCPCTR.BIT.SUREQ)
+ USB0.DCPCTR.BIT.SUREQCLR = 1;
+ hcd_int_enable(rhport);
+ /* Reset should be asserted 10-20ms. */
+ USB0.DVSTCTR0.BIT.USBRST = 1;
+ for (volatile int i = 0; i < 2400000; ++i) ;
+ USB0.DVSTCTR0.BIT.USBRST = 0;
+ USB0.DVSTCTR0.BIT.UACT = 1;
+ _hcd.need_reset = false;
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ (void)rhport;
+ switch (USB0.DVSTCTR0.BIT.RHST) {
+ default: return TUSB_SPEED_INVALID;
+ case USB_DVSTCTR0_FULL: return TUSB_SPEED_FULL;
+ case USB_DVSTCTR0_LOW: return TUSB_SPEED_LOW;
+ }
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ uint16_t volatile *ctr;
+ TU_ASSERT(dev_addr < 6,); /* USBa can only handle addresses from 0 to 5. */
+ if (!dev_addr) return;
+ _hcd.ctl_mps[dev_addr] = 0;
+ uint8_t *ep = &_hcd.ep[dev_addr - 1][0][0];
+ for (int i = 0; i < 2 * 15; ++i, ++ep) {
+ unsigned num = *ep;
+ if (!num || dev_addr != _hcd.pipe[num].dev) continue;
+
+ ctr = (uint16_t volatile*)&USB0.PIPE1CTR.WORD + num - 1;
+ *ctr = 0;
+ USB0.NRDYENB.WORD &= ~TU_BIT(num);
+ USB0.BRDYENB.WORD &= ~TU_BIT(num);
+ USB0.PIPESEL.WORD = num;
+ USB0.PIPECFG.WORD = 0;
+ USB0.PIPEMAXP.WORD = 0;
+
+ _hcd.pipe[num].ep = 0;
+ _hcd.pipe[num].dev = 0;
+ *ep = 0;
+ }
+}
+
+/*--------------------------------------------------------------------+
+ * Endpoints API
+ *--------------------------------------------------------------------+*/
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ (void)rhport;
+ // TU_LOG1("S %d %x\n", dev_addr, USB0.DCPCTR.WORD);
+
+ TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
+ TU_ASSERT(0 == USB0.DCPCTR.BIT.SUREQ);
+
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
+
+ _hcd.pipe[0].buf = NULL;
+ _hcd.pipe[0].length = 8;
+ _hcd.pipe[0].remaining = 0;
+ _hcd.pipe[0].dev = dev_addr;
+
+ while (USB0.DCPCTR.BIT.PBUSY) ;
+ USB0.DCPMAXP.WORD = (dev_addr << 12) | _hcd.ctl_mps[dev_addr];
+
+ /* Set direction in advance for DATA stage */
+ uint8_t const bmRequesttype = setup_packet[0];
+ USB0.DCPCFG.BIT.DIR = tu_edpt_dir(bmRequesttype) ? 0: 1;
+
+ uint16_t const* p = (uint16_t const*)(uintptr_t)&setup_packet[0];
+ USB0.USBREQ.WORD = tu_htole16(p[0]);
+ USB0.USBVAL = p[1];
+ USB0.USBINDX = p[2];
+ USB0.USBLENG = p[3];
+
+ USB0.DCPCTR.BIT.SUREQ = 1;
+ return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void)rhport;
+ TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned mps = tu_edpt_packet_size(ep_desc);
+ if (0 == epn) {
+ USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
+ hcd_devtree_info_t devtree;
+ hcd_devtree_get_info(dev_addr, &devtree);
+ uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t)&USB0.DEVADD0.WORD;
+ devadd += dev_addr;
+ while (USB0.DCPCTR.BIT.PBUSY) ;
+ USB0.DCPMAXP.WORD = (dev_addr << 12) | mps;
+ *devadd = (TUSB_SPEED_FULL == devtree.speed) ? USB_DEVADD_FULL : USB_DEVADD_LOW;
+ _hcd.ctl_mps[dev_addr] = mps;
+ return true;
+ }
+
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ if (xfer == TUSB_XFER_ISOCHRONOUS && mps > 256) {
+ /* USBa supports up to 256 bytes */
+ return false;
+ }
+ const unsigned num = find_pipe(xfer);
+ if (!num) return false;
+ _hcd.pipe[num].dev = dev_addr;
+ _hcd.pipe[num].ep = ep_addr;
+ _hcd.ep[dev_addr - 1][dir_in][epn - 1] = num;
+
+ /* setup pipe */
+ hcd_int_disable(rhport);
+ USB0.PIPESEL.WORD = num;
+ USB0.PIPEMAXP.WORD = (dev_addr << 12) | mps;
+ volatile uint16_t *ctr = get_pipectr(num);
+ *ctr = USB_PIPECTR_ACLRM | USB_PIPECTR_SQCLR;
+ *ctr = 0;
+ unsigned cfg = ((1 ^ dir_in) << 4) | epn;
+ if (xfer == TUSB_XFER_BULK) {
+ cfg |= USB_PIPECFG_BULK | USB_PIPECFG_SHTNAK | USB_PIPECFG_DBLB;
+ } else if (xfer == TUSB_XFER_INTERRUPT) {
+ cfg |= USB_PIPECFG_INT;
+ } else {
+ cfg |= USB_PIPECFG_ISO | USB_PIPECFG_DBLB;
+ }
+ USB0.PIPECFG.WORD = cfg;
+ USB0.BRDYSTS.WORD = 0x1FFu ^ TU_BIT(num);
+ USB0.NRDYENB.WORD |= TU_BIT(num);
+ USB0.BRDYENB.WORD |= TU_BIT(num);
+ if (!dir_in) {
+ *ctr = USB_PIPECTR_PID_BUF;
+ }
+ hcd_int_enable(rhport);
+
+ return true;
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
+{
+ bool r;
+ hcd_int_disable(rhport);
+ // TU_LOG1("X %d %x %u\n", dev_addr, ep_addr, buflen);
+ r = process_edpt_xfer(dev_addr, ep_addr, buffer, buflen);
+ hcd_int_enable(rhport);
+ return r;
+}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ uint16_t volatile *ctr = addr_to_pipectr(dev_addr, ep_addr);
+ TU_ASSERT(ctr);
+
+ const uint32_t pid = *ctr & 0x3;
+ if (pid & 2) {
+ *ctr = pid & 2;
+ *ctr = 0;
+ }
+ *ctr = USB_PIPECTR_SQCLR;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ if (!epn) return true;
+
+ if (!tu_edpt_dir(ep_addr)) { /* OUT */
+ *ctr = USB_PIPECTR_PID_BUF;
+ }
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void hcd_int_handler(uint8_t rhport)
+{
+ (void)rhport;
+#if defined(__CCRX__)
+ static const int Mod37BitPosition[] = {
+ -1, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
+ 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5,
+ 20, 8, 19, 18};
+#endif
+
+ unsigned is1 = USB0.INTSTS1.WORD;
+ unsigned is0 = USB0.INTSTS0.WORD;
+ /* clear active bits except VALID (don't write 0 to already cleared bits according to the HW manual) */
+ USB0.INTSTS1.WORD = ~((USB_IS1_SACK | USB_IS1_SIGN | USB_IS1_ATTCH | USB_IS1_DTCH) & is1);
+ USB0.INTSTS0.WORD = ~((USB_IS0_BRDY | USB_IS0_NRDY | USB_IS0_BEMP) & is0);
+ // TU_LOG1("IS %04x %04x\n", is0, is1);
+ is1 &= USB0.INTENB1.WORD;
+ is0 &= USB0.INTENB0.WORD;
+
+ if (is1 & USB_IS1_SACK) {
+ /* Set DATA1 in advance for the next transfer. */
+ USB0.DCPCTR.BIT.SQSET = 1;
+ hcd_event_xfer_complete(USB0.DCPMAXP.BIT.DEVSEL,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ 8, XFER_RESULT_SUCCESS, true);
+ }
+ if (is1 & USB_IS1_SIGN) {
+ hcd_event_xfer_complete(USB0.DCPMAXP.BIT.DEVSEL,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ 8, XFER_RESULT_FAILED, true);
+ }
+ if (is1 & USB_IS1_ATTCH) {
+ USB0.DVSTCTR0.BIT.UACT = 1;
+ _hcd.need_reset = true;
+ USB0.INTENB1.WORD = (USB0.INTENB1.WORD & ~USB_IS1_ATTCH) | USB_IS1_DTCH;
+ hcd_event_device_attach(rhport, true);
+ }
+ if (is1 & USB_IS1_DTCH) {
+ USB0.DVSTCTR0.BIT.UACT = 0;
+ if (USB0.DCPCTR.BIT.SUREQ)
+ USB0.DCPCTR.BIT.SUREQCLR = 1;
+ USB0.INTENB1.WORD = (USB0.INTENB1.WORD & ~USB_IS1_DTCH) | USB_IS1_ATTCH;
+ hcd_event_device_remove(rhport, true);
+ }
+
+ if (is0 & USB_IS0_BEMP) {
+ const unsigned s = USB0.BEMPSTS.WORD;
+ USB0.BEMPSTS.WORD = 0;
+ if (s & 1) {
+ process_pipe0_bemp(rhport);
+ }
+ }
+ if (is0 & USB_IS0_NRDY) {
+ const unsigned m = USB0.NRDYENB.WORD;
+ unsigned s = USB0.NRDYSTS.WORD & m;
+ USB0.NRDYSTS.WORD = ~s;
+ while (s) {
+#if defined(__CCRX__)
+ const unsigned num = Mod37BitPosition[(-s & s) % 37];
+#else
+ const unsigned num = __builtin_ctz(s);
+#endif
+ process_pipe_nrdy(rhport, num);
+ s &= ~TU_BIT(num);
+ }
+ }
+ if (is0 & USB_IS0_BRDY) {
+ const unsigned m = USB0.BRDYENB.WORD;
+ unsigned s = USB0.BRDYSTS.WORD & m;
+ /* clear active bits (don't write 0 to already cleared bits according to the HW manual) */
+ USB0.BRDYSTS.WORD = ~s;
+ while (s) {
+#if defined(__CCRX__)
+ const unsigned num = Mod37BitPosition[(-s & s) % 37];
+#else
+ const unsigned num = __builtin_ctz(s);
+#endif
+ process_pipe_brdy(rhport, num);
+ s &= ~TU_BIT(num);
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c
index dfe409383..6677891a5 100644
--- a/src/portable/sony/cxd56/dcd_cxd56.c
+++ b/src/portable/sony/cxd56/dcd_cxd56.c
@@ -26,19 +26,20 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_CXD56
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_CXD56
#include <errno.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/arch.h>
#include "device/dcd.h"
+#include "device/usbd_pvt.h"
#define CXD56_EPNUM (7)
#define CXD56_SETUP_QUEUE_DEPTH (4)
#define CXD56_MAX_DATA_OUT_SIZE (64)
-OSAL_QUEUE_DEF(OPT_MODE_DEVICE, _setup_queue_def, CXD56_SETUP_QUEUE_DEPTH, struct usb_ctrlreq_s);
+OSAL_QUEUE_DEF(usbd_int_set, _setup_queue_def, CXD56_SETUP_QUEUE_DEPTH, struct usb_ctrlreq_s);
struct usbdcd_driver_s
{
@@ -246,6 +247,14 @@ void dcd_disconnect(uint8_t rhport)
DEV_DISCONNECT(usbdev);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -362,7 +371,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
if (usbdcd_driver.setup_processed)
{
- if (osal_queue_receive(usbdcd_driver.setup_queue, &ctrl))
+ if (osal_queue_receive(usbdcd_driver.setup_queue, &ctrl, 100))
{
usbdcd_driver.setup_processed = false;
dcd_event_setup_received(0, (uint8_t *)&ctrl, false);
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index ec3964b4a..b90ab7d11 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -109,8 +109,8 @@
#define STM32F1_FSDEV
#endif
-#if TUSB_OPT_DEVICE_ENABLED && \
- ( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4) || \
+#if CFG_TUD_ENABLED && \
+ ( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4, OPT_MCU_STM32WB) || \
(TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) || \
(TU_CHECK_MCU(OPT_MCU_STM32L4) && !defined(DCD_ATTR_DWC2_STM32)) \
)
@@ -288,6 +288,14 @@ void dcd_connect(uint8_t rhport)
}
#endif
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
// Enable device interrupt
void dcd_int_enable (uint8_t rhport)
{
@@ -330,6 +338,10 @@ void dcd_int_enable (uint8_t rhport)
NVIC_EnableIRQ(USB_LP_IRQn);
NVIC_EnableIRQ(USBWakeUp_IRQn);
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ NVIC_EnableIRQ(USB_HP_IRQn);
+ NVIC_EnableIRQ(USB_LP_IRQn);
+
#else
#error Unknown arch in USB driver
#endif
@@ -373,6 +385,10 @@ void dcd_int_disable(uint8_t rhport)
NVIC_DisableIRQ(USB_LP_IRQn);
NVIC_DisableIRQ(USBWakeUp_IRQn);
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ NVIC_DisableIRQ(USB_HP_IRQn);
+ NVIC_DisableIRQ(USB_LP_IRQn);
+
#else
#error Unknown arch in USB driver
#endif
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
index eabefa687..920d12c1b 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
@@ -91,6 +91,13 @@
#include "stm32g4xx.h"
#define PMA_LENGTH (1024u)
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ #include "stm32wbxx.h"
+ #define PMA_LENGTH (1024u)
+ /* ST provided header has incorrect value */
+ #undef USB_PMAADDR
+ #define USB_PMAADDR USB1_PMAADDR
+
#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
#include "stm32l4xx.h"
#define PMA_LENGTH (1024u)
diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c
index 4782ead8c..2fc3adb4f 100644
--- a/src/portable/st/synopsys/dcd_synopsys.c
+++ b/src/portable/st/synopsys/dcd_synopsys.c
@@ -45,7 +45,7 @@
#define STM32L4_SYNOPSYS
#endif
-#if TUSB_OPT_DEVICE_ENABLED && \
+#if CFG_TUD_ENABLED && \
( (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \
CFG_TUSB_MCU == OPT_MCU_STM32F2 || \
CFG_TUSB_MCU == OPT_MCU_STM32F4 || \
@@ -602,6 +602,13 @@ void dcd_disconnect(uint8_t rhport)
dev->DCTL |= USB_OTG_DCTL_SDIS;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
/*------------------------------------------------------------------*/
/* DCD Endpoint port
diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c
new file mode 100644
index 000000000..a0be846a5
--- /dev/null
+++ b/src/portable/sunxi/dcd_sunxi_musb.c
@@ -0,0 +1,1219 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include <stdint.h>
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_F1C100S
+
+#include "osal/osal.h"
+#include <f1c100s-irq.h>
+#include <device/dcd.h>
+#include "musb_def.h"
+#include "bsp/board.h"
+
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+
+#define REQUEST_TYPE_INVALID (0xFFu)
+
+typedef struct {
+ uint_fast16_t beg; /* offset of including first element */
+ uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+typedef struct TU_ATTR_PACKED
+{
+ void *buf; /* the start address of a transfer data buffer */
+ uint16_t length; /* the number of bytes in the buffer */
+ uint16_t remaining; /* the number of bytes remaining in the buffer */
+} pipe_state_t;
+
+typedef struct
+{
+ tusb_control_request_t setup_packet;
+ uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
+ int8_t status_out;
+ pipe_state_t pipe0;
+ pipe_state_t pipe[2][7]; /* pipe[direction][endpoint number - 1] */
+ uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */
+} dcd_data_t;
+
+/*------------------------------------------------------------------
+ * SUNXI FUNCTION
+ *------------------------------------------------------------------*/
+
+static void usb_phy_write(int addr, int data, int len)
+{
+ int j = 0, usbc_bit = 0;
+ void *dest = (void *)USBC_REG_CSR(USBC0_BASE);
+
+ usbc_bit = 1 << (0 * 2);
+ for (j = 0; j < len; j++)
+ {
+ /* set the bit address to be written */
+ USBC_ClrBit_Mask_l(dest, 0xff << 8);
+ USBC_SetBit_Mask_l(dest, (addr + j) << 8);
+
+ USBC_ClrBit_Mask_l(dest, usbc_bit);
+ /* set data bit */
+ if (data & 0x1)
+ USBC_SetBit_Mask_l(dest, 1 << 7);
+ else
+ USBC_ClrBit_Mask_l(dest, 1 << 7);
+
+ USBC_SetBit_Mask_l(dest, usbc_bit);
+
+ USBC_ClrBit_Mask_l(dest, usbc_bit);
+
+ data >>= 1;
+ }
+}
+
+static void delay_ms(uint32_t ms)
+{
+#if CFG_TUSB_OS == OPT_OS_NONE
+ int now = board_millis();
+ while (board_millis() - now <= ms) asm("nop");
+#else
+ osal_task_delay(ms);
+#endif
+}
+
+static void USBC_HardwareReset(void)
+{
+ // Reset phy and controller
+ USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
+ USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
+ delay_ms(2);
+
+ USBC_REG_set_bit_l(USBPHY_CLK_GAT_BIT, USBPHY_CLK_REG);
+ USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
+
+ USBC_REG_set_bit_l(BUS_CLK_USB_BIT, BUS_CLK_GATE0_REG);
+ USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
+}
+
+static void USBC_PhyConfig(void)
+{
+ /* Regulation 45 ohms */
+ usb_phy_write(0x0c, 0x01, 1);
+
+ /* adjust PHY's magnitude and rate */
+ usb_phy_write(0x20, 0x14, 5);
+
+ /* threshold adjustment disconnect */
+ usb_phy_write(0x2a, 3, 2);
+
+ return;
+}
+
+static void USBC_ConfigFIFO_Base(void)
+{
+ u32 reg_value;
+
+ /* config usb fifo, 8kb mode */
+ reg_value = USBC_Readl(SUNXI_SRAMC_BASE + 0x04);
+ reg_value &= ~(0x03 << 0);
+ reg_value |= (1 << 0);
+ USBC_Writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
+}
+
+static unsigned int USBC_WakeUp_ClearChangeDetect(unsigned int reg_val)
+{
+ unsigned int temp = reg_val;
+ /* vbus, id, dpdm, these bit is set 1 to clear, so we clear these bit when operate other bits */
+ temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT);
+ temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT);
+ temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT);
+
+ return temp;
+}
+
+static void USBC_EnableDpDmPullUp(void)
+{
+ u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+ reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
+ reg_val |= 3<<USBC_BP_ISCR_VBUS_VALID_SRC;
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+static void USBC_ForceIdToHigh(void)
+{
+ /* first write 00, then write 10 */
+ u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+ reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+static void USBC_ForceVbusValidToHigh(void)
+{
+ /* first write 00, then write 11 */
+ u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+ reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+ reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+ USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+void USBC_SelectBus(u32 io_type, u32 ep_type, u32 ep_index)
+{
+ u32 reg_val = 0;
+
+ reg_val = USBC_Readb(USBC_REG_VEND0(USBC0_BASE));
+ if (io_type == USBC_IO_TYPE_DMA) {
+ if (ep_type == USBC_EP_TYPE_TX) {
+ reg_val |= ((ep_index - 0x01) << 1) << USBC_BP_VEND0_DRQ_SEL; //drq_sel
+ reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL; //io_dma
+ } else {
+ reg_val |= ((ep_index << 1) - 0x01) << USBC_BP_VEND0_DRQ_SEL;
+ reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL;
+ }
+ } else {
+ //reg_val &= ~(0x1 << USBC_BP_VEND0_DRQ_SEL); //clear drq_sel, select pio
+ reg_val &= 0x00; // clear drq_sel, select pio
+ }
+
+ /* in 1667 1673 and later ic, FIFO_BUS_SEL bit(bit24 of reg0x40 for host/device)
+ * is fixed to 1, the hw guarantee that it's ok for cpu/inner_dma/outer_dma transfer */
+
+// reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL; //for 1663 set 1: enable dma, set 0: enable fifo
+
+ USBC_Writeb(reg_val, USBC_REG_VEND0(USBC0_BASE));
+}
+
+static void USBC_SelectActiveEp(u8 ep_index)
+{
+ USBC_Writeb(ep_index, USBC_REG_EPIND(USBC0_BASE));
+}
+
+static u8 USBC_GetActiveEp(void)
+{
+ return USBC_Readb(USBC_REG_EPIND(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_SendStall(void)
+{
+ USBC_REG_set_bit_w(USBC_BP_CSR0_D_SEND_STALL, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_ClearStall(void)
+{
+ USBC_REG_clear_bit_w(USBC_BP_CSR0_D_SEND_STALL, USBC_REG_CSR0(USBC0_BASE));
+ USBC_REG_clear_bit_w(USBC_BP_CSR0_D_SENT_STALL, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void USBC_Dev_Ctrl_ClearSetupEnd(void)
+{
+ USBC_REG_set_bit_w(USBC_BP_CSR0_D_SERVICED_SETUP_END, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void USBC_Dev_SetAddress(u8 address)
+{
+ USBC_Writeb(address, USBC_REG_FADDR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Tx_SendStall(void)
+{
+ //send stall, and fifo is flushed automaticly
+ USBC_REG_set_bit_w(USBC_BP_TXCSR_D_SEND_STALL, USBC_REG_TXCSR(USBC0_BASE));
+}
+static u32 __USBC_Dev_Tx_IsEpStall(void)
+{
+ return USBC_REG_test_bit_w(USBC_BP_TXCSR_D_SENT_STALL, USBC_REG_TXCSR(USBC0_BASE));
+}
+static void __USBC_Dev_Tx_ClearStall(void)
+{
+ u32 reg_val = USBC_Readw(USBC_REG_TXCSR(USBC0_BASE));
+ reg_val &= ~((1 << USBC_BP_TXCSR_D_SENT_STALL)|(1 << USBC_BP_TXCSR_D_SEND_STALL)|(1<<USBC_BP_TXCSR_D_UNDER_RUN));
+ reg_val |= (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE);
+ USBC_Writew(reg_val, USBC_REG_TXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_SendStall(void)
+{
+ USBC_REG_set_bit_w(USBC_BP_RXCSR_D_SEND_STALL, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static u32 __USBC_Dev_Rx_IsEpStall(void)
+{
+ return USBC_REG_test_bit_w(USBC_BP_RXCSR_D_SENT_STALL, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_ClearStall(void)
+{
+ u32 reg_val = USBC_Readw(USBC_REG_RXCSR(USBC0_BASE));
+ reg_val &= ~((1 << USBC_BP_RXCSR_D_SENT_STALL)|(1 << USBC_BP_RXCSR_D_SEND_STALL)|(1<<USBC_BP_RXCSR_D_OVERRUN));
+ reg_val |= (1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE);
+ USBC_Writew(reg_val, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static tusb_speed_t USBC_Dev_QueryTransferMode(void)
+{
+ if (USBC_REG_test_bit_b(USBC_BP_POWER_D_HIGH_SPEED_FLAG, USBC_REG_PCTL(USBC0_BASE)))
+ return TUSB_SPEED_HIGH;
+ else
+ return TUSB_SPEED_FULL;
+}
+
+static void __USBC_Dev_ep0_ReadDataHalf(void)
+{
+ USBC_Writew(1<<USBC_BP_CSR0_D_SERVICED_RX_PKT_READY, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_ReadDataComplete(void)
+{
+ USBC_Writew((1<<USBC_BP_CSR0_D_SERVICED_RX_PKT_READY) | (1<<USBC_BP_CSR0_D_DATA_END),
+ USBC_REG_CSR0(USBC0_BASE));
+}
+
+
+static void __USBC_Dev_ep0_WriteDataHalf(void)
+{
+ USBC_Writew(1<<USBC_BP_CSR0_D_TX_PKT_READY, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_WriteDataComplete(void)
+{
+ USBC_Writew((1<<USBC_BP_CSR0_D_TX_PKT_READY) | (1<<USBC_BP_CSR0_D_DATA_END),
+ USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_Tx_WriteDataComplete(void)
+{
+ USBC_Writeb((1 << USBC_BP_TXCSR_D_TX_READY), USBC_REG_TXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_ReadDataComplete(void)
+{
+ USBC_Writeb(0, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static u32 __USBC_Dev_Rx_IsReadDataReady(void)
+{
+ return USBC_REG_test_bit_w(USBC_BP_RXCSR_D_RX_PKT_READY, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+/* open a tx ep's interrupt */
+static void USBC_INT_EnableTxEp(u8 ep_index)
+{
+ USBC_REG_set_bit_w(ep_index, USBC_REG_INTTxE(USBC0_BASE));
+}
+
+/* open a rx ep's interrupt */
+static void USBC_INT_EnableRxEp(u8 ep_index)
+{
+ USBC_REG_set_bit_w(ep_index, USBC_REG_INTRxE(USBC0_BASE));
+}
+
+/* close a tx ep's interrupt */
+static void USBC_INT_DisableTxEp(u8 ep_index)
+{
+ USBC_REG_clear_bit_w(ep_index, USBC_REG_INTTxE(USBC0_BASE));
+}
+
+/* close a rx ep's interrupt */
+static void USBC_INT_DisableRxEp(u8 ep_index)
+{
+ USBC_REG_clear_bit_w(ep_index, USBC_REG_INTRxE(USBC0_BASE));
+}
+
+/*------------------------------------------------------------------
+ * INTERNAL FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+
+static dcd_data_t _dcd;
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+ free_block_t *cur = beg;
+ for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+ return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+ free_block_t *p = find_containing_block(blks, blks + num, addr);
+ TU_ASSERT(p != blks + num, -2);
+ if (p->beg == addr) {
+ /* Shrink block */
+ p->beg = addr + size;
+ if (p->beg != p->end) return 0;
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ } else {
+ /* Split into 2 blocks */
+ free_block_t tmp = {
+ .beg = addr + size,
+ .end = p->end
+ };
+ p->end = addr;
+ if (p->beg == p->end) {
+ if (tmp.beg != tmp.end) {
+ *p = tmp;
+ return 0;
+ }
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ }
+ if (tmp.beg == tmp.end) return 0;
+ blks[num] = tmp;
+ return 1;
+ }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+ return blk->end - blk->beg;
+}
+
+#if 0
+static inline void print_block_list(free_block_t const *blk, unsigned num)
+{
+ TU_LOG1("*************\n");
+ for (unsigned i = 0; i < num; ++i) {
+ TU_LOG1(" Blk%u %u %u\n", i, blk->beg, blk->end);
+ ++blk;
+ }
+}
+#else
+#define print_block_list(a,b)
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_F1C100S
+#define USB_FIFO_SIZE_KB 4
+#else
+#error "Unsupported MCU"
+#endif
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+ free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)];
+ unsigned num_blocks = 1;
+ /* Backup current EP to restore later */
+ u8 backup_ep = USBC_GetActiveEp();
+
+ /* Initialize free memory block list */
+ free_blocks[0].beg = 64 / 8;
+ free_blocks[0].end = (USB_FIFO_SIZE_KB << 10) / 8; /* 2KiB / 8 bytes */
+ for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ uint_fast16_t addr;
+ int num;
+ USBC_SelectActiveEp(i);
+ addr = USBC_Readw(USBC_REG_TXFIFOAD(USBC0_BASE));
+ if (addr) {
+ unsigned sz = USBC_Readb(USBC_REG_TXFIFOSZ(USBC0_BASE));
+ unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ addr = USBC_Readw(USBC_REG_RXFIFOAD(USBC0_BASE));
+ if (addr) {
+ unsigned sz = USBC_Readb(USBC_REG_RXFIFOSZ(USBC0_BASE));
+ unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ }
+ print_block_list(free_blocks, num_blocks);
+
+ USBC_SelectActiveEp(backup_ep);
+
+ /* Find the best fit memory block */
+ uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+ free_block_t const *min = NULL;
+ uint_fast16_t min_sz = 0xFFFFu;
+ free_block_t const *end = &free_blocks[num_blocks];
+ for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+ uint_fast16_t sz = free_block_size(cur);
+ if (sz < size_in_8byte_unit) continue;
+ if (size_in_8byte_unit == sz) return cur->beg;
+ if (sz < min_sz) min = cur;
+ }
+ TU_ASSERT(min, 0);
+ return min->beg;
+}
+
+static void pipe_write_packet(void *buff, volatile void *fifo, unsigned cnt)
+{
+ u32 len = 0;
+ u32 i32 = 0;
+ u32 i8 = 0;
+ u8 *buf8 = 0;
+ u32 *buf32 = 0;
+
+ //--<1>-- adjust data
+ buf32 = buff;
+ len = cnt;
+
+ i32 = len >> 2;
+ i8 = len & 0x03;
+
+ //--<2>-- deal with 4byte part
+ while (i32--) {
+ USBC_Writel(*buf32++, fifo);
+ }
+
+ //--<3>-- deal with no 4byte part
+ buf8 = (u8 *)buf32;
+ while (i8--) {
+ USBC_Writeb(*buf8++, fifo);
+ }
+}
+
+static void pipe_read_packet(void *buff, volatile void *fifo, unsigned cnt)
+{
+ u32 len = 0;
+ u32 i32 = 0;
+ u32 i8 = 0;
+ u8 *buf8 = 0;
+ u32 *buf32 = 0;
+
+ //--<1>-- adjust data
+ buf32 = buff;
+ len = cnt;
+
+ i32 = len >> 2;
+ i8 = len & 0x03;
+
+ //--<2>-- deal with 4byte part
+ while (i32--) {
+ *buf32++ = USBC_Readl(fifo);
+ }
+
+ //--<3>-- deal with no 4byte part
+ buf8 = (u8 *)buf32;
+ while (i8--) {
+ *buf8++ = USBC_Readb(fifo);
+ }
+}
+
+static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir)
+{
+ static const struct {
+ void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
+ void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n);
+ void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len);
+ } ops[] = {
+ /* OUT */ {tu_fifo_get_write_info,tu_fifo_advance_write_pointer,pipe_read_packet},
+ /* IN */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet},
+ };
+ tu_fifo_buffer_info_t info;
+ ops[dir].tu_fifo_get_info(f, &info);
+ unsigned total_len = len;
+ len = TU_MIN(total_len, info.len_lin);
+ ops[dir].pipe_read_write(info.ptr_lin, fifo, len);
+ unsigned rem = total_len - len;
+ if (rem) {
+ len = TU_MIN(rem, info.len_wrap);
+ ops[dir].pipe_read_write(info.ptr_wrap, fifo, len);
+ rem -= len;
+ }
+ ops[dir].tu_fifo_advance(f, total_len - rem);
+}
+
+/*------------------------------------------------------------------
+ * TRANSFER FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+
+static void process_setup_packet(uint8_t rhport)
+{
+ uint32_t *p = (uint32_t*)&_dcd.setup_packet;
+ p[0] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
+ p[1] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
+
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ dcd_event_setup_received(rhport, (const uint8_t*)(uintptr_t)&_dcd.setup_packet, true);
+
+ const unsigned len = _dcd.setup_packet.wLength;
+ _dcd.remaining_ctrl = len;
+ const unsigned dir_in = tu_edpt_dir(_dcd.setup_packet.bmRequestType);
+ /* Clear RX FIFO and reverse the transaction direction */
+ if (len && dir_in) __USBC_Dev_ep0_ReadDataHalf();
+}
+
+static bool handle_xfer_in(uint_fast8_t ep_addr)
+{
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+ const unsigned rem = pipe->remaining;
+
+ if (!rem) {
+ pipe->buf = NULL;
+ return true;
+ }
+
+ const unsigned mps = USBC_Readw(USBC_REG_TXMAXP(USBC0_BASE));
+ const unsigned len = TU_MIN(mps, rem);
+ uint8_t *buf = pipe->buf;
+ // TU_LOG1(" %p mps %d len %d rem %d\n", buf, mps, len, rem);
+ if (len) {
+ volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
+ if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
+ pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_IN);
+ } else {
+ pipe_write_packet(buf, addr, len);
+ pipe->buf = buf + len;
+ }
+ pipe->remaining = rem - len;
+ }
+ __USBC_Dev_Tx_WriteDataComplete();
+ // TU_LOG1(" TXCSRL%d = %x %d\n", epnum_minus1 + 1, regs->TXCSRL, rem - len);
+ return false;
+}
+
+static bool handle_xfer_out(uint_fast8_t ep_addr)
+{
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+ // TU_LOG1(" RXCSRL%d = %x\n", epnum_minus1 + 1, regs->RXCSRL);
+
+ TU_ASSERT(__USBC_Dev_Rx_IsReadDataReady());
+
+ const unsigned mps = USBC_Readw(USBC_REG_RXMAXP(USBC0_BASE));
+ const unsigned rem = pipe->remaining;
+ const unsigned vld = USBC_Readw(USBC_REG_RXCOUNT(USBC0_BASE));
+ const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+ uint8_t *buf = pipe->buf;
+ if (len) {
+ volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
+ if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
+ pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_OUT);
+ } else {
+ pipe_read_packet(buf, addr, len);
+ pipe->buf = buf + len;
+ }
+ pipe->remaining = rem - len;
+ }
+ if ((len < mps) || (rem == len)) {
+ pipe->buf = NULL;
+ return NULL != buf;
+ }
+ __USBC_Dev_Rx_ReadDataComplete();
+ return false;
+}
+
+static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+
+ unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ unsigned dir_in = tu_edpt_dir(ep_addr);
+
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1];
+ pipe->buf = buffer;
+ pipe->length = total_bytes;
+ pipe->remaining = total_bytes;
+
+ USBC_SelectActiveEp(tu_edpt_number(ep_addr));
+
+ if (dir_in) {
+ handle_xfer_in(ep_addr);
+ } else {
+ if (__USBC_Dev_Rx_IsReadDataReady())
+ __USBC_Dev_Rx_ReadDataComplete();
+ }
+ return true;
+}
+
+static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */
+
+ const unsigned req = _dcd.setup_packet.bmRequestType;
+ TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0);
+
+ USBC_SelectActiveEp(0);
+
+ if (req == REQUEST_TYPE_INVALID || _dcd.status_out) {
+ /* STATUS OUT stage.
+ * MUSB controller automatically handles STATUS OUT packets without
+ * software helps. We do not have to do anything. And STATUS stage
+ * may have already finished and received the next setup packet
+ * without calling this function, so we have no choice but to
+ * invoke the callback function of status packet here. */
+ // TU_LOG1(" STATUS OUT CSRL0 = %x\n", CSRL0);
+ _dcd.status_out = 0;
+ if (req == REQUEST_TYPE_INVALID) {
+ dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
+ } else {
+ /* The next setup packet has already been received, it aborts
+ * invoking callback function to avoid confusing TUSB stack. */
+ TU_LOG1("Drop CONTROL_STAGE_ACK\n");
+ }
+ return true;
+ }
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
+ TU_ASSERT(total_bytes <= _dcd.remaining_ctrl);
+ const unsigned rem = _dcd.remaining_ctrl;
+ const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
+ if (dir_in) {
+ pipe_write_packet(buffer, (volatile void*) USBC_REG_EPFIFO0(USBC0_BASE), len);
+
+ _dcd.pipe0.buf = buffer + len;
+ _dcd.pipe0.length = len;
+ _dcd.pipe0.remaining = 0;
+
+ _dcd.remaining_ctrl = rem - len;
+ if ((len < 64) || (rem == len)) {
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; /* Change to STATUS/SETUP stage */
+ _dcd.status_out = 1;
+ /* Flush TX FIFO and reverse the transaction direction. */
+ __USBC_Dev_ep0_WriteDataComplete();
+ } else {
+ __USBC_Dev_ep0_WriteDataHalf();
+ }
+ // TU_LOG1(" IN CSRL0 = %x\n", CSRL0);
+ } else {
+ // TU_LOG1(" OUT CSRL0 = %x\n", CSRL0);
+ _dcd.pipe0.buf = buffer;
+ _dcd.pipe0.length = len;
+ _dcd.pipe0.remaining = len;
+ __USBC_Dev_ep0_ReadDataHalf();
+ }
+ } else if (dir_in) {
+ // TU_LOG1(" STATUS IN CSRL0 = %x\n", CSRL0);
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ /* Clear RX FIFO and reverse the transaction direction */
+ __USBC_Dev_ep0_ReadDataComplete();
+ }
+ return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+ USBC_SelectActiveEp(0);
+ uint_fast8_t csrl = USBC_Readw(USBC_REG_CSR0(USBC0_BASE));
+
+ // TU_LOG1(" EP0 CSRL0 = %x\n", csrl);
+
+ if (csrl & USB_CSRL0_STALLED) {
+ /* Returned STALL packet to HOST. */
+ __USBC_Dev_ep0_ClearStall();
+ return;
+ }
+
+ unsigned req = _dcd.setup_packet.bmRequestType;
+ if (csrl & USB_CSRL0_SETEND) {
+ // TU_LOG1(" ABORT by the next packets\n");
+ USBC_Dev_Ctrl_ClearSetupEnd();
+ if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) {
+ /* DATA stage was aborted by receiving STATUS or SETUP packet. */
+ _dcd.pipe0.buf = NULL;
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ dcd_event_xfer_complete(rhport,
+ req & TUSB_DIR_IN_MASK,
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ req = REQUEST_TYPE_INVALID;
+ if (!(csrl & USB_CSRL0_RXRDY)) return; /* Received SETUP packet */
+ }
+
+ if (csrl & USB_CSRL0_RXRDY) {
+ /* Received SETUP or DATA OUT packet */
+ if (req == REQUEST_TYPE_INVALID) {
+ /* SETUP */
+ TU_ASSERT(sizeof(tusb_control_request_t) == USBC_Readw(USBC_REG_COUNT0(USBC0_BASE)),);
+ process_setup_packet(rhport);
+ return;
+ }
+ if (_dcd.pipe0.buf) {
+ /* DATA OUT */
+ const unsigned vld = USBC_Readw(USBC_REG_COUNT0(USBC0_BASE));
+ const unsigned rem = _dcd.pipe0.remaining;
+ const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
+ pipe_read_packet(_dcd.pipe0.buf, (volatile void*)USBC_REG_EPFIFO0(USBC0_BASE), len);
+
+ _dcd.pipe0.remaining = rem - len;
+ _dcd.remaining_ctrl -= len;
+
+ _dcd.pipe0.buf = NULL;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+ return;
+ }
+
+ /* When CSRL0 is zero, it means that completion of sending a any length packet
+ * or receiving a zero length packet. */
+ if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir(req)) {
+ /* STATUS IN */
+ if (*(const uint16_t*)(uintptr_t)&_dcd.setup_packet == 0x0500) {
+ /* The address must be changed on completion of the control transfer. */
+ USBC_Dev_SetAddress((uint8_t)_dcd.setup_packet.wValue);
+ }
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_IN),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ return;
+ }
+ if (_dcd.pipe0.buf) {
+ /* DATA IN */
+ _dcd.pipe0.buf = NULL;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(0, TUSB_DIR_IN),
+ _dcd.pipe0.length - _dcd.pipe0.remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr)
+{
+ bool completed;
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ USBC_SelectActiveEp(epn);
+
+ if (dir_in) {
+ // TU_LOG1(" TXCSRL%d = %x\n", epn_minus1 + 1, regs->TXCSRL);
+ if (__USBC_Dev_Tx_IsEpStall()) {
+ __USBC_Dev_Tx_ClearStall();
+ return;
+ }
+ completed = handle_xfer_in(ep_addr);
+ } else {
+ // TU_LOG1(" RXCSRL%d = %x\n", epn_minus1 + 1, regs->RXCSRL);
+ if (__USBC_Dev_Rx_IsEpStall()) {
+ __USBC_Dev_Rx_ClearStall();
+ return;
+ }
+ completed = handle_xfer_out(ep_addr);
+ }
+
+ if (completed) {
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1];
+ dcd_event_xfer_complete(rhport, ep_addr,
+ pipe->length - pipe->remaining,
+ XFER_RESULT_SUCCESS, true);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF),
+ * a control transfer state is SETUP or STATUS stage. */
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ _dcd.status_out = 0;
+ /* When pipe0.buf has not NULL, DATA stage works in progress. */
+ _dcd.pipe0.buf = NULL;
+
+ USBC_Writew(1, USBC_REG_INTTxE(USBC0_BASE)); /* Enable only EP0 */
+ USBC_Writew(0, USBC_REG_INTRxE(USBC0_BASE));
+
+ dcd_event_bus_reset(rhport, USBC_Dev_QueryTransferMode(), true);
+}
+
+/*------------------------------------------------------------------
+ * Device API
+ *------------------------------------------------------------------*/
+
+static void usb_isr_handler(void) {
+ dcd_int_handler(0);
+}
+
+void dcd_init(uint8_t rhport)
+{
+ dcd_disconnect(rhport);
+ USBC_HardwareReset();
+ USBC_PhyConfig();
+ USBC_ConfigFIFO_Base();
+ USBC_EnableDpDmPullUp();
+ USBC_ForceIdToHigh(); // Force device mode
+ USBC_ForceVbusValidToHigh();
+ USBC_SelectBus(USBC_IO_TYPE_PIO, 0, 0);
+ dcd_edpt_close_all(rhport);
+
+ #if TUD_OPT_HIGH_SPEED
+ USBC_REG_set_bit_b(USBC_BP_POWER_D_HIGH_SPEED_EN, USBC_REG_PCTL(USBC0_BASE));
+ #else
+ USBC_REG_clear_bit_b(USBC_BP_POWER_D_HIGH_SPEED_EN, USBC_REG_PCTL(USBC0_BASE));
+ #endif
+
+ USBC_Writeb((1 << USBC_BP_INTUSBE_EN_SUSPEND)
+ | (1 << USBC_BP_INTUSBE_EN_RESUME)
+ | (1 << USBC_BP_INTUSBE_EN_RESET)
+ | (1 << USBC_BP_INTUSBE_EN_SOF)
+ | (1 << USBC_BP_INTUSBE_EN_DISCONNECT)
+ , USBC_REG_INTUSBE(USBC0_BASE));
+ f1c100s_intc_clear_pend(F1C100S_IRQ_USBOTG);
+ f1c100s_intc_set_isr(F1C100S_IRQ_USBOTG, usb_isr_handler);
+
+ dcd_connect(rhport);
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void)rhport;
+ USBC_REG_set_bit_b(USBC_BP_POWER_D_SOFT_CONNECT, USBC_REG_PCTL(USBC0_BASE));
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void)rhport;
+ USBC_REG_clear_bit_b(USBC_BP_POWER_D_SOFT_CONNECT, USBC_REG_PCTL(USBC0_BASE));
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+ (void)rhport;
+ f1c100s_intc_enable_irq(F1C100S_IRQ_USBOTG);
+}
+
+static void musb_int_mask(void)
+{
+ f1c100s_intc_mask_irq(F1C100S_IRQ_USBOTG);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void)rhport;
+ f1c100s_intc_disable_irq(F1C100S_IRQ_USBOTG);
+}
+
+static void musb_int_unmask(void)
+{
+ f1c100s_intc_unmask_irq(F1C100S_IRQ_USBOTG);
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ (void)rhport;
+ (void)dev_addr;
+ _dcd.pipe0.buf = NULL;
+ _dcd.pipe0.length = 0;
+ _dcd.pipe0.remaining = 0;
+ /* Clear RX FIFO to return ACK. */
+ USBC_SelectActiveEp(0);
+ __USBC_Dev_ep0_ReadDataComplete();
+}
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void)rhport;
+ USBC_REG_set_bit_b(USBC_BP_POWER_D_RESUME, USBC_REG_PCTL(USBC0_BASE));
+ delay_ms(10);
+ USBC_REG_clear_bit_b(USBC_BP_POWER_D_RESUME, USBC_REG_PCTL(USBC0_BASE));
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+#ifndef __ARMCC_VERSION
+#define __clz __builtin_clz
+#endif
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void) rhport;
+
+ uint16_t reg_val;
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir_in = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ const unsigned mps = tu_edpt_packet_size(ep_desc);
+
+ TU_ASSERT(epn < TUP_DCD_ENDPOINT_MAX);
+
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
+ pipe->buf = NULL;
+ pipe->length = 0;
+ pipe->remaining = 0;
+
+ musb_int_mask();
+
+ // volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+ USBC_SelectActiveEp(epn);
+ if (dir_in) {
+ USBC_Writew(mps, USBC_REG_TXMAXP(USBC0_BASE));
+
+ reg_val = (1 << USBC_BP_TXCSR_D_MODE)
+ | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO)
+ | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE);
+ if (xfer == TUSB_XFER_ISOCHRONOUS)
+ reg_val |= (1 << USBC_BP_TXCSR_D_ISO);
+ USBC_Writew(reg_val, USBC_REG_TXCSR(USBC0_BASE));
+
+ USBC_INT_EnableTxEp(epn);
+ } else {
+ USBC_Writew(mps, USBC_REG_RXMAXP(USBC0_BASE));
+
+ reg_val = (1 << USBC_BP_RXCSR_D_FLUSH_FIFO)
+ | (1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE);
+ if (xfer == TUSB_XFER_ISOCHRONOUS)
+ reg_val |= (1 << USBC_BP_RXCSR_D_ISO);
+ USBC_Writew(reg_val, USBC_REG_RXCSR(USBC0_BASE));
+
+ USBC_INT_EnableRxEp(epn);
+ }
+
+ /* Setup FIFO */
+ int size_in_log2_minus3 = 28 - TU_MIN(28, __clz((uint32_t)mps));
+ if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+ unsigned addr = find_free_memory(size_in_log2_minus3);
+ TU_ASSERT(addr);
+
+ if (dir_in) {
+ USBC_Writew(addr, USBC_REG_TXFIFOAD(USBC0_BASE));
+ USBC_Writeb(size_in_log2_minus3, USBC_REG_TXFIFOSZ(USBC0_BASE));
+ } else {
+ USBC_Writew(addr, USBC_REG_RXFIFOAD(USBC0_BASE));
+ USBC_Writeb(size_in_log2_minus3, USBC_REG_RXFIFOSZ(USBC0_BASE));
+ }
+
+ musb_int_unmask();
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void) rhport;
+ musb_int_mask();
+ USBC_Writew(1, USBC_REG_INTTxE(USBC0_BASE)); /* Enable only EP0 */
+ USBC_Writew(0, USBC_REG_INTRxE(USBC0_BASE));
+ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ USBC_SelectActiveEp(i);
+ USBC_Writew(0, USBC_REG_TXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_TXCSR_D_MODE) | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO),
+ USBC_REG_TXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_RXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_D_FLUSH_FIFO),
+ USBC_REG_RXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_TXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_TXFIFOSZ(USBC0_BASE));
+ USBC_Writew(0, USBC_REG_RXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_RXFIFOSZ(USBC0_BASE));
+ }
+ musb_int_unmask();
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ unsigned const dir_in = tu_edpt_dir(ep_addr);
+
+ musb_int_mask();
+ USBC_SelectActiveEp(epn);
+ if (dir_in) {
+ USBC_INT_DisableTxEp(epn);
+ USBC_Writew(0, USBC_REG_TXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_TXCSR_D_MODE) | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO),
+ USBC_REG_TXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_TXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_TXFIFOSZ(USBC0_BASE));
+ } else {
+ USBC_INT_DisableRxEp(epn);
+ USBC_Writew(0, USBC_REG_RXMAXP(USBC0_BASE));
+ USBC_Writew((1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_D_FLUSH_FIFO),
+ USBC_REG_RXCSR(USBC0_BASE));
+
+ USBC_Writew(0, USBC_REG_RXFIFOAD(USBC0_BASE));
+ USBC_Writeb(0, USBC_REG_RXFIFOSZ(USBC0_BASE));
+ }
+ musb_int_unmask();
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ (void)rhport;
+ bool ret;
+ // TU_LOG1("X %x %d\n", ep_addr, total_bytes);
+ unsigned const epnum = tu_edpt_number(ep_addr);
+ musb_int_mask();
+
+ if (epnum) {
+ _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1);
+ ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes);
+ } else {
+ ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
+ }
+ musb_int_unmask();
+ return ret;
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ (void)rhport;
+ bool ret;
+ // TU_LOG1("X %x %d\n", ep_addr, total_bytes);
+ unsigned const epnum = tu_edpt_number(ep_addr);
+ TU_ASSERT(epnum);
+
+ musb_int_mask();
+ _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1);
+ ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes);
+ musb_int_unmask();
+
+ return ret;
+}
+
+// Stall endpoint
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ musb_int_mask();
+ USBC_SelectActiveEp(epn);
+ if (0 == epn) {
+ if (!ep_addr) { /* Ignore EP80 */
+ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+ _dcd.pipe0.buf = NULL;
+ __USBC_Dev_ep0_SendStall();
+ }
+ } else {
+ if (tu_edpt_dir(ep_addr)) { /* IN */
+ __USBC_Dev_Tx_SendStall();
+ } else { /* OUT */
+ TU_ASSERT(!__USBC_Dev_Rx_IsReadDataReady(),);
+ __USBC_Dev_Rx_SendStall();
+ }
+ }
+ musb_int_unmask();
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ unsigned const epn = tu_edpt_number(ep_addr);
+ musb_int_mask();
+ USBC_SelectActiveEp(epn);
+ if (0 != epn) {
+ if (tu_edpt_dir(ep_addr)) { /* IN */
+ __USBC_Dev_Tx_ClearStall();
+ } else { /* OUT */
+ __USBC_Dev_Rx_ClearStall();
+ }
+ }
+ musb_int_unmask();
+}
+
+
+void dcd_int_handler(uint8_t rhport)
+{
+ uint8_t is;
+ uint16_t txis, rxis;
+
+ is = USBC_Readb(USBC_REG_INTUSB(USBC0_BASE)); /* read interrupt status */
+ txis = USBC_Readw(USBC_REG_INTTx(USBC0_BASE)); /* read interrupt status */
+ rxis = USBC_Readw(USBC_REG_INTRx(USBC0_BASE)); /* read interrupt status */
+
+ is &= USBC_Readb(USBC_REG_INTUSBE(USBC0_BASE)); /* ignore disabled interrupts */
+ USBC_Writeb(is, USBC_REG_INTUSB(USBC0_BASE)); /* sunxi musb requires a write to interrupt register to clear */
+ if (is & USBC_INTUSB_DISCONNECT) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+ if (is & USBC_INTUSB_SOF) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+ if (is & USBC_INTUSB_RESET) {
+ /* ep0 FADDR must be 0 when (re)entering peripheral mode */
+ USBC_SelectActiveEp(0);
+ USBC_Dev_SetAddress(0);
+ process_bus_reset(rhport);
+ }
+ if (is & USBC_INTUSB_RESUME) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ }
+ if (is & USBC_INTUSB_SUSPEND) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+ }
+
+ txis &= USBC_Readw(USBC_REG_INTTxE(USBC0_BASE));
+ USBC_Writew(txis, USBC_REG_INTTx(USBC0_BASE));
+ if (txis & USBC_INTTx_FLAG_EP0) {
+ process_ep0(rhport);
+ txis &= ~TU_BIT(0);
+ }
+ while (txis) {
+ unsigned const num = __builtin_ctz(txis);
+ process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN));
+ txis &= ~TU_BIT(num);
+ }
+
+ rxis &= USBC_Readw(USBC_REG_INTRxE(USBC0_BASE));
+ USBC_Writew(rxis, USBC_REG_INTRx(USBC0_BASE));
+ while (rxis) {
+ unsigned const num = __builtin_ctz(rxis);
+ process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT));
+ rxis &= ~TU_BIT(num);
+ }
+}
+
+#endif
diff --git a/src/portable/sunxi/musb_def.h b/src/portable/sunxi/musb_def.h
new file mode 100644
index 000000000..602b4f113
--- /dev/null
+++ b/src/portable/sunxi/musb_def.h
@@ -0,0 +1,643 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_MUSB_DEF
+#define _TUSB_MUSB_DEF
+
+
+#define USBC_Readb(reg) (*(volatile unsigned char *)(reg))
+#define USBC_Readw(reg) (*(volatile unsigned short *)(reg))
+#define USBC_Readl(reg) (*(volatile unsigned long *)(reg))
+
+#define USBC_Writeb(value, reg) (*(volatile unsigned char *)(reg) = (value))
+#define USBC_Writew(value, reg) (*(volatile unsigned short *)(reg) = (value))
+#define USBC_Writel(value, reg) (*(volatile unsigned long *)(reg) = (value))
+
+
+#define USBC_SetBit_Mask_b(reg,mask) do { \
+ unsigned char _r = USBC_Readb(reg); \
+ _r |= (unsigned char)(mask); \
+ USBC_Writeb(_r,reg); \
+ }while(0)
+#define USBC_SetBit_Mask_w(reg,mask) do { \
+ unsigned short _r = USBC_Readw(reg); \
+ _r |= (unsigned short)(mask); \
+ USBC_Writew(_r,reg); \
+ }while(0)
+#define USBC_SetBit_Mask_l(reg,mask) do { \
+ unsigned int _r = USBC_Readl(reg); \
+ _r |= (unsigned int)(mask); \
+ USBC_Writel(_r,reg); \
+ }while(0)
+
+
+#define USBC_ClrBit_Mask_b(reg,mask) do { \
+ unsigned char _r = USBC_Readb(reg); \
+ _r &= (~(unsigned char)(mask)); \
+ USBC_Writeb(_r,reg); \
+ }while(0);
+#define USBC_ClrBit_Mask_w(reg,mask) do { \
+ unsigned short _r = USBC_Readw(reg); \
+ _r &= (~(unsigned short)(mask)); \
+ USBC_Writew(_r,reg); \
+ }while(0)
+#define USBC_ClrBit_Mask_l(reg,mask) do { \
+ unsigned int _r = USBC_Readl(reg); \
+ _r &= (~(unsigned int)(mask)); \
+ USBC_Writel(_r,reg); \
+ }while(0)
+#define USBC_REG_test_bit_b(bp, reg) (USBC_Readb(reg) & (1 << (bp)))
+#define USBC_REG_test_bit_w(bp, reg) (USBC_Readw(reg) & (1 << (bp)))
+#define USBC_REG_test_bit_l(bp, reg) (USBC_Readl(reg) & (1 << (bp)))
+
+#define USBC_REG_set_bit_b(bp, reg) (USBC_Writeb((USBC_Readb(reg) | (1 << (bp))) , (reg)))
+#define USBC_REG_set_bit_w(bp, reg) (USBC_Writew((USBC_Readw(reg) | (1 << (bp))) , (reg)))
+#define USBC_REG_set_bit_l(bp, reg) (USBC_Writel((USBC_Readl(reg) | (1 << (bp))) , (reg)))
+
+#define USBC_REG_clear_bit_b(bp, reg) (USBC_Writeb((USBC_Readb(reg) & (~ (1 << (bp)))) , (reg)))
+#define USBC_REG_clear_bit_w(bp, reg) (USBC_Writew((USBC_Readw(reg) & (~ (1 << (bp)))) , (reg)))
+#define USBC_REG_clear_bit_l(bp, reg) (USBC_Writel((USBC_Readl(reg) & (~ (1 << (bp)))) , (reg)))
+
+#define SW_UDC_EPNUMS 3
+
+#define SUNXI_SRAMC_BASE 0x01c00000
+//---------------------------------------------------------------
+// reg base
+//---------------------------------------------------------------
+#define USBC0_BASE 0x01c13000
+#define USBC1_BASE 0x01c14000
+#define USBC2_BASE 0x01c1E000
+
+//Some reg whithin musb
+#define USBPHY_CLK_REG 0x01c200CC
+#define USBPHY_CLK_RST_BIT 0
+#define USBPHY_CLK_GAT_BIT 1
+
+#define BUS_CLK_RST_REG 0x01c202c0 //Bus Clock Reset Register Bit24 : USB CLK RST
+#define BUS_RST_USB_BIT 24
+
+#define BUS_CLK_GATE0_REG 0x01c20060 //Bus Clock Gating Register Bit24 : USB CLK GATE 0: Mask 1 : Pass
+#define BUS_CLK_USB_BIT 24
+
+//#define USB_INTR
+
+#define NDMA_CFG_REG
+//-----------------------------------------------------------------------
+// musb reg offset
+//-----------------------------------------------------------------------
+
+#define USBC_REG_o_FADDR 0x0098
+#define USBC_REG_o_PCTL 0x0040
+#define USBC_REG_o_INTTx 0x0044
+#define USBC_REG_o_INTRx 0x0046
+#define USBC_REG_o_INTTxE 0x0048
+#define USBC_REG_o_INTRxE 0x004A
+#define USBC_REG_o_INTUSB 0x004C
+#define USBC_REG_o_INTUSBE 0x0050
+#define USBC_REG_o_FRNUM 0x0054
+#define USBC_REG_o_EPIND 0x0042
+#define USBC_REG_o_TMCTL 0x007C
+
+#define USBC_REG_o_TXMAXP 0x0080
+#define USBC_REG_o_CSR0 0x0082
+#define USBC_REG_o_TXCSR 0x0082
+#define USBC_REG_o_RXMAXP 0x0084
+#define USBC_REG_o_RXCSR 0x0086
+#define USBC_REG_o_COUNT0 0x0088
+#define USBC_REG_o_RXCOUNT 0x0088
+#define USBC_REG_o_EP0TYPE 0x008C
+#define USBC_REG_o_TXTYPE 0x008C
+#define USBC_REG_o_NAKLIMIT0 0x008D
+#define USBC_REG_o_TXINTERVAL 0x008D
+#define USBC_REG_o_RXTYPE 0x008E
+#define USBC_REG_o_RXINTERVAL 0x008F
+
+//#define USBC_REG_o_CONFIGDATA 0x001F //
+
+#define USBC_REG_o_EPFIFO0 0x0000
+#define USBC_REG_o_EPFIFO1 0x0004
+#define USBC_REG_o_EPFIFO2 0x0008
+#define USBC_REG_o_EPFIFO3 0x000C
+#define USBC_REG_o_EPFIFO4 0x0010
+#define USBC_REG_o_EPFIFO5 0x0014
+#define USBC_REG_o_EPFIFOx(n) (0x0000 + (n<<2))
+
+#define USBC_REG_o_DEVCTL 0x0041
+
+#define USBC_REG_o_TXFIFOSZ 0x0090
+#define USBC_REG_o_RXFIFOSZ 0x0094
+#define USBC_REG_o_TXFIFOAD 0x0092
+#define USBC_REG_o_RXFIFOAD 0x0096
+
+#define USBC_REG_o_VEND0 0x0043
+#define USBC_REG_o_VEND1 0x007D
+#define USBC_REG_o_VEND3 0x007E
+
+//#define USBC_REG_o_PHYCTL 0x006C
+#define USBC_REG_o_EPINFO 0x0078
+#define USBC_REG_o_RAMINFO 0x0079
+#define USBC_REG_o_LINKINFO 0x007A
+#define USBC_REG_o_VPLEN 0x007B
+#define USBC_REG_o_HSEOF 0x007C
+#define USBC_REG_o_FSEOF 0x007D
+#define USBC_REG_o_LSEOF 0x007E
+
+//new
+#define USBC_REG_o_FADDR0 0x0098
+#define USBC_REG_o_HADDR0 0x009A
+#define USBC_REG_o_HPORT0 0x009B
+#define USBC_REG_o_TXFADDRx 0x0098
+#define USBC_REG_o_TXHADDRx 0x009A
+#define USBC_REG_o_TXHPORTx 0x009B
+#define USBC_REG_o_RXFADDRx 0x009C
+#define USBC_REG_o_RXHADDRx 0x009E
+#define USBC_REG_o_RXHPORTx 0x009F
+
+
+#define USBC_REG_o_RPCOUNT 0x008A
+
+//new
+#define USBC_REG_o_ISCR 0x0400
+#define USBC_REG_o_PHYCTL 0x0404
+#define USBC_REG_o_PHYBIST 0x0408
+#define USBC_REG_o_PHYTUNE 0x040c
+
+#define USBC_REG_o_CSR 0x0410
+
+#define USBC_REG_o_PMU_IRQ 0x0800
+
+//-----------------------------------------------------------------------
+// registers
+//-----------------------------------------------------------------------
+
+#define USBC_REG_FADDR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FADDR )
+#define USBC_REG_PCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PCTL )
+#define USBC_REG_INTTx(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTTx )
+#define USBC_REG_INTRx(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTRx )
+#define USBC_REG_INTTxE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTTxE )
+#define USBC_REG_INTRxE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTRxE )
+#define USBC_REG_INTUSB(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTUSB )
+#define USBC_REG_INTUSBE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_INTUSBE )
+#define USBC_REG_FRNUM(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FRNUM )
+#define USBC_REG_EPIND(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPIND )
+#define USBC_REG_TMCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TMCTL )
+#define USBC_REG_TXMAXP(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXMAXP )
+
+#define USBC_REG_CSR0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_CSR0 )
+#define USBC_REG_TXCSR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXCSR )
+
+#define USBC_REG_RXMAXP(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXMAXP )
+#define USBC_REG_RXCSR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXCSR )
+
+#define USBC_REG_COUNT0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_COUNT0 )
+#define USBC_REG_RXCOUNT(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXCOUNT )
+
+#define USBC_REG_EP0TYPE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EP0TYPE )
+#define USBC_REG_TXTYPE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXTYPE )
+
+#define USBC_REG_NAKLIMIT0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_NAKLIMIT0 )
+#define USBC_REG_TXINTERVAL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXINTERVAL )
+
+#define USBC_REG_RXTYPE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXTYPE )
+#define USBC_REG_RXINTERVAL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXINTERVAL )
+//#define USBC_REG_CONFIGDATA(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_CONFIGDATA )
+#define USBC_REG_EPFIFO0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO0 )
+#define USBC_REG_EPFIFO1(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO1 )
+#define USBC_REG_EPFIFO2(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO2 )
+#define USBC_REG_EPFIFO3(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO3 )
+#define USBC_REG_EPFIFO4(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO4 )
+#define USBC_REG_EPFIFO5(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPFIFO5 )
+#define USBC_REG_EPFIFOx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_EPFIFOx(n) )
+#define USBC_REG_DEVCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_DEVCTL )
+#define USBC_REG_TXFIFOSZ(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXFIFOSZ )
+#define USBC_REG_RXFIFOSZ(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXFIFOSZ )
+#define USBC_REG_TXFIFOAD(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_TXFIFOAD )
+#define USBC_REG_RXFIFOAD(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RXFIFOAD )
+#define USBC_REG_VEND0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_VEND0 )
+#define USBC_REG_VEND1(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_VEND1 )
+#define USBC_REG_EPINFO(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_EPINFO )
+#define USBC_REG_RAMINFO(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_RAMINFO )
+#define USBC_REG_LINKINFO(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_LINKINFO )
+#define USBC_REG_VPLEN(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_VPLEN )
+#define USBC_REG_HSEOF(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_HSEOF )
+#define USBC_REG_FSEOF(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FSEOF )
+#define USBC_REG_LSEOF(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_LSEOF )
+
+#define USBC_REG_FADDR0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_FADDR0 )
+#define USBC_REG_HADDR0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_HADDR0 )
+#define USBC_REG_HPORT0(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_HPORT0 )
+
+#define USBC_REG_TXFADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_TXFADDRx )
+#define USBC_REG_TXHADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_TXHADDRx )
+#define USBC_REG_TXHPORTx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_TXHPORTx )
+#define USBC_REG_RXFADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RXFADDRx )
+#define USBC_REG_RXHADDRx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RXHADDRx )
+#define USBC_REG_RXHPORTx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RXHPORTx )
+
+#define USBC_REG_RPCOUNTx(usbc_base_addr, n) ((usbc_base_addr) + USBC_REG_o_RPCOUNT )
+
+#define USBC_REG_ISCR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_ISCR )
+#define USBC_REG_PHYCTL(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PHYCTL )
+#define USBC_REG_PHYBIST(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PHYBIST )
+#define USBC_REG_PHYTUNE(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PHYTUNE )
+#define USBC_REG_PMU_IRQ(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_PMU_IRQ )
+#define USBC_REG_CSR(usbc_base_addr) ((usbc_base_addr) + USBC_REG_o_CSR)
+//-----------------------------------------------------------------------
+// bit position
+//-----------------------------------------------------------------------
+
+/* USB Power Control for Host only */
+#define USBC_BP_POWER_H_HIGH_SPEED_EN 5
+#define USBC_BP_POWER_H_HIGH_SPEED_FLAG 4
+#define USBC_BP_POWER_H_RESET 3
+#define USBC_BP_POWER_H_RESUME 2
+#define USBC_BP_POWER_H_SUSPEND 1
+#define USBC_BP_POWER_H_SUEPEND_EN 0
+
+/* USB Power Control for device only */
+#define USBC_BP_POWER_D_ISO_UPDATE_EN 7
+#define USBC_BP_POWER_D_SOFT_CONNECT 6
+#define USBC_BP_POWER_D_HIGH_SPEED_EN 5
+#define USBC_BP_POWER_D_HIGH_SPEED_FLAG 4
+#define USBC_BP_POWER_D_RESET_FLAG 3
+#define USBC_BP_POWER_D_RESUME 2
+#define USBC_BP_POWER_D_SUSPEND 1
+#define USBC_BP_POWER_D_ENABLE_SUSPENDM 0
+
+/* interrupt flags for ep0 and the Tx ep1~4 */
+#define USBC_BP_INTTx_FLAG_EP5 5
+#define USBC_BP_INTTx_FLAG_EP4 4
+#define USBC_BP_INTTx_FLAG_EP3 3
+#define USBC_BP_INTTx_FLAG_EP2 2
+#define USBC_BP_INTTx_FLAG_EP1 1
+#define USBC_BP_INTTx_FLAG_EP0 0
+
+/* interrupt flags for Rx ep1~4 */
+#define USBC_BP_INTRx_FLAG_EP5 5
+#define USBC_BP_INTRx_FLAG_EP4 4
+#define USBC_BP_INTRx_FLAG_EP3 3
+#define USBC_BP_INTRx_FLAG_EP2 2
+#define USBC_BP_INTRx_FLAG_EP1 1
+
+/* interrupt enable for Tx ep0~4 */
+#define USBC_BP_INTTxE_EN_EP5 5
+#define USBC_BP_INTTxE_EN_EP4 4
+#define USBC_BP_INTTxE_EN_EP3 3
+#define USBC_BP_INTTxE_EN_EP2 2
+#define USBC_BP_INTTxE_EN_EP1 1
+#define USBC_BP_INTTxE_EN_EP0 0
+
+/* interrupt enable for Rx ep1~4 */
+#define USBC_BP_INTRxE_EN_EP5 5
+#define USBC_BP_INTRxE_EN_EP4 4
+#define USBC_BP_INTRxE_EN_EP3 3
+#define USBC_BP_INTRxE_EN_EP2 2
+#define USBC_BP_INTRxE_EN_EP1 1
+
+/* USB interrupt */
+#define USBC_BP_INTUSB_VBUS_ERROR 7
+#define USBC_BP_INTUSB_SESSION_REQ 6
+#define USBC_BP_INTUSB_DISCONNECT 5
+#define USBC_BP_INTUSB_CONNECT 4
+#define USBC_BP_INTUSB_SOF 3
+#define USBC_BP_INTUSB_RESET 2
+#define USBC_BP_INTUSB_RESUME 1
+#define USBC_BP_INTUSB_SUSPEND 0
+
+/* USB interrupt enable */
+#define USBC_BP_INTUSBE_EN_VBUS_ERROR 7
+#define USBC_BP_INTUSBE_EN_SESSION_REQ 6
+#define USBC_BP_INTUSBE_EN_DISCONNECT 5
+#define USBC_BP_INTUSBE_EN_CONNECT 4
+#define USBC_BP_INTUSBE_EN_SOF 3
+#define USBC_BP_INTUSBE_EN_RESET 2
+#define USBC_BP_INTUSBE_EN_RESUME 1
+#define USBC_BP_INTUSBE_EN_SUSPEND 0
+
+/* Test Mode Control */
+#define USBC_BP_TMCTL_FORCE_HOST 7
+#define USBC_BP_TMCTL_FIFO_ACCESS 6
+#define USBC_BP_TMCTL_FORCE_FS 5
+#define USBC_BP_TMCTL_FORCE_HS 4
+#define USBC_BP_TMCTL_TEST_PACKET 3
+#define USBC_BP_TMCTL_TEST_K 2
+#define USBC_BP_TMCTL_TEST_J 1
+#define USBC_BP_TMCTL_TEST_SE0_NAK 0
+
+/* Tx Max packet */
+#define USBC_BP_TXMAXP_PACKET_COUNT 11
+#define USBC_BP_TXMAXP_MAXIMUM_PAYLOAD 0
+
+/* Control and Status Register for ep0 for Host only */
+#define USBC_BP_CSR0_H_DisPing 11
+#define USBC_BP_CSR0_H_FlushFIFO 8
+#define USBC_BP_CSR0_H_NAK_Timeout 7
+#define USBC_BP_CSR0_H_StatusPkt 6
+#define USBC_BP_CSR0_H_ReqPkt 5
+#define USBC_BP_CSR0_H_Error 4
+#define USBC_BP_CSR0_H_SetupPkt 3
+#define USBC_BP_CSR0_H_RxStall 2
+#define USBC_BP_CSR0_H_TxPkRdy 1
+#define USBC_BP_CSR0_H_RxPkRdy 0
+
+/* Control and Status Register for ep0 for device only */
+#define USBC_BP_CSR0_D_FLUSH_FIFO 8
+#define USBC_BP_CSR0_D_SERVICED_SETUP_END 7
+#define USBC_BP_CSR0_D_SERVICED_RX_PKT_READY 6
+#define USBC_BP_CSR0_D_SEND_STALL 5
+#define USBC_BP_CSR0_D_SETUP_END 4
+#define USBC_BP_CSR0_D_DATA_END 3
+#define USBC_BP_CSR0_D_SENT_STALL 2
+#define USBC_BP_CSR0_D_TX_PKT_READY 1
+#define USBC_BP_CSR0_D_RX_PKT_READY 0
+
+/* Tx ep Control and Status Register for Host only */
+#define USBC_BP_TXCSR_H_AUTOSET 15
+#define USBC_BP_TXCSR_H_RESERVED 14
+#define USBC_BP_TXCSR_H_MODE 13
+#define USBC_BP_TXCSR_H_DMA_REQ_EN 12
+#define USBC_BP_TXCSR_H_FORCE_DATA_TOGGLE 11
+#define USBC_BP_TXCSR_H_DMA_REQ_MODE 10
+#define USBC_BP_TXCSR_H_NAK_TIMEOUT 7
+#define USBC_BP_TXCSR_H_CLEAR_DATA_TOGGLE 6
+#define USBC_BP_TXCSR_H_TX_STALL 5
+#define USBC_BP_TXCSR_H_FLUSH_FIFO 3
+#define USBC_BP_TXCSR_H_ERROR 2
+#define USBC_BP_TXCSR_H_FIFO_NOT_EMPTY 1
+#define USBC_BP_TXCSR_H_TX_READY 0
+
+/* Tx ep Control and Status Register for Device only */
+#define USBC_BP_TXCSR_D_AUTOSET 15
+#define USBC_BP_TXCSR_D_ISO 14
+#define USBC_BP_TXCSR_D_MODE 13
+#define USBC_BP_TXCSR_D_DMA_REQ_EN 12
+#define USBC_BP_TXCSR_D_FORCE_DATA_TOGGLE 11
+#define USBC_BP_TXCSR_D_DMA_REQ_MODE 10
+#define USBC_BP_TXCSR_D_INCOMPLETE 7
+#define USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE 6
+#define USBC_BP_TXCSR_D_SENT_STALL 5
+#define USBC_BP_TXCSR_D_SEND_STALL 4
+#define USBC_BP_TXCSR_D_FLUSH_FIFO 3
+#define USBC_BP_TXCSR_D_UNDER_RUN 2
+#define USBC_BP_TXCSR_D_FIFO_NOT_EMPTY 1
+#define USBC_BP_TXCSR_D_TX_READY 0
+
+/* Rx Max Packet */
+#define USBC_BP_RXMAXP_PACKET_COUNT 11
+#define USBC_BP_RXMAXP_MAXIMUM_PAYLOAD 0
+
+/* Rx ep Control and Status Register for Host only */
+#define USBC_BP_RXCSR_H_AUTO_CLEAR 15
+#define USBC_BP_RXCSR_H_AUTO_REQ 14
+#define USBC_BP_RXCSR_H_DMA_REQ_EN 13
+#define USBC_BP_RXCSR_H_PID_ERROR 12
+#define USBC_BP_RXCSR_H_DMA_REQ_MODE 11
+
+#define USBC_BP_RXCSR_H_INCOMPLETE 8
+#define USBC_BP_RXCSR_H_CLEAR_DATA_TOGGLE 7
+#define USBC_BP_RXCSR_H_RX_STALL 6
+#define USBC_BP_RXCSR_H_REQ_PACKET 5
+#define USBC_BP_RXCSR_H_FLUSH_FIFO 4
+#define USBC_BP_RXCSR_H_NAK_TIMEOUT 3
+#define USBC_BP_RXCSR_H_ERROR 2
+#define USBC_BP_RXCSR_H_FIFO_FULL 1
+#define USBC_BP_RXCSR_H_RX_PKT_READY 0
+
+/* Rx ep Control and Status Register for Device only */
+#define USBC_BP_RXCSR_D_AUTO_CLEAR 15
+#define USBC_BP_RXCSR_D_ISO 14
+#define USBC_BP_RXCSR_D_DMA_REQ_EN 13
+#define USBC_BP_RXCSR_D_DISABLE_NYET 12
+#define USBC_BP_RXCSR_D_DMA_REQ_MODE 11
+
+#define USBC_BP_RXCSR_D_INCOMPLETE 8
+#define USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE 7
+#define USBC_BP_RXCSR_D_SENT_STALL 6
+#define USBC_BP_RXCSR_D_SEND_STALL 5
+#define USBC_BP_RXCSR_D_FLUSH_FIFO 4
+#define USBC_BP_RXCSR_D_DATA_ERROR 3
+#define USBC_BP_RXCSR_D_OVERRUN 2
+#define USBC_BP_RXCSR_D_FIFO_FULL 1
+#define USBC_BP_RXCSR_D_RX_PKT_READY 0
+
+/* Tx Type Register for host only */
+#define USBC_BP_TXTYPE_SPEED 6 //new
+#define USBC_BP_TXTYPE_PROROCOL 4
+#define USBC_BP_TXTYPE_TARGET_EP_NUM 0
+
+/* Rx Type Register for host only */
+#define USBC_BP_RXTYPE_SPEED 6 //new
+#define USBC_BP_RXTYPE_PROROCOL 4
+#define USBC_BP_RXTYPE_TARGET_EP_NUM 0
+
+/* Core Configueation */
+#define USBC_BP_CONFIGDATA_MPRXE 7
+#define USBC_BP_CONFIGDATA_MPTXE 6
+#define USBC_BP_CONFIGDATA_BIGENDIAN 5
+#define USBC_BP_CONFIGDATA_HBRXE 4
+#define USBC_BP_CONFIGDATA_HBTXE 3
+#define USBC_BP_CONFIGDATA_DYNFIFO_SIZING 2
+#define USBC_BP_CONFIGDATA_SOFTCONE 1
+#define USBC_BP_CONFIGDATA_UTMI_DATAWIDTH 0
+
+/* OTG Device Control */
+#define USBC_BP_DEVCTL_B_DEVICE 7
+#define USBC_BP_DEVCTL_FS_DEV 6
+#define USBC_BP_DEVCTL_LS_DEV 5
+
+#define USBC_BP_DEVCTL_VBUS 3
+#define USBC_BP_DEVCTL_HOST_MODE 2
+#define USBC_BP_DEVCTL_HOST_REQ 1
+#define USBC_BP_DEVCTL_SESSION 0
+
+/* Tx EP FIFO size control */
+#define USBC_BP_TXFIFOSZ_DPB 4
+#define USBC_BP_TXFIFOSZ_SZ 0
+
+/* Rx EP FIFO size control */
+#define USBC_BP_RXFIFOSZ_DPB 4
+#define USBC_BP_RXFIFOSZ_SZ 0
+
+/* vendor0 */
+#define USBC_BP_VEND0_DRQ_SEL 1
+#define USBC_BP_VEND0_BUS_SEL 0
+
+/* hub address */
+#define USBC_BP_HADDR_MULTI_TT 7
+
+/* Interface Status and Control */
+#define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30
+#define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29
+#define USBC_BP_ISCR_EXT_ID_STATUS 28
+#define USBC_BP_ISCR_EXT_DM_STATUS 27
+#define USBC_BP_ISCR_EXT_DP_STATUS 26
+#define USBC_BP_ISCR_MERGED_VBUS_STATUS 25
+#define USBC_BP_ISCR_MERGED_ID_STATUS 24
+
+#define USBC_BP_ISCR_ID_PULLUP_EN 17
+#define USBC_BP_ISCR_DPDM_PULLUP_EN 16
+#define USBC_BP_ISCR_FORCE_ID 14
+#define USBC_BP_ISCR_FORCE_VBUS_VALID 12
+#define USBC_BP_ISCR_VBUS_VALID_SRC 10
+
+#define USBC_BP_ISCR_HOSC_EN 7
+#define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6
+#define USBC_BP_ISCR_ID_CHANGE_DETECT 5
+#define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4
+#define USBC_BP_ISCR_IRQ_ENABLE 3
+#define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2
+#define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1
+#define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0
+
+
+#define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10)
+#define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9)
+#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8)
+#define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0)
+//-----------------------------------------------------------------------
+// �Զ���
+//-----------------------------------------------------------------------
+
+/* usb��Դ���� */
+#define USBC_MAX_CTL_NUM 1
+#define USBC_MAX_EP_NUM 3 //ep0~2, ep�ĸ���
+#define USBC_MAX_FIFO_SIZE (2 * 1024)
+
+/* usb OTG mode */
+#define USBC_OTG_HOST 0
+#define USBC_OTG_DEVICE 1
+
+/* usb device type */
+#define USBC_DEVICE_HSDEV 0
+#define USBC_DEVICE_FSDEV 1
+#define USBC_DEVICE_LSDEV 2
+
+/* usb transfer type */
+#define USBC_TS_TYPE_IDLE 0
+#define USBC_TS_TYPE_CTRL 1
+#define USBC_TS_TYPE_ISO 2
+#define USBC_TS_TYPE_INT 3
+#define USBC_TS_TYPE_BULK 4
+
+/* usb transfer mode */
+#define USBC_TS_MODE_UNKOWN 0
+#define USBC_TS_MODE_LS 1
+#define USBC_TS_MODE_FS 2
+#define USBC_TS_MODE_HS 3
+
+/* usb Vbus status */
+#define USBC_VBUS_STATUS_BELOW_SESSIONEND 0
+#define USBC_VBUS_STATUS_ABOVE_SESSIONEND_BELOW_AVALID 1
+#define USBC_VBUS_STATUS_ABOVE_AVALID_BELOW_VBUSVALID 2
+#define USBC_VBUS_STATUS_ABOVE_VBUSVALID 3
+
+/* usb io type */
+#define USBC_IO_TYPE_PIO 0
+#define USBC_IO_TYPE_DMA 1
+
+/* usb ep type */
+#define USBC_EP_TYPE_IDLE 0
+#define USBC_EP_TYPE_EP0 1
+#define USBC_EP_TYPE_TX 2
+#define USBC_EP_TYPE_RX 3
+
+/* usb id type */
+#define USBC_ID_TYPE_DISABLE 0
+#define USBC_ID_TYPE_HOST 1
+#define USBC_ID_TYPE_DEVICE 2
+
+/* usb vbus valid type */
+#define USBC_VBUS_TYPE_DISABLE 0
+#define USBC_VBUS_TYPE_LOW 1
+#define USBC_VBUS_TYPE_HIGH 2
+
+/* usb a valid source */
+#define USBC_A_VALID_SOURCE_UTMI_AVALID 0
+#define USBC_A_VALID_SOURCE_UTMI_VBUS 1
+
+/* usb device switch */
+#define USBC_DEVICE_SWITCH_OFF 0
+#define USBC_DEVICE_SWITCH_ON 1
+
+/* usb fifo config mode */
+#define USBC_FIFO_MODE_4K 0
+#define USBC_FIFO_MODE_8K 1
+
+/*
+ **************************************************
+ * usb interrupt mask
+ *
+ **************************************************
+ */
+
+/* interrupt flags for ep0 and the Tx ep1~4 */
+#define USBC_INTTx_FLAG_EP5 (1 << USBC_BP_INTTx_FLAG_EP5)
+#define USBC_INTTx_FLAG_EP4 (1 << USBC_BP_INTTx_FLAG_EP4)
+#define USBC_INTTx_FLAG_EP3 (1 << USBC_BP_INTTx_FLAG_EP3)
+#define USBC_INTTx_FLAG_EP2 (1 << USBC_BP_INTTx_FLAG_EP2)
+#define USBC_INTTx_FLAG_EP1 (1 << USBC_BP_INTTx_FLAG_EP1)
+#define USBC_INTTx_FLAG_EP0 (1 << USBC_BP_INTTx_FLAG_EP0)
+
+/* interrupt flags for Rx ep1~4 */
+#define USBC_INTRx_FLAG_EP5 (1 << USBC_BP_INTRx_FLAG_EP5)
+#define USBC_INTRx_FLAG_EP4 (1 << USBC_BP_INTRx_FLAG_EP4)
+#define USBC_INTRx_FLAG_EP3 (1 << USBC_BP_INTRx_FLAG_EP3)
+#define USBC_INTRx_FLAG_EP2 (1 << USBC_BP_INTRx_FLAG_EP2)
+#define USBC_INTRx_FLAG_EP1 (1 << USBC_BP_INTRx_FLAG_EP1)
+
+/* USB interrupt */
+#define USBC_INTUSB_VBUS_ERROR (1 << USBC_BP_INTUSB_VBUS_ERROR)
+#define USBC_INTUSB_SESSION_REQ (1 << USBC_BP_INTUSB_SESSION_REQ)
+#define USBC_INTUSB_DISCONNECT (1 << USBC_BP_INTUSB_DISCONNECT)
+#define USBC_INTUSB_CONNECT (1 << USBC_BP_INTUSB_CONNECT)
+#define USBC_INTUSB_SOF (1 << USBC_BP_INTUSB_SOF)
+#define USBC_INTUSB_RESET (1 << USBC_BP_INTUSB_RESET)
+#define USBC_INTUSB_RESUME (1 << USBC_BP_INTUSB_RESUME)
+#define USBC_INTUSB_SUSPEND (1 << USBC_BP_INTUSB_SUSPEND)
+
+#define USB_CSRL0_NAKTO 0x00000080 // NAK Timeout
+#define USB_CSRL0_SETENDC 0x00000080 // Setup End Clear
+#define USB_CSRL0_STATUS 0x00000040 // STATUS Packet
+#define USB_CSRL0_RXRDYC 0x00000040 // RXRDY Clear
+#define USB_CSRL0_REQPKT 0x00000020 // Request Packet
+#define USB_CSRL0_STALL 0x00000020 // Send Stall
+#define USB_CSRL0_SETEND 0x00000010 // Setup End
+#define USB_CSRL0_ERROR 0x00000010 // Error
+#define USB_CSRL0_DATAEND 0x00000008 // Data End
+#define USB_CSRL0_SETUP 0x00000008 // Setup Packet
+#define USB_CSRL0_STALLED 0x00000004 // Endpoint Stalled
+#define USB_CSRL0_TXRDY 0x00000002 // Transmit Packet Ready
+#define USB_CSRL0_RXRDY 0x00000001 // Receive Packet Ready
+
+#define USB_RXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support
+#define USB_RXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size
+
+#define USB_TXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support
+#define USB_TXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index bb21b3dcd..f5ecdfe4f 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -28,23 +28,26 @@
*/
#include "tusb_option.h"
-#include "device/dcd_attr.h"
-#if TUSB_OPT_DEVICE_ENABLED && \
- ( defined(DCD_ATTR_DWC2_STM32) || \
- TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_GD32VF103) || \
- TU_CHECK_MCU(OPT_MCU_EFM32GG, OPT_MCU_BCM2711, OPT_MCU_XMC4000) )
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2)
#include "device/dcd.h"
#include "dwc2_type.h"
-#if defined(DCD_ATTR_DWC2_STM32)
+// Following symbols must be defined by port header
+// - _dwc2_controller[]: array of controllers
+// - DWC2_EP_MAX: largest EP counts of all controllers
+// - dwc2_phy_init/dwc2_phy_update: phy init called before and after core reset
+// - dwc2_dcd_int_enable/dwc2_dcd_int_disable
+// - dwc2_remote_wakeup_delay
+
+#if defined(TUP_USBIP_DWC2_STM32)
#include "dwc2_stm32.h"
#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
#include "dwc2_esp32.h"
#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
#include "dwc2_gd32.h"
-#elif TU_CHECK_MCU(OPT_MCU_BCM2711)
+#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
#include "dwc2_bcm.h"
#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
#include "dwc2_efm32.h"
@@ -59,7 +62,7 @@
//--------------------------------------------------------------------+
// DWC2 registers
-#define DWC2_REG(_port) ((dwc2_regs_t*) DWC2_REG_BASE)
+#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base)
// Debug level for DWC2
#define DWC2_DEBUG 2
@@ -76,7 +79,6 @@
#define dcache_clean_invalidate(_addr, _size)
#endif
-
static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2];
typedef struct {
@@ -97,44 +99,47 @@ static uint16_t ep0_pending[2]; // Index determines direction
static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs)
static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size)
+// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
+static bool _sof_en;
+
// Calculate the RX FIFO size according to recommendations from reference manual
-static inline uint16_t calc_rx_ff_size(uint16_t ep_size)
+static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count)
{
- return 15 + 2*(ep_size/4) + 2*DWC2_EP_MAX;
+ return 15 + 2*(max_ep_size/4) + 2*ep_count;
}
static void update_grxfsiz(uint8_t rhport)
{
- (void) rhport;
-
- dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
// Determine largest EP size for RX FIFO
uint16_t max_epsize = 0;
- for (uint8_t epnum = 0; epnum < DWC2_EP_MAX; epnum++)
+ for (uint8_t epnum = 0; epnum < ep_count; epnum++)
{
max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size);
}
// Update size of RX FIFO
- dwc2->grxfsiz = calc_rx_ff_size(max_epsize);
+ dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count);
}
-// Setup the control endpoint 0.
+// Start of Bus Reset
static void bus_reset(uint8_t rhport)
{
- (void) rhport;
-
- dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
tu_memclr(xfer_status, sizeof(xfer_status));
_out_ep_closed = false;
+ _sof_en = false;
+
// clear device address
dwc2->dcfg &= ~DCFG_DAD_Msk;
// 1. NAK for all OUT endpoints
- for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ )
+ for ( uint8_t n = 0; n < ep_count; n++ )
{
dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
}
@@ -184,22 +189,24 @@ static void bus_reset(uint8_t rhport)
// - 2 for each used OUT endpoint
//
// Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum
- // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x DWC2_EP_MAX = 47 + 2 x DWC2_EP_MAX
- // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x DWC2_EP_MAX = 271 + 2 x DWC2_EP_MAX
+ // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x ep_count = 47 + 2 x ep_count
+ // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x ep_count = 271 + 2 x ep_count
//
// NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge
- // of the overall picture yet. We will use the worst scenario: largest possible + DWC2_EP_MAX
+ // of the overall picture yet. We will use the worst scenario: largest possible + ep_count
//
// For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO
// are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to
// overwrite this.
- dwc2->grxfsiz = calc_rx_ff_size(TUD_OPT_HIGH_SPEED ? 512 : 64);
+ // EP0 out max is 64
+ dwc2->grxfsiz = calc_grxfsiz(64, ep_count);
+ // Setup the control endpoint 0
_allocated_fifo_words_tx = 16;
// Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
- dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
+ dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx);
// Fixed control EP0 size to 64 bytes
dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
@@ -362,7 +369,11 @@ static void reset_core(dwc2_regs_t * dwc2)
static bool phy_hs_supported(dwc2_regs_t * dwc2)
{
// note: esp32 incorrect report its hs_phy_type as utmi
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ return false;
+#else
return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE;
+#endif
}
static void phy_fs_init(dwc2_regs_t * dwc2)
@@ -461,6 +472,7 @@ static bool check_dwc2(dwc2_regs_t * dwc2)
#endif
// For some reasons: GD32VF103 snpsid and all hwcfg register are always zero (skip it)
+ (void) dwc2;
#if !TU_CHECK_MCU(OPT_MCU_GD32VF103)
uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK;
TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID);
@@ -592,6 +604,24 @@ void dcd_disconnect(uint8_t rhport)
dwc2->dctl |= DCTL_SDIS;
}
+// Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose!
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+
+ _sof_en = en;
+
+ if (en)
+ {
+ dwc2->gintsts = GINTSTS_SOF;
+ dwc2->gintmsk |= GINTMSK_SOFM;
+ }
+ else
+ {
+ dwc2->gintmsk &= ~GINTMSK_SOFM;
+ }
+}
/*------------------------------------------------------------------*/
/* DCD Endpoint port
@@ -601,12 +631,13 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
(void) rhport;
- dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
- TU_ASSERT(epnum < DWC2_EP_MAX);
+ TU_ASSERT(epnum < ep_count);
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
xfer->max_size = tu_edpt_packet_size(desc_edpt);
@@ -617,12 +648,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
if(dir == TUSB_DIR_OUT)
{
// Calculate required size of RX FIFO
- uint16_t const sz = calc_rx_ff_size(4*fifo_size);
+ uint16_t const sz = calc_grxfsiz(4*fifo_size, ep_count);
// If size_rx needs to be extended check if possible and if so enlarge it
if (dwc2->grxfsiz < sz)
{
- TU_ASSERT(sz + _allocated_fifo_words_tx <= DWC2_EP_FIFO_SIZE/4);
+ TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size/4);
// Enlarge RX FIFO
dwc2->grxfsiz = sz;
@@ -659,15 +690,15 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
// - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
// Check if free space is available
- TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= DWC2_EP_FIFO_SIZE/4);
+ TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size/4);
_allocated_fifo_words_tx += fifo_size;
- TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %u", fifo_size*4, DWC2_EP_FIFO_SIZE-_allocated_fifo_words_tx*4);
+ TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size*4, _dwc2_controller[rhport].ep_fifo_size-_allocated_fifo_words_tx*4);
// DIEPTXF starts at FIFO #1.
// Both TXFD and TXSA are in unit of 32-bit words.
- dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx);
+ dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx);
dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) |
(epnum << DIEPCTL_TXFNUM_Pos) |
@@ -684,14 +715,13 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
// Close all non-control endpoints, cancel all pending transfers if any.
void dcd_edpt_close_all (uint8_t rhport)
{
- (void) rhport;
-
- dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
// Disable non-control interrupt
dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos);
- for(uint8_t n = 1; n < DWC2_EP_MAX; n++)
+ for(uint8_t n = 1; n < ep_count; n++)
{
// disable OUT endpoint
dwc2->epout[n].doepctl = 0;
@@ -800,8 +830,7 @@ static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall)
}
// Flush the FIFO, and wait until we have confirmed it cleared.
- dwc2->grstctl |= (epnum << GRSTCTL_TXFNUM_Pos);
- dwc2->grstctl |= GRSTCTL_TXFFLSH;
+ dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH);
while ( (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0 ) {}
}
else
@@ -853,8 +882,9 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos;
uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos;
+
// For now only the last opened endpoint can be closed without fuss.
- TU_ASSERT(fifo_start == DWC2_EP_FIFO_SIZE/4 - _allocated_fifo_words_tx,);
+ TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx,);
_allocated_fifo_words_tx -= fifo_size;
}
else
@@ -1057,11 +1087,12 @@ static void handle_rxflvl_irq(uint8_t rhport)
static void handle_epout_irq (uint8_t rhport)
{
- dwc2_regs_t *dwc2 = DWC2_REG(rhport);
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
// DAINT for a given EP clears when DOEPINTx is cleared.
// OEPINT will be cleared when DAINT's out bits are cleared.
- for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ )
+ for ( uint8_t n = 0; n < ep_count; n++ )
{
if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) )
{
@@ -1108,12 +1139,13 @@ static void handle_epout_irq (uint8_t rhport)
static void handle_epin_irq (uint8_t rhport)
{
- dwc2_regs_t *dwc2 = DWC2_REG(rhport);
- dwc2_epin_t* epin = dwc2->epin;
+ dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+ dwc2_epin_t* epin = dwc2->epin;
// DAINT for a given EP clears when DIEPINTx is cleared.
// IEPINT will be cleared when DAINT's out bits are cleared.
- for ( uint8_t n = 0; n < DWC2_EP_MAX; n++ )
+ for ( uint8_t n = 0; n < ep_count; n++ )
{
if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) )
{
@@ -1255,8 +1287,16 @@ void dcd_int_handler(uint8_t rhport)
{
dwc2->gotgint = GINTSTS_SOF;
- // Disable SOF interrupt since currently only used for remote wakeup detection
- dwc2->gintmsk &= ~GINTMSK_SOFM;
+ if (_sof_en)
+ {
+ uint32_t frame = (dwc2->dsts & (DSTS_FNSOF)) >> 8;
+ dcd_event_sof(rhport, frame, true);
+ }
+ else
+ {
+ // Disable SOF interrupt if SOF was not explicitly enabled. SOF was used for remote wakeup detection
+ dwc2->gintmsk &= ~GINTMSK_SOFM;
+ }
dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
}
diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h
index 353bc21ee..732d96ae0 100644
--- a/src/portable/synopsys/dwc2/dwc2_bcm.h
+++ b/src/portable/synopsys/dwc2/dwc2_bcm.h
@@ -31,12 +31,16 @@
extern "C" {
#endif
+#include "broadcom/defines.h"
#include "broadcom/interrupts.h"
#include "broadcom/caches.h"
-#define DWC2_REG_BASE USB_OTG_GLOBAL_BASE
#define DWC2_EP_MAX 8
-#define DWC2_EP_FIFO_SIZE 4096
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = USB_OTG_GLOBAL_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 4096 }
+};
#define dcache_clean(_addr, _size) data_clean(_addr, _size)
#define dcache_invalidate(_addr, _size) data_invalidate(_addr, _size)
@@ -45,17 +49,13 @@
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- BP_EnableIRQ(USB_IRQn);
- __asm__ volatile("isb"); // needed if TIMER1 IRQ is not enabled !?
+ BP_EnableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- BP_DisableIRQ(USB_IRQn);
- __asm__ volatile("isb"); // needed if TIMER1 IRQ is not enabled !?
+ BP_DisableIRQ(_dwc2_controller[rhport].irqnum);
}
static inline void dwc2_remote_wakeup_delay(void)
diff --git a/src/portable/synopsys/dwc2/dwc2_efm32.h b/src/portable/synopsys/dwc2/dwc2_efm32.h
index ee4c3c715..0e3570cbb 100644
--- a/src/portable/synopsys/dwc2/dwc2_efm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_efm32.h
@@ -37,20 +37,22 @@
// EFM32 has custom control register before DWC registers
#define DWC2_REG_BASE (USB_BASE + offsetof(USB_TypeDef, GOTGCTL))
#define DWC2_EP_MAX 7
-#define DWC2_EP_FIFO_SIZE 2048
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = DWC2_REG_BASE, .irqnum = USB_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 }
+};
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- NVIC_EnableIRQ(USB_IRQn);
+ NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- NVIC_DisableIRQ(USB_IRQn);
+ NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum);
}
static inline void dwc2_remote_wakeup_delay(void)
diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
index 78da277d5..c50dd66b8 100644
--- a/src/portable/synopsys/dwc2/dwc2_esp32.h
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -37,10 +37,12 @@
//#include "soc/usb_periph.h"
#define DWC2_REG_BASE 0x60080000UL
-#define DWC2_EP_MAX 5 // USB_OUT_EP_NUM
-#define DWC2_EP_FIFO_SIZE 1024
+#define DWC2_EP_MAX 6 // USB_OUT_EP_NUM. TODO ESP32Sx only has 5 tx fifo (5 endpoint IN)
-// #define EP_FIFO_NUM 5
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1024 }
+};
static intr_handle_t usb_ih;
diff --git a/src/portable/synopsys/dwc2/dwc2_gd32.h b/src/portable/synopsys/dwc2/dwc2_gd32.h
index f8fa01ee0..0375fffe4 100644
--- a/src/portable/synopsys/dwc2/dwc2_gd32.h
+++ b/src/portable/synopsys/dwc2/dwc2_gd32.h
@@ -34,8 +34,11 @@
#define DWC2_REG_BASE 0x50000000UL
#define DWC2_EP_MAX 4
-#define DWC2_EP_FIFO_SIZE 1280
-#define RHPORT_IRQn 86
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ { .reg_base = DWC2_REG_BASE, .irqnum = 86, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 1280 }
+};
extern uint32_t SystemCoreClock;
@@ -57,15 +60,13 @@ static inline void __eclic_disable_interrupt (uint32_t irq){
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- __eclic_enable_interrupt(RHPORT_IRQn);
+ __eclic_enable_interrupt(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- __eclic_disable_interrupt(RHPORT_IRQn);
+ __eclic_disable_interrupt(_dwc2_controller[rhport].irqnum);
}
static inline void dwc2_remote_wakeup_delay(void)
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
index 469045ac4..ea786362e 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -43,10 +43,14 @@
#define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
#define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
+ #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS
+ #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE
+
#elif CFG_TUSB_MCU == OPT_MCU_STM32F4
#include "stm32f4xx.h"
#define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
#define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
+
#define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS
#define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE
@@ -54,13 +58,22 @@
#include "stm32h7xx.h"
#define EP_MAX_FS 9
#define EP_FIFO_SIZE_FS 4096
+
#define EP_MAX_HS 9
#define EP_FIFO_SIZE_HS 4096
+ // NOTE: H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx
+ // USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined
+ #if (! defined USB2_OTG_FS)
+ #define USB_OTG_FS_PERIPH_BASE USB1_OTG_HS_PERIPH_BASE
+ #define OTG_FS_IRQn OTG_HS_IRQn
+ #endif
+
#elif CFG_TUSB_MCU == OPT_MCU_STM32F7
#include "stm32f7xx.h"
#define EP_MAX_FS 6
#define EP_FIFO_SIZE_FS 1280
+
#define EP_MAX_HS 9
#define EP_FIFO_SIZE_HS 4096
@@ -69,39 +82,53 @@
#define EP_MAX_FS 6
#define EP_FIFO_SIZE_FS 1280
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #include "stm32u5xx.h"
+ #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE
+ #define EP_MAX_FS 6
+ #define EP_FIFO_SIZE_FS 1280
+
#else
#error "Unsupported MCUs"
#endif
-// On STM32 we associate Port0 to OTG_FS, and Port1 to OTG_HS
-#if TUD_OPT_RHPORT == 0
- #define DWC2_REG_BASE USB_OTG_FS_PERIPH_BASE
- #define DWC2_EP_MAX EP_MAX_FS
- #define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_FS
- #define RHPORT_IRQn OTG_FS_IRQn
-
+// OTG HS always has higher number of endpoints than FS
+#ifdef USB_OTG_HS_PERIPH_BASE
+ #define DWC2_EP_MAX EP_MAX_HS
#else
- #define DWC2_REG_BASE USB_OTG_HS_PERIPH_BASE
- #define DWC2_EP_MAX EP_MAX_HS
- #define DWC2_EP_FIFO_SIZE EP_FIFO_SIZE_HS
- #define RHPORT_IRQn OTG_HS_IRQn
+ #define DWC2_EP_MAX EP_MAX_FS
+#endif
+// On STM32 for consistency we associate
+// - Port0 to OTG_FS, and Port1 to OTG_HS
+static const dwc2_controller_t _dwc2_controller[] =
+{
+#ifdef USB_OTG_FS_PERIPH_BASE
+ { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS },
+#endif
+
+#ifdef USB_OTG_HS_PERIPH_BASE
+ { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS },
#endif
+};
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
-extern uint32_t SystemCoreClock;
+// SystemCoreClock is alrady included by family header
+// extern uint32_t SystemCoreClock;
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- NVIC_EnableIRQ(RHPORT_IRQn);
+ NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- NVIC_DisableIRQ(RHPORT_IRQn);
+ NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index dbef20314..3fc979337 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -19,6 +19,19 @@
#include "stdint.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// Controller
+typedef struct
+{
+ uintptr_t reg_base;
+ uint32_t irqnum;
+ uint8_t ep_count;
+ uint32_t ep_fifo_size;
+}dwc2_controller_t;
+
/* DWC OTG HW Release versions */
#define DWC2_CORE_REV_2_71a 0x4f54271a
#define DWC2_CORE_REV_2_72a 0x4f54272a
@@ -40,10 +53,6 @@
#define DWC2_FS_IOT_ID 0x55310000
#define DWC2_HS_IOT_ID 0x55320000
-#ifdef __cplusplus
- extern "C" {
-#endif
-
#if 0
// HS PHY
typedef struct
@@ -986,16 +995,16 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
/******************** Bit definition for OTG register ********************/
#define GNPTXFSIZ_NPTXFSA_Pos (0U)
-#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << NPTXFSA_Pos) // 0x0000FFFF */
+#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF */
#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address */
#define GNPTXFSIZ_NPTXFD_Pos (16U)
-#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << NPTXFD_Pos) // 0xFFFF0000 */
+#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000 */
#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth */
#define DIEPTXF0_TX0FSA_Pos (0U)
-#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << TX0FSA_Pos) // 0x0000FFFF */
+#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF */
#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address */
#define DIEPTXF0_TX0FD_Pos (16U)
-#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << TX0FD_Pos) // 0xFFFF0000 */
+#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000 */
#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth */
/******************** Bit definition for DVBUSPULSE register ********************/
diff --git a/src/portable/synopsys/dwc2/dwc2_xmc.h b/src/portable/synopsys/dwc2/dwc2_xmc.h
index 4e6bebb01..63419abf7 100644
--- a/src/portable/synopsys/dwc2/dwc2_xmc.h
+++ b/src/portable/synopsys/dwc2/dwc2_xmc.h
@@ -34,23 +34,24 @@
#include "xmc_device.h"
-// XMC has custom control register before DWC registers
-#define DWC2_REG_BASE USB0_BASE
#define DWC2_EP_MAX 7
-#define DWC2_EP_FIFO_SIZE 2048
+
+static const dwc2_controller_t _dwc2_controller[] =
+{
+ // Note: XMC has some custom control registers before DWC registers
+ { .reg_base = USB0_BASE, .irqnum = USB0_0_IRQn, .ep_count = DWC2_EP_MAX, .ep_fifo_size = 2048 }
+};
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_enable(uint8_t rhport)
{
- (void) rhport;
- NVIC_EnableIRQ(USB0_0_IRQn);
+ NVIC_EnableIRQ(_dwc2_controller[rhport].irqnum);
}
TU_ATTR_ALWAYS_INLINE
static inline void dwc2_dcd_int_disable (uint8_t rhport)
{
- (void) rhport;
- NVIC_DisableIRQ(USB0_0_IRQn);
+ NVIC_DisableIRQ(_dwc2_controller[rhport].irqnum);
}
static inline void dwc2_remote_wakeup_delay(void)
diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c
index 977369300..26b5dce9d 100644
--- a/src/portable/template/dcd_template.c
+++ b/src/portable/template/dcd_template.c
@@ -82,6 +82,14 @@ void dcd_disconnect(uint8_t rhport)
(void) rhport;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
index 3b91f2798..b4dfda575 100644
--- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MSP430x5xx )
+#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MSP430x5xx )
#include "msp430.h"
#include "device/dcd.h"
@@ -222,6 +222,14 @@ void dcd_disconnect(uint8_t rhport)
dcd_int_enable(rhport);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -623,7 +631,18 @@ void dcd_int_handler(uint8_t rhport)
handle_setup_packet();
}
- uint16_t curr_vector = USBVECINT;
+ // Workaround possible bug in MSP430 GCC 9.3.0 where volatile variable
+ // USBVECINT is read from twice when only once is intended. The second
+ // (garbage) read seems to be triggered by certain switch statement
+ // configurations.
+ uint16_t curr_vector;
+ #if __GNUC__ > 9 || (__GNUC__ == 9 && __GNUC_MINOR__ > 2)
+ asm volatile ("mov %1, %0"
+ : "=r" (curr_vector)
+ : "m" (USBVECINT));
+ #else
+ curr_vector = USBVECINT;
+ #endif
switch(curr_vector)
{
diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c
index 837d0c0ce..e368b5f39 100644
--- a/src/portable/valentyusb/eptri/dcd_eptri.c
+++ b/src/portable/valentyusb/eptri/dcd_eptri.c
@@ -24,6 +24,10 @@
* This file is part of the TinyUSB stack.
*/
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
+
#ifndef DEBUG
#define DEBUG 0
#endif
@@ -32,10 +36,6 @@
#define LOG_USB 0
#endif
-#include "tusb_option.h"
-
-#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
-
#include "device/dcd.h"
#include "dcd_eptri.h"
#include "csr.h"
@@ -401,6 +401,13 @@ void dcd_disconnect(uint8_t rhport)
usb_pullup_out_write(0);
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
//--------------------------------------------------------------------+
// DCD Endpoint Port
diff --git a/src/tusb.c b/src/tusb.c
index 9583f509d..c3787ff8f 100644
--- a/src/tusb.c
+++ b/src/tusb.c
@@ -26,23 +26,26 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED || TUSB_OPT_DEVICE_ENABLED
+#if CFG_TUH_ENABLED || CFG_TUD_ENABLED
#include "tusb.h"
+#include "common/tusb_private.h"
// TODO clean up
-#if TUSB_OPT_DEVICE_ENABLED
+#if CFG_TUD_ENABLED
#include "device/usbd_pvt.h"
#endif
bool tusb_init(void)
{
-#if TUSB_OPT_DEVICE_ENABLED
- TU_ASSERT ( tud_init(TUD_OPT_RHPORT) ); // init device stack
+#if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT)
+ // init device stack CFG_TUSB_RHPORTx_MODE must be defined
+ TU_ASSERT ( tud_init(TUD_OPT_RHPORT) );
#endif
-#if TUSB_OPT_HOST_ENABLED
- TU_ASSERT( tuh_init(TUH_OPT_RHPORT) ); // init host stack
+#if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT)
+ // init host stack CFG_TUSB_RHPORTx_MODE must be defined
+ TU_ASSERT( tuh_init(TUH_OPT_RHPORT) );
#endif
return true;
@@ -52,11 +55,11 @@ bool tusb_inited(void)
{
bool ret = false;
-#if TUSB_OPT_DEVICE_ENABLED
+#if CFG_TUD_ENABLED
ret = ret || tud_inited();
#endif
-#if TUSB_OPT_HOST_ENABLED
+#if CFG_TUH_ENABLED
ret = ret || tuh_inited();
#endif
@@ -67,6 +70,52 @@ bool tusb_inited(void)
// Internal Helper for both Host and Device stack
//--------------------------------------------------------------------+
+bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex)
+{
+ (void) mutex;
+
+#if TUSB_OPT_MUTEX
+ // pre-check to help reducing mutex lock
+ TU_VERIFY((ep_state->busy == 0) && (ep_state->claimed == 0));
+ osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+#endif
+
+ // can only claim the endpoint if it is not busy and not claimed yet.
+ bool const available = (ep_state->busy == 0) && (ep_state->claimed == 0);
+ if (available)
+ {
+ ep_state->claimed = 1;
+ }
+
+#if TUSB_OPT_MUTEX
+ osal_mutex_unlock(mutex);
+#endif
+
+ return available;
+}
+
+bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex)
+{
+ (void) mutex;
+
+#if TUSB_OPT_MUTEX
+ osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+#endif
+
+ // can only release the endpoint if it is claimed and not busy
+ bool const ret = (ep_state->claimed == 1) && (ep_state->busy == 0);
+ if (ret)
+ {
+ ep_state->claimed = 0;
+ }
+
+#if TUSB_OPT_MUTEX
+ osal_mutex_unlock(mutex);
+#endif
+
+ return ret;
+}
+
bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed)
{
uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep);
@@ -161,7 +210,27 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf,
#if CFG_TUSB_DEBUG
#include <ctype.h>
-char const* const tusb_strerr[TUSB_ERROR_COUNT] = { ERROR_TABLE(ERROR_STRING) };
+#if CFG_TUSB_DEBUG >= 2
+
+char const* const tu_str_speed[] = { "Full", "Low", "High" };
+char const* const tu_str_std_request[] =
+{
+ "Get Status" ,
+ "Clear Feature" ,
+ "Reserved" ,
+ "Set Feature" ,
+ "Reserved" ,
+ "Set Address" ,
+ "Get Descriptor" ,
+ "Set Descriptor" ,
+ "Get Configuration" ,
+ "Set Configuration" ,
+ "Get Interface" ,
+ "Set Interface" ,
+ "Synch Frame"
+};
+
+#endif
static void dump_str_line(uint8_t const* buf, uint16_t count)
{
@@ -226,7 +295,7 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent)
// fill up last row to 16 for printing ascii
const uint32_t remain = count%16;
- uint8_t nback = (remain ? remain : 16);
+ uint8_t nback = (uint8_t)(remain ? remain : 16);
if ( remain )
{
diff --git a/src/tusb.h b/src/tusb.h
index 0d29e106c..b776d7d01 100644
--- a/src/tusb.h
+++ b/src/tusb.h
@@ -38,8 +38,10 @@
#include "osal/osal.h"
#include "common/tusb_fifo.h"
+#include "class/hid/hid.h"
+
//------------- HOST -------------//
-#if TUSB_OPT_HOST_ENABLED
+#if CFG_TUH_ENABLED
#include "host/usbh.h"
#if CFG_TUH_HID
@@ -61,7 +63,7 @@
#endif
//------------- DEVICE -------------//
-#if TUSB_OPT_DEVICE_ENABLED
+#if CFG_TUD_ENABLED
#include "device/usbd.h"
#if CFG_TUD_HID
@@ -117,8 +119,6 @@
//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
-/** \ingroup group_application_api
- * @{ */
// Initialize device/host stack
// Note: when using with RTOS, this should be called after scheduler/kernel is started.
@@ -131,8 +131,6 @@ bool tusb_inited(void);
// TODO
// bool tusb_teardown(void);
-/** @} */
-
#ifdef __cplusplus
}
#endif
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 2edd310fa..f95ae6273 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -27,10 +27,13 @@
#ifndef _TUSB_OPTION_H_
#define _TUSB_OPTION_H_
+// To avoid GCC compiler warnings when -pedantic option is used (strict ISO C)
+typedef int make_iso_compilers_happy;
+
#include "common/tusb_compiler.h"
#define TUSB_VERSION_MAJOR 0
-#define TUSB_VERSION_MINOR 12
+#define TUSB_VERSION_MINOR 14
#define TUSB_VERSION_REVISION 0
#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
@@ -80,6 +83,8 @@
#define OPT_MCU_STM32L4 309 ///< ST L4
#define OPT_MCU_STM32G0 310 ///< ST G0
#define OPT_MCU_STM32G4 311 ///< ST G4
+#define OPT_MCU_STM32WB 312 ///< ST WB
+#define OPT_MCU_STM32U5 313 ///< ST U5
// Sony
#define OPT_MCU_CXD56 400 ///< SONY CXD56
@@ -94,7 +99,9 @@
#define OPT_MCU_VALENTYUSB_EPTRI 600 ///< Fomu eptri config
// NXP iMX RT
-#define OPT_MCU_MIMXRT10XX 700 ///< NXP iMX RT10xx
+#define OPT_MCU_MIMXRT 700 ///< NXP iMX RT Series
+#define OPT_MCU_MIMXRT10XX OPT_MCU_MIMXRT ///< RT10xx
+#define OPT_MCU_MIMXRT11XX OPT_MCU_MIMXRT ///< RT11xx
// Nuvoton
#define OPT_MCU_NUC121 800
@@ -132,10 +139,27 @@
// Broadcom
#define OPT_MCU_BCM2711 1700 ///< Broadcom BCM2711
+#define OPT_MCU_BCM2835 1701 ///< Broadcom BCM2835
+#define OPT_MCU_BCM2837 1702 ///< Broadcom BCM2837
// Infineon
#define OPT_MCU_XMC4000 1800 ///< Infineon XMC4000
+// PIC
+#define OPT_MCU_PIC32MZ 1900 ///< MicroChip PIC32MZ family
+#define OPT_MCU_PIC32MM 1901 ///< MicroChip PIC32MM family
+#define OPT_MCU_PIC32MX 1902 ///< MicroChip PIC32MX family
+#define OPT_MCU_PIC32MK 1903 ///< MicroChip PIC32MK family
+#define OPT_MCU_PIC24 1910 ///< MicroChip PIC24 family
+#define OPT_MCU_DSPIC33 1911 ///< MicroChip DSPIC33 family
+
+// BridgeTek
+#define OPT_MCU_FT90X 2000 ///< BridgeTek FT90x
+#define OPT_MCU_FT93X 2001 ///< BridgeTek FT93x
+
+// Allwinner
+#define OPT_MCU_F1C100S 2100 ///< Allwinner F1C100s family
+
// Helper to check if configured MCU is one of listed
// Apply _TU_CHECK_MCU with || as separator to list of input
#define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m)
@@ -151,6 +175,7 @@
#define OPT_OS_CUSTOM 4 ///< Custom OS is implemented by application
#define OPT_OS_PICO 5 ///< Raspberry Pi Pico SDK
#define OPT_OS_RTTHREAD 6 ///< RT-Thread
+#define OPT_OS_RTX4 7 ///< Keil RTX 4
// Allow to use command line to change the config name/location
#ifdef CFG_TUSB_CONFIG_FILE
@@ -159,53 +184,95 @@
#include "tusb_config.h"
#endif
+#include "common/tusb_mcu.h"
+
//--------------------------------------------------------------------
// RootHub Mode Configuration
// CFG_TUSB_RHPORTx_MODE contains operation mode and speed for that port
//--------------------------------------------------------------------
-// Lower 4-bit is operational mode
-#define OPT_MODE_NONE 0x00 ///< Disabled
-#define OPT_MODE_DEVICE 0x01 ///< Device Mode
-#define OPT_MODE_HOST 0x02 ///< Host Mode
+// Low byte is operational mode
+#define OPT_MODE_NONE 0x0000 ///< Disabled
+#define OPT_MODE_DEVICE 0x0001 ///< Device Mode
+#define OPT_MODE_HOST 0x0002 ///< Host Mode
-// Higher 4-bit is max operational speed (corresponding to tusb_speed_t)
-#define OPT_MODE_FULL_SPEED 0x00 ///< Max Full Speed
-#define OPT_MODE_LOW_SPEED 0x10 ///< Max Low Speed
-#define OPT_MODE_HIGH_SPEED 0x20 ///< Max High Speed
+// High byte is max operational speed (corresponding to tusb_speed_t)
+#define OPT_MODE_DEFAULT_SPEED 0x0000 ///< Default (max) speed supported by MCU
+#define OPT_MODE_LOW_SPEED 0x0100 ///< Low Speed
+#define OPT_MODE_FULL_SPEED 0x0200 ///< Full Speed
+#define OPT_MODE_HIGH_SPEED 0x0400 ///< High Speed
+#define OPT_MODE_SPEED_MASK 0xff00
+//------------- Roothub as Device -------------//
+
+#if defined(CFG_TUSB_RHPORT0_MODE) && ((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_DEVICE)
+ #define TUD_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE)
+ #define TUD_OPT_RHPORT 0
+#elif defined(CFG_TUSB_RHPORT1_MODE) && ((CFG_TUSB_RHPORT1_MODE) & OPT_MODE_DEVICE)
+ #define TUD_RHPORT_MODE (CFG_TUSB_RHPORT1_MODE)
+ #define TUD_OPT_RHPORT 1
+#else
+ #define TUD_RHPORT_MODE OPT_MODE_NONE
+#endif
+
+#ifndef CFG_TUD_ENABLED
+ // fallback to use CFG_TUSB_RHPORTx_MODE
+ #define CFG_TUD_ENABLED (TUD_RHPORT_MODE & OPT_MODE_DEVICE)
+#endif
-#ifndef CFG_TUSB_RHPORT0_MODE
- #define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE
+#ifndef CFG_TUD_MAX_SPEED
+ // fallback to use CFG_TUSB_RHPORTx_MODE
+ #define CFG_TUD_MAX_SPEED (TUD_RHPORT_MODE & OPT_MODE_SPEED_MASK)
#endif
+// For backward compatible
+#define TUSB_OPT_DEVICE_ENABLED CFG_TUD_ENABLED
-#ifndef CFG_TUSB_RHPORT1_MODE
- #define CFG_TUSB_RHPORT1_MODE OPT_MODE_NONE
+// highspeed support indicator
+#define TUD_OPT_HIGH_SPEED (CFG_TUD_MAX_SPEED ? (CFG_TUD_MAX_SPEED & OPT_MODE_HIGH_SPEED) : TUP_RHPORT_HIGHSPEED)
+
+//------------- Roothub as Host -------------//
+
+#if defined(CFG_TUSB_RHPORT0_MODE) && ((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_HOST)
+ #define TUH_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE)
+ #define TUH_OPT_RHPORT 0
+#elif defined(CFG_TUSB_RHPORT1_MODE) && ((CFG_TUSB_RHPORT1_MODE) & OPT_MODE_HOST)
+ #define TUH_RHPORT_MODE (CFG_TUSB_RHPORT1_MODE)
+ #define TUH_OPT_RHPORT 1
+#else
+ #define TUH_RHPORT_MODE OPT_MODE_NONE
+#endif
+
+#ifndef CFG_TUH_ENABLED
+ // fallback to use CFG_TUSB_RHPORTx_MODE
+ #define CFG_TUH_ENABLED (TUH_RHPORT_MODE & OPT_MODE_HOST)
#endif
-#if (((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_HOST ) && ((CFG_TUSB_RHPORT1_MODE) & OPT_MODE_HOST )) || \
- (((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_DEVICE) && ((CFG_TUSB_RHPORT1_MODE) & OPT_MODE_DEVICE))
- #error "TinyUSB currently does not support same modes on more than 1 roothub port"
+#ifndef CFG_TUH_MAX_SPEED
+ // fallback to use CFG_TUSB_RHPORTx_MODE
+ #define CFG_TUH_MAX_SPEED (TUH_RHPORT_MODE & OPT_MODE_SPEED_MASK)
#endif
-// Which roothub port is configured as host
-#define TUH_OPT_RHPORT ( ((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_HOST) ? 0 : (((CFG_TUSB_RHPORT1_MODE) & OPT_MODE_HOST) ? 1 : -1) )
-#define TUSB_OPT_HOST_ENABLED ( TUH_OPT_RHPORT >= 0 )
+// For backward compatible
+#define TUSB_OPT_HOST_ENABLED CFG_TUH_ENABLED
-// Which roothub port is configured as device
-#define TUD_OPT_RHPORT ( ((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_DEVICE) ? 0 : (((CFG_TUSB_RHPORT1_MODE) & OPT_MODE_DEVICE) ? 1 : -1) )
+//--------------------------------------------------------------------+
+// TODO move later
+//--------------------------------------------------------------------+
-#if TUD_OPT_RHPORT == 0
-#define TUD_OPT_HIGH_SPEED ( (CFG_TUSB_RHPORT0_MODE) & OPT_MODE_HIGH_SPEED )
+// TUP_MCU_STRICT_ALIGN will overwrite TUP_ARCH_STRICT_ALIGN.
+// In case TUP_MCU_STRICT_ALIGN = 1 and TUP_ARCH_STRICT_ALIGN =0, we will not reply on compiler
+// to generate unaligned access code.
+// LPC_IP3511 Highspeed cannot access unaligned memory on USB_RAM
+#if TUD_OPT_HIGH_SPEED && (CFG_TUSB_MCU == OPT_MCU_LPC54XXX || CFG_TUSB_MCU == OPT_MCU_LPC55XX)
+ #define TUP_MCU_STRICT_ALIGN 1
#else
-#define TUD_OPT_HIGH_SPEED ( (CFG_TUSB_RHPORT1_MODE) & OPT_MODE_HIGH_SPEED )
+ #define TUP_MCU_STRICT_ALIGN 0
#endif
-#define TUSB_OPT_DEVICE_ENABLED ( TUD_OPT_RHPORT >= 0 )
//--------------------------------------------------------------------+
-// COMMON OPTIONS
+// Common Options (Default)
//--------------------------------------------------------------------+
// Debug enable to print out error message
@@ -232,14 +299,21 @@
#define CFG_TUSB_OS_INC_PATH
#endif
+// mutex is only needed for RTOS TODO also required with multiple core MCUs
+#define TUSB_OPT_MUTEX (CFG_TUSB_OS != OPT_OS_NONE)
+
//--------------------------------------------------------------------
-// DEVICE OPTIONS
+// Device Options (Default)
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
+#ifndef CFG_TUD_INTERFACE_MAX
+ #define CFG_TUD_INTERFACE_MAX 16
+#endif
+
#ifndef CFG_TUD_CDC
#define CFG_TUD_CDC 0
#endif
@@ -298,9 +372,9 @@
#endif
//--------------------------------------------------------------------
-// HOST OPTIONS
+// Host Options (Default)
//--------------------------------------------------------------------
-#if TUSB_OPT_HOST_ENABLED
+#if CFG_TUH_ENABLED
#ifndef CFG_TUH_DEVICE_MAX
#define CFG_TUH_DEVICE_MAX 1
#endif
@@ -308,7 +382,7 @@
#ifndef CFG_TUH_ENUMERATION_BUFSIZE
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#endif
-#endif // TUSB_OPT_HOST_ENABLED
+#endif // CFG_TUH_ENABLED
//------------- CLASS -------------//
@@ -336,28 +410,17 @@
#define CFG_TUH_VENDOR 0
#endif
-//--------------------------------------------------------------------+
-// Port Specific
-// TUP stand for TinyUSB Port (can be renamed)
-//--------------------------------------------------------------------+
-
-//------------- Unaligned Memory -------------//
+#ifndef CFG_TUH_API_EDPT_XFER
+#define CFG_TUH_API_EDPT_XFER 0
+#endif
-// ARMv7+ (M3-M7, M23-M33) can access unaligned memory
-#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7))
- #define TUP_ARCH_STRICT_ALIGN 0
-#else
- #define TUP_ARCH_STRICT_ALIGN 1
+// Enable PIO-USB software host controller
+#ifndef CFG_TUH_RPI_PIO_USB
+#define CFG_TUH_RPI_PIO_USB 0
#endif
-// TUP_MCU_STRICT_ALIGN will overwrite TUP_ARCH_STRICT_ALIGN.
-// In case TUP_MCU_STRICT_ALIGN = 1 and TUP_ARCH_STRICT_ALIGN =0, we will not reply on compiler
-// to generate unaligned access code.
-// LPC_IP3511 Highspeed cannot access unaligned memory on USB_RAM
-#if TUD_OPT_HIGH_SPEED && (CFG_TUSB_MCU == OPT_MCU_LPC54XXX || CFG_TUSB_MCU == OPT_MCU_LPC55XX)
- #define TUP_MCU_STRICT_ALIGN 1
-#else
- #define TUP_MCU_STRICT_ALIGN 0
+#ifndef CFG_TUD_RPI_PIO_USB
+#define CFG_TUD_RPI_PIO_USB 0
#endif