Squashed 'third_party/pico-sdk/lib/tinyusb/' content from commit 868948f67c

Change-Id: I5d33c2566dd597be9d4b1c30d4b3723c5ef4a265
git-subtree-dir: third_party/pico-sdk/lib/tinyusb
git-subtree-split: 868948f67c90fa7c2553cdcd604b52862cf55720
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h
new file mode 100644
index 0000000..6f9c1a6
--- /dev/null
+++ b/src/class/audio/audio.h
@@ -0,0 +1,933 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * 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.
+ */
+
+/** \ingroup group_class
+ *  \defgroup ClassDriver_Audio Audio
+ *            Currently only MIDI subclass is supported
+ *  @{ */
+
+#ifndef _TUSB_AUDIO_H__
+#define _TUSB_AUDIO_H__
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// Audio Device Class Codes
+
+/// A.2 - Audio Function Subclass Codes
+typedef enum
+{
+  AUDIO_FUNCTION_SUBCLASS_UNDEFINED = 0x00,
+} audio_function_subclass_type_t;
+
+/// A.3 - Audio Function Protocol Codes
+typedef enum
+{
+  AUDIO_FUNC_PROTOCOL_CODE_UNDEF       = 0x00,
+  AUDIO_FUNC_PROTOCOL_CODE_V2          = 0x20, ///< Version 2.0
+} audio_function_protocol_code_t;
+
+/// A.5 - Audio Interface Subclass Codes
+typedef enum
+{
+  AUDIO_SUBCLASS_UNDEFINED = 0x00,
+  AUDIO_SUBCLASS_CONTROL         , ///< Audio Control
+  AUDIO_SUBCLASS_STREAMING       , ///< Audio Streaming
+  AUDIO_SUBCLASS_MIDI_STREAMING  , ///< MIDI Streaming
+} audio_subclass_type_t;
+
+/// A.6 - Audio Interface Protocol Codes
+typedef enum
+{
+  AUDIO_INT_PROTOCOL_CODE_UNDEF       = 0x00,
+  AUDIO_INT_PROTOCOL_CODE_V2          = 0x20, ///< Version 2.0
+} audio_interface_protocol_code_t;
+
+/// A.7 - Audio Function Category Codes
+typedef enum
+{
+  AUDIO_FUNC_UNDEF              = 0x00,
+  AUDIO_FUNC_DESKTOP_SPEAKER    = 0x01,
+  AUDIO_FUNC_HOME_THEATER       = 0x02,
+  AUDIO_FUNC_MICROPHONE         = 0x03,
+  AUDIO_FUNC_HEADSET            = 0x04,
+  AUDIO_FUNC_TELEPHONE          = 0x05,
+  AUDIO_FUNC_CONVERTER          = 0x06,
+  AUDIO_FUNC_SOUND_RECODER      = 0x07,
+  AUDIO_FUNC_IO_BOX             = 0x08,
+  AUDIO_FUNC_MUSICAL_INSTRUMENT = 0x09,
+  AUDIO_FUNC_PRO_AUDIO          = 0x0A,
+  AUDIO_FUNC_AUDIO_VIDEO        = 0x0B,
+  AUDIO_FUNC_CONTROL_PANEL      = 0x0C,
+  AUDIO_FUNC_OTHER              = 0xFF,
+} audio_function_code_t;
+
+/// A.9 - Audio Class-Specific AC Interface Descriptor Subtypes UAC2
+typedef enum
+{
+  AUDIO_CS_AC_INTERFACE_AC_DESCRIPTOR_UNDEF   = 0x00,
+  AUDIO_CS_AC_INTERFACE_HEADER                = 0x01,
+  AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL        = 0x02,
+  AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL       = 0x03,
+  AUDIO_CS_AC_INTERFACE_MIXER_UNIT            = 0x04,
+  AUDIO_CS_AC_INTERFACE_SELECTOR_UNIT         = 0x05,
+  AUDIO_CS_AC_INTERFACE_FEATURE_UNIT          = 0x06,
+  AUDIO_CS_AC_INTERFACE_EFFECT_UNIT           = 0x07,
+  AUDIO_CS_AC_INTERFACE_PROCESSING_UNIT       = 0x08,
+  AUDIO_CS_AC_INTERFACE_EXTENSION_UNIT        = 0x09,
+  AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE          = 0x0A,
+  AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR        = 0x0B,
+  AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER      = 0x0C,
+  AUDIO_CS_AC_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D,
+} audio_cs_ac_interface_subtype_t;
+
+/// A.10 - Audio Class-Specific AS Interface Descriptor Subtypes UAC2
+typedef enum
+{
+  AUDIO_CS_AS_INTERFACE_AS_DESCRIPTOR_UNDEF   = 0x00,
+  AUDIO_CS_AS_INTERFACE_AS_GENERAL            = 0x01,
+  AUDIO_CS_AS_INTERFACE_FORMAT_TYPE           = 0x02,
+  AUDIO_CS_AS_INTERFACE_ENCODER               = 0x03,
+  AUDIO_CS_AS_INTERFACE_DECODER               = 0x04,
+} audio_cs_as_interface_subtype_t;
+
+/// A.11 - Effect Unit Effect Types
+typedef enum
+{
+  AUDIO_EFFECT_TYPE_UNDEF                     = 0x00,
+  AUDIO_EFFECT_TYPE_PARAM_EQ_SECTION          = 0x01,
+  AUDIO_EFFECT_TYPE_REVERBERATION             = 0x02,
+  AUDIO_EFFECT_TYPE_MOD_DELAY                 = 0x03,
+  AUDIO_EFFECT_TYPE_DYN_RANGE_COMP            = 0x04,
+} audio_effect_unit_effect_type_t;
+
+/// A.12 - Processing Unit Process Types
+typedef enum
+{
+  AUDIO_PROCESS_TYPE_UNDEF                    = 0x00,
+  AUDIO_PROCESS_TYPE_UP_DOWN_MIX              = 0x01,
+  AUDIO_PROCESS_TYPE_DOLBY_PROLOGIC           = 0x02,
+  AUDIO_PROCESS_TYPE_STEREO_EXTENDER          = 0x03,
+} audio_processing_unit_process_type_t;
+
+/// A.13 - Audio Class-Specific EP Descriptor Subtypes UAC2
+typedef enum
+{
+  AUDIO_CS_EP_SUBTYPE_UNDEF                   = 0x00,
+  AUDIO_CS_EP_SUBTYPE_GENERAL                 = 0x01,
+} audio_cs_ep_subtype_t;
+
+/// A.14 - Audio Class-Specific Request Codes
+typedef enum
+{
+  AUDIO_CS_REQ_UNDEF                          = 0x00,
+  AUDIO_CS_REQ_CUR                            = 0x01,
+  AUDIO_CS_REQ_RANGE                          = 0x02,
+  AUDIO_CS_REQ_MEM                            = 0x03,
+} audio_cs_req_t;
+
+/// A.17 - Control Selector Codes
+
+/// A.17.1 - Clock Source Control Selectors
+typedef enum
+{
+  AUDIO_CS_CTRL_UNDEF                         = 0x00,
+  AUDIO_CS_CTRL_SAM_FREQ                      = 0x01,
+  AUDIO_CS_CTRL_CLK_VALID                     = 0x02,
+} audio_clock_src_control_selector_t;
+
+/// A.17.2 - Clock Selector Control Selectors
+typedef enum
+{
+  AUDIO_CX_CTRL_UNDEF                         = 0x00,
+  AUDIO_CX_CTRL_CONTROL                       = 0x01,
+} audio_clock_sel_control_selector_t;
+
+/// A.17.3 - Clock Multiplier Control Selectors
+typedef enum
+{
+  AUDIO_CM_CTRL_UNDEF                         = 0x00,
+  AUDIO_CM_CTRL_NUMERATOR_CONTROL             = 0x01,
+  AUDIO_CM_CTRL_DENOMINATOR_CONTROL           = 0x02,
+} audio_clock_mul_control_selector_t;
+
+/// A.17.4 - Terminal Control Selectors
+typedef enum
+{
+  AUDIO_TE_CTRL_UNDEF                         = 0x00,
+  AUDIO_TE_CTRL_COPY_PROTECT                  = 0x01,
+  AUDIO_TE_CTRL_CONNECTOR                     = 0x02,
+  AUDIO_TE_CTRL_OVERLOAD                      = 0x03,
+  AUDIO_TE_CTRL_CLUSTER                       = 0x04,
+  AUDIO_TE_CTRL_UNDERFLOW                     = 0x05,
+  AUDIO_TE_CTRL_OVERFLOW                      = 0x06,
+  AUDIO_TE_CTRL_LATENCY                       = 0x07,
+} audio_terminal_control_selector_t;
+
+/// A.17.5 - Mixer Control Selectors
+typedef enum
+{
+  AUDIO_MU_CTRL_UNDEF                         = 0x00,
+  AUDIO_MU_CTRL_MIXER                         = 0x01,
+  AUDIO_MU_CTRL_CLUSTER                       = 0x02,
+  AUDIO_MU_CTRL_UNDERFLOW                     = 0x03,
+  AUDIO_MU_CTRL_OVERFLOW                      = 0x04,
+  AUDIO_MU_CTRL_LATENCY                       = 0x05,
+} audio_mixer_control_selector_t;
+
+/// A.17.6 - Selector Control Selectors
+typedef enum
+{
+  AUDIO_SU_CTRL_UNDEF                         = 0x00,
+  AUDIO_SU_CTRL_SELECTOR                      = 0x01,
+  AUDIO_SU_CTRL_LATENCY                       = 0x02,
+} audio_sel_control_selector_t;
+
+/// A.17.7 - Feature Unit Control Selectors
+typedef enum
+{
+  AUDIO_FU_CTRL_UNDEF                         = 0x00,
+  AUDIO_FU_CTRL_MUTE                          = 0x01,
+  AUDIO_FU_CTRL_VOLUME                        = 0x02,
+  AUDIO_FU_CTRL_BASS                          = 0x03,
+  AUDIO_FU_CTRL_MID                           = 0x04,
+  AUDIO_FU_CTRL_TREBLE                        = 0x05,
+  AUDIO_FU_CTRL_GRAPHIC_EQUALIZER             = 0x06,
+  AUDIO_FU_CTRL_AGC                           = 0x07,
+  AUDIO_FU_CTRL_DELAY                         = 0x08,
+  AUDIO_FU_CTRL_BASS_BOOST                    = 0x09,
+  AUDIO_FU_CTRL_LOUDNESS                      = 0x0A,
+  AUDIO_FU_CTRL_INPUT_GAIN                    = 0x0B,
+  AUDIO_FU_CTRL_GAIN_PAD                      = 0x0C,
+  AUDIO_FU_CTRL_INVERTER                      = 0x0D,
+  AUDIO_FU_CTRL_UNDERFLOW                     = 0x0E,
+  AUDIO_FU_CTRL_OVERVLOW                      = 0x0F,
+  AUDIO_FU_CTRL_LATENCY                       = 0x10,
+} audio_feature_unit_control_selector_t;
+
+/// A.17.8 Effect Unit Control Selectors
+
+/// A.17.8.1 Parametric Equalizer Section Effect Unit Control Selectors
+typedef enum
+{
+  AUDIO_PE_CTRL_UNDEF                         = 0x00,
+  AUDIO_PE_CTRL_ENABLE                        = 0x01,
+  AUDIO_PE_CTRL_CENTERFREQ                    = 0x02,
+  AUDIO_PE_CTRL_QFACTOR                       = 0x03,
+  AUDIO_PE_CTRL_GAIN                          = 0x04,
+  AUDIO_PE_CTRL_UNDERFLOW                     = 0x05,
+  AUDIO_PE_CTRL_OVERFLOW                      = 0x06,
+  AUDIO_PE_CTRL_LATENCY                       = 0x07,
+} audio_parametric_equalizer_control_selector_t;
+
+/// A.17.8.2 Reverberation Effect Unit Control Selectors
+typedef enum
+{
+  AUDIO_RV_CTRL_UNDEF                         = 0x00,
+  AUDIO_RV_CTRL_ENABLE                        = 0x01,
+  AUDIO_RV_CTRL_TYPE                          = 0x02,
+  AUDIO_RV_CTRL_LEVEL                         = 0x03,
+  AUDIO_RV_CTRL_TIME                          = 0x04,
+  AUDIO_RV_CTRL_FEEDBACK                      = 0x05,
+  AUDIO_RV_CTRL_PREDELAY                      = 0x06,
+  AUDIO_RV_CTRL_DENSITY                       = 0x07,
+  AUDIO_RV_CTRL_HIFREQ_ROLLOFF                = 0x08,
+  AUDIO_RV_CTRL_UNDERFLOW                     = 0x09,
+  AUDIO_RV_CTRL_OVERFLOW                      = 0x0A,
+  AUDIO_RV_CTRL_LATENCY                       = 0x0B,
+} audio_reverberation_effect_control_selector_t;
+
+/// A.17.8.3 Modulation Delay Effect Unit Control Selectors
+typedef enum
+{
+  AUDIO_MD_CTRL_UNDEF                         = 0x00,
+  AUDIO_MD_CTRL_ENABLE                        = 0x01,
+  AUDIO_MD_CTRL_BALANCE                       = 0x02,
+  AUDIO_MD_CTRL_RATE                          = 0x03,
+  AUDIO_MD_CTRL_DEPTH                         = 0x04,
+  AUDIO_MD_CTRL_TIME                          = 0x05,
+  AUDIO_MD_CTRL_FEEDBACK                      = 0x06,
+  AUDIO_MD_CTRL_UNDERFLOW                     = 0x07,
+  AUDIO_MD_CTRL_OVERFLOW                      = 0x08,
+  AUDIO_MD_CTRL_LATENCY                       = 0x09,
+} audio_modulation_delay_control_selector_t;
+
+/// A.17.8.4 Dynamic Range Compressor Effect Unit Control Selectors
+typedef enum
+{
+  AUDIO_DR_CTRL_UNDEF                         = 0x00,
+  AUDIO_DR_CTRL_ENABLE                        = 0x01,
+  AUDIO_DR_CTRL_COMPRESSION_RATE              = 0x02,
+  AUDIO_DR_CTRL_MAXAMPL                       = 0x03,
+  AUDIO_DR_CTRL_THRESHOLD                     = 0x04,
+  AUDIO_DR_CTRL_ATTACK_TIME                   = 0x05,
+  AUDIO_DR_CTRL_RELEASE_TIME                  = 0x06,
+  AUDIO_DR_CTRL_UNDERFLOW                     = 0x07,
+  AUDIO_DR_CTRL_OVERFLOW                      = 0x08,
+  AUDIO_DR_CTRL_LATENCY                       = 0x09,
+} audio_dynamic_range_compression_control_selector_t;
+
+/// A.17.9 Processing Unit Control Selectors
+
+/// A.17.9.1 Up/Down-mix Processing Unit Control Selectors
+typedef enum
+{
+  AUDIO_UD_CTRL_UNDEF                         = 0x00,
+  AUDIO_UD_CTRL_ENABLE                        = 0x01,
+  AUDIO_UD_CTRL_MODE_SELECT                   = 0x02,
+  AUDIO_UD_CTRL_CLUSTER                       = 0x03,
+  AUDIO_UD_CTRL_UNDERFLOW                     = 0x04,
+  AUDIO_UD_CTRL_OVERFLOW                      = 0x05,
+  AUDIO_UD_CTRL_LATENCY                       = 0x06,
+} audio_up_down_mix_control_selector_t;
+
+/// A.17.9.2 Dolby Prologic ™ Processing Unit Control Selectors
+typedef enum
+{
+  AUDIO_DP_CTRL_UNDEF                         = 0x00,
+  AUDIO_DP_CTRL_ENABLE                        = 0x01,
+  AUDIO_DP_CTRL_MODE_SELECT                   = 0x02,
+  AUDIO_DP_CTRL_CLUSTER                       = 0x03,
+  AUDIO_DP_CTRL_UNDERFLOW                     = 0x04,
+  AUDIO_DP_CTRL_OVERFLOW                      = 0x05,
+  AUDIO_DP_CTRL_LATENCY                       = 0x06,
+} audio_dolby_prologic_control_selector_t;
+
+/// A.17.9.3 Stereo Extender Processing Unit Control Selectors
+typedef enum
+{
+  AUDIO_ST_EXT_CTRL_UNDEF                     = 0x00,
+  AUDIO_ST_EXT_CTRL_ENABLE                    = 0x01,
+  AUDIO_ST_EXT_CTRL_WIDTH                     = 0x02,
+  AUDIO_ST_EXT_CTRL_UNDERFLOW                 = 0x03,
+  AUDIO_ST_EXT_CTRL_OVERFLOW                  = 0x04,
+  AUDIO_ST_EXT_CTRL_LATENCY                   = 0x05,
+} audio_stereo_extender_control_selector_t;
+
+/// A.17.10 Extension Unit Control Selectors
+typedef enum
+{
+  AUDIO_XU_CTRL_UNDEF                         = 0x00,
+  AUDIO_XU_CTRL_ENABLE                        = 0x01,
+  AUDIO_XU_CTRL_CLUSTER                       = 0x02,
+  AUDIO_XU_CTRL_UNDERFLOW                     = 0x03,
+  AUDIO_XU_CTRL_OVERFLOW                      = 0x04,
+  AUDIO_XU_CTRL_LATENCY                       = 0x05,
+} audio_extension_unit_control_selector_t;
+
+/// A.17.11 AudioStreaming Interface Control Selectors
+typedef enum
+{
+  AUDIO_AS_CTRL_UNDEF                         = 0x00,
+  AUDIO_AS_CTRL_ACT_ALT_SETTING               = 0x01,
+  AUDIO_AS_CTRL_VAL_ALT_SETTINGS              = 0x02,
+  AUDIO_AS_CTRL_AUDIO_DATA_FORMAT             = 0x03,
+} audio_audiostreaming_interface_control_selector_t;
+
+/// A.17.12 Encoder Control Selectors
+typedef enum
+{
+  AUDIO_EN_CTRL_UNDEF                         = 0x00,
+  AUDIO_EN_CTRL_BIT_RATE                      = 0x01,
+  AUDIO_EN_CTRL_QUALITY                       = 0x02,
+  AUDIO_EN_CTRL_VBR                           = 0x03,
+  AUDIO_EN_CTRL_TYPE                          = 0x04,
+  AUDIO_EN_CTRL_UNDERFLOW                     = 0x05,
+  AUDIO_EN_CTRL_OVERFLOW                      = 0x06,
+  AUDIO_EN_CTRL_ENCODER_ERROR                 = 0x07,
+  AUDIO_EN_CTRL_PARAM1                        = 0x08,
+  AUDIO_EN_CTRL_PARAM2                        = 0x09,
+  AUDIO_EN_CTRL_PARAM3                        = 0x0A,
+  AUDIO_EN_CTRL_PARAM4                        = 0x0B,
+  AUDIO_EN_CTRL_PARAM5                        = 0x0C,
+  AUDIO_EN_CTRL_PARAM6                        = 0x0D,
+  AUDIO_EN_CTRL_PARAM7                        = 0x0E,
+  AUDIO_EN_CTRL_PARAM8                        = 0x0F,
+} audio_encoder_control_selector_t;
+
+/// A.17.13 Decoder Control Selectors
+
+/// A.17.13.1 MPEG Decoder Control Selectors
+typedef enum
+{
+  AUDIO_MPD_CTRL_UNDEF                        = 0x00,
+  AUDIO_MPD_CTRL_DUAL_CHANNEL                 = 0x01,
+  AUDIO_MPD_CTRL_SECOND_STEREO                = 0x02,
+  AUDIO_MPD_CTRL_MULTILINGUAL                 = 0x03,
+  AUDIO_MPD_CTRL_DYN_RANGE                    = 0x04,
+  AUDIO_MPD_CTRL_SCALING                      = 0x05,
+  AUDIO_MPD_CTRL_HILO_SCALING                 = 0x06,
+  AUDIO_MPD_CTRL_UNDERFLOW                    = 0x07,
+  AUDIO_MPD_CTRL_OVERFLOW                     = 0x08,
+  AUDIO_MPD_CTRL_DECODER_ERROR                = 0x09,
+} audio_MPEG_decoder_control_selector_t;
+
+/// A.17.13.2 AC-3 Decoder Control Selectors
+typedef enum
+{
+  AUDIO_AD_CTRL_UNDEF                         = 0x00,
+  AUDIO_AD_CTRL_MODE                          = 0x01,
+  AUDIO_AD_CTRL_DYN_RANGE                     = 0x02,
+  AUDIO_AD_CTRL_SCALING                       = 0x03,
+  AUDIO_AD_CTRL_HILO_SCALING                  = 0x04,
+  AUDIO_AD_CTRL_UNDERFLOW                     = 0x05,
+  AUDIO_AD_CTRL_OVERFLOW                      = 0x06,
+  AUDIO_AD_CTRL_DECODER_ERROR                 = 0x07,
+} audio_AC3_decoder_control_selector_t;
+
+/// A.17.13.3 WMA Decoder Control Selectors
+typedef enum
+{
+  AUDIO_WD_CTRL_UNDEF                         = 0x00,
+  AUDIO_WD_CTRL_UNDERFLOW                     = 0x01,
+  AUDIO_WD_CTRL_OVERFLOW                      = 0x02,
+  AUDIO_WD_CTRL_DECODER_ERROR                 = 0x03,
+} audio_WMA_decoder_control_selector_t;
+
+/// A.17.13.4 DTS Decoder Control Selectors
+typedef enum
+{
+  AUDIO_DD_CTRL_UNDEF                         = 0x00,
+  AUDIO_DD_CTRL_UNDERFLOW                     = 0x01,
+  AUDIO_DD_CTRL_OVERFLOW                      = 0x02,
+  AUDIO_DD_CTRL_DECODER_ERROR                 = 0x03,
+} audio_DTS_decoder_control_selector_t;
+
+/// A.17.14 Endpoint Control Selectors
+typedef enum
+{
+  AUDIO_EP_CTRL_UNDEF                         = 0x00,
+  AUDIO_EP_CTRL_PITCH                         = 0x01,
+  AUDIO_EP_CTRL_DATA_OVERRUN                  = 0x02,
+  AUDIO_EP_CTRL_DATA_UNDERRUN                 = 0x03,
+} audio_EP_control_selector_t;
+
+/// Terminal Types
+
+/// 2.1 - Audio Class-Terminal Types UAC2
+typedef enum
+{
+  AUDIO_TERM_TYPE_USB_UNDEFINED       = 0x0100,
+  AUDIO_TERM_TYPE_USB_STREAMING       = 0x0101,
+  AUDIO_TERM_TYPE_USB_VENDOR_SPEC     = 0x01FF,
+} audio_terminal_type_t;
+
+/// 2.2 - Audio Class-Input Terminal Types UAC2
+typedef enum
+{
+  AUDIO_TERM_TYPE_IN_UNDEFINED        = 0x0200,
+  AUDIO_TERM_TYPE_IN_GENERIC_MIC      = 0x0201,
+  AUDIO_TERM_TYPE_IN_DESKTOP_MIC      = 0x0202,
+  AUDIO_TERM_TYPE_IN_PERSONAL_MIC     = 0x0203,
+  AUDIO_TERM_TYPE_IN_OMNI_MIC         = 0x0204,
+  AUDIO_TERM_TYPE_IN_ARRAY_MIC        = 0x0205,
+  AUDIO_TERM_TYPE_IN_PROC_ARRAY_MIC   = 0x0206,
+} audio_terminal_input_type_t;
+
+/// 2.3 - Audio Class-Output Terminal Types UAC2
+typedef enum
+{
+  AUDIO_TERM_TYPE_OUT_UNDEFINED               = 0x0300,
+  AUDIO_TERM_TYPE_OUT_GENERIC_SPEAKER         = 0x0301,
+  AUDIO_TERM_TYPE_OUT_HEADPHONES              = 0x0302,
+  AUDIO_TERM_TYPE_OUT_HEAD_MNT_DISP_AUIDO     = 0x0303,
+  AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER         = 0x0304,
+  AUDIO_TERM_TYPE_OUT_ROOM_SPEAKER            = 0x0305,
+  AUDIO_TERM_TYPE_OUT_COMMUNICATION_SPEAKER   = 0x0306,
+  AUDIO_TERM_TYPE_OUT_LOW_FRQ_EFFECTS_SPEAKER = 0x0307,
+} audio_terminal_output_type_t;
+
+/// Rest is yet to be implemented
+
+/// Additional Audio Device Class Codes - Source: Audio Data Formats
+
+/// A.1 - Audio Class-Format Type Codes UAC2
+typedef enum
+{
+  AUDIO_FORMAT_TYPE_UNDEFINED     = 0x00,
+  AUDIO_FORMAT_TYPE_I             = 0x01,
+  AUDIO_FORMAT_TYPE_II            = 0x02,
+  AUDIO_FORMAT_TYPE_III           = 0x03,
+  AUDIO_FORMAT_TYPE_IV            = 0x04,
+  AUDIO_EXT_FORMAT_TYPE_I         = 0x81,
+  AUDIO_EXT_FORMAT_TYPE_II        = 0x82,
+  AUDIO_EXT_FORMAT_TYPE_III       = 0x83,
+} audio_format_type_t;
+
+// A.2.1 - Audio Class-Audio Data Format Type I UAC2
+typedef enum
+{
+  AUDIO_DATA_FORMAT_TYPE_I_PCM            = (uint32_t) (1 << 0),
+  AUDIO_DATA_FORMAT_TYPE_I_PCM8           = (uint32_t) (1 << 1),
+  AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT     = (uint32_t) (1 << 2),
+  AUDIO_DATA_FORMAT_TYPE_I_ALAW           = (uint32_t) (1 << 3),
+  AUDIO_DATA_FORMAT_TYPE_I_MULAW          = (uint32_t) (1 << 4),
+  AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA       = 0x80000000,
+} audio_data_format_type_I_t;
+
+/// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification
+
+/// Audio Class-Control Values UAC2
+typedef enum
+{
+  AUDIO_CTRL_NONE     = 0x00,         ///< No Host access
+  AUDIO_CTRL_R        = 0x01,         ///< Host read access only
+  AUDIO_CTRL_RW       = 0x03,         ///< Host read write access
+} audio_control_t;
+
+/// Audio Class-Specific AC Interface Descriptor Controls UAC2
+typedef enum
+{
+  AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS  = 0,
+} audio_cs_ac_interface_control_pos_t;
+
+/// Audio Class-Specific AS Interface Descriptor Controls UAC2
+typedef enum
+{
+  AUDIO_CS_AS_INTERFACE_CTRL_ACTIVE_ALT_SET_POS   = 0,
+  AUDIO_CS_AS_INTERFACE_CTRL_VALID_ALT_SET_POS    = 2,
+} audio_cs_as_interface_control_pos_t;
+
+/// Audio Class-Specific AS Isochronous Data EP Attributes UAC2
+typedef enum
+{
+  AUDIO_CS_AS_ISO_DATA_EP_ATT_MAX_PACKETS_ONLY    = 0x80,
+  AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK  = 0x00,
+} audio_cs_as_iso_data_ep_attribute_t;
+
+/// Audio Class-Specific AS Isochronous Data EP Controls UAC2
+typedef enum
+{
+  AUDIO_CS_AS_ISO_DATA_EP_CTRL_PITCH_POS          = 0,
+  AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_OVERRUN_POS   = 2,
+  AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_UNDERRUN_POS  = 4,
+} audio_cs_as_iso_data_ep_control_pos_t;
+
+/// Audio Class-Specific AS Isochronous Data EP Lock Delay Units UAC2
+typedef enum
+{
+  AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED       = 0x00,
+  AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC        = 0x01,
+  AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_PCM_SAMPLES     = 0x02,
+} audio_cs_as_iso_data_ep_lock_delay_unit_t;
+
+/// Audio Class-Clock Source Attributes UAC2
+typedef enum
+{
+  AUDIO_CLOCK_SOURCE_ATT_EXT_CLK      = 0x00,
+  AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK  = 0x01,
+  AUDIO_CLOCK_SOURCE_ATT_INT_VAR_CLK  = 0x02,
+  AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK  = 0x03,
+  AUDIO_CLOCK_SOURCE_ATT_CLK_SYC_SOF  = 0x04,
+} audio_clock_source_attribute_t;
+
+/// Audio Class-Clock Source Controls UAC2
+typedef enum
+{
+  AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS     = 0,
+  AUDIO_CLOCK_SOURCE_CTRL_CLK_VAL_POS     = 2,
+} audio_clock_source_control_pos_t;
+
+/// Audio Class-Clock Selector Controls UAC2
+typedef enum
+{
+  AUDIO_CLOCK_SELECTOR_CTRL_POS   = 0,
+} audio_clock_selector_control_pos_t;
+
+/// Audio Class-Clock Multiplier Controls UAC2
+typedef enum
+{
+  AUDIO_CLOCK_MULTIPLIER_CTRL_NUMERATOR_POS       = 0,
+  AUDIO_CLOCK_MULTIPLIER_CTRL_DENOMINATOR_POS     = 2,
+} audio_clock_multiplier_control_pos_t;
+
+/// Audio Class-Input Terminal Controls UAC2
+typedef enum
+{
+  AUDIO_IN_TERM_CTRL_CPY_PROT_POS     = 0,
+  AUDIO_IN_TERM_CTRL_CONNECTOR_POS    = 2,
+  AUDIO_IN_TERM_CTRL_OVERLOAD_POS     = 4,
+  AUDIO_IN_TERM_CTRL_CLUSTER_POS      = 6,
+  AUDIO_IN_TERM_CTRL_UNDERFLOW_POS    = 8,
+  AUDIO_IN_TERM_CTRL_OVERFLOW_POS     = 10,
+} audio_terminal_input_control_pos_t;
+
+/// Audio Class-Output Terminal Controls UAC2
+typedef enum
+{
+  AUDIO_OUT_TERM_CTRL_CPY_PROT_POS    = 0,
+  AUDIO_OUT_TERM_CTRL_CONNECTOR_POS   = 2,
+  AUDIO_OUT_TERM_CTRL_OVERLOAD_POS    = 4,
+  AUDIO_OUT_TERM_CTRL_UNDERFLOW_POS   = 6,
+  AUDIO_OUT_TERM_CTRL_OVERFLOW_POS    = 8,
+} audio_terminal_output_control_pos_t;
+
+/// Audio Class-Feature Unit Controls UAC2
+typedef enum
+{
+  AUDIO_FEATURE_UNIT_CTRL_MUTE_POS            = 0,
+  AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS          = 2,
+  AUDIO_FEATURE_UNIT_CTRL_BASS_POS            = 4,
+  AUDIO_FEATURE_UNIT_CTRL_MID_POS             = 6,
+  AUDIO_FEATURE_UNIT_CTRL_TREBLE_POS          = 8,
+  AUDIO_FEATURE_UNIT_CTRL_GRAPHIC_EQU_POS     = 10,
+  AUDIO_FEATURE_UNIT_CTRL_AGC_POS             = 12,
+  AUDIO_FEATURE_UNIT_CTRL_DELAY_POS           = 14,
+  AUDIO_FEATURE_UNIT_CTRL_BASS_BOOST_POS      = 16,
+  AUDIO_FEATURE_UNIT_CTRL_LOUDNESS_POS        = 18,
+  AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_POS      = 20,
+  AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_PAD_POS  = 22,
+  AUDIO_FEATURE_UNIT_CTRL_PHASE_INV_POS       = 24,
+  AUDIO_FEATURE_UNIT_CTRL_UNDERFLOW_POS       = 26,
+  AUDIO_FEATURE_UNIT_CTRL_OVERFLOW_POS        = 28,
+} audio_feature_unit_control_pos_t;
+
+/// Audio Class-Audio Channel Configuration UAC2
+typedef enum
+{
+  AUDIO_CHANNEL_CONFIG_NON_PREDEFINED             = 0x00000000,
+  AUDIO_CHANNEL_CONFIG_FRONT_LEFT                 = 0x00000001,
+  AUDIO_CHANNEL_CONFIG_FRONT_RIGHT                = 0x00000002,
+  AUDIO_CHANNEL_CONFIG_FRONT_CENTER               = 0x00000004,
+  AUDIO_CHANNEL_CONFIG_LOW_FRQ_EFFECTS            = 0x00000008,
+  AUDIO_CHANNEL_CONFIG_BACK_LEFT                  = 0x00000010,
+  AUDIO_CHANNEL_CONFIG_BACK_RIGHT                 = 0x00000020,
+  AUDIO_CHANNEL_CONFIG_FRONT_LEFT_OF_CENTER       = 0x00000040,
+  AUDIO_CHANNEL_CONFIG_FRONT_RIGHT_OF_CENTER      = 0x00000080,
+  AUDIO_CHANNEL_CONFIG_BACK_CENTER                = 0x00000100,
+  AUDIO_CHANNEL_CONFIG_SIDE_LEFT                  = 0x00000200,
+  AUDIO_CHANNEL_CONFIG_SIDE_RIGHT                 = 0x00000400,
+  AUDIO_CHANNEL_CONFIG_TOP_CENTER                 = 0x00000800,
+  AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT             = 0x00001000,
+  AUDIO_CHANNEL_CONFIG_TOP_FRONT_CENTER           = 0x00002000,
+  AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT            = 0x00004000,
+  AUDIO_CHANNEL_CONFIG_TOP_BACK_LEFT              = 0x00008000,
+  AUDIO_CHANNEL_CONFIG_TOP_BACK_CENTER            = 0x00010000,
+  AUDIO_CHANNEL_CONFIG_TOP_BACK_RIGHT             = 0x00020000,
+  AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT_OF_CENTER   = 0x00040000,
+  AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT_OF_CENTER  = 0x00080000,
+  AUDIO_CHANNEL_CONFIG_LEFT_LOW_FRQ_EFFECTS       = 0x00100000,
+  AUDIO_CHANNEL_CONFIG_RIGHT_LOW_FRQ_EFFECTS      = 0x00200000,
+  AUDIO_CHANNEL_CONFIG_TOP_SIDE_LEFT              = 0x00400000,
+  AUDIO_CHANNEL_CONFIG_TOP_SIDE_RIGHT             = 0x00800000,
+  AUDIO_CHANNEL_CONFIG_BOTTOM_CENTER              = 0x01000000,
+  AUDIO_CHANNEL_CONFIG_BACK_LEFT_OF_CENTER        = 0x02000000,
+  AUDIO_CHANNEL_CONFIG_BACK_RIGHT_OF_CENTER       = 0x04000000,
+  AUDIO_CHANNEL_CONFIG_RAW_DATA                   = 0x80000000,
+} audio_channel_config_t;
+
+/// AUDIO Channel Cluster Descriptor (4.1)
+typedef struct TU_ATTR_PACKED {
+  uint8_t                 bNrChannels;        ///< Number of channels currently connected.
+  audio_channel_config_t  bmChannelConfig;    ///< Bitmap according to 'audio_channel_config_t' with a 1 set if channel is connected and 0 else. In case channels are non-predefined ignore them here (see UAC2 specification 4.1 Audio Channel Cluster Descriptor.
+  uint8_t                 iChannelNames;      ///< Index of a string descriptor, describing the name of the first inserted channel with a non-predefined spatial location.
+} audio_desc_channel_cluster_t;
+
+/// AUDIO Class-Specific AC Interface Header Descriptor (4.7.2)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes: 9.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_HEADER.
+  uint16_t bcdADC            ; ///< Audio Device Class Specification Release Number in Binary-Coded Decimal. Value: U16_TO_U8S_LE(0x0200).
+  uint8_t bCategory          ; ///< Constant, indicating the primary use of this audio function, as intended by the manufacturer. See: audio_function_t.
+  uint16_t wTotalLength      ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors.
+  uint8_t bmControls         ; ///< See: audio_cs_ac_interface_control_pos_t.
+} audio_desc_cs_ac_interface_t;
+
+/// AUDIO Clock Source Descriptor (4.7.2.1)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes: 8.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE.
+  uint8_t bClockID           ; ///< Constant uniquely identifying the Clock Source Entity within the audio function. This value is used in all requests to address this Entity.
+  uint8_t bmAttributes       ; ///< See: audio_clock_source_attribute_t.
+  uint8_t bmControls         ; ///< See: audio_clock_source_control_pos_t.
+  uint8_t bAssocTerminal     ; ///< Terminal ID of the Terminal that is associated with this Clock Source.
+  uint8_t iClockSource       ; ///< Index of a string descriptor, describing the Clock Source Entity.
+} audio_desc_clock_source_t;
+
+/// AUDIO Clock Selector Descriptor (4.7.2.2) for ONE pin
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 7+p.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR.
+  uint8_t bClockID           ; ///< Constant uniquely identifying the Clock Selector Entity within the audio function. This value is used in all requests to address this Entity.
+  uint8_t bNrInPins          ; ///< Number of Input Pins of this Unit: p = 1 thus bNrInPins = 1.
+  uint8_t baCSourceID        ; ///< ID of the Clock Entity to which the first Clock Input Pin of this Clock Selector Entity is connected..
+  uint8_t bmControls         ; ///< See: audio_clock_selector_control_pos_t.
+  uint8_t iClockSource       ; ///< Index of a string descriptor, describing the Clock Selector Entity.
+} audio_desc_clock_selector_t;
+
+/// AUDIO Clock Selector Descriptor (4.7.2.2) for multiple pins
+#define audio_desc_clock_selector_n_t(source_num) \
+    struct TU_ATTR_PACKED {       \
+  uint8_t bLength               ; \
+  uint8_t bDescriptorType       ; \
+  uint8_t bDescriptorSubType    ; \
+  uint8_t bClockID              ; \
+  uint8_t bNrInPins             ; \
+  struct TU_ATTR_PACKED {         \
+    uint8_t baSourceID          ; \
+  } sourceID[source_num]        ; \
+  uint8_t bmControls            ; \
+  uint8_t iClockSource          ; \
+}
+
+/// AUDIO Clock Multiplier Descriptor (4.7.2.3)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 7.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER.
+  uint8_t bClockID           ; ///< Constant uniquely identifying the Clock Multiplier Entity within the audio function. This value is used in all requests to address this Entity.
+  uint8_t bCSourceID         ; ///< ID of the Clock Entity to which the last Clock Input Pin of this Clock Selector Entity is connected.
+  uint8_t bmControls         ; ///< See: audio_clock_multiplier_control_pos_t.
+  uint8_t iClockSource       ; ///< Index of a string descriptor, describing the Clock Multiplier Entity.
+} audio_desc_clock_multiplier_t;
+
+/// AUDIO Input Terminal Descriptor(4.7.2.4)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 17.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL.
+  uint16_t wTerminalType     ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types.
+  uint8_t bAssocTerminal     ; ///< ID of the Output Terminal to which this Input Terminal is associated.
+  uint8_t bCSourceID         ; ///< ID of the Clock Entity to which this Input Terminal is connected.
+  uint8_t bNrChannels        ; ///< Number of logical output channels in the Terminal’s output audio channel cluster.
+  uint32_t bmChannelConfig   ; ///< Describes the spatial location of the logical channels. See:audio_channel_config_t.
+  uint16_t bmControls        ; ///< See: audio_terminal_input_control_pos_t.
+  uint8_t iTerminal          ; ///< Index of a string descriptor, describing the Input Terminal.
+} audio_desc_input_terminal_t;
+
+/// AUDIO Output Terminal Descriptor(4.7.2.5)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 12.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL.
+  uint8_t bTerminalID        ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this Terminal.
+  uint16_t wTerminalType     ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_output_type_t for other output types.
+  uint8_t bAssocTerminal     ; ///< Constant, identifying the Input Terminal to which this Output Terminal is associated.
+  uint8_t bSourceID          ; ///< ID of the Unit or Terminal to which this Terminal is connected.
+  uint8_t bCSourceID         ; ///< ID of the Clock Entity to which this Output Terminal is connected.
+  uint16_t bmControls        ; ///< See: audio_terminal_output_type_t.
+  uint8_t iTerminal          ; ///< Index of a string descriptor, describing the Output Terminal.
+} audio_desc_output_terminal_t;
+
+/// AUDIO Feature Unit Descriptor(4.7.2.8) for ONE channel
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 14.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_FEATURE_UNIT.
+  uint8_t bUnitID            ; ///< Constant uniquely identifying the Unit within the audio function. This value is used in all requests to address this Unit.
+  uint8_t bSourceID          ; ///< ID of the Unit or Terminal to which this Feature Unit is connected.
+  struct TU_ATTR_PACKED {
+    uint32_t bmaControls     ; ///< See: audio_feature_unit_control_pos_t. Controls0 is master channel 0 (always present) and Controls1 is logical channel 1.
+  } controls[2]              ;
+  uint8_t iTerminal          ; ///< Index of a string descriptor, describing this Feature Unit.
+} audio_desc_feature_unit_t;
+
+/// AUDIO Feature Unit Descriptor(4.7.2.8) for multiple channels
+#define audio_desc_feature_unit_n_t(ch_num)\
+    struct TU_ATTR_PACKED {         \
+  uint8_t bLength               ; /* 6+(ch_num+1)*4 */\
+    uint8_t bDescriptorType     ; \
+    uint8_t bDescriptorSubType  ; \
+    uint8_t bUnitID             ; \
+    uint8_t bSourceID           ; \
+    struct TU_ATTR_PACKED {       \
+      uint32_t bmaControls      ; \
+    } controls[ch_num+1]        ; \
+    uint8_t iTerminal           ; \
+}
+
+/// AUDIO Class-Specific AS Interface Descriptor(4.9.2)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 16.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_AS_GENERAL.
+  uint8_t bTerminalLink      ; ///< The Terminal ID of the Terminal to which this interface is connected.
+  uint8_t bmControls         ; ///< See: audio_cs_as_interface_control_pos_t.
+  uint8_t bFormatType        ; ///< Constant identifying the Format Type the AudioStreaming interface is using. See: audio_format_type_t.
+  uint32_t bmFormats         ; ///< The Audio Data Format(s) that can be used to communicate with this interface.See: audio_data_format_type_I_t.
+  uint8_t bNrChannels        ; ///< Number of physical channels in the AS Interface audio channel cluster.
+  uint32_t bmChannelConfig   ; ///< Describes the spatial location of the physical channels. See: audio_channel_config_t.
+  uint8_t iChannelNames      ; ///< Index of a string descriptor, describing the name of the first physical channel.
+} audio_desc_cs_as_interface_t;
+
+/// AUDIO Type I Format Type Descriptor(2.3.1.6 - Audio Formats)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 6.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_FORMAT_TYPE.
+  uint8_t bFormatType        ; ///< Constant identifying the Format Type the AudioStreaming interface is using. Value: AUDIO_FORMAT_TYPE_I.
+  uint8_t bSubslotSize       ; ///< The number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4.
+  uint8_t bBitResolution     ; ///< The number of effectively used bits from the available bits in an audio subslot.
+} audio_desc_type_I_format_t;
+
+/// AUDIO Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 8.
+  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_ENDPOINT.
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_EP_SUBTYPE_GENERAL.
+  uint8_t bmAttributes       ; ///< See: audio_cs_as_iso_data_ep_attribute_t.
+  uint8_t bmControls         ; ///< See: audio_cs_as_iso_data_ep_control_pos_t.
+  uint8_t bLockDelayUnits    ; ///< Indicates the units used for the wLockDelay field. See: audio_cs_as_iso_data_ep_lock_delay_unit_t.
+  uint16_t wLockDelay        ; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field.
+} audio_desc_cs_as_iso_data_ep_t;
+
+// 5.2.2 Control Request Layout
+typedef struct TU_ATTR_PACKED
+{
+    union
+    {
+        struct TU_ATTR_PACKED
+        {
+            uint8_t recipient :  5; ///< Recipient type tusb_request_recipient_t.
+            uint8_t type      :  2; ///< Request type tusb_request_type_t.
+            uint8_t direction :  1; ///< Direction type. tusb_dir_t
+        } bmRequestType_bit;
+        
+        uint8_t bmRequestType;
+    };
+    
+    uint8_t bRequest;  ///< Request type audio_cs_req_t
+    uint8_t bChannelNumber;
+    uint8_t bControlSelector;
+    union
+    {
+        uint8_t bInterface;
+        uint8_t bEndpoint;
+    };
+    uint8_t bEntityID;
+    uint16_t wLength;
+} audio_control_request_t;
+
+//// 5.2.3 Control Request Parameter Block Layout
+
+// 5.2.3.1 1-byte Control CUR Parameter Block
+typedef struct TU_ATTR_PACKED
+{
+  int8_t bCur               ;   ///< The setting for the CUR attribute of the addressed Control
+} audio_control_cur_1_t;
+
+// 5.2.3.2 2-byte Control CUR Parameter Block
+typedef struct TU_ATTR_PACKED
+{
+  int16_t bCur              ;   ///< The setting for the CUR attribute of the addressed Control
+} audio_control_cur_2_t;
+
+// 5.2.3.3 4-byte Control CUR Parameter Block
+typedef struct TU_ATTR_PACKED
+{
+  int32_t bCur              ;   ///< The setting for the CUR attribute of the addressed Control
+} audio_control_cur_4_t;
+
+// Use the following ONLY for RECEIVED data - compiler does not know how many subranges are defined! Use the one below for predefined lengths - or if you know what you are doing do what you like
+// 5.2.3.1 1-byte Control RANGE Parameter Block
+typedef struct TU_ATTR_PACKED {
+  uint16_t wNumSubRanges;
+  struct TU_ATTR_PACKED {
+    int8_t bMin             ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/
+    int8_t bMax             ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/
+    uint8_t bRes            ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/
+  } subrange[]              ;
+} audio_control_range_1_t;
+
+// 5.2.3.2 2-byte Control RANGE Parameter Block
+typedef struct TU_ATTR_PACKED {
+  uint16_t wNumSubRanges;
+  struct TU_ATTR_PACKED {
+    int16_t bMin            ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/
+    int16_t bMax            ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/
+    uint16_t bRes           ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/
+  } subrange[]              ;
+} audio_control_range_2_t;
+
+// 5.2.3.3 4-byte Control RANGE Parameter Block
+typedef struct TU_ATTR_PACKED {
+  uint16_t wNumSubRanges;
+  struct TU_ATTR_PACKED {
+    int32_t bMin            ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/
+    int32_t bMax            ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/
+    uint32_t bRes           ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/
+  } subrange[]              ;
+} audio_control_range_4_t;
+
+// 5.2.3.1 1-byte Control RANGE Parameter Block
+#define audio_control_range_1_n_t(numSubRanges) \
+    struct TU_ATTR_PACKED {                     \
+  uint16_t wNumSubRanges;                       \
+  struct TU_ATTR_PACKED {                       \
+      int8_t bMin               ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\
+    int8_t bMax                 ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\
+    uint8_t bRes                ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\
+    } subrange[numSubRanges]    ;               \
+}
+
+/// 5.2.3.2 2-byte Control RANGE Parameter Block
+#define audio_control_range_2_n_t(numSubRanges) \
+    struct TU_ATTR_PACKED {                     \
+  uint16_t wNumSubRanges;                       \
+  struct TU_ATTR_PACKED {                       \
+      int16_t bMin          ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\
+    int16_t bMax            ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\
+    uint16_t bRes           ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\
+    } subrange[numSubRanges];                   \
+}
+
+// 5.2.3.3 4-byte Control RANGE Parameter Block
+#define audio_control_range_4_n_t(numSubRanges) \
+    struct TU_ATTR_PACKED {                     \
+  uint16_t wNumSubRanges;                       \
+  struct TU_ATTR_PACKED {                       \
+      int32_t bMin          ; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\
+    int32_t bMax            ; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\
+    uint32_t bRes           ; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\
+    } subrange[numSubRanges];                   \
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/** @} */
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
new file mode 100644
index 0000000..d9f2e28
--- /dev/null
+++ b/src/class/audio/audio_device.c
@@ -0,0 +1,2290 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Reinhard Panhuber, 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.
+ */
+
+/*
+ * This driver supports at most one out EP, one in EP, one control EP, and one feedback EP and one alternative interface other than zero. Hence, only one input terminal and one output terminal are support, if you need more adjust the driver!
+ * It supports multiple TX and RX channels.
+ *
+ * In case you need more alternate interfaces, you need to define additional defines for this specific alternate interface. Just define them and set them in the set_interface function.
+ *
+ * There are three data flow structures currently implemented, where at least one SW-FIFO is used to decouple the asynchronous processes MCU vs. host
+ *
+ * 1. Input data -> SW-FIFO -> MCU USB
+ *
+ * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_xfer_fifo() is available)
+ *
+ * 2. Input data -> SW-FIFO -> Linear buffer -> MCU USB
+ *
+ * In case the target MCU can not handle a SW-FIFO, a linear buffer is used. This uses the default function dcd_edpt_xfer(). In this case more memory is required.
+ *
+ * 3. (Input data 1 | Input data 2 | ... | Input data N) ->  (SW-FIFO 1 | SW-FIFO 2 | ... | SW-FIFO N) -> Linear buffer -> MCU USB
+ *
+ * This case is used if you have more channels which need to be combined into one stream. Every channel has its own SW-FIFO. All data is encoded into an Linear buffer.
+ *
+ * The same holds in the RX case.
+ *
+ * */
+
+#include "tusb_option.h"
+
+#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "audio_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+// 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
+#define TUD_AUDIO_PREFER_RING_BUFFER 0
+#else
+#define TUD_AUDIO_PREFER_RING_BUFFER 1
+#endif
+#endif
+
+// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer
+// is available or driver is would need to be changed dramatically
+
+// Only STM32 synopsys and dcd_transdimension use non-linear buffer for now
+// Synopsys detection copied from dcd_synopsys.c (refactor later on)
+#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
+    defined (STM32F107xB) || defined (STM32F107xC)
+#define STM32F1_SYNOPSYS
+#endif
+
+#if defined (STM32L475xx) || defined (STM32L476xx) ||                          \
+    defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
+    defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
+    defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
+#define STM32L4_SYNOPSYS
+#endif
+
+#if (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \
+    CFG_TUSB_MCU == OPT_MCU_STM32F2                               || \
+    CFG_TUSB_MCU == OPT_MCU_STM32F4                               || \
+    CFG_TUSB_MCU == OPT_MCU_STM32F7                               || \
+    CFG_TUSB_MCU == OPT_MCU_STM32H7                               || \
+    (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) || \
+    CFG_TUSB_MCU == OPT_MCU_RX63X                                 || \
+    CFG_TUSB_MCU == OPT_MCU_RX65X                                 || \
+    CFG_TUSB_MCU == OPT_MCU_RX72N                                 || \
+    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_MSP432E4
+#if TUD_AUDIO_PREFER_RING_BUFFER
+#define  USE_LINEAR_BUFFER     0
+#else
+#define  USE_LINEAR_BUFFER     1
+#endif
+#else
+#define  USE_LINEAR_BUFFER     1
+#endif
+
+// Declaration of buffers
+
+// Check for maximum supported numbers
+#if CFG_TUD_AUDIO > 3
+#error Maximum number of audio functions restricted to three!
+#endif
+
+// EP IN software buffers and mutexes
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t ep_in_ff_mutex_wr_1;                                                             // No need for read mutex as only USB driver reads from FIFO
+#endif
+#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t ep_in_ff_mutex_wr_2;                                                             // No need for read mutex as only USB driver reads from FIFO
+#endif
+#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t ep_in_ff_mutex_wr_3;                                                             // No need for read mutex as only USB driver reads from FIFO
+#endif
+#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
+#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+
+// Linear buffer TX in case:
+// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR
+// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
+#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
+#endif
+#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
+
+// EP OUT software buffers and mutexes
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t ep_out_ff_mutex_rd_1;                                                            // No need for write mutex as only USB driver writes into FIFO
+#endif
+#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t ep_out_ff_mutex_rd_2;                                                            // No need for write mutex as only USB driver writes into FIFO
+#endif
+#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t ep_out_ff_mutex_rd_3;                                                            // No need for write mutex as only USB driver writes into FIFO
+#endif
+#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+
+// Linear buffer RX in case:
+// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR
+// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
+#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
+#endif
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
+
+// Control buffers
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
+#if CFG_TUD_AUDIO > 1
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
+#endif
+#if CFG_TUD_AUDIO > 2
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
+#endif
+
+// Active alternate setting of interfaces
+uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
+uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
+uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
+#endif
+
+// Software encoding/decoding support FIFOs
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
+tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];                   // No need for read mutex as only USB driver reads from FIFO
+#endif
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
+tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];                   // No need for read mutex as only USB driver reads from FIFO
+#endif
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
+tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];                   // No need for read mutex as only USB driver reads from FIFO
+#endif
+#endif
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
+tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];                   // No need for write mutex as only USB driver writes into FIFO
+#endif
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
+tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];                   // No need for write mutex as only USB driver writes into FIFO
+#endif
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
+tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
+#if CFG_FIFO_MUTEX
+osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];                   // No need for write mutex as only USB driver writes into FIFO
+#endif
+#endif
+#endif
+
+typedef struct
+{
+  uint8_t rhport;
+  uint8_t const * p_desc;       // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+  uint8_t ep_in;                // TX audio data EP.
+  uint16_t ep_in_sz;            // Current size of TX EP
+  uint8_t ep_in_as_intf_num;    // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+  uint8_t ep_out;               // Incoming (into uC) audio data EP.
+  uint16_t ep_out_sz;           // Current size of RX EP
+  uint8_t ep_out_as_intf_num;   // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
+
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+  uint8_t ep_fb;                // Feedback EP.
+#endif
+
+#endif
+
+#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
+  uint8_t ep_int_ctr;           // Audio control interrupt EP.
+#endif
+
+  /*------------- From this point, data is not cleared by bus reset -------------*/
+
+  uint16_t desc_length;         // Length of audio function descriptor
+
+  // Buffer for control requests
+  uint8_t * ctrl_buf;
+  uint8_t ctrl_buf_sz;
+
+  // Current active alternate settings
+  uint8_t * alt_setting;   // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP!
+
+  // EP Transfer buffers and FIFOs
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+#if !CFG_TUD_AUDIO_ENABLE_DECODING
+  tu_fifo_t ep_out_ff;
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+  uint32_t fb_val;                                                              // Feedback value for asynchronous mode (in 16.16 format).
+#endif
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+  tu_fifo_t ep_in_ff;
+#endif
+
+  // 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];
+#endif
+
+  // Decoding parameters - parameters are set when alternate AS interface is set by host
+  // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently.
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
+  audio_format_type_t format_type_rx;
+  uint8_t n_channels_rx;
+
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
+  audio_data_format_type_I_t format_type_I_rx;
+  uint8_t n_bytes_per_sampe_rx;
+  uint8_t n_channels_per_ff_rx;
+  uint8_t n_ff_used_rx;
+#endif
+#endif
+
+  // Encoding parameters - parameters are set when alternate AS interface is set by host
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+  audio_format_type_t format_type_tx;
+  uint8_t n_channels_tx;
+
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
+  audio_data_format_type_I_t format_type_I_tx;
+  uint8_t n_bytes_per_sampe_tx;
+  uint8_t n_channels_per_ff_tx;
+  uint8_t n_ff_used_tx;
+#endif
+#endif
+
+  // Support FIFOs for software encoding and decoding
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
+  tu_fifo_t * rx_supp_ff;
+  uint8_t n_rx_supp_ff;
+  uint16_t rx_supp_ff_sz_max;
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+  tu_fifo_t * tx_supp_ff;
+  uint8_t n_tx_supp_ff;
+  uint16_t tx_supp_ff_sz_max;
+#endif
+
+  // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
+  uint8_t * lin_buf_out;
+#define USE_LINEAR_BUFFER_RX   1
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
+  uint8_t * lin_buf_in;
+#define USE_LINEAR_BUFFER_TX   1
+#endif
+
+} audiod_function_t;
+
+#ifndef USE_LINEAR_BUFFER_TX
+#define USE_LINEAR_BUFFER_TX   0
+#endif
+
+#ifndef USE_LINEAR_BUFFER_RX
+#define USE_LINEAR_BUFFER_RX   0
+#endif
+
+#define ITF_MEM_RESET_SIZE   offsetof(audiod_function_t, ctrl_buf)
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+CFG_TUSB_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
+static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
+static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio);
+#endif
+
+static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request);
+static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request);
+
+static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int);
+static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int);
+static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id);
+static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id);
+static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id);
+static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio);
+
+#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
+static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf);
+
+static inline uint8_t tu_desc_subtype(void const* desc)
+{
+  return ((uint8_t const*) desc)[2];
+}
+#endif
+
+bool tud_audio_n_mounted(uint8_t func_id)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO);
+  audiod_function_t* audio = &_audiod_fct[func_id];
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+  if (audio->ep_out == 0) return false;
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+  if (audio->ep_in == 0) return false;
+#endif
+
+#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
+  if (audio->ep_int_ctr == 0) return false;
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+  if (audio->ep_fb == 0) return false;
+#endif
+
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// READ API
+//--------------------------------------------------------------------+
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+
+uint16_t tud_audio_n_available(uint8_t func_id)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
+  return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff);
+}
+
+uint16_t tud_audio_n_read(uint8_t func_id, void* buffer, uint16_t bufsize)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
+  return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize);
+}
+
+bool tud_audio_n_clear_ep_out_ff(uint8_t func_id)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
+  return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff);
+}
+
+tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id)
+{
+  if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff;
+  return NULL;
+}
+
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
+// Delete all content in the support RX FIFOs
+bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
+  return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
+}
+
+uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
+  return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
+}
+
+uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
+  return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize);
+}
+
+tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
+{
+  if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx];
+  return NULL;
+}
+#endif
+
+// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels).
+// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0.
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+
+static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
+{
+  uint8_t idxItf;
+  uint8_t const *dummy2;
+  uint8_t idx_audio_fct = 0;
+
+  if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb)
+  {
+    idx_audio_fct = audiod_get_audio_fct_idx(audio);
+    TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2));
+  }
+
+  // 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 CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
+
+  switch (audio->format_type_rx)
+  {
+    case AUDIO_FORMAT_TYPE_UNDEFINED:
+      // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE!
+      TU_LOG2("  Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
+      TU_BREAKPOINT();
+      break;
+
+    case AUDIO_FORMAT_TYPE_I:
+
+      switch (audio->format_type_I_tx)
+      {
+        case AUDIO_DATA_FORMAT_TYPE_I_PCM:
+          TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received));
+          break;
+
+        default:
+          // DESIRED CFG_TUD_AUDIO_FORMAT_TYPE_I_RX NOT IMPLEMENTED!
+          TU_LOG2("  Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n");
+          TU_BREAKPOINT();
+          break;
+      }
+      break;
+
+        default:
+          // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!
+          TU_LOG2("  Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n");
+          TU_BREAKPOINT();
+          break;
+  }
+
+  // Prepare for next transmission
+  TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
+
+#else
+
+#if USE_LINEAR_BUFFER_RX
+  // Data currently is in linear buffer, copy into EP OUT FIFO
+  TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received));
+
+  // Schedule for next receive
+  TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
+#else
+  // Data is already placed in EP FIFO, schedule for next receive
+  TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
+#endif
+
+#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]));
+
+  return true;
+}
+
+#endif //CFG_TUD_AUDIO_ENABLE_EP_OUT
+
+// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0
+#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
+
+// Decoding according to 2.3.1.5 Audio Streams
+
+// Helper function
+static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used)
+{
+
+  // This function is an optimized version of
+  //  while((uint8_t *)dst < dst_end)
+  //  {
+  //    memcpy(dst, src, nBytesToCopy);
+  //    dst = (uint8_t *)dst + nBytesToCopy;
+  //    src += nBytesToCopy * n_ff_used;
+  //  }
+
+  // Optimize for fast half word copies
+  typedef struct{
+    uint16_t val;
+  } __attribute((__packed__)) unaligned_uint16_t;
+
+  // Optimize for fast word copies
+  typedef struct{
+    uint32_t val;
+  } __attribute((__packed__)) unaligned_uint32_t;
+
+  switch (nBytesToCopy)
+  {
+    case 1:
+      while((uint8_t *)dst < dst_end)
+      {
+        *(uint8_t *)dst++ = *src;
+        src += n_ff_used;
+      }
+      break;
+
+    case 2:
+      while((uint8_t *)dst < dst_end)
+      {
+        *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
+        dst += 2;
+        src += 2 * n_ff_used;
+      }
+      break;
+
+    case 3:
+      while((uint8_t *)dst < dst_end)
+      {
+        //        memcpy(dst, src, 3);
+        //        dst = (uint8_t *)dst + 3;
+        //        src += 3 * n_ff_used;
+
+        // TODO: Is there a faster way to copy 3 bytes?
+        *(uint8_t *)dst++ = *src++;
+        *(uint8_t *)dst++ = *src++;
+        *(uint8_t *)dst++ = *src++;
+
+        src += 3 * (n_ff_used - 1);
+      }
+      break;
+
+    case 4:
+      while((uint8_t *)dst < dst_end)
+      {
+        *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
+        dst += 4;
+        src += 4 * n_ff_used;
+      }
+      break;
+  }
+
+  return src;
+}
+
+static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
+{
+  (void) rhport;
+
+  // Determine amount of samples
+  uint8_t const n_ff_used               = audio->n_ff_used_rx;
+  uint16_t const nBytesPerFFToRead      = n_bytes_received / n_ff_used;
+  uint8_t cnt_ff;
+
+  // Decode
+  uint8_t * src;
+  uint8_t * dst_end;
+
+  tu_fifo_buffer_info_t info;
+
+  for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
+  {
+    tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info);
+
+    if (info.len_lin != 0)
+    {
+      info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
+      src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx];
+      dst_end = info.ptr_lin + info.len_lin;
+      src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used);
+
+      // Handle wrapped part of FIFO
+      info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
+      if (info.len_wrap != 0)
+      {
+        dst_end = info.ptr_wrap + info.len_wrap;
+        audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used);
+      }
+      tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
+    }
+  }
+
+  // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it
+  // TU_VERIFY(cnt != n_bytes);
+
+  return true;
+}
+#endif //CFG_TUD_AUDIO_ENABLE_DECODING
+
+//--------------------------------------------------------------------+
+// WRITE API
+//--------------------------------------------------------------------+
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+
+/**
+ * \brief           Write data to EP in buffer
+ *
+ *  Write data to buffer. If it is full, new data can be inserted once a transmit was scheduled. See audiod_tx_done_cb().
+ *  If TX FIFOs are used, this function is not available in order to not let the user mess up the encoding process.
+ *
+ * \param[in]       func_id: Index of audio function interface
+ * \param[in]       data: Pointer to data array to be copied from
+ * \param[in]       len: # of array elements to copy
+ * \return          Number of bytes actually written
+ */
+uint16_t tud_audio_n_write(uint8_t func_id, const void * data, uint16_t len)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
+  return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len);
+}
+
+bool tud_audio_n_clear_ep_in_ff(uint8_t func_id)                          // Delete all content in the EP IN FIFO
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
+  return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff);
+}
+
+tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id)
+{
+  if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff;
+  return NULL;
+}
+
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
+
+uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id)                 // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
+  audiod_function_t* audio = &_audiod_fct[func_id];
+
+  uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]);
+
+  TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio));
+
+  n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]);
+  n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size;
+
+  return n_bytes_copied;
+}
+
+bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
+  return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]);
+}
+
+uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
+  return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len);
+}
+
+tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
+{
+  if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx];
+  return NULL;
+}
+
+#endif
+
+
+#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
+
+// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user
+uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len)
+{
+  TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
+
+  // We write directly into the EP's buffer - abort if previous transfer not complete
+  TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr));
+
+  // Check length
+  TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE);
+
+  memcpy(_audiod_fct[func_id].ep_int_ctr_buf, buffer, len);
+
+  // Schedule transmit
+  TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len));
+
+  return true;
+}
+
+#endif
+
+
+// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
+// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write.
+
+// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame.
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio)
+{
+  uint8_t idxItf;
+  uint8_t const *dummy2;
+
+  uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
+  TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2));
+
+  // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications
+  if (audio->alt_setting[idxItf] == 0) return false;
+
+  // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or
+  // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer().
+  if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
+
+  // Send everything in ISO EP FIFO
+  uint16_t n_bytes_tx;
+
+  // If support FIFOs are used, encode and schedule transmit
+#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
+  switch (audio->format_type_tx)
+  {
+    case AUDIO_FORMAT_TYPE_UNDEFINED:
+      // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE!
+      TU_LOG2("  Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
+      TU_BREAKPOINT();
+      n_bytes_tx = 0;
+      break;
+
+    case AUDIO_FORMAT_TYPE_I:
+
+      switch (audio->format_type_I_tx)
+      {
+        case AUDIO_DATA_FORMAT_TYPE_I_PCM:
+
+          n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio);
+          break;
+
+        default:
+          // YOUR ENCODING IS REQUIRED HERE!
+          TU_LOG2("  Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n");
+          TU_BREAKPOINT();
+          n_bytes_tx = 0;
+          break;
+      }
+      break;
+
+        default:
+          // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!
+          TU_LOG2("  Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n");
+          TU_BREAKPOINT();
+          n_bytes_tx = 0;
+          break;
+  }
+
+  TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
+
+#else
+  // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule
+
+  n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz);      // Limit up to max packet size, more can not be done for ISO
+
+#if USE_LINEAR_BUFFER_TX
+  tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx);
+  TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
+#else
+  // Send everything in ISO EP FIFO
+  TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx));
+#endif
+
+#endif
+
+  // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame
+  if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
+
+  return true;
+}
+
+#endif //CFG_TUD_AUDIO_ENABLE_EP_IN
+
+#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
+// Take samples from the support buffer and encode them into the IN EP software FIFO
+// Returns number of bytes written into linear buffer
+
+/* 2.3.1.7.1 PCM Format
+The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio
+data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It
+is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused
+bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the
+range [-1, +1)
+ */
+
+/*
+ * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples
+ * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and
+ * does not change the number of bytes per sample.
+ * */
+
+// Helper function
+static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used)
+{
+  // Optimize for fast half word copies
+  typedef struct{
+    uint16_t val;
+  } __attribute((__packed__)) unaligned_uint16_t;
+
+  // Optimize for fast word copies
+  typedef struct{
+    uint32_t val;
+  } __attribute((__packed__)) unaligned_uint32_t;
+
+  switch (nBytesToCopy)
+  {
+    case 1:
+      while(src < src_end)
+      {
+        *dst = *src++;
+        dst += n_ff_used;
+      }
+      break;
+
+    case 2:
+      while(src < src_end)
+      {
+        *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
+        src += 2;
+        dst += 2 * n_ff_used;
+      }
+      break;
+
+    case 3:
+      while(src < src_end)
+      {
+        //        memcpy(dst, src, 3);
+        //        src = (uint8_t *)src + 3;
+        //        dst += 3 * n_ff_used;
+
+        // TODO: Is there a faster way to copy 3 bytes?
+        *dst++ = *src++;
+        *dst++ = *src++;
+        *dst++ = *src++;
+
+        dst += 3 * (n_ff_used - 1);
+      }
+      break;
+
+    case 4:
+      while(src < src_end)
+      {
+        *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
+        src += 4;
+        dst += 4 * n_ff_used;
+      }
+      break;
+  }
+
+  return dst;
+}
+
+static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio)
+{
+  // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap
+  // This is ensured within set_interface, where the FIFOs are reconfigured according to this size
+
+  // We encode directly into IN EP's linear buffer - abort if previous transfer not complete
+  TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
+
+  // Determine amount of samples
+  uint8_t const n_ff_used               = audio->n_ff_used_tx;
+  uint16_t const nBytesToCopy           = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx;
+  uint16_t const capPerFF               = audio->ep_in_sz / n_ff_used;                                        // Sample capacity per FIFO in bytes
+  uint16_t nBytesPerFFToSend            = tu_fifo_count(&audio->tx_supp_ff[0]);
+  uint8_t cnt_ff;
+
+  for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++)
+  {
+    uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]);
+    if (count < nBytesPerFFToSend)
+    {
+      nBytesPerFFToSend = count;
+    }
+  }
+
+  // Check if there is enough
+  if (nBytesPerFFToSend == 0)    return 0;
+
+  // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
+  nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF);
+
+  // Round to full number of samples (flooring)
+  nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy;
+
+  // Encode
+  uint8_t * dst;
+  uint8_t * src_end;
+
+  tu_fifo_buffer_info_t info;
+
+  for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
+  {
+    dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx];
+
+    tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info);
+
+    if (info.len_lin != 0)
+    {
+      info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin);       // Limit up to desired length
+      src_end = (uint8_t *)info.ptr_lin + info.len_lin;
+      dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used);
+
+      // Limit up to desired length
+      info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
+
+      // Handle wrapped part of FIFO
+      if (info.len_wrap != 0)
+      {
+        src_end = (uint8_t *)info.ptr_wrap + info.len_wrap;
+        audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used);
+      }
+
+      tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
+    }
+  }
+
+  return nBytesPerFFToSend * n_ff_used;
+}
+#endif //CFG_TUD_AUDIO_ENABLE_ENCODING
+
+// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent
+
+#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);
+}
+#endif
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void audiod_init(void)
+{
+  tu_memclr(_audiod_fct, sizeof(_audiod_fct));
+
+  for(uint8_t i=0; i<CFG_TUD_AUDIO; i++)
+  {
+    audiod_function_t* audio = &_audiod_fct[i];
+
+    // Initialize control buffers
+    switch (i)
+    {
+      case 0:
+        audio->ctrl_buf = ctrl_buf_1;
+        audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ;
+        break;
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0
+      case 1:
+        audio->ctrl_buf = ctrl_buf_2;
+        audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0
+      case 2:
+        audio->ctrl_buf = ctrl_buf_3;
+        audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ;
+        break;
+#endif
+    }
+
+    // Initialize active alternate interface buffers
+    switch (i)
+    {
+#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0
+      case 0:
+        audio->alt_setting = alt_setting_1;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
+      case 1:
+        audio->alt_setting = alt_setting_2;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
+      case 2:
+        audio->alt_setting = alt_setting_3;
+        break;
+#endif
+    }
+
+    // Initialize IN EP FIFO if required
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+
+    switch (i)
+    {
+#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
+      case 0:
+        tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+        tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL);
+#endif
+        break;
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
+      case 1:
+        tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+        tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL);
+#endif
+        break;
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
+      case 2:
+        tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+        tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL);
+#endif
+        break;
+#endif
+    }
+#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+
+    // Initialize linear buffers
+#if USE_LINEAR_BUFFER_TX
+    switch (i)
+    {
+#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
+      case 0:
+        audio->lin_buf_in = lin_buf_in_1;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
+      case 1:
+        audio->lin_buf_in = lin_buf_in_2;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
+      case 2:
+        audio->lin_buf_in = lin_buf_in_3;
+        break;
+#endif
+    }
+#endif // USE_LINEAR_BUFFER_TX
+
+    // Initialize OUT EP FIFO if required
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+
+    switch (i)
+    {
+#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
+      case 0:
+        tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+        tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1));
+#endif
+        break;
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
+      case 1:
+        tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+        tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2));
+#endif
+        break;
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
+      case 2:
+        tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+        tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3));
+#endif
+        break;
+#endif
+    }
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+
+    // Initialize linear buffers
+#if USE_LINEAR_BUFFER_RX
+    switch (i)
+    {
+#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
+      case 0:
+        audio->lin_buf_out = lin_buf_out_1;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
+      case 1:
+        audio->lin_buf_out = lin_buf_out_2;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
+      case 2:
+        audio->lin_buf_out = lin_buf_out_3;
+        break;
+#endif
+    }
+#endif // USE_LINEAR_BUFFER_TX
+
+    // Initialize TX support FIFOs if required
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+
+    switch (i)
+    {
+#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
+      case 0:
+        audio->tx_supp_ff = tx_supp_ff_1;
+        audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO;
+        audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ;
+        for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++)
+        {
+          tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+          tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL);
+#endif
+        }
+
+        break;
+#endif // CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
+
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
+      case 1:
+        audio->tx_supp_ff = tx_supp_ff_2;
+        audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO;
+        audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ;
+        for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++)
+        {
+          tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+          tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL);
+#endif
+        }
+
+        break;
+#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
+
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
+      case 2:
+        audio->tx_supp_ff = tx_supp_ff_3;
+        audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO;
+        audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ;
+        for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++)
+        {
+          tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+          tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL);
+#endif
+        }
+
+        break;
+#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
+    }
+#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+
+    // Set encoding parameters for Type_I formats
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
+    switch (i)
+    {
+#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
+      case 0:
+        audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
+      case 1:
+        audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
+      case 2:
+        audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX;
+        break;
+#endif
+    }
+#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
+
+    // Initialize RX support FIFOs if required
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
+
+    switch (i)
+    {
+#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
+      case 0:
+        audio->rx_supp_ff = rx_supp_ff_1;
+        audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO;
+        audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ;
+        for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++)
+        {
+          tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+          tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL);
+#endif
+        }
+
+        break;
+#endif // CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
+
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
+      case 1:
+        audio->rx_supp_ff = rx_supp_ff_2;
+        audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO;
+        audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ;
+        for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++)
+        {
+          tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+          tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL);
+#endif
+        }
+
+        break;
+#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
+
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
+      case 2:
+        audio->rx_supp_ff = rx_supp_ff_3;
+        audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO;
+        audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ;
+        for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++)
+        {
+          tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true);
+#if CFG_FIFO_MUTEX
+          tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL);
+#endif
+        }
+
+        break;
+#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
+    }
+#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+
+    // Set encoding parameters for Type_I formats
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
+    switch (i)
+    {
+#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
+      case 0:
+        audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
+      case 1:
+        audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX;
+        break;
+#endif
+#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
+      case 2:
+        audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX;
+        break;
+#endif
+    }
+#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
+  }
+}
+
+void audiod_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  for(uint8_t i=0; i<CFG_TUD_AUDIO; i++)
+  {
+    audiod_function_t* audio = &_audiod_fct[i];
+    tu_memclr(audio, ITF_MEM_RESET_SIZE);
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+    tu_fifo_clear(&audio->ep_in_ff);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+    tu_fifo_clear(&audio->ep_out_ff);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+    for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
+    {
+      tu_fifo_clear(&audio->tx_supp_ff[cnt]);
+    }
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
+    for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
+    {
+      tu_fifo_clear(&audio->rx_supp_ff[cnt]);
+    }
+#endif
+  }
+}
+
+uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
+{
+  (void) max_len;
+
+  TU_VERIFY ( TUSB_CLASS_AUDIO  == itf_desc->bInterfaceClass &&
+              AUDIO_SUBCLASS_CONTROL    == itf_desc->bInterfaceSubClass);
+
+  // Verify version is correct - this check can be omitted
+  TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2);
+
+  // Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted
+  if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed
+  {
+    TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0);
+  }
+
+  // Alternate setting MUST be zero - this check can be omitted
+  TU_VERIFY(itf_desc->bAlternateSetting == 0);
+
+  // Find available audio driver interface
+  uint8_t i;
+  for (i = 0; i < CFG_TUD_AUDIO; i++)
+  {
+    if (!_audiod_fct[i].p_desc)
+    {
+      _audiod_fct[i].p_desc = (uint8_t const *)itf_desc;    // Save pointer to AC descriptor which is by specification always the first one
+      _audiod_fct[i].rhport = rhport;
+
+      // Setup descriptor lengths
+      switch (i)
+      {
+        case 0:
+          _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN;
+          break;
+#if CFG_TUD_AUDIO > 1
+        case 1:
+          _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN;
+          break;
+#endif
+#if CFG_TUD_AUDIO > 2
+        case 2:
+          _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN;
+          break;
+#endif
+      }
+
+      break;
+    }
+  }
+
+  // Verify we found a free one
+  TU_ASSERT( i < CFG_TUD_AUDIO );
+
+  // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification)
+  uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;    // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor
+
+  return drv_len;
+}
+
+static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+  uint8_t const itf = tu_u16_low(p_request->wIndex);
+
+  // Find index of audio streaming interface
+  uint8_t func_id, idxItf;
+  uint8_t const *dummy;
+
+  TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy));
+  TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1));
+
+  TU_LOG2("  Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]);
+
+  return true;
+}
+
+static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+  (void) rhport;
+
+  // Here we need to do the following:
+
+  // 1. Find the audio driver assigned to the given interface to be set
+  // Since one audio driver interface has to be able to cover an unknown number of interfaces (AC, AS + its alternate settings), the best memory efficient way to solve this is to always search through the descriptors.
+  // The audio driver is mapped to an audio function by a reference pointer to the corresponding AC interface of this audio function which serves as a starting point for searching
+
+  // 2. Close EPs which are currently open
+  // To do so it is not necessary to know the current active alternate interface since we already save the current EP addresses - we simply close them
+
+  // 3. Open new EP
+
+  uint8_t const itf = tu_u16_low(p_request->wIndex);
+  uint8_t const alt = tu_u16_low(p_request->wValue);
+
+  TU_LOG2("  Set itf: %u - alt: %u\r\n", itf, alt);
+
+  // Find index of audio streaming interface and index of interface
+  uint8_t func_id, idxItf;
+  uint8_t const *p_desc;
+  TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc));
+
+  audiod_function_t* audio = &_audiod_fct[func_id];
+
+  // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open)
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+  if (audio->ep_in_as_intf_num == itf)
+  {
+    audio->ep_in_as_intf_num = 0;
+    usbd_edpt_close(rhport, audio->ep_in);
+
+    // Clear FIFOs, since data is no longer valid
+#if !CFG_TUD_AUDIO_ENABLE_ENCODING
+    tu_fifo_clear(&audio->ep_in_ff);
+#else
+    for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
+    {
+      tu_fifo_clear(&audio->tx_supp_ff[cnt]);
+    }
+#endif
+    
+    // Invoke callback - can be used to stop data sampling
+    if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
+
+    audio->ep_in = 0;                           // Necessary?
+
+  }
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+  if (audio->ep_out_as_intf_num == itf)
+  {
+    audio->ep_out_as_intf_num = 0;
+    usbd_edpt_close(rhport, audio->ep_out);
+
+    // Clear FIFOs, since data is no longer valid
+#if !CFG_TUD_AUDIO_ENABLE_DECODING
+    tu_fifo_clear(&audio->ep_out_ff);
+#else
+    for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
+    {
+      tu_fifo_clear(&audio->rx_supp_ff[cnt]);
+    }
+#endif
+
+    // Invoke callback - can be used to stop data sampling
+    if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
+
+    audio->ep_out = 0;                          // Necessary?
+
+    // Close corresponding feedback EP
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+    usbd_edpt_close(rhport, audio->ep_fb);
+    audio->ep_fb = 0;                           // Necessary?
+#endif
+  }
+#endif
+
+  // Save current alternative interface setting
+  audio->alt_setting[idxItf] = alt;
+
+  // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface
+  // Get pointer at end
+  uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
+
+  // p_desc starts at required interface with alternate setting zero
+  while (p_desc < p_desc_end)
+  {
+    // Find correct interface
+    if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt)
+    {
+#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
+      uint8_t const * p_desc_parse_for_params = p_desc;
+#endif
+      // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary
+      uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints;
+      while (foundEPs < nEps && p_desc < p_desc_end)
+      {
+        if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
+        {
+          tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+          TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
+
+          uint8_t const ep_addr = desc_ep->bEndpointAddress;
+
+          //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND!
+          usbd_edpt_clear_stall(rhport, ep_addr);
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+          if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00)   // Check if usage is data EP
+          {
+            // Save address
+            audio->ep_in = ep_addr;
+            audio->ep_in_as_intf_num = itf;
+            audio->ep_in_sz = tu_edpt_packet_size(desc_ep);
+
+            // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters
+#if CFG_TUD_AUDIO_ENABLE_ENCODING
+            audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
+
+            // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
+            const uint16_t active_fifo_depth = (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);
+            }
+            audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx;
+            TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff );
+#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
+            TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
+          }
+#endif // CFG_TUD_AUDIO_ENABLE_EP_IN
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+
+          if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT)     // Checking usage not necessary
+          {
+            // Save address
+            audio->ep_out = ep_addr;
+            audio->ep_out_as_intf_num = itf;
+            audio->ep_out_sz = tu_edpt_packet_size(desc_ep);
+
+#if CFG_TUD_AUDIO_ENABLE_DECODING
+            audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
+
+            // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
+            const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx;
+            for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
+            {
+              tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
+            }
+            audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx;
+            TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff );
+#endif
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+            // In case of asynchronous EP, call Cb after ep_fb is set
+            if ( !(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);
+#else
+            TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
+#endif
+          }
+
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+          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;
+
+            // Invoke callback after ep_out is set
+            if (audio->ep_out != 0)
+            {
+              if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+            }
+          }
+#endif
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
+
+          foundEPs += 1;
+        }
+        p_desc = tu_desc_next(p_desc);
+      }
+
+      TU_VERIFY(foundEPs == nEps);
+
+      // We are done - abort loop
+      break;
+    }
+
+    // Moving forward
+    p_desc = tu_desc_next(p_desc);
+  }
+
+  tud_control_status(rhport, p_request);
+
+  return true;
+}
+
+// Invoked when class request DATA stage is finished.
+// return false to stall control EP (e.g Host send non-sense DATA)
+static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+  // Handle audio class specific set requests
+  if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT)
+  {
+    uint8_t func_id;
+
+    switch (p_request->bmRequestType_bit.recipient)
+    {
+      case TUSB_REQ_RCPT_INTERFACE:
+      {
+        uint8_t itf = TU_U16_LOW(p_request->wIndex);
+        uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+        if (entityID != 0)
+        {
+          if (tud_audio_set_req_entity_cb)
+          {
+            // Check if entity is present and get corresponding driver index
+            TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+
+            // Invoke callback
+            return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+          }
+          else
+          {
+            TU_LOG2("  No entity set request callback available!\r\n");
+            return false;     // In case no callback function is present or request can not be conducted we stall it
+          }
+        }
+        else
+        {
+          if (tud_audio_set_req_itf_cb)
+          {
+            // Find index of audio driver structure and verify interface really exists
+            TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+
+            // Invoke callback
+            return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+          }
+          else
+          {
+            TU_LOG2("  No interface set request callback available!\r\n");
+            return false;     // In case no callback function is present or request can not be conducted we stall it
+          }
+        }
+      }
+      break;
+
+      case TUSB_REQ_RCPT_ENDPOINT:
+      {
+        uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+        if (tud_audio_set_req_ep_cb)
+        {
+          // Check if entity is present and get corresponding driver index
+          TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
+
+          // Invoke callback
+          return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+        }
+        else
+        {
+          TU_LOG2("  No EP set request callback available!\r\n");
+          return false;   // In case no callback function is present or request can not be conducted we stall it
+        }
+      }
+      break;
+      // Unknown/Unsupported recipient
+      default: TU_BREAKPOINT(); return false;
+    }
+  }
+  return true;
+}
+
+// Handle class control request
+// return false to stall control endpoint (e.g unsupported request)
+static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+  (void) rhport;
+
+  // Handle standard requests - standard set requests usually have no data stage so we also handle set requests here
+  if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
+  {
+    switch (p_request->bRequest)
+    {
+      case TUSB_REQ_GET_INTERFACE:
+        return audiod_get_interface(rhport, p_request);
+
+      case TUSB_REQ_SET_INTERFACE:
+        return audiod_set_interface(rhport, p_request);
+
+        // Unknown/Unsupported request
+      default: TU_BREAKPOINT(); return false;
+    }
+  }
+
+  // Handle class requests
+  if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
+  {
+    uint8_t itf = TU_U16_LOW(p_request->wIndex);
+    uint8_t func_id;
+
+    // Conduct checks which depend on the recipient
+    switch (p_request->bmRequestType_bit.recipient)
+    {
+      case TUSB_REQ_RCPT_INTERFACE:
+      {
+        uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+        // Verify if entity is present
+        if (entityID != 0)
+        {
+          // Find index of audio driver structure and verify entity really exists
+          TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+
+          // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+          if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
+          {
+            if (tud_audio_get_req_entity_cb)
+            {
+              return tud_audio_get_req_entity_cb(rhport, p_request);
+            }
+            else
+            {
+              TU_LOG2("  No entity get request callback available!\r\n");
+              return false;   // Stall
+            }
+          }
+        }
+        else
+        {
+          // Find index of audio driver structure and verify interface really exists
+          TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+
+          // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+          if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
+          {
+            if (tud_audio_get_req_itf_cb)
+            {
+              return tud_audio_get_req_itf_cb(rhport, p_request);
+            }
+            else
+            {
+              TU_LOG2("  No interface get request callback available!\r\n");
+              return false;   // Stall
+            }
+          }
+        }
+      }
+      break;
+
+      case TUSB_REQ_RCPT_ENDPOINT:
+      {
+        uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+        // Find index of audio driver structure and verify EP really exists
+        TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
+
+        // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+        if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
+        {
+          if (tud_audio_get_req_ep_cb)
+          {
+            return tud_audio_get_req_ep_cb(rhport, p_request);
+          }
+          else
+          {
+            TU_LOG2("  No EP get request callback available!\r\n");
+            return false;     // Stall
+          }
+        }
+      }
+      break;
+
+      // Unknown/Unsupported recipient
+      default: TU_LOG2("  Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
+    }
+
+    // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished
+    TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz));
+    return true;
+  }
+
+  // There went something wrong - unsupported control request type
+  TU_BREAKPOINT();
+  return false;
+}
+
+bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  if ( stage == CONTROL_STAGE_SETUP )
+  {
+    return audiod_control_request(rhport, request);
+  }
+  else if ( stage == CONTROL_STAGE_DATA )
+  {
+    return audiod_control_complete(rhport, request);
+  }
+
+  return true;
+}
+
+bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) result;
+  (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++)
+  {
+
+#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
+
+    // Data transmission of control interrupt finished
+    if (_audiod_fct[func_id].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 ???
+      // In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ???
+
+      // I assume here, that things above are handled by PHY
+      // All transmission is done - what remains to do is to inform job was completed
+
+      if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes));
+    }
+
+#endif
+
+#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)
+    {
+      // 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."
+      // This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP.
+
+      // Check if there is data to load into EPs buffer - if not load it with ZLP
+      // Be aware - we as a device are not able to know if the host polls for data with a faster rate as we stated this in the descriptors. Therefore we always have to put something into the EPs buffer. However, once we did that, there is no way of aborting this or replacing what we put into the buffer before!
+      // 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]));
+
+      // Transmission of ZLP is done by audiod_tx_done_cb()
+      return true;
+    }
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+
+    // New audio packet received
+    if (_audiod_fct[func_id].ep_out == ep_addr)
+    {
+      TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_fct[func_id], (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 (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
+
+      // Schedule a transmit with the new value if EP is not busy 
+      if (!usbd_edpt_busy(rhport, _audiod_fct[func_id].ep_fb))
+      {
+        // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
+        return audiod_fb_send(rhport, &_audiod_fct[func_id]);
+      }
+    }
+#endif
+#endif
+  }
+
+  return false;
+}
+
+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
+  if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false;
+
+  // Get corresponding driver index
+  uint8_t func_id;
+  uint8_t itf = TU_U16_LOW(p_request->wIndex);
+
+  // Conduct checks which depend on the recipient
+  switch (p_request->bmRequestType_bit.recipient)
+  {
+    case TUSB_REQ_RCPT_INTERFACE:
+    {
+      uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+      // Verify if entity is present
+      if (entityID != 0)
+      {
+        // Find index of audio driver structure and verify entity really exists
+        TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+      }
+      else
+      {
+        // Find index of audio driver structure and verify interface really exists
+        TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+      }
+    }
+    break;
+
+    case TUSB_REQ_RCPT_ENDPOINT:
+    {
+      uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+      // Find index of audio driver structure and verify EP really exists
+      TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
+    }
+    break;
+
+    // Unknown/Unsupported recipient
+    default: TU_LOG2("  Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
+  }
+
+  // Crop length
+  if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz;
+
+  // Copy into buffer
+  memcpy((void *)_audiod_fct[func_id].ctrl_buf, data, (size_t)len);
+
+  // Schedule transmit
+  return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len);
+}
+
+// This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function
+// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and
+// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero.
+static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int)
+{
+  if (audio->p_desc)
+  {
+    // Get pointer at end
+    uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
+
+    // Advance past AC descriptors
+    uint8_t const *p_desc = tu_desc_next(audio->p_desc);
+    p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
+
+    uint8_t tmp = 0;
+    while (p_desc < p_desc_end)
+    {
+      // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero!
+      if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0)
+      {
+        if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
+        {
+          *idxItf = tmp;
+          *pp_desc_int = p_desc;
+          return true;
+        }
+        // Increase index, bytes read, and pointer
+        tmp++;
+      }
+      p_desc = tu_desc_next(p_desc);
+    }
+  }
+  return false;
+}
+
+// This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function
+// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and
+// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero.
+static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int)
+{
+  // Loop over audio driver interfaces
+  uint8_t i;
+  for (i = 0; i < CFG_TUD_AUDIO; i++)
+  {
+    if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int))
+    {
+      *func_id = i;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// Verify an entity with the given ID exists and returns also the corresponding driver index
+static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id)
+{
+  uint8_t i;
+  for (i = 0; i < CFG_TUD_AUDIO; i++)
+  {
+    // Look for the correct driver by checking if the unique standard AC interface number fits
+    if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf)
+    {
+      // Get pointers after class specific AC descriptors and end of AC descriptors - entities are defined in between
+      uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc);                                          // Points to CS AC descriptor
+      uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc;
+      p_desc = tu_desc_next(p_desc);                                                                            // Get past CS AC descriptor
+
+      while (p_desc < p_desc_end)
+      {
+        if (p_desc[3] == entityID)  // Entity IDs are always at offset 3
+        {
+          *func_id = i;
+          return true;
+        }
+        p_desc = tu_desc_next(p_desc);
+      }
+    }
+  }
+  return false;
+}
+
+static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id)
+{
+  uint8_t i;
+  for (i = 0; i < CFG_TUD_AUDIO; i++)
+  {
+    if (_audiod_fct[i].p_desc)
+    {
+      // Get pointer at beginning and end
+      uint8_t const *p_desc = _audiod_fct[i].p_desc;
+      uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
+
+      while (p_desc < p_desc_end)
+      {
+        if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf)
+        {
+          *func_id = i;
+          return true;
+        }
+        p_desc = tu_desc_next(p_desc);
+      }
+    }
+  }
+  return false;
+}
+
+static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id)
+{
+  uint8_t i;
+  for (i = 0; i < CFG_TUD_AUDIO; i++)
+  {
+    if (_audiod_fct[i].p_desc)
+    {
+      // Get pointer at end
+      uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length;
+
+      // Advance past AC descriptors - EP we look for are streaming EPs
+      uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc);
+      p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
+
+      while (p_desc < p_desc_end)
+      {
+        if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep)
+        {
+          *func_id = i;
+          return true;
+        }
+        p_desc = tu_desc_next(p_desc);
+      }
+    }
+  }
+  return false;
+}
+
+#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
+// p_desc points to the AS interface of alternate setting zero
+// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter
+// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for!
+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)
+{
+  p_desc = tu_desc_next(p_desc);    // Exclude standard AS interface descriptor of current alternate interface descriptor
+
+  while (p_desc < p_desc_end)
+  {
+    // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished
+    if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break;
+
+    // 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)
+      {
+        audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
+        audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType);
+
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
+        audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats);
+#endif
+      }
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+      if (as_itf == audio->ep_out_as_intf_num)
+      {
+        audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
+        audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType;
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
+        audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats;
+#endif
+      }
+#endif
+    }
+
+    // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats)
+#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
+    if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I)
+    {
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
+      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)
+      {
+        audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
+      }
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+      if (as_itf == audio->ep_out_as_intf_num)
+      {
+        audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
+      }
+#endif
+    }
+#endif
+
+    // Other format types are not supported yet
+
+    p_desc = tu_desc_next(p_desc);
+  }
+}
+#endif
+
+#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;
+
+  // For FS format is 10.14
+  *(fb++) = (feedback >> 2) & 0xFF;
+  *(fb++) = (feedback >> 10) & 0xFF;
+  *(fb++) = (feedback >> 18) & 0xFF;
+  // 4th byte is needed to work correctly with MS Windows
+  *fb = 0;
+#else
+  // For HS format is 16.16 as originally demanded
+  _audiod_fct[func_id].fb_val = feedback;
+#endif
+
+  // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
+  if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))
+  {
+    return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]);
+  }
+
+  return true;
+}
+#endif
+
+// No security checks here - internal function only which should always succeed
+uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio)
+{
+  for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++)
+  {
+    if (&_audiod_fct[cnt] == audio) return cnt;
+  }
+  return 0;
+}
+
+#endif //TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO
diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h
new file mode 100644
index 0000000..5a46952
--- /dev/null
+++ b/src/class/audio/audio_device.h
@@ -0,0 +1,627 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Ha Thach (tinyusb.org)
+ * 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.
+ */
+
+#ifndef _TUSB_AUDIO_DEVICE_H_
+#define _TUSB_AUDIO_DEVICE_H_
+
+#include "audio.h"
+
+//--------------------------------------------------------------------+
+// Class Driver Configuration
+//--------------------------------------------------------------------+
+
+// All sizes are in bytes!
+
+#ifndef CFG_TUD_AUDIO_FUNC_1_DESC_LEN
+#error You must tell the driver the length of the audio function descriptor including IAD descriptor
+#endif
+#if CFG_TUD_AUDIO > 1
+#ifndef CFG_TUD_AUDIO_FUNC_2_DESC_LEN
+#error You must tell the driver the length of the audio function descriptor including IAD descriptor
+#endif
+#endif
+#if CFG_TUD_AUDIO > 2
+#ifndef CFG_TUD_AUDIO_FUNC_3_DESC_LEN
+#error You must tell the driver the length of the audio function descriptor including IAD descriptor
+#endif
+#endif
+
+// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces
+#ifndef CFG_TUD_AUDIO_FUNC_1_N_AS_INT
+#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor!
+#endif
+#if CFG_TUD_AUDIO > 1
+#ifndef CFG_TUD_AUDIO_FUNC_2_N_AS_INT
+#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor!
+#endif
+#endif
+#if CFG_TUD_AUDIO > 2
+#ifndef CFG_TUD_AUDIO_FUNC_3_N_AS_INT
+#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor!
+#endif
+#endif
+
+// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors
+#ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ
+#error You must define an audio class control request buffer size!
+#endif
+
+#if CFG_TUD_AUDIO > 1
+#ifndef CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ
+#error You must define an audio class control request buffer size!
+#endif
+#endif
+
+#if CFG_TUD_AUDIO > 2
+#ifndef CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ
+#error You must define an audio class control request buffer size!
+#endif
+#endif
+
+// End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024
+#ifndef CFG_TUD_AUDIO_ENABLE_EP_IN
+#define CFG_TUD_AUDIO_ENABLE_EP_IN 0   // TX
+#endif
+
+#ifndef CFG_TUD_AUDIO_ENABLE_EP_OUT
+#define CFG_TUD_AUDIO_ENABLE_EP_OUT 0  // RX
+#endif
+
+// Maximum EP sizes for all alternate AS interface settings - used for checks and buffer allocation
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX
+#error You must tell the driver the biggest EP IN size!
+#endif
+#if CFG_TUD_AUDIO > 1
+#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX
+#error You must tell the driver the biggest EP IN size!
+#endif
+#endif
+#if CFG_TUD_AUDIO > 2
+#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX
+#error You must tell the driver the biggest EP IN size!
+#endif
+#endif
+#endif // CFG_TUD_AUDIO_ENABLE_EP_IN
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX
+#error You must tell the driver the biggest EP OUT size!
+#endif
+#if CFG_TUD_AUDIO > 1
+#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX
+#error You must tell the driver the biggest EP OUT size!
+#endif
+#endif
+#if CFG_TUD_AUDIO > 2
+#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX
+#error You must tell the driver the biggest EP OUT size!
+#endif
+#endif
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
+
+// Software EP FIFO buffer sizes - must be >= max EP SIZEs!
+#ifndef CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ                0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ
+#define CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ                0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ
+#define CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ                0
+#endif
+
+#ifndef CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ
+#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ               0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ
+#define CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ               0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ
+#define CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ               0
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX
+#error EP software buffer size MUST BE at least as big as maximum EP size
+#endif
+
+#if CFG_TUD_AUDIO > 1
+#if CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX
+#error EP software buffer size MUST BE at least as big as maximum EP size
+#endif
+#endif
+
+#if CFG_TUD_AUDIO > 2
+#if CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX
+#error EP software buffer size MUST BE at least as big as maximum EP size
+#endif
+#endif
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX
+#error EP software buffer size MUST BE at least as big as maximum EP size
+#endif
+
+#if CFG_TUD_AUDIO > 1
+#if CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX
+#error EP software buffer size MUST BE at least as big as maximum EP size
+#endif
+#endif
+
+#if CFG_TUD_AUDIO > 2
+#if CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ < CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX
+#error EP software buffer size MUST BE at least as big as maximum EP size
+#endif
+#endif
+#endif
+
+// Enable/disable feedback EP (required for asynchronous RX applications)
+#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP                    0                             // Feedback - 0 or 1
+#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)
+#endif
+
+#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE
+#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE          6                             // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74)
+#endif
+
+// Use software encoding/decoding
+
+// The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved
+// into a single PCM stream as SAMPLE_1 | SAMPLE_2 | SAMPLE_3 | SAMPLE_4.
+//
+// Currently, only PCM type I encoding/decoding is supported!
+//
+// If the coding feature is to be used, support FIFOs need to be configured. Their sizes and numbers are defined below.
+
+// Encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the
+// support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using
+// - tud_audio_n_write() or
+// - tud_audio_n_read().
+// To write/read to/from the support FIFOs use
+// - tud_audio_n_write_support_ff() or
+// - tud_audio_n_read_support_ff().
+//
+// The encoding/decoding format type done is defined below.
+//
+// The encoding/decoding starts when the private callback functions
+// - audio_tx_done_cb()
+// - audio_rx_done_cb()
+// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there.
+// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions
+// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb()
+// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb()
+// if you want to get informed what happened.
+//
+// If you don't use the support FIFOs you may use the public callback functions
+// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb()
+// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb()
+// to write/read from/into the EP_X_SW_BUFFER_FIFOs at the right time.
+//
+// If you need a different encoding which is not support so far implement it in the
+// - audio_tx_done_cb()
+// - audio_rx_done_cb()
+// functions.
+
+// Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size
+// The actual coding parameters of active AS alternate interface is parsed from the descriptors
+
+// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sampe_sz) * sampe_sz)!
+// This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!!
+
+// For PCM encoding/decoding
+
+#ifndef CFG_TUD_AUDIO_ENABLE_ENCODING
+#define CFG_TUD_AUDIO_ENABLE_ENCODING                       0
+#endif
+
+#ifndef CFG_TUD_AUDIO_ENABLE_DECODING
+#define CFG_TUD_AUDIO_ENABLE_DECODING                       0
+#endif
+
+// This enabling allows to save the current coding parameters e.g. # of bytes per sample etc. - TYPE_I includes common PCM encoding
+#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
+#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING                0
+#endif
+
+#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
+#define CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING                0
+#endif
+
+// Type I Coding parameters not given within UAC2 descriptors
+// It would be possible to allow for a more flexible setting and not fix this parameter as done below. However, this is most often not needed and kept for later if really necessary. The more flexible setting could be implemented within set_interface(), however, how the values are saved per alternate setting is to be determined!
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
+#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX
+#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
+#endif
+#if CFG_TUD_AUDIO > 1
+#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX
+#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
+#endif
+#endif
+#if CFG_TUD_AUDIO > 2
+#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX
+#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
+#endif
+#endif
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
+#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX
+#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
+#endif
+#if CFG_TUD_AUDIO > 1
+#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX
+#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
+#endif
+#endif
+#if CFG_TUD_AUDIO > 2
+#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX
+#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
+#endif
+#endif
+#endif
+
+// Remaining types not support so far
+
+// Number of support FIFOs to set up - multiple channels can be handled by one FIFO - very common is two channels per FIFO stemming from one I2S interface
+#ifndef CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO
+#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO              0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO
+#define CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO              0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO
+#define CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO              0
+#endif
+
+#ifndef CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO
+#define CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO              0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO
+#define CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO              0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO
+#define CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO              0
+#endif
+
+// Size of support FIFOs IN BYTES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_FUNC_X_N_TX_SUPP_SW_FIFO and CFG_TUD_AUDIO_FUNC_X_N_RX_SUPP_SW_FIFO
+#ifndef CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ
+#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ             0         // FIFO size - minimum size: ceil(f_s/1000) * max(# of TX channels) / (# of TX support FIFOs) * max(# of bytes per sample)
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ
+#define CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ             0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ
+#define CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ             0
+#endif
+
+#ifndef CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ
+#define CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ             0         // FIFO size - minimum size: ceil(f_s/1000) * max(# of RX channels) / (# of RX support FIFOs) * max(# of bytes per sample)
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ
+#define CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ             0
+#endif
+#ifndef CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ
+#define CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ             0
+#endif
+
+//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!");
+
+// Supported types of this driver:
+// AUDIO_DATA_FORMAT_TYPE_I_PCM     -   Required definitions: CFG_TUD_AUDIO_N_CHANNELS and CFG_TUD_AUDIO_BYTES_PER_CHANNEL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \addtogroup AUDIO_Serial Serial
+ *  @{
+ *  \defgroup   AUDIO_Serial_Device Device
+ *  @{ */
+
+//--------------------------------------------------------------------+
+// Application API (Multiple Interfaces)
+// CFG_TUD_AUDIO > 1
+//--------------------------------------------------------------------+
+bool     tud_audio_n_mounted    (uint8_t func_id);
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+uint16_t tud_audio_n_available                    (uint8_t func_id);
+uint16_t tud_audio_n_read                         (uint8_t func_id, void* buffer, uint16_t bufsize);
+bool     tud_audio_n_clear_ep_out_ff              (uint8_t func_id);                          // Delete all content in the EP OUT FIFO
+tu_fifo_t*   tud_audio_n_get_ep_out_ff            (uint8_t func_id);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
+bool     tud_audio_n_clear_rx_support_ff          (uint8_t func_id, uint8_t ff_idx);       // Delete all content in the support RX FIFOs
+uint16_t tud_audio_n_available_support_ff         (uint8_t func_id, uint8_t ff_idx);
+uint16_t tud_audio_n_read_support_ff              (uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize);
+tu_fifo_t* tud_audio_n_get_rx_support_ff          (uint8_t func_id, uint8_t ff_idx);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+uint16_t tud_audio_n_write                        (uint8_t func_id, const void * data, uint16_t len);
+bool     tud_audio_n_clear_ep_in_ff               (uint8_t func_id);                          // Delete all content in the EP IN FIFO
+tu_fifo_t*   tud_audio_n_get_ep_in_ff             (uint8_t func_id);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+uint16_t tud_audio_n_flush_tx_support_ff          (uint8_t func_id);      // Force all content in the support TX FIFOs to be written into EP SW FIFO
+bool     tud_audio_n_clear_tx_support_ff          (uint8_t func_id, uint8_t ff_idx);
+uint16_t tud_audio_n_write_support_ff             (uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len);
+tu_fifo_t* tud_audio_n_get_tx_support_ff          (uint8_t func_id, uint8_t ff_idx);
+#endif
+
+#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
+uint16_t    tud_audio_int_ctr_n_write             (uint8_t func_id, uint8_t const* buffer, uint16_t len);
+#endif
+
+//--------------------------------------------------------------------+
+// Application API (Interface0)
+//--------------------------------------------------------------------+
+
+static inline bool         tud_audio_mounted                (void);
+
+// RX API
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+static inline uint16_t     tud_audio_available              (void);
+static inline bool         tud_audio_clear_ep_out_ff        (void);                       // Delete all content in the EP OUT FIFO
+static inline uint16_t     tud_audio_read                   (void* buffer, uint16_t bufsize);
+static inline tu_fifo_t*   tud_audio_get_ep_out_ff          (void);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
+static inline bool     tud_audio_clear_rx_support_ff        (uint8_t ff_idx);
+static inline uint16_t tud_audio_available_support_ff       (uint8_t ff_idx);
+static inline uint16_t tud_audio_read_support_ff            (uint8_t ff_idx, void* buffer, uint16_t bufsize);
+static inline tu_fifo_t* tud_audio_get_rx_support_ff        (uint8_t ff_idx);
+#endif
+
+// TX API
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+static inline uint16_t tud_audio_write                      (const void * data, uint16_t len);
+static inline bool 	   tud_audio_clear_ep_in_ff             (void);
+static inline tu_fifo_t* tud_audio_get_ep_in_ff             (void);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+static inline uint16_t tud_audio_flush_tx_support_ff        (void);
+static inline uint16_t tud_audio_clear_tx_support_ff        (uint8_t ff_idx);
+static inline uint16_t tud_audio_write_support_ff           (uint8_t ff_idx, const void * data, uint16_t len);
+static inline tu_fifo_t* tud_audio_get_tx_support_ff        (uint8_t ff_idx);
+#endif
+
+// INT CTR API
+
+#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
+static inline uint16_t tud_audio_int_ctr_write              (uint8_t const* buffer, uint16_t len);
+#endif
+
+// Buffer control EP data and schedule a transmit
+// This function is intended to be used if you do not have a persistent buffer or memory location available (e.g. non-local variables) and need to answer onto a
+// get request. This function buffers your answer request frame into the control buffer of the corresponding audio driver and schedules a transmit for sending it.
+// Since transmission is triggered via interrupts, a persistent memory location is required onto which the buffer pointer in pointing. If you already have such
+// available you may directly use 'tud_control_xfer(...)'. In this case data does not need to be copied into an additional buffer and you save some time.
+// If the request's wLength is zero, a status packet is sent instead.
+bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len);
+
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting);
+TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting);
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting);
+TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting);
+#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.
+bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback);
+static inline bool tud_audio_fb_set(uint32_t feedback);
+#endif
+
+#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);
+#endif
+
+// Invoked when audio set interface request received
+TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio set interface request received which closes an EP
+TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio class specific set request received for an EP
+TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff);
+
+// Invoked when audio class specific set request received for an interface
+TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff);
+
+// Invoked when audio class specific set request received for an entity
+TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff);
+
+// Invoked when audio class specific get request received for an EP
+TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio class specific get request received for an interface
+TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio class specific get request received for an entity
+TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+//--------------------------------------------------------------------+
+// Inline Functions
+//--------------------------------------------------------------------+
+
+static inline bool tud_audio_mounted(void)
+{
+  return tud_audio_n_mounted(0);
+}
+
+// RX API
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+
+static inline uint16_t tud_audio_available(void)
+{
+  return tud_audio_n_available(0);
+}
+
+static inline uint16_t tud_audio_read(void* buffer, uint16_t bufsize)
+{
+  return tud_audio_n_read(0, buffer, bufsize);
+}
+
+static inline bool tud_audio_clear_ep_out_ff(void)
+{
+  return tud_audio_n_clear_ep_out_ff(0);
+}
+
+static inline tu_fifo_t* tud_audio_get_ep_out_ff(void)
+{
+  return tud_audio_n_get_ep_out_ff(0);
+}
+
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
+
+static inline bool tud_audio_clear_rx_support_ff(uint8_t ff_idx)
+{
+  return tud_audio_n_clear_rx_support_ff(0, ff_idx);
+}
+
+static inline uint16_t tud_audio_available_support_ff(uint8_t ff_idx)
+{
+  return tud_audio_n_available_support_ff(0, ff_idx);
+}
+
+static inline uint16_t tud_audio_read_support_ff(uint8_t ff_idx, void* buffer, uint16_t bufsize)
+{
+  return tud_audio_n_read_support_ff(0, ff_idx, buffer, bufsize);
+}
+
+static inline tu_fifo_t* tud_audio_get_rx_support_ff(uint8_t ff_idx)
+{
+  return tud_audio_n_get_rx_support_ff(0, ff_idx);
+}
+
+#endif
+
+// TX API
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+
+static inline uint16_t tud_audio_write(const void * data, uint16_t len)
+{
+  return tud_audio_n_write(0, data, len);
+}
+
+static inline bool tud_audio_clear_ep_in_ff(void)
+{
+  return tud_audio_n_clear_ep_in_ff(0);
+}
+
+static inline tu_fifo_t* tud_audio_get_ep_in_ff(void)
+{
+  return tud_audio_n_get_ep_in_ff(0);
+}
+
+#endif
+
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
+
+static inline uint16_t tud_audio_flush_tx_support_ff(void)
+{
+  return tud_audio_n_flush_tx_support_ff(0);
+}
+
+static inline uint16_t tud_audio_clear_tx_support_ff(uint8_t ff_idx)
+{
+  return tud_audio_n_clear_tx_support_ff(0, ff_idx);
+}
+
+static inline uint16_t tud_audio_write_support_ff(uint8_t ff_idx, const void * data, uint16_t len)
+{
+  return tud_audio_n_write_support_ff(0, ff_idx, data, len);
+}
+
+static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx)
+{
+  return tud_audio_n_get_tx_support_ff(0, ff_idx);
+}
+
+#endif
+
+#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
+static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len)
+{
+  return tud_audio_int_ctr_n_write(0, buffer, len);
+}
+#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
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void     audiod_init           (void);
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_AUDIO_DEVICE_H_ */
+
+/** @} */
+/** @} */
diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c
new file mode 100755
index 0000000..8ef6096
--- /dev/null
+++ b/src/class/bth/bth_device.c
@@ -0,0 +1,258 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 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 (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_BTH)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "bth_device.h"
+#include <device/usbd_pvt.h>
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_ev;
+  uint8_t ep_acl_in;
+  uint8_t ep_acl_out;
+  uint8_t ep_voice[2];  // Not used yet
+  uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT];
+
+  // Endpoint Transfer buffer
+  CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd;
+  CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE];
+
+} btd_interface_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+CFG_TUSB_MEM_SECTION btd_interface_t _btd_itf;
+
+static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
+{
+  // skip if previous transfer not complete
+  TU_VERIFY(!usbd_edpt_busy(TUD_OPT_RHPORT, ep));
+
+  TU_ASSERT(usbd_edpt_xfer(TUD_OPT_RHPORT, ep, data, len));
+
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// READ API
+//--------------------------------------------------------------------+
+
+
+//--------------------------------------------------------------------+
+// WRITE API
+//--------------------------------------------------------------------+
+
+bool tud_bt_event_send(void *event, uint16_t event_len)
+{
+  return bt_tx_data(_btd_itf.ep_ev, event, event_len);
+}
+
+bool tud_bt_acl_data_send(void *event, uint16_t event_len)
+{
+  return bt_tx_data(_btd_itf.ep_acl_in, event, event_len);
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void btd_init(void)
+{
+  tu_memclr(&_btd_itf, sizeof(_btd_itf));
+}
+
+void btd_reset(uint8_t rhport)
+{
+  (void)rhport;
+}
+
+uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
+{
+  tusb_desc_endpoint_t const *desc_ep;
+  uint16_t drv_len = 0;
+  // Size of single alternative of ISO interface
+  const uint16_t iso_alt_itf_size = sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t);
+  // Size of hci interface
+  const uint16_t hci_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t);
+  // Ensure this is BT Primary Controller
+  TU_VERIFY(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass &&
+            TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
+            TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0);
+
+  TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= hci_itf_size);
+
+  _btd_itf.itf_num = itf_desc->bInterfaceNumber;
+
+  desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+
+  TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
+  TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
+  _btd_itf.ep_ev = desc_ep->bEndpointAddress;
+
+  // Open endpoint pair
+  TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(desc_ep), 2, TUSB_XFER_BULK, &_btd_itf.ep_acl_out,
+                                &_btd_itf.ep_acl_in), 0);
+
+  itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(tu_desc_next(desc_ep)));
+
+  // Prepare for incoming data from host
+  TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0);
+
+  drv_len = hci_itf_size;
+
+  // Ensure this is still BT Primary Controller
+  TU_ASSERT(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass &&
+            TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
+            TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0);
+  TU_ASSERT(itf_desc->bNumEndpoints == 2 && max_len >= iso_alt_itf_size + drv_len);
+
+  uint8_t dir;
+
+  desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc);
+  TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0);
+  TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0);
+  dir = tu_edpt_dir(desc_ep->bEndpointAddress);
+  _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress;
+  // Store endpoint size for alternative
+  _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
+
+  desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
+  TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0);
+  dir = tu_edpt_dir(desc_ep->bEndpointAddress);
+  _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress;
+  // Store endpoint size for alternative
+  _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
+  drv_len += iso_alt_itf_size;
+
+  for (int i = 1; i < CFG_TUD_BTH_ISO_ALT_COUNT && drv_len + iso_alt_itf_size <= max_len; ++i) {
+    // Make sure rest of alternatives matches
+    itf_desc = (tusb_desc_interface_t const *)tu_desc_next(desc_ep);
+    if (itf_desc->bDescriptorType != TUSB_DESC_INTERFACE ||
+        TUSB_CLASS_WIRELESS_CONTROLLER != itf_desc->bInterfaceClass ||
+        TUD_BT_APP_SUBCLASS != itf_desc->bInterfaceSubClass ||
+        TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol)
+    {
+      // Not an Iso interface instance
+      break;
+    }
+    TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0);
+
+    desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc);
+    dir = tu_edpt_dir(desc_ep->bEndpointAddress);
+    // Verify that alternative endpoint are same as first ones
+    TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT &&
+              _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0);
+    _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
+
+    desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
+    dir = tu_edpt_dir(desc_ep->bEndpointAddress);
+    // Verify that alternative endpoint are same as first ones
+    TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT &&
+              _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0);
+    _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
+    drv_len += iso_alt_itf_size;
+  }
+
+  return drv_len;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
+{
+  (void)rhport;
+
+  if ( stage == CONTROL_STAGE_SETUP )
+  {
+    if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
+        request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE)
+    {
+      // HCI command packet addressing for single function Primary Controllers
+      TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0);
+    }
+    else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE)
+    {
+      if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex)
+      {
+        // TODO: Set interface it would involve changing size of endpoint size
+      }
+      else
+      {
+        // HCI command packet for Primary Controller function in a composite device
+        TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == _btd_itf.itf_num);
+      }
+    }
+    else return false;
+
+    return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, sizeof(_btd_itf.hci_cmd));
+  }
+  else if ( stage == CONTROL_STAGE_DATA )
+  {
+    // Handle class request only
+    TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
+
+    if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, tu_min16(request->wLength, sizeof(_btd_itf.hci_cmd)));
+  }
+
+  return true;
+}
+
+bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void)result;
+
+  // received new data from host
+  if (ep_addr == _btd_itf.ep_acl_out)
+  {
+    if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_itf.epout_buf, xferred_bytes);
+
+    // prepare for next data
+    TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE));
+  }
+  else if (ep_addr == _btd_itf.ep_ev)
+  {
+    if (tud_bt_event_sent_cb) tud_bt_event_sent_cb((uint16_t)xferred_bytes);
+  }
+  else if (ep_addr == _btd_itf.ep_acl_in)
+  {
+    if (tud_bt_acl_data_sent_cb) tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes);
+  }
+
+  return true;
+}
+
+#endif
diff --git a/src/class/bth/bth_device.h b/src/class/bth/bth_device.h
new file mode 100755
index 0000000..1b90d09
--- /dev/null
+++ b/src/class/bth/bth_device.h
@@ -0,0 +1,109 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 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.
+ */
+
+#ifndef _TUSB_BTH_DEVICE_H_
+#define _TUSB_BTH_DEVICE_H_
+
+#include <common/tusb_common.h>
+#include <device/usbd.h>
+
+//--------------------------------------------------------------------+
+// Class Driver Configuration
+//--------------------------------------------------------------------+
+#ifndef CFG_TUD_BTH_EVENT_EPSIZE
+#define CFG_TUD_BTH_EVENT_EPSIZE     16
+#endif
+#ifndef CFG_TUD_BTH_DATA_EPSIZE
+#define CFG_TUD_BTH_DATA_EPSIZE      64
+#endif
+
+typedef struct TU_ATTR_PACKED
+{
+  uint16_t op_code;
+  uint8_t param_length;
+  uint8_t param[255];
+} bt_hci_cmd_t;
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+
+// Invoked when HCI command was received over USB from Bluetooth host.
+// Detailed format is described in Bluetooth core specification Vol 2,
+// Part E, 5.4.1.
+// Length of the command is from 3 bytes (2 bytes for OpCode,
+// 1 byte for parameter total length) to 258.
+TU_ATTR_WEAK void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len);
+
+// Invoked when ACL data was received over USB from Bluetooth host.
+// Detailed format is described in Bluetooth core specification Vol 2,
+// Part E, 5.4.2.
+// Length is from 4 bytes, (12 bits for Handle, 4 bits for flags
+// and 16 bits for data total length) to endpoint size.
+TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len);
+
+// Called when event sent with tud_bt_event_send() was delivered to BT stack.
+// Controller can release/reuse buffer with Event packet at this point.
+TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes);
+
+// Called when ACL data that was sent with tud_bt_acl_data_send()
+// was delivered to BT stack.
+// Controller can release/reuse buffer with ACL packet at this point.
+TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes);
+
+// Bluetooth controller calls this function when it wants to send even packet
+// as described in Bluetooth core specification Vol 2, Part E, 5.4.4.
+// Event has at least 2 bytes, first is Event code second contains parameter
+// total length. Controller can release/reuse event memory after
+// tud_bt_event_sent_cb() is called.
+bool tud_bt_event_send(void *event, uint16_t event_len);
+
+// Bluetooth controller calls this to send ACL data packet
+// as described in Bluetooth core specification Vol 2, Part E, 5.4.2
+// Minimum length is 4 bytes, (12 bits for Handle, 4 bits for flags
+// and 16 bits for data total length). Upper limit is not limited
+// to endpoint size since buffer is allocate by controller
+// and must not be reused till tud_bt_acl_data_sent_cb() is called.
+bool tud_bt_acl_data_send(void *acl_data, uint16_t data_len);
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void     btd_init            (void);
+void     btd_reset           (uint8_t rhport);
+uint16_t btd_open            (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     btd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
+bool     btd_xfer_cb         (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_BTH_DEVICE_H_ */
diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h
new file mode 100644
index 0000000..e345139
--- /dev/null
+++ b/src/class/cdc/cdc.h
@@ -0,0 +1,409 @@
+/*
+ * 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_class
+ *  \defgroup ClassDriver_CDC Communication Device Class (CDC)
+ *            Currently only Abstract Control Model subclass is supported
+ *  @{ */
+
+#ifndef _TUSB_CDC_H__
+#define _TUSB_CDC_H__
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/** \defgroup ClassDriver_CDC_Common Common Definitions
+ *  @{ */
+
+// TODO remove
+/// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In)
+typedef enum
+{
+  CDC_PIPE_NOTIFICATION , ///< Notification pipe
+  CDC_PIPE_DATA_IN      , ///< Data in pipe
+  CDC_PIPE_DATA_OUT     , ///< Data out pipe
+  CDC_PIPE_ERROR        , ///< Invalid Pipe ID
+}cdc_pipeid_t;
+
+//--------------------------------------------------------------------+
+// CDC Communication Interface Class
+//--------------------------------------------------------------------+
+
+/// Communication Interface Subclass Codes
+typedef enum
+{
+  CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL      = 0x01 , ///< Direct Line Control Model         [USBPSTN1.2]
+  CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL         = 0x02 , ///< Abstract Control Model            [USBPSTN1.2]
+  CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL        = 0x03 , ///< Telephone Control Model           [USBPSTN1.2]
+  CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL     = 0x04 , ///< Multi-Channel Control Model       [USBISDN1.2]
+  CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL             = 0x05 , ///< CAPI Control Model                [USBISDN1.2]
+  CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL         = 0x06 , ///< Ethernet Networking Control Model [USBECM1.2]
+  CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL   = 0x07 , ///< ATM Networking Control Model      [USBATM1.2]
+  CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL = 0x08 , ///< Wireless Handset Control Model    [USBWMC1.1]
+  CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT              = 0x09 , ///< Device Management                 [USBWMC1.1]
+  CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL       = 0x0A , ///< Mobile Direct Line Model          [USBWMC1.1]
+  CDC_COMM_SUBCLASS_OBEX                           = 0x0B , ///< OBEX                              [USBWMC1.1]
+  CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL       = 0x0C , ///< Ethernet Emulation Model          [USBEEM1.0]
+  CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL          = 0x0D   ///< Network Control Model             [USBNCM1.0]
+} cdc_comm_sublcass_type_t;
+
+/// Communication Interface Protocol Codes
+typedef enum
+{
+  CDC_COMM_PROTOCOL_NONE                          = 0x00 , ///< No specific protocol
+  CDC_COMM_PROTOCOL_ATCOMMAND                     = 0x01 , ///< AT Commands: V.250 etc
+  CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101            = 0x02 , ///< AT Commands defined by PCCA-101
+  CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO = 0x03 , ///< AT Commands defined by PCCA-101 & Annex O
+  CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707             = 0x04 , ///< AT Commands defined by GSM 07.07
+  CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007          = 0x05 , ///< AT Commands defined by 3GPP 27.007
+  CDC_COMM_PROTOCOL_ATCOMMAND_CDMA                = 0x06 , ///< AT Commands defined by TIA for CDMA
+  CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL      = 0x07   ///< Ethernet Emulation Model
+} cdc_comm_protocol_type_t;
+
+//------------- SubType Descriptor in COMM Functional Descriptor -------------//
+/// Communication Interface SubType Descriptor
+typedef enum
+{
+  CDC_FUNC_DESC_HEADER                                           = 0x00 , ///< Header Functional Descriptor, which marks the beginning of the concatenated set of functional descriptors for the interface.
+  CDC_FUNC_DESC_CALL_MANAGEMENT                                  = 0x01 , ///< Call Management Functional Descriptor.
+  CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT                      = 0x02 , ///< Abstract Control Management Functional Descriptor.
+  CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT                           = 0x03 , ///< Direct Line Management Functional Descriptor.
+  CDC_FUNC_DESC_TELEPHONE_RINGER                                 = 0x04 , ///< Telephone Ringer Functional Descriptor.
+  CDC_FUNC_DESC_TELEPHONE_CALL_AND_LINE_STATE_REPORTING_CAPACITY = 0x05 , ///< Telephone Call and Line State Reporting Capabilities Functional Descriptor.
+  CDC_FUNC_DESC_UNION                                            = 0x06 , ///< Union Functional Descriptor
+  CDC_FUNC_DESC_COUNTRY_SELECTION                                = 0x07 , ///< Country Selection Functional Descriptor
+  CDC_FUNC_DESC_TELEPHONE_OPERATIONAL_MODES                      = 0x08 , ///< Telephone Operational ModesFunctional Descriptor
+  CDC_FUNC_DESC_USB_TERMINAL                                     = 0x09 , ///< USB Terminal Functional Descriptor
+  CDC_FUNC_DESC_NETWORK_CHANNEL_TERMINAL                         = 0x0A , ///< Network Channel Terminal Descriptor
+  CDC_FUNC_DESC_PROTOCOL_UNIT                                    = 0x0B , ///< Protocol Unit Functional Descriptor
+  CDC_FUNC_DESC_EXTENSION_UNIT                                   = 0x0C , ///< Extension Unit Functional Descriptor
+  CDC_FUNC_DESC_MULTICHANEL_MANAGEMENT                           = 0x0D , ///< Multi-Channel Management Functional Descriptor
+  CDC_FUNC_DESC_CAPI_CONTROL_MANAGEMENT                          = 0x0E , ///< CAPI Control Management Functional Descriptor
+  CDC_FUNC_DESC_ETHERNET_NETWORKING                              = 0x0F , ///< Ethernet Networking Functional Descriptor
+  CDC_FUNC_DESC_ATM_NETWORKING                                   = 0x10 , ///< ATM Networking Functional Descriptor
+  CDC_FUNC_DESC_WIRELESS_HANDSET_CONTROL_MODEL                   = 0x11 , ///< Wireless Handset Control Model Functional Descriptor
+  CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL                         = 0x12 , ///< Mobile Direct Line Model Functional Descriptor
+  CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL_DETAIL                  = 0x13 , ///< MDLM Detail Functional Descriptor
+  CDC_FUNC_DESC_DEVICE_MANAGEMENT_MODEL                          = 0x14 , ///< Device Management Model Functional Descriptor
+  CDC_FUNC_DESC_OBEX                                             = 0x15 , ///< OBEX Functional Descriptor
+  CDC_FUNC_DESC_COMMAND_SET                                      = 0x16 , ///< Command Set Functional Descriptor
+  CDC_FUNC_DESC_COMMAND_SET_DETAIL                               = 0x17 , ///< Command Set Detail Functional Descriptor
+  CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL                          = 0x18 , ///< Telephone Control Model Functional Descriptor
+  CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER                          = 0x19 , ///< OBEX Service Identifier Functional Descriptor
+  CDC_FUNC_DESC_NCM                                              = 0x1A , ///< NCM Functional Descriptor
+}cdc_func_desc_type_t;
+
+//--------------------------------------------------------------------+
+// CDC Data Interface Class
+//--------------------------------------------------------------------+
+
+// SUBCLASS code of Data Interface is not used and should/must be zero
+
+// Data Interface Protocol Codes
+typedef enum{
+  CDC_DATA_PROTOCOL_ISDN_BRI                               = 0x30, ///< Physical interface protocol for ISDN BRI
+  CDC_DATA_PROTOCOL_HDLC                                   = 0x31, ///< HDLC
+  CDC_DATA_PROTOCOL_TRANSPARENT                            = 0x32, ///< Transparent
+  CDC_DATA_PROTOCOL_Q921_MANAGEMENT                        = 0x50, ///< Management protocol for Q.921 data link protocol
+  CDC_DATA_PROTOCOL_Q921_DATA_LINK                         = 0x51, ///< Data link protocol for Q.931
+  CDC_DATA_PROTOCOL_Q921_TEI_MULTIPLEXOR                   = 0x52, ///< TEI-multiplexor for Q.921 data link protocol
+  CDC_DATA_PROTOCOL_V42BIS_DATA_COMPRESSION                = 0x90, ///< Data compression procedures
+  CDC_DATA_PROTOCOL_EURO_ISDN                              = 0x91, ///< Euro-ISDN protocol control
+  CDC_DATA_PROTOCOL_V24_RATE_ADAPTION_TO_ISDN              = 0x92, ///< V.24 rate adaptation to ISDN
+  CDC_DATA_PROTOCOL_CAPI_COMMAND                           = 0x93, ///< CAPI Commands
+  CDC_DATA_PROTOCOL_HOST_BASED_DRIVER                      = 0xFD, ///< Host based driver. Note: This protocol code should only be used in messages between host and device to identify the host driver portion of a protocol stack.
+  CDC_DATA_PROTOCOL_IN_PROTOCOL_UNIT_FUNCTIONAL_DESCRIPTOR = 0xFE  ///< The protocol(s) are described using a ProtocolUnit Functional Descriptors on Communications Class Interface
+}cdc_data_protocol_type_t;
+
+//--------------------------------------------------------------------+
+// Management Element Request (Control Endpoint)
+//--------------------------------------------------------------------+
+
+/// Communication Interface Management Element Request Codes
+typedef enum
+{
+  CDC_REQUEST_SEND_ENCAPSULATED_COMMAND                    = 0x00, ///< is used to issue a command in the format of the supported control protocol of the Communications Class interface
+  CDC_REQUEST_GET_ENCAPSULATED_RESPONSE                    = 0x01, ///< is used to request a response in the format of the supported control protocol of the Communications Class interface.
+  CDC_REQUEST_SET_COMM_FEATURE                             = 0x02,
+  CDC_REQUEST_GET_COMM_FEATURE                             = 0x03,
+  CDC_REQUEST_CLEAR_COMM_FEATURE                           = 0x04,
+
+  CDC_REQUEST_SET_AUX_LINE_STATE                           = 0x10,
+  CDC_REQUEST_SET_HOOK_STATE                               = 0x11,
+  CDC_REQUEST_PULSE_SETUP                                  = 0x12,
+  CDC_REQUEST_SEND_PULSE                                   = 0x13,
+  CDC_REQUEST_SET_PULSE_TIME                               = 0x14,
+  CDC_REQUEST_RING_AUX_JACK                                = 0x15,
+
+  CDC_REQUEST_SET_LINE_CODING                              = 0x20,
+  CDC_REQUEST_GET_LINE_CODING                              = 0x21,
+  CDC_REQUEST_SET_CONTROL_LINE_STATE                       = 0x22,
+  CDC_REQUEST_SEND_BREAK                                   = 0x23,
+
+  CDC_REQUEST_SET_RINGER_PARMS                             = 0x30,
+  CDC_REQUEST_GET_RINGER_PARMS                             = 0x31,
+  CDC_REQUEST_SET_OPERATION_PARMS                          = 0x32,
+  CDC_REQUEST_GET_OPERATION_PARMS                          = 0x33,
+  CDC_REQUEST_SET_LINE_PARMS                               = 0x34,
+  CDC_REQUEST_GET_LINE_PARMS                               = 0x35,
+  CDC_REQUEST_DIAL_DIGITS                                  = 0x36,
+  CDC_REQUEST_SET_UNIT_PARAMETER                           = 0x37,
+  CDC_REQUEST_GET_UNIT_PARAMETER                           = 0x38,
+  CDC_REQUEST_CLEAR_UNIT_PARAMETER                         = 0x39,
+  CDC_REQUEST_GET_PROFILE                                  = 0x3A,
+
+  CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS               = 0x40,
+  CDC_REQUEST_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41,
+  CDC_REQUEST_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42,
+  CDC_REQUEST_SET_ETHERNET_PACKET_FILTER                   = 0x43,
+  CDC_REQUEST_GET_ETHERNET_STATISTIC                       = 0x44,
+
+  CDC_REQUEST_SET_ATM_DATA_FORMAT                          = 0x50,
+  CDC_REQUEST_GET_ATM_DEVICE_STATISTICS                    = 0x51,
+  CDC_REQUEST_SET_ATM_DEFAULT_VC                           = 0x52,
+  CDC_REQUEST_GET_ATM_VC_STATISTICS                        = 0x53,
+
+  CDC_REQUEST_MDLM_SEMANTIC_MODEL                          = 0x60,
+}cdc_management_request_t;
+
+//--------------------------------------------------------------------+
+// Management Elemenent Notification (Notification Endpoint)
+//--------------------------------------------------------------------+
+
+/// 6.3 Notification Codes
+typedef enum
+{
+  CDC_NOTIF_NETWORK_CONNECTION               = 0x00, ///< This notification allows the device to notify the host about network connection status.
+  CDC_NOTIF_RESPONSE_AVAILABLE               = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request.
+  CDC_NOTIF_AUX_JACK_HOOK_STATE              = 0x08,
+  CDC_NOTIF_RING_DETECT                      = 0x09,
+  CDC_NOTIF_SERIAL_STATE                     = 0x20,
+  CDC_NOTIF_CALL_STATE_CHANGE                = 0x28,
+  CDC_NOTIF_LINE_STATE_CHANGE                = 0x29,
+  CDC_NOTIF_CONNECTION_SPEED_CHANGE          = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred
+  CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,
+}cdc_notification_request_t;
+
+//--------------------------------------------------------------------+
+// Class Specific Functional Descriptor (Communication Interface)
+//--------------------------------------------------------------------+
+
+// Start of all packed definitions for compiler without per-type packed
+TU_ATTR_PACKED_BEGIN
+TU_ATTR_BIT_FIELD_ORDER_BEGIN
+
+/// Header Functional Descriptor (Communication Interface)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUNC_DESC_
+  uint16_t bcdCDC            ; ///< CDC release number in Binary-Coded Decimal
+}cdc_desc_func_header_t;
+
+/// Union Functional Descriptor (Communication Interface)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength                  ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType          ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType       ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
+  uint8_t bControlInterface        ; ///< Interface number of Communication Interface
+  uint8_t bSubordinateInterface    ; ///< Array of Interface number of Data Interface
+}cdc_desc_func_union_t;
+
+#define cdc_desc_func_union_n_t(no_slave)\
+ struct TU_ATTR_PACKED {                   \
+  uint8_t bLength                         ;\
+  uint8_t bDescriptorType                 ;\
+  uint8_t bDescriptorSubType              ;\
+  uint8_t bControlInterface               ;\
+  uint8_t bSubordinateInterface[no_slave] ;\
+}
+
+/// Country Selection Functional Descriptor (Communication Interface)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength             ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType     ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType  ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
+  uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes.
+  uint16_t wCountryCode       ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country.
+}cdc_desc_func_country_selection_t;
+
+#define cdc_desc_func_country_selection_n_t(no_country) \
+  struct TU_ATTR_PACKED {            \
+  uint8_t bLength                   ;\
+  uint8_t bDescriptorType           ;\
+  uint8_t bDescriptorSubType        ;\
+  uint8_t iCountryCodeRelDate       ;\
+  uint16_t wCountryCode[no_country] ;\
+}
+
+//--------------------------------------------------------------------+
+// PUBLIC SWITCHED TELEPHONE NETWORK (PSTN) SUBCLASS
+//--------------------------------------------------------------------+
+
+/// \brief Call Management Functional Descriptor
+/// \details This functional descriptor describes the processing of calls for the Communications Class interface.
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
+
+  struct {
+    uint8_t handle_call    : 1; ///< 0 - Device sends/receives call management information only over the Communications Class interface. 1 - Device can send/receive call management information over a Data Class interface.
+    uint8_t send_recv_call : 1; ///< 0 - Device does not handle call management itself. 1 - Device handles call management itself.
+    uint8_t TU_RESERVED    : 6;
+  } bmCapabilities;
+
+  uint8_t bDataInterface;
+}cdc_desc_func_call_management_t;
+
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t support_comm_request                    : 1; ///< Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature.
+  uint8_t support_line_request                    : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State.
+  uint8_t support_send_break                      : 1; ///< Device supports the request Send_Break
+  uint8_t support_notification_network_connection : 1; ///< Device supports the notification Network_Connection.
+  uint8_t TU_RESERVED                             : 4;
+}cdc_acm_capability_t;
+
+TU_VERIFY_STATIC(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compiler");
+
+/// Abstract Control Management Functional Descriptor
+/// This functional descriptor describes the commands supported by by the Communications Class interface with SubClass code of \ref CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength                  ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType          ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType       ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
+  cdc_acm_capability_t bmCapabilities ;
+}cdc_desc_func_acm_t;
+
+/// \brief Direct Line Management Functional Descriptor
+/// \details This functional descriptor describes the commands supported by the Communications Class interface with SubClass code of \ref CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
+  struct {
+    uint8_t require_pulse_setup   : 1; ///< Device requires extra Pulse_Setup request during pulse dialing sequence to disengage holding circuit.
+    uint8_t support_aux_request   : 1; ///< Device supports the request combination of Set_Aux_Line_State, Ring_Aux_Jack, and notification Aux_Jack_Hook_State.
+    uint8_t support_pulse_request : 1; ///< Device supports the request combination of Pulse_Setup, Send_Pulse, and Set_Pulse_Time.
+    uint8_t TU_RESERVED           : 5;
+  } bmCapabilities;
+}cdc_desc_func_direct_line_management_t;
+
+/// \brief Telephone Ringer Functional Descriptor
+/// \details The Telephone Ringer functional descriptor describes the ringer capabilities supported by the Communications Class interface,
+/// with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
+  uint8_t bRingerVolSteps    ;
+  uint8_t bNumRingerPatterns ;
+}cdc_desc_func_telephone_ringer_t;
+
+/// \brief Telephone Operational Modes Functional Descriptor
+/// \details The Telephone Operational Modes functional descriptor describes the operational modes supported by
+/// the Communications Class interface, with the SubClass code of \ref CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
+  struct {
+    uint8_t simple_mode           : 1;
+    uint8_t standalone_mode       : 1;
+    uint8_t computer_centric_mode : 1;
+    uint8_t TU_RESERVED           : 5;
+  } bmCapabilities;
+}cdc_desc_func_telephone_operational_modes_t;
+
+/// \brief Telephone Call and Line State Reporting Capabilities Descriptor
+/// \details The Telephone Call and Line State Reporting Capabilities functional descriptor describes the abilities of a
+/// telephone device to report optional call and line states.
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
+  struct {
+    uint32_t interrupted_dialtone   : 1; ///< 0 : Reports only dialtone (does not differentiate between normal and interrupted dialtone). 1 : Reports interrupted dialtone in addition to normal dialtone
+    uint32_t ringback_busy_fastbusy : 1; ///< 0 : Reports only dialing state. 1 : Reports ringback, busy, and fast busy states.
+    uint32_t caller_id              : 1; ///< 0 : Does not report caller ID. 1 : Reports caller ID information.
+    uint32_t incoming_distinctive   : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns.
+    uint32_t dual_tone_multi_freq   : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line. 1 : Can report DTMF digits input remotely over the telephone line.
+    uint32_t line_state_change      : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notification
+    uint32_t TU_RESERVED            : 26;
+  } bmCapabilities;
+}cdc_desc_func_telephone_call_state_reporting_capabilities_t;
+
+// TODO remove
+static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc)
+{
+  return p_desc[2];
+}
+
+//--------------------------------------------------------------------+
+// Requests
+//--------------------------------------------------------------------+
+typedef struct TU_ATTR_PACKED
+{
+  uint32_t bit_rate;
+  uint8_t  stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
+  uint8_t  parity;    ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
+  uint8_t  data_bits; ///< can be 5, 6, 7, 8 or 16
+} cdc_line_coding_t;
+
+TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct");
+
+typedef struct TU_ATTR_PACKED
+{
+  uint16_t dte_is_present : 1; ///< Indicates to DCE if DTE is presentor not. This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR.
+  uint16_t half_duplex_carrier_control : 1;
+  uint16_t : 14;
+} cdc_line_control_state_t;
+
+TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct");
+
+TU_ATTR_PACKED_END  // End of all packed definitions
+TU_ATTR_BIT_FIELD_ORDER_END
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+
+/** @} */
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
new file mode 100644
index 0000000..08f2af2
--- /dev/null
+++ b/src/class/cdc/cdc_device.c
@@ -0,0 +1,486 @@
+/* 
+ * 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 (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC)
+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "cdc_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+enum
+{
+  BULK_PACKET_SIZE = (TUD_OPT_HIGH_SPEED ? 512 : 64)
+};
+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_notif;
+  uint8_t ep_in;
+  uint8_t ep_out;
+
+  // Bit 0:  DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
+  uint8_t line_state;
+
+  /*------------- From this point, data is not cleared by bus reset -------------*/
+  char    wanted_char;
+  cdc_line_coding_t line_coding;
+
+  // FIFO
+  tu_fifo_t rx_ff;
+  tu_fifo_t tx_ff;
+
+  uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE];
+  uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE];
+
+#if CFG_FIFO_MUTEX
+  osal_mutex_def_t rx_ff_mutex;
+  osal_mutex_def_t tx_ff_mutex;
+#endif
+
+  // Endpoint Transfer buffer
+  CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE];
+  CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE];
+
+}cdcd_interface_t;
+
+#define ITF_MEM_RESET_SIZE   offsetof(cdcd_interface_t, wanted_char)
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
+
+static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
+{
+  uint8_t const rhport = TUD_OPT_RHPORT;
+  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));
+
+  // claim endpoint
+  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) )
+  {
+    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;
+  }
+}
+
+//--------------------------------------------------------------------+
+// APPLICATION API
+//--------------------------------------------------------------------+
+bool tud_cdc_n_connected(uint8_t itf)
+{
+  // DTR (bit 0) active  is considered as connected
+  return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0);
+}
+
+uint8_t tud_cdc_n_get_line_state (uint8_t itf)
+{
+  return _cdcd_itf[itf].line_state;
+}
+
+void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding)
+{
+  (*coding) = _cdcd_itf[itf].line_coding;
+}
+
+void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted)
+{
+  _cdcd_itf[itf].wanted_char = wanted;
+}
+
+
+//--------------------------------------------------------------------+
+// READ API
+//--------------------------------------------------------------------+
+uint32_t tud_cdc_n_available(uint8_t itf)
+{
+  return tu_fifo_count(&_cdcd_itf[itf].rx_ff);
+}
+
+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);
+  _prep_out_transaction(p_cdc);
+  return num_read;
+}
+
+bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr)
+{
+  return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr);
+}
+
+void tud_cdc_n_read_flush (uint8_t itf)
+{
+  cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
+  tu_fifo_clear(&p_cdc->rx_ff);
+  _prep_out_transaction(p_cdc);
+}
+
+//--------------------------------------------------------------------+
+// WRITE API
+//--------------------------------------------------------------------+
+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);
+
+  // flush if queue more than packet size
+  if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE )
+  {
+    tud_cdc_n_write_flush(itf);
+  }
+
+  return ret;
+}
+
+uint32_t tud_cdc_n_write_flush (uint8_t itf)
+{
+  cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
+
+  // Skip if usb is not ready yet
+  TU_VERIFY( tud_ready(), 0 );
+
+  // No data to send
+  if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0;
+
+  uint8_t const rhport = TUD_OPT_RHPORT;
+
+  // Claim the endpoint
+  TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 );
+
+  // Pull data from FIFO
+  uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf));
+
+  if ( count )
+  {
+    TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 );
+    return count;
+  }else
+  {
+    // Release endpoint since we don't make any transfer
+    // Note: data is dropped if terminal is not connected
+    usbd_edpt_release(rhport, p_cdc->ep_in);
+    return 0;
+  }
+}
+
+uint32_t tud_cdc_n_write_available (uint8_t itf)
+{
+  return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff);
+}
+
+bool tud_cdc_n_write_clear (uint8_t itf)
+{
+  return tu_fifo_clear(&_cdcd_itf[itf].tx_ff);
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void cdcd_init(void)
+{
+  tu_memclr(_cdcd_itf, sizeof(_cdcd_itf));
+
+  for(uint8_t i=0; i<CFG_TUD_CDC; i++)
+  {
+    cdcd_interface_t* p_cdc = &_cdcd_itf[i];
+
+    p_cdc->wanted_char = (char) -1;
+
+    // default line coding is : stop bit = 1, parity = none, data bits = 8
+    p_cdc->line_coding.bit_rate  = 115200;
+    p_cdc->line_coding.stop_bits = 0;
+    p_cdc->line_coding.parity    = 0;
+    p_cdc->line_coding.data_bits = 8;
+
+    // Config RX fifo
+    tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, TU_ARRAY_SIZE(p_cdc->rx_ff_buf), 1, false);
+
+    // Config TX fifo as overwritable at initialization and will be changed to non-overwritable
+    // if terminal supports DTR bit. Without DTR we do not know if data is actually polled by terminal.
+    // In this way, the most current data is prioritized.
+    tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true);
+
+#if CFG_FIFO_MUTEX
+    tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex));
+    tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL);
+#endif
+  }
+}
+
+void cdcd_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  for(uint8_t i=0; i<CFG_TUD_CDC; i++)
+  {
+    cdcd_interface_t* p_cdc = &_cdcd_itf[i];
+
+    tu_memclr(p_cdc, ITF_MEM_RESET_SIZE);
+    tu_fifo_clear(&p_cdc->rx_ff);
+    tu_fifo_clear(&p_cdc->tx_ff);
+    tu_fifo_set_overwritable(&p_cdc->tx_ff, true);
+  }
+}
+
+uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
+{
+  // Only support ACM subclass
+  TU_VERIFY( TUSB_CLASS_CDC                           == itf_desc->bInterfaceClass &&
+             CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0);
+
+  // Find available interface
+  cdcd_interface_t * p_cdc = NULL;
+  for(uint8_t cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++)
+  {
+    if ( _cdcd_itf[cdc_id].ep_in == 0 )
+    {
+      p_cdc = &_cdcd_itf[cdc_id];
+      break;
+    }
+  }
+  TU_ASSERT(p_cdc, 0);
+
+  //------------- Control Interface -------------//
+  p_cdc->itf_num = itf_desc->bInterfaceNumber;
+
+  uint16_t drv_len = sizeof(tusb_desc_interface_t);
+  uint8_t const * p_desc = tu_desc_next( itf_desc );
+
+  // Communication Functional Descriptors
+  while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
+  {
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
+  {
+    // notification endpoint
+    tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+
+    TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 );
+    p_cdc->ep_notif = desc_ep->bEndpointAddress;
+
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  //------------- Data Interface (if any) -------------//
+  if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
+       (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
+  {
+    // next to endpoint descriptor
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+
+    // Open endpoint pair
+    TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0 );
+
+    drv_len += 2*sizeof(tusb_desc_endpoint_t);
+  }
+
+  // Prepare for incoming data
+  _prep_out_transaction(p_cdc);
+
+  return drv_len;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  // Handle class request only
+  TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
+
+  uint8_t itf = 0;
+  cdcd_interface_t* p_cdc = _cdcd_itf;
+
+  // Identify which interface to use
+  for ( ; ; itf++, p_cdc++)
+  {
+    if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
+
+    if ( p_cdc->itf_num == request->wIndex ) break;
+  }
+
+  switch ( request->bRequest )
+  {
+    case CDC_REQUEST_SET_LINE_CODING:
+      if (stage == CONTROL_STAGE_SETUP)
+      {
+        TU_LOG2("  Set Line Coding\r\n");
+        tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
+      }
+      else if ( stage == CONTROL_STAGE_ACK)
+      {
+        if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
+      }
+    break;
+
+    case CDC_REQUEST_GET_LINE_CODING:
+      if (stage == CONTROL_STAGE_SETUP)
+      {
+        TU_LOG2("  Get Line Coding\r\n");
+        tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
+      }
+    break;
+
+    case CDC_REQUEST_SET_CONTROL_LINE_STATE:
+      if (stage == CONTROL_STAGE_SETUP)
+      {
+        tud_control_status(rhport, request);
+      }
+      else if (stage == CONTROL_STAGE_ACK)
+      {
+        // CDC PSTN v1.2 section 6.3.12
+        // Bit 0: Indicates if DTE is present or not.
+        //        This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready)
+        // Bit 1: Carrier control for half-duplex modems.
+        //        This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send)
+        bool const dtr = tu_bit_test(request->wValue, 0);
+        bool const rts = tu_bit_test(request->wValue, 1);
+
+        p_cdc->line_state = (uint8_t) request->wValue;
+        
+        // Disable fifo overwriting if DTR bit is set
+        tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr);
+
+        TU_LOG2("  Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts);
+
+        // Invoke callback
+        if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts);
+      }
+    break;
+    case CDC_REQUEST_SEND_BREAK:
+      if (stage == CONTROL_STAGE_SETUP)
+      {
+        tud_control_status(rhport, request);
+      }
+      else if (stage == CONTROL_STAGE_ACK)
+      {
+        TU_LOG2("  Send Break\r\n");
+        if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue);
+      }
+    break;
+
+    default: return false; // stall unsupported request
+  }
+
+  return true;
+}
+
+bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) result;
+
+  uint8_t itf;
+  cdcd_interface_t* p_cdc;
+
+  // Identify which interface to use
+  for (itf = 0; itf < CFG_TUD_CDC; itf++)
+  {
+    p_cdc = &_cdcd_itf[itf];
+    if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break;
+  }
+  TU_ASSERT(itf < CFG_TUD_CDC);
+
+  // Received new data
+  if ( ep_addr == p_cdc->ep_out )
+  {
+    tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, xferred_bytes);
+    
+    // Check for wanted char and invoke callback if needed
+    if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) )
+    {
+      for ( uint32_t i = 0; i < xferred_bytes; i++ )
+      {
+        if ( (p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff) )
+        {
+          tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
+        }
+      }
+    }
+    
+    // invoke receive callback (if there is still data)
+    if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf);
+    
+    // prepare for OUT transaction
+    _prep_out_transaction(p_cdc);
+  }
+  
+  // Data sent to host, we continue to fetch from tx fifo to send.
+  // Note: This will cause incorrect baudrate set in line coding.
+  //       Though maybe the baudrate is not really important !!!
+  if ( ep_addr == p_cdc->ep_in )
+  {
+    // invoke transmit callback to possibly refill tx fifo
+    if ( tud_cdc_tx_complete_cb ) tud_cdc_tx_complete_cb(itf);
+
+    if ( 0 == tud_cdc_n_write_flush(itf) )
+    {
+      // If there is no data left, a ZLP should be sent if
+      // xferred_bytes is multiple of EP Packet size and not zero
+      if ( !tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) )
+      {
+        if ( usbd_edpt_claim(rhport, p_cdc->ep_in) )
+        {
+          usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0);
+        }
+      }
+    }
+  }
+
+  // nothing to do with notif endpoint for now
+
+  return true;
+}
+
+#endif
diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h
new file mode 100644
index 0000000..fbc7162
--- /dev/null
+++ b/src/class/cdc/cdc_device.h
@@ -0,0 +1,260 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_CDC_DEVICE_H_
+#define _TUSB_CDC_DEVICE_H_
+
+#include "common/tusb_common.h"
+#include "cdc.h"
+
+//--------------------------------------------------------------------+
+// Class Driver Configuration
+//--------------------------------------------------------------------+
+#if !defined(CFG_TUD_CDC_EP_BUFSIZE) && defined(CFG_TUD_CDC_EPSIZE)
+  #warning CFG_TUD_CDC_EPSIZE is renamed to CFG_TUD_CDC_EP_BUFSIZE, please update to use the new name
+  #define CFG_TUD_CDC_EP_BUFSIZE    CFG_TUD_CDC_EPSIZE
+#endif
+
+#ifndef CFG_TUD_CDC_EP_BUFSIZE
+  #define CFG_TUD_CDC_EP_BUFSIZE    (TUD_OPT_HIGH_SPEED ? 512 : 64)
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/** \addtogroup CDC_Serial Serial
+ *  @{
+ *  \defgroup   CDC_Serial_Device Device
+ *  @{ */
+
+//--------------------------------------------------------------------+
+// Application API (Multiple Ports)
+// CFG_TUD_CDC > 1
+//--------------------------------------------------------------------+
+
+// Check if terminal is connected to this port
+bool     tud_cdc_n_connected       (uint8_t itf);
+
+// Get current line state. Bit 0:  DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
+uint8_t  tud_cdc_n_get_line_state  (uint8_t itf);
+
+// Get current line encoding: bit rate, stop bits parity etc ..
+void     tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding);
+
+// Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving
+void     tud_cdc_n_set_wanted_char (uint8_t itf, char wanted);
+
+// Get the number of bytes available for reading
+uint32_t tud_cdc_n_available       (uint8_t itf);
+
+// Read received bytes
+uint32_t tud_cdc_n_read            (uint8_t itf, void* buffer, uint32_t bufsize);
+
+// Read a byte, return -1 if there is none
+static inline
+int32_t  tud_cdc_n_read_char       (uint8_t itf);
+
+// Clear the received FIFO
+void     tud_cdc_n_read_flush      (uint8_t itf);
+
+// Get a byte from FIFO at the specified position without removing it
+bool     tud_cdc_n_peek            (uint8_t itf, uint8_t* ui8);
+
+// Write bytes to TX FIFO, data may remain in the FIFO for a while
+uint32_t tud_cdc_n_write           (uint8_t itf, void const* buffer, uint32_t bufsize);
+
+// Write a byte
+static inline
+uint32_t tud_cdc_n_write_char      (uint8_t itf, char ch);
+
+// Write a null-terminated string
+static inline
+uint32_t tud_cdc_n_write_str       (uint8_t itf, char const* str);
+
+// Force sending data if possible, return number of forced bytes
+uint32_t tud_cdc_n_write_flush     (uint8_t itf);
+
+// Return the number of bytes (characters) available for writing to TX FIFO buffer in a single n_write operation.
+uint32_t tud_cdc_n_write_available (uint8_t itf);
+
+// Clear the transmit FIFO
+bool tud_cdc_n_write_clear (uint8_t itf);
+
+//--------------------------------------------------------------------+
+// Application API (Single Port)
+//--------------------------------------------------------------------+
+static inline bool     tud_cdc_connected       (void);
+static inline uint8_t  tud_cdc_get_line_state  (void);
+static inline void     tud_cdc_get_line_coding (cdc_line_coding_t* coding);
+static inline void     tud_cdc_set_wanted_char (char wanted);
+
+static inline uint32_t tud_cdc_available       (void);
+static inline int32_t  tud_cdc_read_char       (void);
+static inline uint32_t tud_cdc_read            (void* buffer, uint32_t bufsize);
+static inline void     tud_cdc_read_flush      (void);
+static inline bool     tud_cdc_peek            (uint8_t* ui8);
+
+static inline uint32_t tud_cdc_write_char      (char ch);
+static inline uint32_t tud_cdc_write           (void const* buffer, uint32_t bufsize);
+static inline uint32_t tud_cdc_write_str       (char const* str);
+static inline uint32_t tud_cdc_write_flush     (void);
+static inline uint32_t tud_cdc_write_available (void);
+static inline bool     tud_cdc_write_clear     (void);
+
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+
+// Invoked when received new data
+TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf);
+
+// Invoked when received `wanted_char`
+TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
+
+// Invoked when space becomes available in TX buffer
+TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf);
+
+// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
+TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
+
+// Invoked when line coding is change via SET_LINE_CODING
+TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
+
+// Invoked when received send break
+TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms);
+
+//--------------------------------------------------------------------+
+// Inline Functions
+//--------------------------------------------------------------------+
+static inline int32_t tud_cdc_n_read_char (uint8_t itf)
+{
+  uint8_t ch;
+  return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1;
+}
+
+static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch)
+{
+  return tud_cdc_n_write(itf, &ch, 1);
+}
+
+static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str)
+{
+  return tud_cdc_n_write(itf, str, strlen(str));
+}
+
+static inline bool tud_cdc_connected (void)
+{
+  return tud_cdc_n_connected(0);
+}
+
+static inline uint8_t tud_cdc_get_line_state (void)
+{
+  return tud_cdc_n_get_line_state(0);
+}
+
+static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding)
+{
+  tud_cdc_n_get_line_coding(0, coding);
+}
+
+static inline void tud_cdc_set_wanted_char (char wanted)
+{
+  tud_cdc_n_set_wanted_char(0, wanted);
+}
+
+static inline uint32_t tud_cdc_available (void)
+{
+  return tud_cdc_n_available(0);
+}
+
+static inline int32_t tud_cdc_read_char (void)
+{
+  return tud_cdc_n_read_char(0);
+}
+
+static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize)
+{
+  return tud_cdc_n_read(0, buffer, bufsize);
+}
+
+static inline void tud_cdc_read_flush (void)
+{
+  tud_cdc_n_read_flush(0);
+}
+
+static inline bool tud_cdc_peek (uint8_t* ui8)
+{
+  return tud_cdc_n_peek(0, ui8);
+}
+
+static inline uint32_t tud_cdc_write_char (char ch)
+{
+  return tud_cdc_n_write_char(0, ch);
+}
+
+static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize)
+{
+  return tud_cdc_n_write(0, buffer, bufsize);
+}
+
+static inline uint32_t tud_cdc_write_str (char const* str)
+{
+  return tud_cdc_n_write_str(0, str);
+}
+
+static inline uint32_t tud_cdc_write_flush (void)
+{
+  return tud_cdc_n_write_flush(0);
+}
+
+static inline uint32_t tud_cdc_write_available(void)
+{
+  return tud_cdc_n_write_available(0);
+}
+
+static inline bool tud_cdc_write_clear(void)
+{
+  return tud_cdc_n_write_clear(0);
+}
+
+/** @} */
+/** @} */
+
+//--------------------------------------------------------------------+
+// INTERNAL USBD-CLASS DRIVER API
+//--------------------------------------------------------------------+
+void     cdcd_init            (void);
+void     cdcd_reset           (uint8_t rhport);
+uint16_t cdcd_open            (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     cdcd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+bool     cdcd_xfer_cb         (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CDC_DEVICE_H_ */
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
new file mode 100644
index 0000000..f4fb6c1
--- /dev/null
+++ b/src/class/cdc/cdc_host.c
@@ -0,0 +1,249 @@
+/* 
+ * 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 (TUSB_OPT_HOST_ENABLED && CFG_TUH_CDC)
+
+#include "host/usbh.h"
+#include "host/usbh_classdriver.h"
+
+#include "cdc_host.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef struct {
+  uint8_t itf_num;
+  uint8_t itf_protocol;
+
+  uint8_t ep_notif;
+  uint8_t ep_in;
+  uint8_t ep_out;
+
+  cdc_acm_capability_t acm_capability;
+
+} cdch_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+static cdch_data_t cdch_data[CFG_TUH_DEVICE_MAX];
+
+static inline cdch_data_t* get_itf(uint8_t dev_addr)
+{
+  return &cdch_data[dev_addr-1];
+}
+
+bool tuh_cdc_mounted(uint8_t dev_addr)
+{
+  cdch_data_t* cdc = get_itf(dev_addr);
+  return cdc->ep_in && cdc->ep_out;
+}
+
+bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid)
+{
+  if ( !tuh_cdc_mounted(dev_addr) ) return false;
+
+  cdch_data_t const * p_cdc = get_itf(dev_addr);
+
+  switch (pipeid)
+  {
+    case CDC_PIPE_NOTIFICATION:
+      return usbh_edpt_busy(dev_addr, p_cdc->ep_notif );
+
+    case CDC_PIPE_DATA_IN:
+      return usbh_edpt_busy(dev_addr, p_cdc->ep_in );
+
+    case CDC_PIPE_DATA_OUT:
+      return usbh_edpt_busy(dev_addr, p_cdc->ep_out );
+
+    default:
+      return false;
+  }
+}
+
+//--------------------------------------------------------------------+
+// APPLICATION API (parameter validation needed)
+//--------------------------------------------------------------------+
+bool tuh_cdc_serial_is_mounted(uint8_t dev_addr)
+{
+  // TODO consider all AT Command as serial candidate
+  return tuh_cdc_mounted(dev_addr)                                         &&
+      (cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA);
+}
+
+bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify)
+{
+  (void) is_notify;
+  TU_VERIFY( tuh_cdc_mounted(dev_addr) );
+  TU_VERIFY( p_data != NULL && length, TUSB_ERROR_INVALID_PARA);
+
+  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);
+}
+
+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);
+
+  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);
+}
+
+bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_complete_cb_t complete_cb)
+{
+  cdch_data_t const * p_cdc = get_itf(dev_addr);
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_INTERFACE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
+    },
+    .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
+    .wValue   = (rts ? 2 : 0) | (dtr ? 1 : 0),
+    .wIndex   = p_cdc->itf_num,
+    .wLength  = 0
+  };
+
+  TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, complete_cb) );
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// USBH-CLASS DRIVER API
+//--------------------------------------------------------------------+
+void cdch_init(void)
+{
+  tu_memclr(cdch_data, sizeof(cdch_data));
+}
+
+bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
+{
+  (void) max_len;
+
+  // Only support ACM subclass
+  // Protocol 0xFF can be RNDIS device for windows XP
+  TU_VERIFY( TUSB_CLASS_CDC                           == itf_desc->bInterfaceClass &&
+             CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass &&
+             0xFF                                     != itf_desc->bInterfaceProtocol);
+
+  cdch_data_t * p_cdc = get_itf(dev_addr);
+
+  p_cdc->itf_num      = itf_desc->bInterfaceNumber;
+  p_cdc->itf_protocol = itf_desc->bInterfaceProtocol;
+
+  //------------- Communication Interface -------------//
+  uint16_t drv_len = tu_desc_len(itf_desc);
+  uint8_t const * p_desc = tu_desc_next(itf_desc);
+
+  // Communication Functional Descriptors
+  while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
+  {
+    if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
+    {
+      // save ACM bmCapabilities
+      p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
+    }
+
+    drv_len += tu_desc_len(p_desc);
+    p_desc = tu_desc_next(p_desc);
+  }
+
+  if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
+  {
+    // 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) );
+    p_cdc->ep_notif = desc_ep->bEndpointAddress;
+
+    drv_len += tu_desc_len(p_desc);
+    p_desc = tu_desc_next(p_desc);
+  }
+
+  //------------- Data Interface (if any) -------------//
+  if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
+       (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
+  {
+    // next to endpoint descriptor
+    drv_len += tu_desc_len(p_desc);
+    p_desc = tu_desc_next(p_desc);
+
+    // data endpoints expected to be in pairs
+    for(uint32_t i=0; i<2; i++)
+    {
+      tusb_desc_endpoint_t const *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));
+
+      if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
+      {
+        p_cdc->ep_in = desc_ep->bEndpointAddress;
+      }else
+      {
+        p_cdc->ep_out = desc_ep->bEndpointAddress;
+      }
+
+      drv_len += tu_desc_len(p_desc);
+      p_desc = tu_desc_next( p_desc );
+    }
+  }
+
+  return true;
+}
+
+bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num)
+{
+  (void) dev_addr; (void) itf_num;
+  return true;
+}
+
+bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
+{
+  (void) ep_addr;
+  tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes );
+  return true;
+}
+
+void cdch_close(uint8_t dev_addr)
+{
+  TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
+
+  cdch_data_t * p_cdc = get_itf(dev_addr);
+  tu_memclr(p_cdc, sizeof(cdch_data_t));
+}
+
+#endif
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
new file mode 100644
index 0000000..0d43513
--- /dev/null
+++ b/src/class/cdc/cdc_host.h
@@ -0,0 +1,134 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_CDC_HOST_H_
+#define _TUSB_CDC_HOST_H_
+
+#include "cdc.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// CDC APPLICATION PUBLIC API
+//--------------------------------------------------------------------+
+/** \ingroup ClassDriver_CDC Communication Device Class (CDC)
+ * \addtogroup CDC_Serial Serial
+ * @{
+ * \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);
+
+static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_control_complete_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)
+{
+  return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb);
+}
+
+/** \brief 			Check if device support CDC Serial interface or not
+ * \param[in]		dev_addr	device address
+ * \retval      true if device supports
+ * \retval      false if device does not support or is not mounted
+ */
+bool tuh_cdc_serial_is_mounted(uint8_t dev_addr);
+
+/** \brief      Check if the interface is currently busy or not
+ * \param[in]   dev_addr device address
+ * \param[in]   pipeid value from \ref cdc_pipeid_t to indicate target pipe.
+ * \retval      true if the interface is busy, meaning the stack is still transferring/waiting data from/to device
+ * \retval      false if the interface is not busy, meaning the stack successfully transferred data from/to device
+ * \note        This function is used to check if previous transfer is complete (success or error), so that the next transfer
+ *              can be scheduled. User needs to make sure the corresponding interface is mounted
+ *              (by \ref tuh_cdc_serial_is_mounted) before calling this function.
+ */
+bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid);
+
+/** \brief 			Perform USB OUT transfer to device
+ * \param[in]		dev_addr	device address
+ * \param[in]	  p_data    Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION)
+ * \param[in]		length    Number of bytes to be transferred via USB bus
+ * \retval      TUSB_ERROR_NONE on success
+ * \retval      TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device
+ * \retval      TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request)
+ * \retval      TUSB_ERROR_INVALID_PARA if input parameters are not correct
+ * \note        This function is non-blocking and returns immediately. The result of USB transfer will be reported by the
+ *              interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION.
+ */
+bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify);
+
+/** \brief 			Perform USB IN transfer to get data from device
+ * \param[in]		dev_addr	device address
+ * \param[in]	  p_buffer  Buffer containing received data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION)
+ * \param[in]		length    Number of bytes to be transferred via USB bus
+ * \retval      TUSB_ERROR_NONE on success
+ * \retval      TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device
+ * \retval      TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request)
+ * \retval      TUSB_ERROR_INVALID_PARA if input parameters are not correct
+ * \note        This function is non-blocking and returns immediately. The result of USB transfer will be reported by the
+ *              interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION.
+ */
+bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify);
+
+//--------------------------------------------------------------------+
+// CDC APPLICATION CALLBACKS
+//--------------------------------------------------------------------+
+
+/** \brief      Callback function that is invoked when an transferring event occurred
+ * \param[in]		dev_addr	Address of device
+ * \param[in]   event an value from \ref xfer_result_t
+ * \param[in]   pipe_id value from \ref cdc_pipeid_t indicate the pipe
+ * \param[in]   xferred_bytes Number of bytes transferred via USB bus
+ * \note        event can be one of following
+ *              - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
+ *              - XFER_RESULT_FAILED   : previously scheduled transfer encountered a transaction error.
+ *              - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device.
+ * \note
+ */
+void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes);
+
+/// @} // group CDC_Serial_Host
+/// @}
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void cdch_init       (void);
+bool cdch_open       (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
+bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool cdch_xfer_cb    (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+void cdch_close      (uint8_t dev_addr);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CDC_HOST_H_ */
diff --git a/src/class/cdc/cdc_rndis.h b/src/class/cdc/cdc_rndis.h
new file mode 100644
index 0000000..e0f129f
--- /dev/null
+++ b/src/class/cdc/cdc_rndis.h
@@ -0,0 +1,301 @@
+/* 
+ * 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 ClassDriver_CDC Communication Device Class (CDC)
+ * \defgroup CDC_RNDIS Remote Network Driver Interface Specification (RNDIS)
+ *  @{
+ *  \defgroup CDC_RNDIS_Common Common Definitions
+ *  @{ */
+
+#ifndef _TUSB_CDC_RNDIS_H_
+#define _TUSB_CDC_RNDIS_H_
+
+#include "cdc.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#ifdef __CC_ARM
+#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range
+#endif
+
+/// RNDIS Message Types
+typedef enum
+{
+  RNDIS_MSG_PACKET           = 0x00000001UL, ///< The host and device use this to send network data to one another.
+
+  RNDIS_MSG_INITIALIZE       = 0x00000002UL, ///< Sent by the host to initialize the device.
+  RNDIS_MSG_INITIALIZE_CMPLT = 0x80000002UL, ///< Device response to an initialize message.
+
+  RNDIS_MSG_HALT             = 0x00000003UL, ///< Sent by the host to halt the device. This does not have a response. It is optional for the device to send this message to the host.
+
+  RNDIS_MSG_QUERY            = 0x00000004UL, ///< Sent by the host to send a query OID.
+  RNDIS_MSG_QUERY_CMPLT      = 0x80000004UL, ///< Device response to a query OID.
+
+  RNDIS_MSG_SET              = 0x00000005UL, ///< Sent by the host to send a set OID.
+  RNDIS_MSG_SET_CMPLT        = 0x80000005UL, ///< Device response to a set OID.
+
+  RNDIS_MSG_RESET            = 0x00000006UL, ///< Sent by the host to perform a soft reset on the device.
+  RNDIS_MSG_RESET_CMPLT      = 0x80000006UL, ///< Device response to reset message.
+
+  RNDIS_MSG_INDICATE_STATUS  = 0x00000007UL, ///< Sent by the device to indicate its status or an error when an unrecognized message is received.
+
+  RNDIS_MSG_KEEP_ALIVE       = 0x00000008UL, ///< During idle periods, sent every few seconds by the host to check that the device is still responsive. It is optional for the device to send this message to check if the host is active.
+  RNDIS_MSG_KEEP_ALIVE_CMPLT = 0x80000008UL  ///< The device response to a keepalivemessage. The host can respond with this message to a keepalive message from the device when the device implements the optional KeepAliveTimer.
+}rndis_msg_type_t;
+
+/// RNDIS Message Status Values
+typedef enum
+{
+  RNDIS_STATUS_SUCCESS          = 0x00000000UL, ///< Success
+  RNDIS_STATUS_FAILURE          = 0xC0000001UL, ///< Unspecified error
+  RNDIS_STATUS_INVALID_DATA     = 0xC0010015UL, ///< Invalid data error
+  RNDIS_STATUS_NOT_SUPPORTED    = 0xC00000BBUL, ///< Unsupported request error
+  RNDIS_STATUS_MEDIA_CONNECT    = 0x4001000BUL, ///< Device is connected to a network medium.
+  RNDIS_STATUS_MEDIA_DISCONNECT = 0x4001000CUL  ///< Device is disconnected from the medium.
+}rndis_msg_status_t;
+
+#ifdef __CC_ARM
+#pragma diag_default 66 // return Keil 66 to normal severity
+#endif
+
+//--------------------------------------------------------------------+
+// MESSAGE STRUCTURE
+//--------------------------------------------------------------------+
+
+//------------- Initialize -------------//
+/// \brief Initialize Message
+/// \details This message MUST be sent by the host to initialize the device.
+typedef struct {
+  uint32_t type          ; ///< Message type, must be \ref RNDIS_MSG_INITIALIZE
+  uint32_t length        ; ///< Message length in bytes, must be 0x18
+  uint32_t request_id    ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device.
+  uint32_t major_version ; ///< The major version of the RNDIS Protocol implemented by the host.
+  uint32_t minor_version ; ///< The minor version of the RNDIS Protocol implemented by the host
+  uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the host expects to receive from the device.
+}rndis_msg_initialize_t;
+
+/// \brief Initialize Complete Message
+/// \details This message MUST be sent by the device in response to an initialize message.
+typedef struct {
+  uint32_t type                    ; ///< Message Type, must be \ref RNDIS_MSG_INITIALIZE_CMPLT
+  uint32_t length                  ; ///< Message length in bytes, must be 0x30
+  uint32_t request_id              ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_initialize_t to which this message is a response.
+  uint32_t status                  ; ///< The initialization status of the device, has value from \ref rndis_msg_status_t
+  uint32_t major_version           ; ///< the highest-numbered RNDIS Protocol version supported by the device.
+  uint32_t minor_version           ; ///< the highest-numbered RNDIS Protocol version supported by the device.
+  uint32_t device_flags            ; ///< MUST be set to 0x000000010. Other values are reserved for future use.
+  uint32_t medium                  ; ///< is 0x00 for RNDIS_MEDIUM_802_3
+  uint32_t max_packet_per_xfer     ; ///< The maximum number of concatenated \ref RNDIS_MSG_PACKET messages that the device can handle in a single bus transfer to it. This value MUST be at least 1.
+  uint32_t max_xfer_size           ; ///< The maximum size, in bytes, of any single bus data transfer that the device expects to receive from the host.
+  uint32_t packet_alignment_factor ; ///< The byte alignment the device expects for each RNDIS message that is part of a multimessage transfer to it. The value is specified as an exponent of 2; for example, the host uses 2<SUP>{PacketAlignmentFactor}</SUP> as the alignment value.
+  uint32_t reserved[2]             ;
+} rndis_msg_initialize_cmplt_t;
+
+//------------- Query -------------//
+/// \brief Query Message
+/// \details This message MUST be sent by the host to query an OID.
+typedef struct {
+  uint32_t type          ; ///< Message Type, must be \ref RNDIS_MSG_QUERY
+  uint32_t length        ; ///< Message length in bytes, including the header and the \a oid_buffer
+  uint32_t request_id    ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device.
+  uint32_t oid           ; ///< The integer value of the host operating system-defined identifier, for the parameter of the device being queried for.
+  uint32_t buffer_length ; ///< The length, in bytes, of the input data required for the OID query. This MUST be set to 0 when there is no input data associated with the OID.
+  uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the input data for the query is located in the message. This value MUST be set to 0 when there is no input data associated with the OID.
+  uint32_t reserved      ;
+  uint8_t  oid_buffer[]  ; ///< Flexible array contains the input data supplied by the host, required for the OID query request processing by the device, as per the host NDIS specification.
+} rndis_msg_query_t, rndis_msg_set_t;
+
+TU_VERIFY_STATIC(sizeof(rndis_msg_query_t) == 28, "Make sure flexible array member does not affect layout");
+
+/// \brief Query Complete Message
+/// \details This message MUST be sent by the device in response to a query OID message.
+typedef struct {
+  uint32_t type          ; ///< Message Type, must be \ref RNDIS_MSG_QUERY_CMPLT
+  uint32_t length        ; ///< Message length in bytes, including the header and the \a oid_buffer
+  uint32_t request_id    ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_query_t to which this message is a response.
+  uint32_t status        ; ///< The status of processing for the query request, has value from \ref rndis_msg_status_t.
+  uint32_t buffer_length ; ///< The length, in bytes, of the data in the response to the query. This MUST be set to 0 when there is no OIDInputBuffer.
+  uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the response data for the query is located in the message. This MUST be set to 0 when there is no \ref oid_buffer.
+  uint8_t  oid_buffer[]  ; ///< Flexible array member contains the response data to the OID query request as specified by the host.
+} rndis_msg_query_cmplt_t;
+
+TU_VERIFY_STATIC(sizeof(rndis_msg_query_cmplt_t) == 24, "Make sure flexible array member does not affect layout");
+
+//------------- Reset -------------//
+/// \brief Reset Message
+/// \details This message MUST be sent by the host to perform a soft reset on the device.
+typedef struct {
+  uint32_t type     ; ///< Message Type, must be \ref RNDIS_MSG_RESET
+  uint32_t length   ; ///< Message length in bytes, MUST be 0x06
+  uint32_t reserved ;
+} rndis_msg_reset_t;
+
+/// \brief Reset Complete Message
+/// \details This message MUST be sent by the device in response to a reset message.
+typedef struct {
+  uint32_t type             ; ///< Message Type, must be \ref RNDIS_MSG_RESET_CMPLT
+  uint32_t length           ; ///< Message length in bytes, MUST be 0x10
+  uint32_t status           ; ///< The status of processing for the \ref rndis_msg_reset_t, has value from \ref rndis_msg_status_t.
+  uint32_t addressing_reset ; ///< This field indicates whether the addressing information, which is the multicast address list or packet filter, has been lost during the reset operation. This MUST be set to 0x00000001 if the device requires that the host to resend addressing information or MUST be set to zero otherwise.
+} rndis_msg_reset_cmplt_t;
+
+//typedef struct {
+//  uint32_t type;
+//  uint32_t length;
+//  uint32_t status;
+//  uint32_t buffer_length;
+//  uint32_t buffer_offset;
+//  uint32_t diagnostic_status; // optional
+//  uint32_t diagnostic_error_offset; // optional
+//  uint32_t status_buffer[0]; // optional
+//} rndis_msg_indicate_status_t;
+
+/// \brief Keep Alive Message
+/// \details This message MUST be sent by the host to check that device is still responsive. It is optional for the device to send this message to check if the host is active
+typedef struct {
+  uint32_t type       ; ///< Message Type
+  uint32_t length     ; ///< Message length in bytes, MUST be 0x10
+  uint32_t request_id ;
+} rndis_msg_keep_alive_t, rndis_msg_halt_t;
+
+/// \brief Set Complete Message
+/// \brief This message MUST be sent in response to a the request message
+typedef struct {
+  uint32_t type       ; ///< Message Type
+  uint32_t length     ; ///< Message length in bytes, MUST be 0x10
+  uint32_t request_id ; ///< must be the same as requesting message
+  uint32_t status     ; ///< The status of processing for the request message request by the device to which this message is the response.
+} rndis_msg_set_cmplt_t, rndis_msg_keep_alive_cmplt_t;
+
+/// \brief Packet Data Message
+/// \brief This message MUST be used by the host and the device to send network data to one another.
+typedef struct {
+  uint32_t type                          ; ///< Message Type, must be \ref RNDIS_MSG_PACKET
+  uint32_t length                        ; ///< Message length in bytes, The total length of this RNDIS message including the header, payload, and padding.
+  uint32_t data_offset                   ; ///< Specifies the offset, in bytes, from the start of this \a data_offset field of this message to the start of the data. This MUST be an integer multiple of 4.
+  uint32_t data_length                   ; ///< Specifies the number of bytes in the payload of this message.
+  uint32_t out_of_band_data_offet        ; ///< Specifies the offset, in bytes, of the first out-of-band data record from the start of the DataOffset field in this message. MUST be an integer multiple of 4 when out-of-band data is present or set to 0 otherwise. When there are multiple out-ofband data records, each subsequent record MUST immediately follow the previous out-of-band data record.
+  uint32_t out_of_band_data_length       ; ///< Specifies, in bytes, the total length of the out-of-band data.
+  uint32_t num_out_of_band_data_elements ; ///< Specifies the number of out-of-band records in this message.
+  uint32_t per_packet_info_offset        ; ///< Specifies the offset, in bytes, of the start of per-packet-info data record from the start of the \a data_offset field in this message. MUST be an integer multiple of 4 when per-packet-info data record is present or MUST be set to 0 otherwise. When there are multiple per-packet-info data records, each subsequent record MUST immediately follow the previous record.
+  uint32_t per_packet_info_length        ; ///< Specifies, in bytes, the total length of per-packetinformation contained in this message.
+  uint32_t reserved[2]                   ;
+  uint32_t payload[0]                    ; ///< Network data contained in this message.
+
+  // uint8_t  padding[0]
+  // Additional bytes of zeros added at the end of the message to comply with
+  // the internal and external padding requirements. Internal padding SHOULD be as per the
+  // specification of the out-of-band data record and per-packet-info data record. The external
+  //padding size SHOULD be determined based on the PacketAlignmentFactor field specification
+  //in REMOTE_NDIS_INITIALIZE_CMPLT message by the device, when multiple
+  //REMOTE_NDIS_PACKET_MSG messages are bundled together in a single bus-native message.
+  //In this case, all but the very last REMOTE_NDIS_PACKET_MSG MUST respect the
+  //PacketAlignmentFactor field.
+
+  // rndis_msg_packet_t [0] : (optional) more packet if multiple packet per bus transaction is supported
+} rndis_msg_packet_t;
+
+
+typedef struct {
+  uint32_t size    ; ///< Length, in bytes, of this header and appended data and padding. This value MUST be an integer multiple of 4.
+  uint32_t type    ; ///< MUST be as per host operating system specification.
+  uint32_t offset  ; ///< The byte offset from the beginning of this record to the beginning of data.
+  uint32_t data[0] ; ///< Flexible array contains data
+} rndis_msg_out_of_band_data_t, rndis_msg_per_packet_info_t;
+
+//--------------------------------------------------------------------+
+// NDIS Object ID
+//--------------------------------------------------------------------+
+
+/// NDIS Object ID
+typedef enum
+{
+  //------------- General Required OIDs -------------//
+  RNDIS_OID_GEN_SUPPORTED_LIST          = 0x00010101, ///< List of supported OIDs
+  RNDIS_OID_GEN_HARDWARE_STATUS         = 0x00010102, ///< Hardware status
+  RNDIS_OID_GEN_MEDIA_SUPPORTED         = 0x00010103, ///< Media types supported (encoded)
+  RNDIS_OID_GEN_MEDIA_IN_USE            = 0x00010104, ///< Media types in use (encoded)
+  RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD       = 0x00010105, ///<
+  RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE      = 0x00010106, ///< Maximum frame size in bytes
+  RNDIS_OID_GEN_LINK_SPEED              = 0x00010107, ///< Link speed in units of 100 bps
+  RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE   = 0x00010108, ///< Transmit buffer space
+  RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE    = 0x00010109, ///< Receive buffer space
+  RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE     = 0x0001010A, ///< Minimum amount of storage, in bytes, that a single packet occupies in the transmit buffer space of the NIC
+  RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE      = 0x0001010B, ///< Amount of storage, in bytes, that a single packet occupies in the receive buffer space of the NIC
+  RNDIS_OID_GEN_VENDOR_ID               = 0x0001010C, ///< Vendor NIC code
+  RNDIS_OID_GEN_VENDOR_DESCRIPTION      = 0x0001010D, ///< Vendor network card description
+  RNDIS_OID_GEN_CURRENT_PACKET_FILTER   = 0x0001010E, ///< Current packet filter (encoded)
+  RNDIS_OID_GEN_CURRENT_LOOKAHEAD       = 0x0001010F, ///< Current lookahead size in bytes
+  RNDIS_OID_GEN_DRIVER_VERSION          = 0x00010110, ///< NDIS version number used by the driver
+  RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE      = 0x00010111, ///< Maximum total packet length in bytes
+  RNDIS_OID_GEN_PROTOCOL_OPTIONS        = 0x00010112, ///< Optional protocol flags (encoded)
+  RNDIS_OID_GEN_MAC_OPTIONS             = 0x00010113, ///< Optional NIC flags (encoded)
+  RNDIS_OID_GEN_MEDIA_CONNECT_STATUS    = 0x00010114, ///< Whether the NIC is connected to the network
+  RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS    = 0x00010115, ///< The maximum number of send packets the driver can accept per call to its MiniportSendPacketsfunction
+
+  //------------- General Optional OIDs -------------//
+  RNDIS_OID_GEN_VENDOR_DRIVER_VERSION   = 0x00010116, ///< Vendor-assigned version number of the driver
+  RNDIS_OID_GEN_SUPPORTED_GUIDS         = 0x00010117, ///< The custom GUIDs (Globally Unique Identifier) supported by the miniport driver
+  RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118, ///< List of network-layer addresses associated with the binding between a transport and the driver
+  RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119, ///< Size of packets' additional headers
+  RNDIS_OID_GEN_MEDIA_CAPABILITIES      = 0x00010201, ///<
+  RNDIS_OID_GEN_PHYSICAL_MEDIUM         = 0x00010202, ///< Physical media supported by the miniport driver (encoded)
+
+  //------------- 802.3 Objects (Ethernet) -------------//
+  RNDIS_OID_802_3_PERMANENT_ADDRESS     = 0x01010101, ///< Permanent station address
+  RNDIS_OID_802_3_CURRENT_ADDRESS       = 0x01010102, ///< Current station address
+  RNDIS_OID_802_3_MULTICAST_LIST        = 0x01010103, ///< Current multicast address list
+  RNDIS_OID_802_3_MAXIMUM_LIST_SIZE     = 0x01010104, ///< Maximum size of multicast address list
+} rndis_oid_type_t;
+
+/// RNDIS Packet Filter Bits \ref RNDIS_OID_GEN_CURRENT_PACKET_FILTER.
+typedef enum
+{
+  RNDIS_PACKET_TYPE_DIRECTED              = 0x00000001, ///< Directed packets. Directed packets contain a destination address equal to the station address of the NIC.
+  RNDIS_PACKET_TYPE_MULTICAST             = 0x00000002, ///< Multicast address packets sent to addresses in the multicast address list.
+  RNDIS_PACKET_TYPE_ALL_MULTICAST         = 0x00000004, ///< All multicast address packets, not just the ones enumerated in the multicast address list.
+  RNDIS_PACKET_TYPE_BROADCAST             = 0x00000008, ///< Broadcast packets.
+  RNDIS_PACKET_TYPE_SOURCE_ROUTING        = 0x00000010, ///< All source routing packets. If the protocol driver sets this bit, the NDIS library attempts to act as a source routing bridge.
+  RNDIS_PACKET_TYPE_PROMISCUOUS           = 0x00000020, ///< Specifies all packets regardless of whether VLAN filtering is enabled or not and whether the VLAN identifier matches or not.
+  RNDIS_PACKET_TYPE_SMT                   = 0x00000040, ///< SMT packets that an FDDI NIC receives.
+  RNDIS_PACKET_TYPE_ALL_LOCAL             = 0x00000080, ///< All packets sent by installed protocols and all packets indicated by the NIC that is identified by a given NdisBindingHandle.
+  RNDIS_PACKET_TYPE_GROUP                 = 0x00001000, ///< Packets sent to the current group address.
+  RNDIS_PACKET_TYPE_ALL_FUNCTIONAL        = 0x00002000, ///< All functional address packets, not just the ones in the current functional address.
+  RNDIS_PACKET_TYPE_FUNCTIONAL            = 0x00004000, ///< Functional address packets sent to addresses included in the current functional address.
+  RNDIS_PACKET_TYPE_MAC_FRAME             = 0x00008000, ///< NIC driver frames that a Token Ring NIC receives.
+  RNDIS_PACKET_TYPE_NO_LOCAL              = 0x00010000,
+} rndis_packet_filter_type_t;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CDC_RNDIS_H_ */
+
+/** @} */
+/** @} */
diff --git a/src/class/cdc/cdc_rndis_host.c b/src/class/cdc/cdc_rndis_host.c
new file mode 100644
index 0000000..cc4ffd1
--- /dev/null
+++ b/src/class/cdc/cdc_rndis_host.c
@@ -0,0 +1,279 @@
+/* 
+ * 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 (TUSB_OPT_HOST_ENABLED && CFG_TUH_CDC && CFG_TUH_CDC_RNDIS)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "common/tusb_common.h"
+#include "cdc_host.h"
+#include "cdc_rndis_host.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+#define RNDIS_MSG_PAYLOAD_MAX   (1024*4)
+
+CFG_TUSB_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8];
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX];
+
+static rndish_data_t rndish_data[CFG_TUH_DEVICE_MAX];
+
+// TODO Microsoft requires message length for any get command must be at least 4096 bytes
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+static tusb_error_t rndis_body_subtask(void);
+static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc,
+                                                       uint8_t * p_mess, uint32_t mess_length,
+                                                       uint8_t *p_response );
+
+//--------------------------------------------------------------------+
+// APPLICATION API
+//--------------------------------------------------------------------+
+tusb_error_t tusbh_cdc_rndis_get_mac_addr(uint8_t dev_addr, uint8_t mac_address[6])
+{
+  TU_ASSERT( tusbh_cdc_rndis_is_mounted(dev_addr),  TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED);
+  TU_VERIFY( mac_address,  TUSB_ERROR_INVALID_PARA);
+
+  memcpy(mac_address, rndish_data[dev_addr-1].mac_address, 6);
+
+  return TUSB_ERROR_NONE;
+}
+
+//--------------------------------------------------------------------+
+// IMPLEMENTATION
+//--------------------------------------------------------------------+
+
+// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper
+// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with
+// forever loop cannot have any return at all.
+OSAL_TASK_FUNCTION(cdch_rndis_task) (void* param;)
+{
+  OSAL_TASK_BEGIN
+  rndis_body_subtask();
+  OSAL_TASK_END
+}
+
+static tusb_error_t rndis_body_subtask(void)
+{
+  static uint8_t relative_addr;
+
+  OSAL_SUBTASK_BEGIN
+
+  for (relative_addr = 0; relative_addr < CFG_TUH_DEVICE_MAX; relative_addr++)
+  {
+
+  }
+
+  osal_task_delay(100);
+
+  OSAL_SUBTASK_END
+}
+
+//--------------------------------------------------------------------+
+// RNDIS-CDC Driver API
+//--------------------------------------------------------------------+
+void rndish_init(void)
+{
+  tu_memclr(rndish_data, sizeof(rndish_data_t)*CFG_TUH_DEVICE_MAX);
+
+  //------------- Task creation -------------//
+
+  //------------- semaphore creation for notificaiton pipe -------------//
+  for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
+  {
+    rndish_data[i].sem_notification_hdl = osal_semaphore_create( OSAL_SEM_REF(rndish_data[i].semaphore_notification) );
+  }
+}
+
+void rndish_close(uint8_t dev_addr)
+{
+  osal_semaphore_reset( rndish_data[dev_addr-1].sem_notification_hdl );
+//  tu_memclr(&rndish_data[dev_addr-1], sizeof(rndish_data_t)); TODO need to move semaphore & its handle out before memclr
+}
+
+
+static rndis_msg_initialize_t const msg_init =
+{
+    .type          = RNDIS_MSG_INITIALIZE,
+    .length        = sizeof(rndis_msg_initialize_t),
+    .request_id    = 1, // TODO should use some magic number
+    .major_version = 1,
+    .minor_version = 0,
+    .max_xfer_size = 0x4000 // TODO mimic windows
+};
+
+static rndis_msg_query_t const msg_query_permanent_addr =
+{
+    .type          = RNDIS_MSG_QUERY,
+    .length        = sizeof(rndis_msg_query_t)+6,
+    .request_id    = 1,
+    .oid           = RNDIS_OID_802_3_PERMANENT_ADDRESS,
+    .buffer_length = 6,
+    .buffer_offset = 20,
+};
+
+static rndis_msg_set_t const msg_set_packet_filter =
+{
+    .type          = RNDIS_MSG_SET,
+    .length        = sizeof(rndis_msg_set_t)+4,
+    .request_id    = 1,
+    .oid           = RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
+    .buffer_length = 4,
+    .buffer_offset = 20,
+};
+
+tusb_error_t rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc)
+{
+  tusb_error_t error;
+
+  OSAL_SUBTASK_BEGIN
+
+  //------------- Message Initialize -------------//
+  memcpy(msg_payload, &msg_init, sizeof(rndis_msg_initialize_t));
+  STASK_INVOKE(
+      send_message_get_response_subtask( dev_addr, p_cdc,
+                                         msg_payload, sizeof(rndis_msg_initialize_t),
+                                         msg_payload),
+      error
+  );
+  if ( TUSB_ERROR_NONE != error )   STASK_RETURN(error);
+
+  // TODO currently not support multiple data packets per xfer
+  rndis_msg_initialize_cmplt_t * const p_init_cmpt = (rndis_msg_initialize_cmplt_t *) msg_payload;
+  STASK_ASSERT(p_init_cmpt->type == RNDIS_MSG_INITIALIZE_CMPLT && p_init_cmpt->status == RNDIS_STATUS_SUCCESS &&
+                 p_init_cmpt->max_packet_per_xfer == 1 && p_init_cmpt->max_xfer_size <= RNDIS_MSG_PAYLOAD_MAX);
+  rndish_data[dev_addr-1].max_xfer_size = p_init_cmpt->max_xfer_size;
+
+  //------------- Message Query 802.3 Permanent Address -------------//
+  memcpy(msg_payload, &msg_query_permanent_addr, sizeof(rndis_msg_query_t));
+  tu_memclr(msg_payload + sizeof(rndis_msg_query_t), 6); // 6 bytes for MAC address
+
+  STASK_INVOKE(
+      send_message_get_response_subtask( dev_addr, p_cdc,
+                                         msg_payload, sizeof(rndis_msg_query_t) + 6,
+                                         msg_payload),
+      error
+  );
+  if ( TUSB_ERROR_NONE != error )   STASK_RETURN(error);
+
+  rndis_msg_query_cmplt_t * const p_query_cmpt = (rndis_msg_query_cmplt_t *) msg_payload;
+  STASK_ASSERT(p_query_cmpt->type == RNDIS_MSG_QUERY_CMPLT && p_query_cmpt->status == RNDIS_STATUS_SUCCESS);
+  memcpy(rndish_data[dev_addr-1].mac_address, msg_payload + 8 + p_query_cmpt->buffer_offset, 6);
+
+  //------------- Set OID_GEN_CURRENT_PACKET_FILTER to (DIRECTED | MULTICAST | BROADCAST) -------------//
+  memcpy(msg_payload, &msg_set_packet_filter, sizeof(rndis_msg_set_t));
+  tu_memclr(msg_payload + sizeof(rndis_msg_set_t), 4); // 4 bytes for filter flags
+  ((rndis_msg_set_t*) msg_payload)->oid_buffer[0] = (RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_MULTICAST | RNDIS_PACKET_TYPE_BROADCAST);
+
+  STASK_INVOKE(
+      send_message_get_response_subtask( dev_addr, p_cdc,
+                                         msg_payload, sizeof(rndis_msg_set_t) + 4,
+                                         msg_payload),
+      error
+  );
+  if ( TUSB_ERROR_NONE != error )   STASK_RETURN(error);
+
+  rndis_msg_set_cmplt_t * const p_set_cmpt = (rndis_msg_set_cmplt_t *) msg_payload;
+  STASK_ASSERT(p_set_cmpt->type == RNDIS_MSG_SET_CMPLT && p_set_cmpt->status == RNDIS_STATUS_SUCCESS);
+
+  tusbh_cdc_rndis_mounted_cb(dev_addr);
+
+  OSAL_SUBTASK_END
+}
+
+void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes)
+{
+  if ( pipehandle_is_equal(pipe_hdl, p_cdc->pipe_notification) )
+  {
+    osal_semaphore_post( rndish_data[pipe_hdl.dev_addr-1].sem_notification_hdl );
+  }
+}
+
+//--------------------------------------------------------------------+
+// INTERNAL & HELPER
+//--------------------------------------------------------------------+
+static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc,
+                                                       uint8_t * p_mess, uint32_t mess_length,
+                                                       uint8_t *p_response)
+{
+  tusb_error_t error;
+
+  OSAL_SUBTASK_BEGIN
+
+  //------------- Send RNDIS Control Message -------------//
+  STASK_INVOKE(
+      usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_OUT, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE),
+                                 CDC_REQUEST_SEND_ENCAPSULATED_COMMAND, 0, p_cdc->interface_number,
+                                 mess_length, p_mess),
+      error
+  );
+  if ( TUSB_ERROR_NONE != error )   STASK_RETURN(error);
+
+  //------------- waiting for Response Available notification -------------//
+  (void) usbh_edpt_xfer(p_cdc->pipe_notification, msg_notification[dev_addr-1], 8);
+  osal_semaphore_wait(rndish_data[dev_addr-1].sem_notification_hdl, OSAL_TIMEOUT_NORMAL, &error);
+  if ( TUSB_ERROR_NONE != error )   STASK_RETURN(error);
+  STASK_ASSERT(msg_notification[dev_addr-1][0] == 1);
+
+  //------------- Get RNDIS Message Initialize Complete -------------//
+  STASK_INVOKE(
+    usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_CLASS, TUSB_REQ_RCPT_INTERFACE),
+                               CDC_REQUEST_GET_ENCAPSULATED_RESPONSE, 0, p_cdc->interface_number,
+                               RNDIS_MSG_PAYLOAD_MAX, p_response),
+    error
+  );
+  if ( TUSB_ERROR_NONE != error )   STASK_RETURN(error);
+
+  OSAL_SUBTASK_END
+}
+
+//static tusb_error_t send_process_msg_initialize_subtask(uint8_t dev_addr, cdch_data_t *p_cdc)
+//{
+//  tusb_error_t error;
+//
+//  OSAL_SUBTASK_BEGIN
+//
+//  *((rndis_msg_initialize_t*) msg_payload) = (rndis_msg_initialize_t)
+//                                            {
+//                                                .type          = RNDIS_MSG_INITIALIZE,
+//                                                .length        = sizeof(rndis_msg_initialize_t),
+//                                                .request_id    = 1, // TODO should use some magic number
+//                                                .major_version = 1,
+//                                                .minor_version = 0,
+//                                                .max_xfer_size = 0x4000 // TODO mimic windows
+//                                            };
+//
+//
+//
+//  OSAL_SUBTASK_END
+//}
+#endif
diff --git a/src/class/cdc/cdc_rndis_host.h b/src/class/cdc/cdc_rndis_host.h
new file mode 100644
index 0000000..170cb3b
--- /dev/null
+++ b/src/class/cdc/cdc_rndis_host.h
@@ -0,0 +1,63 @@
+/* 
+ * 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 CDC_RNDIS
+ * \defgroup CDC_RNSID_Host Host
+ *  @{ */
+
+#ifndef _TUSB_CDC_RNDIS_HOST_H_
+#define _TUSB_CDC_RNDIS_HOST_H_
+
+#include "common/tusb_common.h"
+#include "host/usbh.h"
+#include "cdc_rndis.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// INTERNAL RNDIS-CDC Driver API
+//--------------------------------------------------------------------+
+typedef struct {
+  OSAL_SEM_DEF(semaphore_notification);
+  osal_semaphore_handle_t sem_notification_hdl;  // used to wait on notification pipe
+  uint32_t max_xfer_size; // got from device's msg initialize complete
+  uint8_t mac_address[6];
+}rndish_data_t;
+
+void rndish_init(void);
+tusb_error_t 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);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CDC_RNDIS_HOST_H_ */
+
+/** @} */
diff --git a/src/class/dfu/dfu.h b/src/class/dfu/dfu.h
new file mode 100644
index 0000000..114c827
--- /dev/null
+++ b/src/class/dfu/dfu.h
@@ -0,0 +1,119 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 XMOS LIMITED
+ *
+ * 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_DFU_H_
+#define _TUSB_DFU_H_
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Common Definitions
+//--------------------------------------------------------------------+
+
+// DFU Protocol
+typedef enum
+{
+  DFU_PROTOCOL_RT  = 0x01,
+  DFU_PROTOCOL_DFU = 0x02,
+} dfu_protocol_type_t;
+
+// DFU Descriptor Type
+typedef enum
+{
+  DFU_DESC_FUNCTIONAL = 0x21,
+} dfu_descriptor_type_t;
+
+// DFU Requests
+typedef enum {
+  DFU_REQUEST_DETACH         = 0,
+  DFU_REQUEST_DNLOAD         = 1,
+  DFU_REQUEST_UPLOAD         = 2,
+  DFU_REQUEST_GETSTATUS      = 3,
+  DFU_REQUEST_CLRSTATUS      = 4,
+  DFU_REQUEST_GETSTATE       = 5,
+  DFU_REQUEST_ABORT          = 6,
+} dfu_requests_t;
+
+// DFU States
+typedef enum {
+  APP_IDLE                   = 0,
+  APP_DETACH                 = 1,
+  DFU_IDLE                   = 2,
+  DFU_DNLOAD_SYNC            = 3,
+  DFU_DNBUSY                 = 4,
+  DFU_DNLOAD_IDLE            = 5,
+  DFU_MANIFEST_SYNC          = 6,
+  DFU_MANIFEST               = 7,
+  DFU_MANIFEST_WAIT_RESET    = 8,
+  DFU_UPLOAD_IDLE            = 9,
+  DFU_ERROR                  = 10,
+} dfu_state_t;
+
+// DFU Status
+typedef enum {
+  DFU_STATUS_OK               = 0x00,
+  DFU_STATUS_ERR_TARGET       = 0x01,
+  DFU_STATUS_ERR_FILE         = 0x02,
+  DFU_STATUS_ERR_WRITE        = 0x03,
+  DFU_STATUS_ERR_ERASE        = 0x04,
+  DFU_STATUS_ERR_CHECK_ERASED = 0x05,
+  DFU_STATUS_ERR_PROG         = 0x06,
+  DFU_STATUS_ERR_VERIFY       = 0x07,
+  DFU_STATUS_ERR_ADDRESS      = 0x08,
+  DFU_STATUS_ERR_NOTDONE      = 0x09,
+  DFU_STATUS_ERR_FIRMWARE     = 0x0A,
+  DFU_STATUS_ERR_VENDOR       = 0x0B,
+  DFU_STATUS_ERR_USBR         = 0x0C,
+  DFU_STATUS_ERR_POR          = 0x0D,
+  DFU_STATUS_ERR_UNKNOWN      = 0x0E,
+  DFU_STATUS_ERR_STALLEDPKT   = 0x0F,
+} dfu_status_t;
+
+#define DFU_ATTR_CAN_DOWNLOAD              (1u << 0)
+#define DFU_ATTR_CAN_UPLOAD                (1u << 1)
+#define DFU_ATTR_MANIFESTATION_TOLERANT    (1u << 2)
+#define DFU_ATTR_WILL_DETACH               (1u << 3)
+
+// DFU Status Request Payload
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bStatus;
+  uint8_t bwPollTimeout[3];
+  uint8_t bState;
+  uint8_t iString;
+} dfu_status_response_t;
+
+TU_VERIFY_STATIC( sizeof(dfu_status_response_t) == 6, "size is not correct");
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_DFU_H_ */
diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c
new file mode 100644
index 0000000..ddfa608
--- /dev/null
+++ b/src/class/dfu/dfu_device.c
@@ -0,0 +1,458 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 XMOS LIMITED
+ *
+ * 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_TUD_DFU)
+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "dfu_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+typedef struct
+{
+  uint8_t attrs;
+  uint8_t alt;
+
+  dfu_state_t state;
+  dfu_status_t status;
+
+  bool flashing_in_progress;
+  uint16_t block;
+  uint16_t length;
+
+  CFG_TUSB_MEM_ALIGN uint8_t transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE];
+} dfu_state_ctx_t;
+
+// Only a single dfu state is allowed
+CFG_TUSB_MEM_SECTION static dfu_state_ctx_t _dfu_ctx;
+
+static void reset_state(void)
+{
+  _dfu_ctx.state = DFU_IDLE;
+  _dfu_ctx.status = DFU_STATUS_OK;
+  _dfu_ctx.flashing_in_progress = false;
+}
+
+static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout);
+static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+
+//--------------------------------------------------------------------+
+// Debug
+//--------------------------------------------------------------------+
+#if CFG_TUSB_DEBUG >= 2
+
+static tu_lookup_entry_t const _dfu_request_lookup[] =
+{
+  { .key = DFU_REQUEST_DETACH         , .data = "DETACH"    },
+  { .key = DFU_REQUEST_DNLOAD         , .data = "DNLOAD"    },
+  { .key = DFU_REQUEST_UPLOAD         , .data = "UPLOAD"    },
+  { .key = DFU_REQUEST_GETSTATUS      , .data = "GETSTATUS" },
+  { .key = DFU_REQUEST_CLRSTATUS      , .data = "CLRSTATUS" },
+  { .key = DFU_REQUEST_GETSTATE       , .data = "GETSTATE"  },
+  { .key = DFU_REQUEST_ABORT          , .data = "ABORT"     },
+};
+
+static tu_lookup_table_t const _dfu_request_table =
+{
+  .count = TU_ARRAY_SIZE(_dfu_request_lookup),
+  .items = _dfu_request_lookup
+};
+
+static tu_lookup_entry_t const _dfu_state_lookup[] =
+{
+  { .key = APP_IDLE                   , .data = "APP_IDLE"                },
+  { .key = APP_DETACH                 , .data = "APP_DETACH"              },
+  { .key = DFU_IDLE                   , .data = "IDLE"                },
+  { .key = DFU_DNLOAD_SYNC            , .data = "DNLOAD_SYNC"         },
+  { .key = DFU_DNBUSY                 , .data = "DNBUSY"              },
+  { .key = DFU_DNLOAD_IDLE            , .data = "DNLOAD_IDLE"         },
+  { .key = DFU_MANIFEST_SYNC          , .data = "MANIFEST_SYNC"       },
+  { .key = DFU_MANIFEST               , .data = "MANIFEST"            },
+  { .key = DFU_MANIFEST_WAIT_RESET    , .data = "MANIFEST_WAIT_RESET" },
+  { .key = DFU_UPLOAD_IDLE            , .data = "UPLOAD_IDLE"         },
+  { .key = DFU_ERROR                  , .data = "ERROR"               },
+};
+
+static tu_lookup_table_t const _dfu_state_table =
+{
+  .count = TU_ARRAY_SIZE(_dfu_state_lookup),
+  .items = _dfu_state_lookup
+};
+
+static tu_lookup_entry_t const _dfu_status_lookup[] =
+{
+  { .key = DFU_STATUS_OK               , .data = "OK"              },
+  { .key = DFU_STATUS_ERR_TARGET       , .data = "errTARGET"       },
+  { .key = DFU_STATUS_ERR_FILE         , .data = "errFILE"         },
+  { .key = DFU_STATUS_ERR_WRITE        , .data = "errWRITE"        },
+  { .key = DFU_STATUS_ERR_ERASE        , .data = "errERASE"        },
+  { .key = DFU_STATUS_ERR_CHECK_ERASED , .data = "errCHECK_ERASED" },
+  { .key = DFU_STATUS_ERR_PROG         , .data = "errPROG"         },
+  { .key = DFU_STATUS_ERR_VERIFY       , .data = "errVERIFY"       },
+  { .key = DFU_STATUS_ERR_ADDRESS      , .data = "errADDRESS"      },
+  { .key = DFU_STATUS_ERR_NOTDONE      , .data = "errNOTDONE"      },
+  { .key = DFU_STATUS_ERR_FIRMWARE     , .data = "errFIRMWARE"     },
+  { .key = DFU_STATUS_ERR_VENDOR       , .data = "errVENDOR"       },
+  { .key = DFU_STATUS_ERR_USBR         , .data = "errUSBR"         },
+  { .key = DFU_STATUS_ERR_POR          , .data = "errPOR"          },
+  { .key = DFU_STATUS_ERR_UNKNOWN      , .data = "errUNKNOWN"      },
+  { .key = DFU_STATUS_ERR_STALLEDPKT   , .data = "errSTALLEDPKT"   },
+};
+
+static tu_lookup_table_t const _dfu_status_table =
+{
+  .count = TU_ARRAY_SIZE(_dfu_status_lookup),
+  .items = _dfu_status_lookup
+};
+
+#endif
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void dfu_moded_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  _dfu_ctx.attrs = 0;
+  _dfu_ctx.alt = 0;
+
+  reset_state();
+}
+
+void dfu_moded_init(void)
+{
+  dfu_moded_reset(0);
+}
+
+uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
+{
+  (void) rhport;
+
+  //------------- Interface (with Alt) descriptor -------------//
+  uint8_t const itf_num = itf_desc->bInterfaceNumber;
+  uint8_t alt_count = 0;
+
+  uint16_t drv_len = 0;
+  while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU)
+  {
+    TU_ASSERT(max_len > drv_len, 0);
+
+    // Alternate must have the same interface number
+    TU_ASSERT(itf_desc->bInterfaceNumber == itf_num, 0);
+
+    // Alt should increase by one every time
+    TU_ASSERT(itf_desc->bAlternateSetting == alt_count, 0);
+    alt_count++;
+
+    drv_len += tu_desc_len(itf_desc);
+    itf_desc = (tusb_desc_interface_t const *) tu_desc_next(itf_desc);
+  }
+
+  //------------- DFU Functional descriptor -------------//
+  tusb_desc_dfu_functional_t const *func_desc = (tusb_desc_dfu_functional_t const *) itf_desc;
+  TU_ASSERT(tu_desc_type(func_desc) == TUSB_DESC_FUNCTIONAL, 0);
+  drv_len += sizeof(tusb_desc_dfu_functional_t);
+
+  _dfu_ctx.attrs = func_desc->bAttributes;
+
+  // CFG_TUD_DFU_XFER_BUFSIZE has to be set to the buffer size used in TUD_DFU_DESCRIPTOR
+  uint16_t const transfer_size = tu_le16toh( tu_unaligned_read16((uint8_t const*) func_desc + offsetof(tusb_desc_dfu_functional_t, wTransferSize)) );
+  TU_ASSERT(transfer_size <= CFG_TUD_DFU_XFER_BUFSIZE, drv_len);
+
+  return drv_len;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
+
+  TU_LOG2("  DFU State  : %s, Status: %s\r\n", tu_lookup_find(&_dfu_state_table, _dfu_ctx.state), tu_lookup_find(&_dfu_status_table, _dfu_ctx.status));
+
+  if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD )
+  {
+    // Standard request include GET/SET_INTERFACE
+    switch ( request->bRequest )
+    {
+      case TUSB_REQ_SET_INTERFACE:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          // Switch Alt interface and reset state machine
+          _dfu_ctx.alt = (uint8_t) request->wValue;
+          reset_state();
+          return tud_control_status(rhport, request);
+        }
+      break;
+
+      case TUSB_REQ_GET_INTERFACE:
+        if(stage == CONTROL_STAGE_SETUP)
+        {
+          return tud_control_xfer(rhport, request, &_dfu_ctx.alt, 1);
+        }
+      break;
+
+      // unsupported request
+      default: return false;
+    }
+  }
+  else if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS )
+  {
+    TU_LOG2("  DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest));
+
+    // Class request
+    switch ( request->bRequest )
+    {
+      case DFU_REQUEST_DETACH:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          tud_control_status(rhport, request);
+        }
+        else if ( stage == CONTROL_STAGE_ACK )
+        {
+          if ( tud_dfu_detach_cb ) tud_dfu_detach_cb();
+        }
+      break;
+
+      case DFU_REQUEST_CLRSTATUS:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          reset_state();
+          tud_control_status(rhport, request);
+        }
+      break;
+
+      case DFU_REQUEST_GETSTATE:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          tud_control_xfer(rhport, request, &_dfu_ctx.state, 1);
+        }
+      break;
+
+      case DFU_REQUEST_ABORT:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          reset_state();
+          tud_control_status(rhport, request);
+        }
+        else if ( stage == CONTROL_STAGE_ACK )
+        {
+          if ( tud_dfu_abort_cb ) tud_dfu_abort_cb(_dfu_ctx.alt);
+        }
+      break;
+
+      case DFU_REQUEST_UPLOAD:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD);
+          TU_VERIFY(tud_dfu_upload_cb);
+          TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE);
+
+          uint16_t const xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_ctx.transfer_buf, request->wLength);
+
+          return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, xfer_len);
+        }
+      break;
+
+      case DFU_REQUEST_DNLOAD:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_DOWNLOAD);
+          TU_VERIFY(_dfu_ctx.state == DFU_IDLE || _dfu_ctx.state == DFU_DNLOAD_IDLE);
+          TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE);
+
+          // set to true for both download and manifest
+          _dfu_ctx.flashing_in_progress = true;
+
+          // save block and length for flashing
+          _dfu_ctx.block  = request->wValue;
+          _dfu_ctx.length = request->wLength;
+
+          if ( request->wLength )
+          {
+            // Download with payload -> transition to DOWNLOAD SYNC
+            _dfu_ctx.state = DFU_DNLOAD_SYNC;
+            return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, request->wLength);
+          }
+          else
+          {
+            // Download is complete -> transition to MANIFEST SYNC
+            _dfu_ctx.state = DFU_MANIFEST_SYNC;
+            return tud_control_status(rhport, request);
+          }
+        }
+      break;
+
+      case DFU_REQUEST_GETSTATUS:
+        switch ( _dfu_ctx.state )
+        {
+          case DFU_DNLOAD_SYNC:
+            return process_download_get_status(rhport, stage, request);
+          break;
+
+          case DFU_MANIFEST_SYNC:
+            return process_manifest_get_status(rhport, stage, request);
+          break;
+
+          default:
+            if ( stage == CONTROL_STAGE_SETUP ) return reply_getstatus(rhport, request, _dfu_ctx.state, _dfu_ctx.status, 0);
+          break;
+        }
+      break;
+
+      default: return false; // stall unsupported request
+    }
+  }else
+  {
+    return false; // unsupported request
+  }
+
+  return true;
+}
+
+void tud_dfu_finish_flashing(uint8_t status)
+{
+  _dfu_ctx.flashing_in_progress = false;
+
+  if ( status == DFU_STATUS_OK )
+  {
+    if (_dfu_ctx.state == DFU_DNBUSY)
+    {
+      _dfu_ctx.state = DFU_DNLOAD_SYNC;
+    }
+    else if (_dfu_ctx.state == DFU_MANIFEST)
+    {
+      _dfu_ctx.state = (_dfu_ctx.attrs & DFU_ATTR_MANIFESTATION_TOLERANT)
+                               ? DFU_MANIFEST_SYNC : DFU_MANIFEST_WAIT_RESET;
+    }
+  }
+  else
+  {
+    // failed while flashing, move to dfuError
+    _dfu_ctx.state = DFU_ERROR;
+    _dfu_ctx.status = (dfu_status_t)status;
+  }
+}
+
+static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  if ( stage == CONTROL_STAGE_SETUP )
+  {
+    // only transition to next state on CONTROL_STAGE_ACK
+    dfu_state_t next_state;
+    uint32_t timeout;
+
+    if ( _dfu_ctx.flashing_in_progress )
+    {
+      next_state = DFU_DNBUSY;
+      timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, (uint8_t) next_state);
+    }
+    else
+    {
+      next_state = DFU_DNLOAD_IDLE;
+      timeout = 0;
+    }
+
+    return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout);
+  }
+  else if ( stage == CONTROL_STAGE_ACK )
+  {
+    if ( _dfu_ctx.flashing_in_progress )
+    {
+      _dfu_ctx.state = DFU_DNBUSY;
+      tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _dfu_ctx.transfer_buf, _dfu_ctx.length);
+    }else
+    {
+      _dfu_ctx.state = DFU_DNLOAD_IDLE;
+    }
+  }
+
+  return true;
+}
+
+static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  if ( stage == CONTROL_STAGE_SETUP )
+  {
+    // only transition to next state on CONTROL_STAGE_ACK
+    dfu_state_t next_state;
+    uint32_t timeout;
+
+    if ( _dfu_ctx.flashing_in_progress )
+    {
+      next_state = DFU_MANIFEST;
+      timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, next_state);
+    }
+    else
+    {
+      next_state = DFU_IDLE;
+      timeout = 0;
+    }
+
+    return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout);
+  }
+  else if ( stage == CONTROL_STAGE_ACK )
+  {
+    if ( _dfu_ctx.flashing_in_progress )
+    {
+      _dfu_ctx.state = DFU_MANIFEST;
+      tud_dfu_manifest_cb(_dfu_ctx.alt);
+    }
+    else
+    {
+      _dfu_ctx.state = DFU_IDLE;
+    }
+  }
+
+  return true;
+}
+
+static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout)
+{
+  dfu_status_response_t resp;
+  resp.bStatus          = (uint8_t) status;
+  resp.bwPollTimeout[0] = TU_U32_BYTE0(timeout);
+  resp.bwPollTimeout[1] = TU_U32_BYTE1(timeout);
+  resp.bwPollTimeout[2] = TU_U32_BYTE2(timeout);
+  resp.bState           = (uint8_t) state;
+  resp.iString          = 0;
+
+  return tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t));
+}
+
+#endif
diff --git a/src/class/dfu/dfu_device.h b/src/class/dfu/dfu_device.h
new file mode 100644
index 0000000..fecf859
--- /dev/null
+++ b/src/class/dfu/dfu_device.h
@@ -0,0 +1,98 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 XMOS LIMITED
+ *
+ * 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_DFU_DEVICE_H_
+#define _TUSB_DFU_DEVICE_H_
+
+#include "dfu.h"
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Class Driver Default Configure & Validation
+//--------------------------------------------------------------------+
+
+#if !defined(CFG_TUD_DFU_XFER_BUFSIZE)
+  #error "CFG_TUD_DFU_XFER_BUFSIZE must be defined, it has to be set to the buffer size used in TUD_DFU_DESCRIPTOR"
+#endif
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
+// Must be called when the application is done with flashing started by
+// tud_dfu_download_cb() and tud_dfu_manifest_cb().
+// status is DFU_STATUS_OK if successful, any other error status will cause state to enter dfuError
+void tud_dfu_finish_flashing(uint8_t status);
+
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+
+// Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc.
+
+// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST)
+// Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation.
+// During this period, USB host won't try to communicate with us.
+uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state);
+
+// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests
+// This callback could be returned before flashing op is complete (async).
+// Once finished flashing, application must call tud_dfu_finish_flashing()
+void tud_dfu_download_cb (uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length);
+
+// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest)
+// Application can do checksum, or actual flashing if buffered entire image previously.
+// Once finished flashing, application must call tud_dfu_finish_flashing()
+void tud_dfu_manifest_cb(uint8_t alt);
+
+// Invoked when received DFU_UPLOAD request
+// Application must populate data with up to length bytes and
+// Return the number of written bytes
+TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length);
+
+// Invoked when a DFU_DETACH request is received
+TU_ATTR_WEAK void tud_dfu_detach_cb(void);
+
+// Invoked when the Host has terminated a download or upload transfer
+TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt);
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void     dfu_moded_init(void);
+void     dfu_moded_reset(uint8_t rhport);
+uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_DFU_MODE_DEVICE_H_ */
diff --git a/src/class/dfu/dfu_rt_device.c b/src/class/dfu/dfu_rt_device.c
new file mode 100644
index 0000000..afee2aa
--- /dev/null
+++ b/src/class/dfu/dfu_rt_device.c
@@ -0,0 +1,128 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * 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_TUD_DFU_RUNTIME)
+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "dfu_rt_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void dfu_rtd_init(void)
+{
+}
+
+void dfu_rtd_reset(uint8_t rhport)
+{
+    (void) rhport;
+}
+
+uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
+{
+  (void) rhport;
+  (void) max_len;
+
+  // Ensure this is DFU Runtime
+  TU_VERIFY((itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS) &&
+            (itf_desc->bInterfaceProtocol == DFU_PROTOCOL_RT), 0);
+
+  uint8_t const * p_desc = tu_desc_next( itf_desc );
+  uint16_t drv_len = sizeof(tusb_desc_interface_t);
+
+  if ( TUSB_DESC_FUNCTIONAL == tu_desc_type(p_desc) )
+  {
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  return drv_len;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  // nothing to do with DATA or ACK stage
+  if ( stage != CONTROL_STAGE_SETUP ) return true;
+
+  TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
+
+  // dfu-util will try to claim the interface with SET_INTERFACE request before sending DFU request
+  if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type &&
+       TUSB_REQ_SET_INTERFACE == request->bRequest )
+  {
+    tud_control_status(rhport, request);
+    return true;
+  }
+
+  // Handle class request only from here
+  TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
+
+  switch (request->bRequest)
+  {
+    case DFU_REQUEST_DETACH:
+    {
+      TU_LOG2("  DFU RT Request: DETACH\r\n");
+      tud_control_status(rhport, request);
+      tud_dfu_runtime_reboot_to_dfu_cb();
+    }
+    break;
+
+    case DFU_REQUEST_GETSTATUS:
+    {
+      TU_LOG2("  DFU RT Request: GETSTATUS\r\n");
+      dfu_status_response_t resp;
+      // Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0
+      memset(&resp, 0x00, sizeof(dfu_status_response_t));
+      tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t));
+    }
+    break;
+
+    default:
+    {
+      TU_LOG2("  DFU RT Unexpected Request: %d\r\n", request->bRequest);
+      return false; // stall unsupported request
+    }
+  }
+
+  return true;
+}
+
+#endif
diff --git a/src/class/dfu/dfu_rt_device.h b/src/class/dfu/dfu_rt_device.h
new file mode 100644
index 0000000..babaa82
--- /dev/null
+++ b/src/class/dfu/dfu_rt_device.h
@@ -0,0 +1,54 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * 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_DFU_RT_DEVICE_H_
+#define _TUSB_DFU_RT_DEVICE_H_
+
+#include "dfu.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+// Invoked when a DFU_DETACH request is received and bitWillDetach is set
+void tud_dfu_runtime_reboot_to_dfu_cb(void);
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void     dfu_rtd_init(void);
+void     dfu_rtd_reset(uint8_t rhport);
+uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_DFU_RT_DEVICE_H_ */
diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h
new file mode 100644
index 0000000..9265a2e
--- /dev/null
+++ b/src/class/hid/hid.h
@@ -0,0 +1,1119 @@
+/* 
+ * 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_class
+ *  \defgroup ClassDriver_HID Human Interface Device (HID)
+ *  @{ */
+
+#ifndef _TUSB_HID_H_
+#define _TUSB_HID_H_
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Common Definitions
+//--------------------------------------------------------------------+
+/** \defgroup ClassDriver_HID_Common Common Definitions
+ *  @{ */
+
+ /// USB HID Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength;         /**< Numeric expression that is the total size of the HID descriptor */
+  uint8_t  bDescriptorType; /**< Constant name specifying type of HID descriptor. */
+
+  uint16_t bcdHID;          /**< Numeric expression identifying the HID Class Specification release */
+  uint8_t  bCountryCode;    /**< Numeric expression identifying country code of the localized hardware.  */
+  uint8_t  bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */
+
+  uint8_t  bReportType;     /**< Type of HID class report. */
+  uint16_t wReportLength;   /**< the total size of the Report descriptor. */
+} tusb_hid_descriptor_hid_t;
+
+/// HID Subclass
+typedef enum
+{
+  HID_SUBCLASS_NONE = 0, ///< No Subclass
+  HID_SUBCLASS_BOOT = 1  ///< Boot Interface Subclass
+}hid_subclass_enum_t;
+
+/// HID Interface Protocol
+typedef enum
+{
+  HID_ITF_PROTOCOL_NONE     = 0, ///< None
+  HID_ITF_PROTOCOL_KEYBOARD = 1, ///< Keyboard
+  HID_ITF_PROTOCOL_MOUSE    = 2  ///< Mouse
+}hid_interface_protocol_enum_t;
+
+/// HID Descriptor Type
+typedef enum
+{
+  HID_DESC_TYPE_HID      = 0x21, ///< HID Descriptor
+  HID_DESC_TYPE_REPORT   = 0x22, ///< Report Descriptor
+  HID_DESC_TYPE_PHYSICAL = 0x23  ///< Physical Descriptor
+}hid_descriptor_enum_t;
+
+/// HID Request Report Type
+typedef enum
+{
+  HID_REPORT_TYPE_INVALID = 0,
+  HID_REPORT_TYPE_INPUT,      ///< Input
+  HID_REPORT_TYPE_OUTPUT,     ///< Output
+  HID_REPORT_TYPE_FEATURE     ///< Feature
+}hid_report_type_t;
+
+/// HID Class Specific Control Request
+typedef enum
+{
+  HID_REQ_CONTROL_GET_REPORT   = 0x01, ///< Get Report
+  HID_REQ_CONTROL_GET_IDLE     = 0x02, ///< Get Idle
+  HID_REQ_CONTROL_GET_PROTOCOL = 0x03, ///< Get Protocol
+  HID_REQ_CONTROL_SET_REPORT   = 0x09, ///< Set Report
+  HID_REQ_CONTROL_SET_IDLE     = 0x0a, ///< Set Idle
+  HID_REQ_CONTROL_SET_PROTOCOL = 0x0b  ///< Set Protocol
+}hid_request_enum_t;
+
+/// HID Local Code
+typedef enum
+{
+  HID_LOCAL_NotSupported = 0   , ///< NotSupported
+  HID_LOCAL_Arabic             , ///< Arabic
+  HID_LOCAL_Belgian            , ///< Belgian
+  HID_LOCAL_Canadian_Bilingual , ///< Canadian_Bilingual
+  HID_LOCAL_Canadian_French    , ///< Canadian_French
+  HID_LOCAL_Czech_Republic     , ///< Czech_Republic
+  HID_LOCAL_Danish             , ///< Danish
+  HID_LOCAL_Finnish            , ///< Finnish
+  HID_LOCAL_French             , ///< French
+  HID_LOCAL_German             , ///< German
+  HID_LOCAL_Greek              , ///< Greek
+  HID_LOCAL_Hebrew             , ///< Hebrew
+  HID_LOCAL_Hungary            , ///< Hungary
+  HID_LOCAL_International      , ///< International
+  HID_LOCAL_Italian            , ///< Italian
+  HID_LOCAL_Japan_Katakana     , ///< Japan_Katakana
+  HID_LOCAL_Korean             , ///< Korean
+  HID_LOCAL_Latin_American     , ///< Latin_American
+  HID_LOCAL_Netherlands_Dutch  , ///< Netherlands/Dutch
+  HID_LOCAL_Norwegian          , ///< Norwegian
+  HID_LOCAL_Persian_Farsi      , ///< Persian (Farsi)
+  HID_LOCAL_Poland             , ///< Poland
+  HID_LOCAL_Portuguese         , ///< Portuguese
+  HID_LOCAL_Russia             , ///< Russia
+  HID_LOCAL_Slovakia           , ///< Slovakia
+  HID_LOCAL_Spanish            , ///< Spanish
+  HID_LOCAL_Swedish            , ///< Swedish
+  HID_LOCAL_Swiss_French       , ///< Swiss/French
+  HID_LOCAL_Swiss_German       , ///< Swiss/German
+  HID_LOCAL_Switzerland        , ///< Switzerland
+  HID_LOCAL_Taiwan             , ///< Taiwan
+  HID_LOCAL_Turkish_Q          , ///< Turkish-Q
+  HID_LOCAL_UK                 , ///< UK
+  HID_LOCAL_US                 , ///< US
+  HID_LOCAL_Yugoslavia         , ///< Yugoslavia
+  HID_LOCAL_Turkish_F            ///< Turkish-F
+} hid_local_enum_t;
+
+// HID protocol value used by GetProtocol / SetProtocol
+typedef enum
+{
+  HID_PROTOCOL_BOOT = 0,
+  HID_PROTOCOL_REPORT = 1
+} hid_protocol_mode_enum_t;
+
+/** @} */
+
+//--------------------------------------------------------------------+
+// GAMEPAD
+//--------------------------------------------------------------------+
+/** \addtogroup ClassDriver_HID_Gamepad Gamepad
+ *  @{ */
+
+/* From https://www.kernel.org/doc/html/latest/input/gamepad.html
+          ____________________________              __
+         / [__ZL__]          [__ZR__] \               |
+        / [__ TL __]        [__ TR __] \              | Front Triggers
+     __/________________________________\__         __|
+    /                                  _   \          |
+   /      /\           __             (N)   \         |
+  /       ||      __  |MO|  __     _       _ \        | Main Pad
+ |    <===DP===> |SE|      |ST|   (W) -|- (E) |       |
+  \       ||    ___          ___       _     /        |
+  /\      \/   /   \        /   \     (S)   /\      __|
+ /  \________ | LS  | ____ |  RS | ________/  \       |
+|         /  \ \___/ /    \ \___/ /  \         |      | Control Sticks
+|        /    \_____/      \_____/    \        |    __|
+|       /                              \       |
+ \_____/                                \_____/
+
+     |________|______|    |______|___________|
+       D-Pad    Left       Right   Action Pad
+               Stick       Stick
+
+                 |_____________|
+                    Menu Pad
+
+  Most gamepads have the following features:
+  - Action-Pad 4 buttons in diamonds-shape (on the right side) NORTH, SOUTH, WEST and EAST.
+  - D-Pad (Direction-pad) 4 buttons (on the left side) that point up, down, left and right.
+  - Menu-Pad Different constellations, but most-times 2 buttons: SELECT - START.
+  - Analog-Sticks provide freely moveable sticks to control directions, Analog-sticks may also
+  provide a digital button if you press them.
+  - Triggers are located on the upper-side of the pad in vertical direction. The upper buttons
+  are normally named Left- and Right-Triggers, the lower buttons Z-Left and Z-Right.
+  - Rumble Many devices provide force-feedback features. But are mostly just simple rumble motors.
+ */
+
+/// HID Gamepad Protocol Report.
+typedef struct TU_ATTR_PACKED
+{
+  int8_t  x;         ///< Delta x  movement of left analog-stick
+  int8_t  y;         ///< Delta y  movement of left analog-stick
+  int8_t  z;         ///< Delta z  movement of right analog-joystick
+  int8_t  rz;        ///< Delta Rz movement of right analog-joystick
+  int8_t  rx;        ///< Delta Rx movement of analog left trigger
+  int8_t  ry;        ///< Delta Ry movement of analog right trigger
+  uint8_t hat;       ///< Buttons mask for currently pressed buttons in the DPad/hat
+  uint32_t buttons;  ///< Buttons mask for currently pressed buttons
+}hid_gamepad_report_t;
+
+/// Standard Gamepad Buttons Bitmap
+typedef enum
+{
+  GAMEPAD_BUTTON_0  = TU_BIT(0),
+  GAMEPAD_BUTTON_1  = TU_BIT(1),
+  GAMEPAD_BUTTON_2  = TU_BIT(2),
+  GAMEPAD_BUTTON_3  = TU_BIT(3),
+  GAMEPAD_BUTTON_4  = TU_BIT(4),
+  GAMEPAD_BUTTON_5  = TU_BIT(5),
+  GAMEPAD_BUTTON_6  = TU_BIT(6),
+  GAMEPAD_BUTTON_7  = TU_BIT(7),
+  GAMEPAD_BUTTON_8  = TU_BIT(8),
+  GAMEPAD_BUTTON_9  = TU_BIT(9),
+  GAMEPAD_BUTTON_10 = TU_BIT(10),
+  GAMEPAD_BUTTON_11 = TU_BIT(11),
+  GAMEPAD_BUTTON_12 = TU_BIT(12),
+  GAMEPAD_BUTTON_13 = TU_BIT(13),
+  GAMEPAD_BUTTON_14 = TU_BIT(14),
+  GAMEPAD_BUTTON_15 = TU_BIT(15),
+  GAMEPAD_BUTTON_16 = TU_BIT(16),
+  GAMEPAD_BUTTON_17 = TU_BIT(17),
+  GAMEPAD_BUTTON_18 = TU_BIT(18),
+  GAMEPAD_BUTTON_19 = TU_BIT(19),
+  GAMEPAD_BUTTON_20 = TU_BIT(20),
+  GAMEPAD_BUTTON_21 = TU_BIT(21),
+  GAMEPAD_BUTTON_22 = TU_BIT(22),
+  GAMEPAD_BUTTON_23 = TU_BIT(23),
+  GAMEPAD_BUTTON_24 = TU_BIT(24),
+  GAMEPAD_BUTTON_25 = TU_BIT(25),
+  GAMEPAD_BUTTON_26 = TU_BIT(26),
+  GAMEPAD_BUTTON_27 = TU_BIT(27),
+  GAMEPAD_BUTTON_28 = TU_BIT(28),
+  GAMEPAD_BUTTON_29 = TU_BIT(29),
+  GAMEPAD_BUTTON_30 = TU_BIT(30),
+  GAMEPAD_BUTTON_31 = TU_BIT(31),
+}hid_gamepad_button_bm_t;
+
+/// Standard Gamepad Buttons Naming from Linux input event codes
+/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
+#define GAMEPAD_BUTTON_A       GAMEPAD_BUTTON_0
+#define GAMEPAD_BUTTON_SOUTH   GAMEPAD_BUTTON_0
+
+#define GAMEPAD_BUTTON_B       GAMEPAD_BUTTON_1
+#define GAMEPAD_BUTTON_EAST    GAMEPAD_BUTTON_1
+
+#define GAMEPAD_BUTTON_C       GAMEPAD_BUTTON_2
+
+#define GAMEPAD_BUTTON_X       GAMEPAD_BUTTON_3
+#define GAMEPAD_BUTTON_NORTH   GAMEPAD_BUTTON_3
+
+#define GAMEPAD_BUTTON_Y       GAMEPAD_BUTTON_4
+#define GAMEPAD_BUTTON_WEST    GAMEPAD_BUTTON_4
+
+#define GAMEPAD_BUTTON_Z       GAMEPAD_BUTTON_5
+#define GAMEPAD_BUTTON_TL      GAMEPAD_BUTTON_6
+#define GAMEPAD_BUTTON_TR      GAMEPAD_BUTTON_7
+#define GAMEPAD_BUTTON_TL2     GAMEPAD_BUTTON_8
+#define GAMEPAD_BUTTON_TR2     GAMEPAD_BUTTON_9
+#define GAMEPAD_BUTTON_SELECT  GAMEPAD_BUTTON_10
+#define GAMEPAD_BUTTON_START   GAMEPAD_BUTTON_11
+#define GAMEPAD_BUTTON_MODE    GAMEPAD_BUTTON_12
+#define GAMEPAD_BUTTON_THUMBL  GAMEPAD_BUTTON_13
+#define GAMEPAD_BUTTON_THUMBR  GAMEPAD_BUTTON_14
+
+/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes)
+typedef enum
+{
+  GAMEPAD_HAT_CENTERED   = 0,  ///< DPAD_CENTERED
+  GAMEPAD_HAT_UP         = 1,  ///< DPAD_UP
+  GAMEPAD_HAT_UP_RIGHT   = 2,  ///< DPAD_UP_RIGHT
+  GAMEPAD_HAT_RIGHT      = 3,  ///< DPAD_RIGHT
+  GAMEPAD_HAT_DOWN_RIGHT = 4,  ///< DPAD_DOWN_RIGHT
+  GAMEPAD_HAT_DOWN       = 5,  ///< DPAD_DOWN
+  GAMEPAD_HAT_DOWN_LEFT  = 6,  ///< DPAD_DOWN_LEFT
+  GAMEPAD_HAT_LEFT       = 7,  ///< DPAD_LEFT
+  GAMEPAD_HAT_UP_LEFT    = 8,  ///< DPAD_UP_LEFT
+}hid_gamepad_hat_t;
+
+/// @}
+
+//--------------------------------------------------------------------+
+// MOUSE
+//--------------------------------------------------------------------+
+/** \addtogroup ClassDriver_HID_Mouse Mouse
+ *  @{ */
+
+/// Standard HID Boot Protocol Mouse Report.
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */
+  int8_t  x;       /**< Current delta x movement of the mouse. */
+  int8_t  y;       /**< Current delta y movement on the mouse. */
+  int8_t  wheel;   /**< Current delta wheel movement on the mouse. */
+  int8_t  pan;     // using AC Pan
+} hid_mouse_report_t;
+
+/// Standard Mouse Buttons Bitmap
+typedef enum
+{
+  MOUSE_BUTTON_LEFT     = TU_BIT(0), ///< Left button
+  MOUSE_BUTTON_RIGHT    = TU_BIT(1), ///< Right button
+  MOUSE_BUTTON_MIDDLE   = TU_BIT(2), ///< Middle button
+  MOUSE_BUTTON_BACKWARD = TU_BIT(3), ///< Backward button,
+  MOUSE_BUTTON_FORWARD  = TU_BIT(4), ///< Forward button,
+}hid_mouse_button_bm_t;
+
+/// @}
+
+//--------------------------------------------------------------------+
+// Keyboard
+//--------------------------------------------------------------------+
+/** \addtogroup ClassDriver_HID_Keyboard Keyboard
+ *  @{ */
+
+/// Standard HID Boot Protocol Keyboard Report.
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t modifier;   /**< Keyboard modifier (KEYBOARD_MODIFIER_* masks). */
+  uint8_t reserved;   /**< Reserved for OEM use, always set to 0. */
+  uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */
+} hid_keyboard_report_t;
+
+/// Keyboard modifier codes bitmap
+typedef enum
+{
+  KEYBOARD_MODIFIER_LEFTCTRL   = TU_BIT(0), ///< Left Control
+  KEYBOARD_MODIFIER_LEFTSHIFT  = TU_BIT(1), ///< Left Shift
+  KEYBOARD_MODIFIER_LEFTALT    = TU_BIT(2), ///< Left Alt
+  KEYBOARD_MODIFIER_LEFTGUI    = TU_BIT(3), ///< Left Window
+  KEYBOARD_MODIFIER_RIGHTCTRL  = TU_BIT(4), ///< Right Control
+  KEYBOARD_MODIFIER_RIGHTSHIFT = TU_BIT(5), ///< Right Shift
+  KEYBOARD_MODIFIER_RIGHTALT   = TU_BIT(6), ///< Right Alt
+  KEYBOARD_MODIFIER_RIGHTGUI   = TU_BIT(7)  ///< Right Window
+}hid_keyboard_modifier_bm_t;
+
+typedef enum
+{
+  KEYBOARD_LED_NUMLOCK    = TU_BIT(0), ///< Num Lock LED
+  KEYBOARD_LED_CAPSLOCK   = TU_BIT(1), ///< Caps Lock LED
+  KEYBOARD_LED_SCROLLLOCK = TU_BIT(2), ///< Scroll Lock LED
+  KEYBOARD_LED_COMPOSE    = TU_BIT(3), ///< Composition Mode
+  KEYBOARD_LED_KANA       = TU_BIT(4) ///< Kana mode
+}hid_keyboard_led_bm_t;
+
+/// @}
+
+//--------------------------------------------------------------------+
+// HID KEYCODE
+//--------------------------------------------------------------------+
+#define HID_KEY_NONE                      0x00
+#define HID_KEY_A                         0x04
+#define HID_KEY_B                         0x05
+#define HID_KEY_C                         0x06
+#define HID_KEY_D                         0x07
+#define HID_KEY_E                         0x08
+#define HID_KEY_F                         0x09
+#define HID_KEY_G                         0x0A
+#define HID_KEY_H                         0x0B
+#define HID_KEY_I                         0x0C
+#define HID_KEY_J                         0x0D
+#define HID_KEY_K                         0x0E
+#define HID_KEY_L                         0x0F
+#define HID_KEY_M                         0x10
+#define HID_KEY_N                         0x11
+#define HID_KEY_O                         0x12
+#define HID_KEY_P                         0x13
+#define HID_KEY_Q                         0x14
+#define HID_KEY_R                         0x15
+#define HID_KEY_S                         0x16
+#define HID_KEY_T                         0x17
+#define HID_KEY_U                         0x18
+#define HID_KEY_V                         0x19
+#define HID_KEY_W                         0x1A
+#define HID_KEY_X                         0x1B
+#define HID_KEY_Y                         0x1C
+#define HID_KEY_Z                         0x1D
+#define HID_KEY_1                         0x1E
+#define HID_KEY_2                         0x1F
+#define HID_KEY_3                         0x20
+#define HID_KEY_4                         0x21
+#define HID_KEY_5                         0x22
+#define HID_KEY_6                         0x23
+#define HID_KEY_7                         0x24
+#define HID_KEY_8                         0x25
+#define HID_KEY_9                         0x26
+#define HID_KEY_0                         0x27
+#define HID_KEY_ENTER                     0x28
+#define HID_KEY_ESCAPE                    0x29
+#define HID_KEY_BACKSPACE                 0x2A
+#define HID_KEY_TAB                       0x2B
+#define HID_KEY_SPACE                     0x2C
+#define HID_KEY_MINUS                     0x2D
+#define HID_KEY_EQUAL                     0x2E
+#define HID_KEY_BRACKET_LEFT              0x2F
+#define HID_KEY_BRACKET_RIGHT             0x30
+#define HID_KEY_BACKSLASH                 0x31
+#define HID_KEY_EUROPE_1                  0x32
+#define HID_KEY_SEMICOLON                 0x33
+#define HID_KEY_APOSTROPHE                0x34
+#define HID_KEY_GRAVE                     0x35
+#define HID_KEY_COMMA                     0x36
+#define HID_KEY_PERIOD                    0x37
+#define HID_KEY_SLASH                     0x38
+#define HID_KEY_CAPS_LOCK                 0x39
+#define HID_KEY_F1                        0x3A
+#define HID_KEY_F2                        0x3B
+#define HID_KEY_F3                        0x3C
+#define HID_KEY_F4                        0x3D
+#define HID_KEY_F5                        0x3E
+#define HID_KEY_F6                        0x3F
+#define HID_KEY_F7                        0x40
+#define HID_KEY_F8                        0x41
+#define HID_KEY_F9                        0x42
+#define HID_KEY_F10                       0x43
+#define HID_KEY_F11                       0x44
+#define HID_KEY_F12                       0x45
+#define HID_KEY_PRINT_SCREEN              0x46
+#define HID_KEY_SCROLL_LOCK               0x47
+#define HID_KEY_PAUSE                     0x48
+#define HID_KEY_INSERT                    0x49
+#define HID_KEY_HOME                      0x4A
+#define HID_KEY_PAGE_UP                   0x4B
+#define HID_KEY_DELETE                    0x4C
+#define HID_KEY_END                       0x4D
+#define HID_KEY_PAGE_DOWN                 0x4E
+#define HID_KEY_ARROW_RIGHT               0x4F
+#define HID_KEY_ARROW_LEFT                0x50
+#define HID_KEY_ARROW_DOWN                0x51
+#define HID_KEY_ARROW_UP                  0x52
+#define HID_KEY_NUM_LOCK                  0x53
+#define HID_KEY_KEYPAD_DIVIDE             0x54
+#define HID_KEY_KEYPAD_MULTIPLY           0x55
+#define HID_KEY_KEYPAD_SUBTRACT           0x56
+#define HID_KEY_KEYPAD_ADD                0x57
+#define HID_KEY_KEYPAD_ENTER              0x58
+#define HID_KEY_KEYPAD_1                  0x59
+#define HID_KEY_KEYPAD_2                  0x5A
+#define HID_KEY_KEYPAD_3                  0x5B
+#define HID_KEY_KEYPAD_4                  0x5C
+#define HID_KEY_KEYPAD_5                  0x5D
+#define HID_KEY_KEYPAD_6                  0x5E
+#define HID_KEY_KEYPAD_7                  0x5F
+#define HID_KEY_KEYPAD_8                  0x60
+#define HID_KEY_KEYPAD_9                  0x61
+#define HID_KEY_KEYPAD_0                  0x62
+#define HID_KEY_KEYPAD_DECIMAL            0x63
+#define HID_KEY_EUROPE_2                  0x64
+#define HID_KEY_APPLICATION               0x65
+#define HID_KEY_POWER                     0x66
+#define HID_KEY_KEYPAD_EQUAL              0x67
+#define HID_KEY_F13                       0x68
+#define HID_KEY_F14                       0x69
+#define HID_KEY_F15                       0x6A
+#define HID_KEY_F16                       0x6B
+#define HID_KEY_F17                       0x6C
+#define HID_KEY_F18                       0x6D
+#define HID_KEY_F19                       0x6E
+#define HID_KEY_F20                       0x6F
+#define HID_KEY_F21                       0x70
+#define HID_KEY_F22                       0x71
+#define HID_KEY_F23                       0x72
+#define HID_KEY_F24                       0x73
+#define HID_KEY_EXECUTE                   0x74
+#define HID_KEY_HELP                      0x75
+#define HID_KEY_MENU                      0x76
+#define HID_KEY_SELECT                    0x77
+#define HID_KEY_STOP                      0x78
+#define HID_KEY_AGAIN                     0x79
+#define HID_KEY_UNDO                      0x7A
+#define HID_KEY_CUT                       0x7B
+#define HID_KEY_COPY                      0x7C
+#define HID_KEY_PASTE                     0x7D
+#define HID_KEY_FIND                      0x7E
+#define HID_KEY_MUTE                      0x7F
+#define HID_KEY_VOLUME_UP                 0x80
+#define HID_KEY_VOLUME_DOWN               0x81
+#define HID_KEY_LOCKING_CAPS_LOCK         0x82
+#define HID_KEY_LOCKING_NUM_LOCK          0x83
+#define HID_KEY_LOCKING_SCROLL_LOCK       0x84
+#define HID_KEY_KEYPAD_COMMA              0x85
+#define HID_KEY_KEYPAD_EQUAL_SIGN         0x86
+#define HID_KEY_KANJI1                    0x87
+#define HID_KEY_KANJI2                    0x88
+#define HID_KEY_KANJI3                    0x89
+#define HID_KEY_KANJI4                    0x8A
+#define HID_KEY_KANJI5                    0x8B
+#define HID_KEY_KANJI6                    0x8C
+#define HID_KEY_KANJI7                    0x8D
+#define HID_KEY_KANJI8                    0x8E
+#define HID_KEY_KANJI9                    0x8F
+#define HID_KEY_LANG1                     0x90
+#define HID_KEY_LANG2                     0x91
+#define HID_KEY_LANG3                     0x92
+#define HID_KEY_LANG4                     0x93
+#define HID_KEY_LANG5                     0x94
+#define HID_KEY_LANG6                     0x95
+#define HID_KEY_LANG7                     0x96
+#define HID_KEY_LANG8                     0x97
+#define HID_KEY_LANG9                     0x98
+#define HID_KEY_ALTERNATE_ERASE           0x99
+#define HID_KEY_SYSREQ_ATTENTION          0x9A
+#define HID_KEY_CANCEL                    0x9B
+#define HID_KEY_CLEAR                     0x9C
+#define HID_KEY_PRIOR                     0x9D
+#define HID_KEY_RETURN                    0x9E
+#define HID_KEY_SEPARATOR                 0x9F
+#define HID_KEY_OUT                       0xA0
+#define HID_KEY_OPER                      0xA1
+#define HID_KEY_CLEAR_AGAIN               0xA2
+#define HID_KEY_CRSEL_PROPS               0xA3
+#define HID_KEY_EXSEL                     0xA4
+// RESERVED					                      0xA5-DF
+#define HID_KEY_CONTROL_LEFT              0xE0
+#define HID_KEY_SHIFT_LEFT                0xE1
+#define HID_KEY_ALT_LEFT                  0xE2
+#define HID_KEY_GUI_LEFT                  0xE3
+#define HID_KEY_CONTROL_RIGHT             0xE4
+#define HID_KEY_SHIFT_RIGHT               0xE5
+#define HID_KEY_ALT_RIGHT                 0xE6
+#define HID_KEY_GUI_RIGHT                 0xE7
+
+
+//--------------------------------------------------------------------+
+// REPORT DESCRIPTOR
+//--------------------------------------------------------------------+
+
+//------------- ITEM & TAG -------------//
+#define HID_REPORT_DATA_0(data)
+#define HID_REPORT_DATA_1(data) , data
+#define HID_REPORT_DATA_2(data) , U16_TO_U8S_LE(data)
+#define HID_REPORT_DATA_3(data) , U32_TO_U8S_LE(data)
+
+#define HID_REPORT_ITEM(data, tag, type, size) \
+  (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data)
+
+// Report Item Types
+enum {
+  RI_TYPE_MAIN   = 0,
+  RI_TYPE_GLOBAL = 1,
+  RI_TYPE_LOCAL  = 2
+};
+
+//------------- Main Items - HID 1.11 section 6.2.2.4 -------------//
+
+// Report Item Main group
+enum {
+  RI_MAIN_INPUT          = 8,
+  RI_MAIN_OUTPUT         = 9,
+  RI_MAIN_COLLECTION     = 10,
+  RI_MAIN_FEATURE        = 11,
+  RI_MAIN_COLLECTION_END = 12
+};
+
+#define HID_INPUT(x)           HID_REPORT_ITEM(x, RI_MAIN_INPUT         , RI_TYPE_MAIN, 1)
+#define HID_OUTPUT(x)          HID_REPORT_ITEM(x, RI_MAIN_OUTPUT        , RI_TYPE_MAIN, 1)
+#define HID_COLLECTION(x)      HID_REPORT_ITEM(x, RI_MAIN_COLLECTION    , RI_TYPE_MAIN, 1)
+#define HID_FEATURE(x)         HID_REPORT_ITEM(x, RI_MAIN_FEATURE       , RI_TYPE_MAIN, 1)
+#define HID_COLLECTION_END     HID_REPORT_ITEM(x, RI_MAIN_COLLECTION_END, RI_TYPE_MAIN, 0)
+
+//------------- Input, Output, Feature - HID 1.11 section 6.2.2.5 -------------//
+#define HID_DATA             (0<<0)
+#define HID_CONSTANT         (1<<0)
+
+#define HID_ARRAY            (0<<1)
+#define HID_VARIABLE         (1<<1)
+
+#define HID_ABSOLUTE         (0<<2)
+#define HID_RELATIVE         (1<<2)
+
+#define HID_WRAP_NO          (0<<3)
+#define HID_WRAP             (1<<3)
+
+#define HID_LINEAR           (0<<4)
+#define HID_NONLINEAR        (1<<4)
+
+#define HID_PREFERRED_STATE  (0<<5)
+#define HID_PREFERRED_NO     (1<<5)
+
+#define HID_NO_NULL_POSITION (0<<6)
+#define HID_NULL_STATE       (1<<6)
+
+#define HID_NON_VOLATILE     (0<<7)
+#define HID_VOLATILE         (1<<7)
+
+#define HID_BITFIELD         (0<<8)
+#define HID_BUFFERED_BYTES   (1<<8)
+
+//------------- Collection Item - HID 1.11 section 6.2.2.6 -------------//
+enum {
+  HID_COLLECTION_PHYSICAL = 0,
+  HID_COLLECTION_APPLICATION,
+  HID_COLLECTION_LOGICAL,
+  HID_COLLECTION_REPORT,
+  HID_COLLECTION_NAMED_ARRAY,
+  HID_COLLECTION_USAGE_SWITCH,
+  HID_COLLECTION_USAGE_MODIFIER
+};
+
+//------------- Global Items - HID 1.11 section 6.2.2.7 -------------//
+
+// Report Item Global group
+enum {
+  RI_GLOBAL_USAGE_PAGE    = 0,
+  RI_GLOBAL_LOGICAL_MIN   = 1,
+  RI_GLOBAL_LOGICAL_MAX   = 2,
+  RI_GLOBAL_PHYSICAL_MIN  = 3,
+  RI_GLOBAL_PHYSICAL_MAX  = 4,
+  RI_GLOBAL_UNIT_EXPONENT = 5,
+  RI_GLOBAL_UNIT          = 6,
+  RI_GLOBAL_REPORT_SIZE   = 7,
+  RI_GLOBAL_REPORT_ID     = 8,
+  RI_GLOBAL_REPORT_COUNT  = 9,
+  RI_GLOBAL_PUSH          = 10,
+  RI_GLOBAL_POP           = 11
+};
+
+#define HID_USAGE_PAGE(x)         HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, 1)
+#define HID_USAGE_PAGE_N(x, n)    HID_REPORT_ITEM(x, RI_GLOBAL_USAGE_PAGE, RI_TYPE_GLOBAL, n)
+
+#define HID_LOGICAL_MIN(x)        HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, 1)
+#define HID_LOGICAL_MIN_N(x, n)   HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MIN, RI_TYPE_GLOBAL, n)
+
+#define HID_LOGICAL_MAX(x)        HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, 1)
+#define HID_LOGICAL_MAX_N(x, n)   HID_REPORT_ITEM(x, RI_GLOBAL_LOGICAL_MAX, RI_TYPE_GLOBAL, n)
+
+#define HID_PHYSICAL_MIN(x)       HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, 1)
+#define HID_PHYSICAL_MIN_N(x, n)  HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MIN, RI_TYPE_GLOBAL, n)
+
+#define HID_PHYSICAL_MAX(x)       HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, 1)
+#define HID_PHYSICAL_MAX_N(x, n)  HID_REPORT_ITEM(x, RI_GLOBAL_PHYSICAL_MAX, RI_TYPE_GLOBAL, n)
+
+#define HID_UNIT_EXPONENT(x)      HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, 1)
+#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, RI_GLOBAL_UNIT_EXPONENT, RI_TYPE_GLOBAL, n)
+
+#define HID_UNIT(x)               HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, 1)
+#define HID_UNIT_N(x, n)          HID_REPORT_ITEM(x, RI_GLOBAL_UNIT, RI_TYPE_GLOBAL, n)
+
+#define HID_REPORT_SIZE(x)        HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, 1)
+#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_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)
+
+#define HID_PUSH                  HID_REPORT_ITEM(x, RI_GLOBAL_PUSH, RI_TYPE_GLOBAL, 0)
+#define HID_POP                   HID_REPORT_ITEM(x, RI_GLOBAL_POP, RI_TYPE_GLOBAL, 0)
+
+//------------- LOCAL ITEMS 6.2.2.8 -------------//
+
+enum {
+  RI_LOCAL_USAGE            = 0,
+  RI_LOCAL_USAGE_MIN        = 1,
+  RI_LOCAL_USAGE_MAX        = 2,
+  RI_LOCAL_DESIGNATOR_INDEX = 3,
+  RI_LOCAL_DESIGNATOR_MIN   = 4,
+  RI_LOCAL_DESIGNATOR_MAX   = 5,
+  // 6 is reserved
+  RI_LOCAL_STRING_INDEX     = 7,
+  RI_LOCAL_STRING_MIN       = 8,
+  RI_LOCAL_STRING_MAX       = 9,
+  RI_LOCAL_DELIMITER        = 10,
+};
+
+#define HID_USAGE(x)              HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, 1)
+#define HID_USAGE_N(x, n)         HID_REPORT_ITEM(x, RI_LOCAL_USAGE, RI_TYPE_LOCAL, n)
+
+#define HID_USAGE_MIN(x)          HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, 1)
+#define HID_USAGE_MIN_N(x, n)     HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MIN, RI_TYPE_LOCAL, n)
+
+#define HID_USAGE_MAX(x)          HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, 1)
+#define HID_USAGE_MAX_N(x, n)     HID_REPORT_ITEM(x, RI_LOCAL_USAGE_MAX, RI_TYPE_LOCAL, n)
+
+//--------------------------------------------------------------------+
+// Usage Table
+//--------------------------------------------------------------------+
+
+/// HID Usage Table - Table 1: Usage Page Summary
+enum {
+  HID_USAGE_PAGE_DESKTOP         = 0x01,
+  HID_USAGE_PAGE_SIMULATE        = 0x02,
+  HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03,
+  HID_USAGE_PAGE_SPORT           = 0x04,
+  HID_USAGE_PAGE_GAME            = 0x05,
+  HID_USAGE_PAGE_GENERIC_DEVICE  = 0x06,
+  HID_USAGE_PAGE_KEYBOARD        = 0x07,
+  HID_USAGE_PAGE_LED             = 0x08,
+  HID_USAGE_PAGE_BUTTON          = 0x09,
+  HID_USAGE_PAGE_ORDINAL         = 0x0a,
+  HID_USAGE_PAGE_TELEPHONY       = 0x0b,
+  HID_USAGE_PAGE_CONSUMER        = 0x0c,
+  HID_USAGE_PAGE_DIGITIZER       = 0x0d,
+  HID_USAGE_PAGE_PID             = 0x0f,
+  HID_USAGE_PAGE_UNICODE         = 0x10,
+  HID_USAGE_PAGE_ALPHA_DISPLAY   = 0x14,
+  HID_USAGE_PAGE_MEDICAL         = 0x40,
+  HID_USAGE_PAGE_MONITOR         = 0x80, //0x80 - 0x83
+  HID_USAGE_PAGE_POWER           = 0x84, // 0x084 - 0x87
+  HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c,
+  HID_USAGE_PAGE_SCALE           = 0x8d,
+  HID_USAGE_PAGE_MSR             = 0x8e,
+  HID_USAGE_PAGE_CAMERA          = 0x90,
+  HID_USAGE_PAGE_ARCADE          = 0x91,
+  HID_USAGE_PAGE_VENDOR          = 0xFF00 // 0xFF00 - 0xFFFF
+};
+
+/// HID Usage Table - Table 6: Generic Desktop Page
+enum {
+  HID_USAGE_DESKTOP_POINTER                               = 0x01,
+  HID_USAGE_DESKTOP_MOUSE                                 = 0x02,
+  HID_USAGE_DESKTOP_JOYSTICK                              = 0x04,
+  HID_USAGE_DESKTOP_GAMEPAD                               = 0x05,
+  HID_USAGE_DESKTOP_KEYBOARD                              = 0x06,
+  HID_USAGE_DESKTOP_KEYPAD                                = 0x07,
+  HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER                 = 0x08,
+  HID_USAGE_DESKTOP_TABLET_PC_SYSTEM                      = 0x09,
+  HID_USAGE_DESKTOP_X                                     = 0x30,
+  HID_USAGE_DESKTOP_Y                                     = 0x31,
+  HID_USAGE_DESKTOP_Z                                     = 0x32,
+  HID_USAGE_DESKTOP_RX                                    = 0x33,
+  HID_USAGE_DESKTOP_RY                                    = 0x34,
+  HID_USAGE_DESKTOP_RZ                                    = 0x35,
+  HID_USAGE_DESKTOP_SLIDER                                = 0x36,
+  HID_USAGE_DESKTOP_DIAL                                  = 0x37,
+  HID_USAGE_DESKTOP_WHEEL                                 = 0x38,
+  HID_USAGE_DESKTOP_HAT_SWITCH                            = 0x39,
+  HID_USAGE_DESKTOP_COUNTED_BUFFER                        = 0x3a,
+  HID_USAGE_DESKTOP_BYTE_COUNT                            = 0x3b,
+  HID_USAGE_DESKTOP_MOTION_WAKEUP                         = 0x3c,
+  HID_USAGE_DESKTOP_START                                 = 0x3d,
+  HID_USAGE_DESKTOP_SELECT                                = 0x3e,
+  HID_USAGE_DESKTOP_VX                                    = 0x40,
+  HID_USAGE_DESKTOP_VY                                    = 0x41,
+  HID_USAGE_DESKTOP_VZ                                    = 0x42,
+  HID_USAGE_DESKTOP_VBRX                                  = 0x43,
+  HID_USAGE_DESKTOP_VBRY                                  = 0x44,
+  HID_USAGE_DESKTOP_VBRZ                                  = 0x45,
+  HID_USAGE_DESKTOP_VNO                                   = 0x46,
+  HID_USAGE_DESKTOP_FEATURE_NOTIFICATION                  = 0x47,
+  HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER                 = 0x48,
+  HID_USAGE_DESKTOP_SYSTEM_CONTROL                        = 0x80,
+  HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN                     = 0x81,
+  HID_USAGE_DESKTOP_SYSTEM_SLEEP                          = 0x82,
+  HID_USAGE_DESKTOP_SYSTEM_WAKE_UP                        = 0x83,
+  HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU                   = 0x84,
+  HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU                      = 0x85,
+  HID_USAGE_DESKTOP_SYSTEM_APP_MENU                       = 0x86,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_HELP                      = 0x87,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT                      = 0x88,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT                    = 0x89,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT                     = 0x8A,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT                      = 0x8B,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_UP                        = 0x8C,
+  HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN                      = 0x8D,
+  HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART                   = 0x8E,
+  HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART                   = 0x8F,
+  HID_USAGE_DESKTOP_DPAD_UP                               = 0x90,
+  HID_USAGE_DESKTOP_DPAD_DOWN                             = 0x91,
+  HID_USAGE_DESKTOP_DPAD_RIGHT                            = 0x92,
+  HID_USAGE_DESKTOP_DPAD_LEFT                             = 0x93,
+  HID_USAGE_DESKTOP_SYSTEM_DOCK                           = 0xA0,
+  HID_USAGE_DESKTOP_SYSTEM_UNDOCK                         = 0xA1,
+  HID_USAGE_DESKTOP_SYSTEM_SETUP                          = 0xA2,
+  HID_USAGE_DESKTOP_SYSTEM_BREAK                          = 0xA3,
+  HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK                 = 0xA4,
+  HID_USAGE_DESKTOP_APPLICATION_BREAK                     = 0xA5,
+  HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK            = 0xA6,
+  HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE                   = 0xA7,
+  HID_USAGE_DESKTOP_SYSTEM_HIBERNATE                      = 0xA8,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT                 = 0xB0,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL               = 0xB1,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL               = 0xB2,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH                   = 0xB3,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL                   = 0xB4,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT         = 0xB5,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6,
+  HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE          = 0xB7
+};
+
+
+/// HID Usage Table: Consumer Page (0x0C)
+/// Only contains controls that supported by Windows (whole list is too long)
+enum
+{
+  // Generic Control
+  HID_USAGE_CONSUMER_CONTROL                           = 0x0001,
+
+  // Power Control
+  HID_USAGE_CONSUMER_POWER                             = 0x0030,
+  HID_USAGE_CONSUMER_RESET                             = 0x0031,
+  HID_USAGE_CONSUMER_SLEEP                             = 0x0032,
+
+  // Screen Brightness
+  HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT              = 0x006F,
+  HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT              = 0x0070,
+
+  // These HID usages operate only on mobile systems (battery powered) and
+  // require Windows 8 (build 8302 or greater).
+  HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS           = 0x000C,
+  HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS            = 0x00C6,
+  HID_USAGE_CONSUMER_WIRELESS_RADIO_LED                = 0x00C7,
+  HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH      = 0x00C8,
+
+  // Media Control
+  HID_USAGE_CONSUMER_PLAY_PAUSE                        = 0x00CD,
+  HID_USAGE_CONSUMER_SCAN_NEXT                         = 0x00B5,
+  HID_USAGE_CONSUMER_SCAN_PREVIOUS                     = 0x00B6,
+  HID_USAGE_CONSUMER_STOP                              = 0x00B7,
+  HID_USAGE_CONSUMER_VOLUME                            = 0x00E0,
+  HID_USAGE_CONSUMER_MUTE                              = 0x00E2,
+  HID_USAGE_CONSUMER_BASS                              = 0x00E3,
+  HID_USAGE_CONSUMER_TREBLE                            = 0x00E4,
+  HID_USAGE_CONSUMER_BASS_BOOST                        = 0x00E5,
+  HID_USAGE_CONSUMER_VOLUME_INCREMENT                  = 0x00E9,
+  HID_USAGE_CONSUMER_VOLUME_DECREMENT                  = 0x00EA,
+  HID_USAGE_CONSUMER_BASS_INCREMENT                    = 0x0152,
+  HID_USAGE_CONSUMER_BASS_DECREMENT                    = 0x0153,
+  HID_USAGE_CONSUMER_TREBLE_INCREMENT                  = 0x0154,
+  HID_USAGE_CONSUMER_TREBLE_DECREMENT                  = 0x0155,
+
+  // Application Launcher
+  HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183,
+  HID_USAGE_CONSUMER_AL_EMAIL_READER                   = 0x018A,
+  HID_USAGE_CONSUMER_AL_CALCULATOR                     = 0x0192,
+  HID_USAGE_CONSUMER_AL_LOCAL_BROWSER                  = 0x0194,
+
+  // Browser/Explorer Specific
+  HID_USAGE_CONSUMER_AC_SEARCH                         = 0x0221,
+  HID_USAGE_CONSUMER_AC_HOME                           = 0x0223,
+  HID_USAGE_CONSUMER_AC_BACK                           = 0x0224,
+  HID_USAGE_CONSUMER_AC_FORWARD                        = 0x0225,
+  HID_USAGE_CONSUMER_AC_STOP                           = 0x0226,
+  HID_USAGE_CONSUMER_AC_REFRESH                        = 0x0227,
+  HID_USAGE_CONSUMER_AC_BOOKMARKS                      = 0x022A,
+
+  // Mouse Horizontal scroll
+  HID_USAGE_CONSUMER_AC_PAN                            = 0x0238,
+};
+
+/*--------------------------------------------------------------------
+ * ASCII to KEYCODE Conversion
+ *  Expand to array of [128][2] (shift, keycode)
+ *
+ * Usage: example to convert input chr into keyboard report (modifier + keycode)
+ *
+ *  uint8_t const conv_table[128][2] =  { HID_ASCII_TO_KEYCODE };
+ *
+ *  uint8_t keycode[6] = { 0 };
+ *  uint8_t modifier   = 0;
+ *
+ *  if ( conv_table[chr][0] ) modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
+ *  keycode[0] = conv_table[chr][1];
+ *  tud_hid_keyboard_report(report_id, modifier, keycode);
+ *
+ *--------------------------------------------------------------------*/
+#define HID_ASCII_TO_KEYCODE \
+    {0, 0                     }, /* 0x00 Null      */ \
+    {0, 0                     }, /* 0x01           */ \
+    {0, 0                     }, /* 0x02           */ \
+    {0, 0                     }, /* 0x03           */ \
+    {0, 0                     }, /* 0x04           */ \
+    {0, 0                     }, /* 0x05           */ \
+    {0, 0                     }, /* 0x06           */ \
+    {0, 0                     }, /* 0x07           */ \
+    {0, HID_KEY_BACKSPACE     }, /* 0x08 Backspace */ \
+    {0, HID_KEY_TAB           }, /* 0x09 Tab       */ \
+    {0, HID_KEY_ENTER         }, /* 0x0A Line Feed */ \
+    {0, 0                     }, /* 0x0B           */ \
+    {0, 0                     }, /* 0x0C           */ \
+    {0, HID_KEY_ENTER         }, /* 0x0D CR        */ \
+    {0, 0                     }, /* 0x0E           */ \
+    {0, 0                     }, /* 0x0F           */ \
+    {0, 0                     }, /* 0x10           */ \
+    {0, 0                     }, /* 0x11           */ \
+    {0, 0                     }, /* 0x12           */ \
+    {0, 0                     }, /* 0x13           */ \
+    {0, 0                     }, /* 0x14           */ \
+    {0, 0                     }, /* 0x15           */ \
+    {0, 0                     }, /* 0x16           */ \
+    {0, 0                     }, /* 0x17           */ \
+    {0, 0                     }, /* 0x18           */ \
+    {0, 0                     }, /* 0x19           */ \
+    {0, 0                     }, /* 0x1A           */ \
+    {0, HID_KEY_ESCAPE        }, /* 0x1B Escape    */ \
+    {0, 0                     }, /* 0x1C           */ \
+    {0, 0                     }, /* 0x1D           */ \
+    {0, 0                     }, /* 0x1E           */ \
+    {0, 0                     }, /* 0x1F           */ \
+                                                      \
+    {0, HID_KEY_SPACE         }, /* 0x20           */ \
+    {1, HID_KEY_1             }, /* 0x21 !         */ \
+    {1, HID_KEY_APOSTROPHE    }, /* 0x22 "         */ \
+    {1, HID_KEY_3             }, /* 0x23 #         */ \
+    {1, HID_KEY_4             }, /* 0x24 $         */ \
+    {1, HID_KEY_5             }, /* 0x25 %         */ \
+    {1, HID_KEY_7             }, /* 0x26 &         */ \
+    {0, HID_KEY_APOSTROPHE    }, /* 0x27 '         */ \
+    {1, HID_KEY_9             }, /* 0x28 (         */ \
+    {1, HID_KEY_0             }, /* 0x29 )         */ \
+    {1, HID_KEY_8             }, /* 0x2A *         */ \
+    {1, HID_KEY_EQUAL         }, /* 0x2B +         */ \
+    {0, HID_KEY_COMMA         }, /* 0x2C ,         */ \
+    {0, HID_KEY_MINUS         }, /* 0x2D -         */ \
+    {0, HID_KEY_PERIOD        }, /* 0x2E .         */ \
+    {0, HID_KEY_SLASH         }, /* 0x2F /         */ \
+    {0, HID_KEY_0             }, /* 0x30 0         */ \
+    {0, HID_KEY_1             }, /* 0x31 1         */ \
+    {0, HID_KEY_2             }, /* 0x32 2         */ \
+    {0, HID_KEY_3             }, /* 0x33 3         */ \
+    {0, HID_KEY_4             }, /* 0x34 4         */ \
+    {0, HID_KEY_5             }, /* 0x35 5         */ \
+    {0, HID_KEY_6             }, /* 0x36 6         */ \
+    {0, HID_KEY_7             }, /* 0x37 7         */ \
+    {0, HID_KEY_8             }, /* 0x38 8         */ \
+    {0, HID_KEY_9             }, /* 0x39 9         */ \
+    {1, HID_KEY_SEMICOLON     }, /* 0x3A :         */ \
+    {0, HID_KEY_SEMICOLON     }, /* 0x3B ;         */ \
+    {1, HID_KEY_COMMA         }, /* 0x3C <         */ \
+    {0, HID_KEY_EQUAL         }, /* 0x3D =         */ \
+    {1, HID_KEY_PERIOD        }, /* 0x3E >         */ \
+    {1, HID_KEY_SLASH         }, /* 0x3F ?         */ \
+                                                      \
+    {1, HID_KEY_2             }, /* 0x40 @         */ \
+    {1, HID_KEY_A             }, /* 0x41 A         */ \
+    {1, HID_KEY_B             }, /* 0x42 B         */ \
+    {1, HID_KEY_C             }, /* 0x43 C         */ \
+    {1, HID_KEY_D             }, /* 0x44 D         */ \
+    {1, HID_KEY_E             }, /* 0x45 E         */ \
+    {1, HID_KEY_F             }, /* 0x46 F         */ \
+    {1, HID_KEY_G             }, /* 0x47 G         */ \
+    {1, HID_KEY_H             }, /* 0x48 H         */ \
+    {1, HID_KEY_I             }, /* 0x49 I         */ \
+    {1, HID_KEY_J             }, /* 0x4A J         */ \
+    {1, HID_KEY_K             }, /* 0x4B K         */ \
+    {1, HID_KEY_L             }, /* 0x4C L         */ \
+    {1, HID_KEY_M             }, /* 0x4D M         */ \
+    {1, HID_KEY_N             }, /* 0x4E N         */ \
+    {1, HID_KEY_O             }, /* 0x4F O         */ \
+    {1, HID_KEY_P             }, /* 0x50 P         */ \
+    {1, HID_KEY_Q             }, /* 0x51 Q         */ \
+    {1, HID_KEY_R             }, /* 0x52 R         */ \
+    {1, HID_KEY_S             }, /* 0x53 S         */ \
+    {1, HID_KEY_T             }, /* 0x55 T         */ \
+    {1, HID_KEY_U             }, /* 0x55 U         */ \
+    {1, HID_KEY_V             }, /* 0x56 V         */ \
+    {1, HID_KEY_W             }, /* 0x57 W         */ \
+    {1, HID_KEY_X             }, /* 0x58 X         */ \
+    {1, HID_KEY_Y             }, /* 0x59 Y         */ \
+    {1, HID_KEY_Z             }, /* 0x5A Z         */ \
+    {0, HID_KEY_BRACKET_LEFT  }, /* 0x5B [         */ \
+    {0, HID_KEY_BACKSLASH     }, /* 0x5C '\'       */ \
+    {0, HID_KEY_BRACKET_RIGHT }, /* 0x5D ]         */ \
+    {1, HID_KEY_6             }, /* 0x5E ^         */ \
+    {1, HID_KEY_MINUS         }, /* 0x5F _         */ \
+                                                      \
+    {0, HID_KEY_GRAVE         }, /* 0x60 `         */ \
+    {0, HID_KEY_A             }, /* 0x61 a         */ \
+    {0, HID_KEY_B             }, /* 0x62 b         */ \
+    {0, HID_KEY_C             }, /* 0x63 c         */ \
+    {0, HID_KEY_D             }, /* 0x66 d         */ \
+    {0, HID_KEY_E             }, /* 0x65 e         */ \
+    {0, HID_KEY_F             }, /* 0x66 f         */ \
+    {0, HID_KEY_G             }, /* 0x67 g         */ \
+    {0, HID_KEY_H             }, /* 0x68 h         */ \
+    {0, HID_KEY_I             }, /* 0x69 i         */ \
+    {0, HID_KEY_J             }, /* 0x6A j         */ \
+    {0, HID_KEY_K             }, /* 0x6B k         */ \
+    {0, HID_KEY_L             }, /* 0x6C l         */ \
+    {0, HID_KEY_M             }, /* 0x6D m         */ \
+    {0, HID_KEY_N             }, /* 0x6E n         */ \
+    {0, HID_KEY_O             }, /* 0x6F o         */ \
+    {0, HID_KEY_P             }, /* 0x70 p         */ \
+    {0, HID_KEY_Q             }, /* 0x71 q         */ \
+    {0, HID_KEY_R             }, /* 0x72 r         */ \
+    {0, HID_KEY_S             }, /* 0x73 s         */ \
+    {0, HID_KEY_T             }, /* 0x75 t         */ \
+    {0, HID_KEY_U             }, /* 0x75 u         */ \
+    {0, HID_KEY_V             }, /* 0x76 v         */ \
+    {0, HID_KEY_W             }, /* 0x77 w         */ \
+    {0, HID_KEY_X             }, /* 0x78 x         */ \
+    {0, HID_KEY_Y             }, /* 0x79 y         */ \
+    {0, HID_KEY_Z             }, /* 0x7A z         */ \
+    {1, HID_KEY_BRACKET_LEFT  }, /* 0x7B {         */ \
+    {1, HID_KEY_BACKSLASH     }, /* 0x7C |         */ \
+    {1, HID_KEY_BRACKET_RIGHT }, /* 0x7D }         */ \
+    {1, HID_KEY_GRAVE         }, /* 0x7E ~         */ \
+    {0, HID_KEY_DELETE        }  /* 0x7F Delete    */ \
+
+/*--------------------------------------------------------------------
+ * KEYCODE to Ascii Conversion
+ *  Expand to array of [128][2] (ascii without shift, ascii with shift)
+ *
+ * Usage: example to convert ascii from keycode (key) and shift modifier (shift).
+ * Here we assume key < 128 ( printable )
+ *
+ *  uint8_t const conv_table[128][2] =  { HID_KEYCODE_TO_ASCII };
+ *  char ch = shift ? conv_table[chr][1] : conv_table[chr][0];
+ *
+ *--------------------------------------------------------------------*/
+#define HID_KEYCODE_TO_ASCII    \
+    {0     , 0      }, /* 0x00 */ \
+    {0     , 0      }, /* 0x01 */ \
+    {0     , 0      }, /* 0x02 */ \
+    {0     , 0      }, /* 0x03 */ \
+    {'a'   , 'A'    }, /* 0x04 */ \
+    {'b'   , 'B'    }, /* 0x05 */ \
+    {'c'   , 'C'    }, /* 0x06 */ \
+    {'d'   , 'D'    }, /* 0x07 */ \
+    {'e'   , 'E'    }, /* 0x08 */ \
+    {'f'   , 'F'    }, /* 0x09 */ \
+    {'g'   , 'G'    }, /* 0x0a */ \
+    {'h'   , 'H'    }, /* 0x0b */ \
+    {'i'   , 'I'    }, /* 0x0c */ \
+    {'j'   , 'J'    }, /* 0x0d */ \
+    {'k'   , 'K'    }, /* 0x0e */ \
+    {'l'   , 'L'    }, /* 0x0f */ \
+    {'m'   , 'M'    }, /* 0x10 */ \
+    {'n'   , 'N'    }, /* 0x11 */ \
+    {'o'   , 'O'    }, /* 0x12 */ \
+    {'p'   , 'P'    }, /* 0x13 */ \
+    {'q'   , 'Q'    }, /* 0x14 */ \
+    {'r'   , 'R'    }, /* 0x15 */ \
+    {'s'   , 'S'    }, /* 0x16 */ \
+    {'t'   , 'T'    }, /* 0x17 */ \
+    {'u'   , 'U'    }, /* 0x18 */ \
+    {'v'   , 'V'    }, /* 0x19 */ \
+    {'w'   , 'W'    }, /* 0x1a */ \
+    {'x'   , 'X'    }, /* 0x1b */ \
+    {'y'   , 'Y'    }, /* 0x1c */ \
+    {'z'   , 'Z'    }, /* 0x1d */ \
+    {'1'   , '!'    }, /* 0x1e */ \
+    {'2'   , '@'    }, /* 0x1f */ \
+    {'3'   , '#'    }, /* 0x20 */ \
+    {'4'   , '$'    }, /* 0x21 */ \
+    {'5'   , '%'    }, /* 0x22 */ \
+    {'6'   , '^'    }, /* 0x23 */ \
+    {'7'   , '&'    }, /* 0x24 */ \
+    {'8'   , '*'    }, /* 0x25 */ \
+    {'9'   , '('    }, /* 0x26 */ \
+    {'0'   , ')'    }, /* 0x27 */ \
+    {'\r'  , '\r'   }, /* 0x28 */ \
+    {'\x1b', '\x1b' }, /* 0x29 */ \
+    {'\b'  , '\b'   }, /* 0x2a */ \
+    {'\t'  , '\t'   }, /* 0x2b */ \
+    {' '   , ' '    }, /* 0x2c */ \
+    {'-'   , '_'    }, /* 0x2d */ \
+    {'='   , '+'    }, /* 0x2e */ \
+    {'['   , '{'    }, /* 0x2f */ \
+    {']'   , '}'    }, /* 0x30 */ \
+    {'\\'  , '|'    }, /* 0x31 */ \
+    {'#'   , '~'    }, /* 0x32 */ \
+    {';'   , ':'    }, /* 0x33 */ \
+    {'\''  , '\"'   }, /* 0x34 */ \
+    {'`'   , '~'    }, /* 0x35 */ \
+    {','   , '<'    }, /* 0x36 */ \
+    {'.'   , '>'    }, /* 0x37 */ \
+    {'/'   , '?'    }, /* 0x38 */ \
+                                  \
+    {0     , 0      }, /* 0x39 */ \
+    {0     , 0      }, /* 0x3a */ \
+    {0     , 0      }, /* 0x3b */ \
+    {0     , 0      }, /* 0x3c */ \
+    {0     , 0      }, /* 0x3d */ \
+    {0     , 0      }, /* 0x3e */ \
+    {0     , 0      }, /* 0x3f */ \
+    {0     , 0      }, /* 0x40 */ \
+    {0     , 0      }, /* 0x41 */ \
+    {0     , 0      }, /* 0x42 */ \
+    {0     , 0      }, /* 0x43 */ \
+    {0     , 0      }, /* 0x44 */ \
+    {0     , 0      }, /* 0x45 */ \
+    {0     , 0      }, /* 0x46 */ \
+    {0     , 0      }, /* 0x47 */ \
+    {0     , 0      }, /* 0x48 */ \
+    {0     , 0      }, /* 0x49 */ \
+    {0     , 0      }, /* 0x4a */ \
+    {0     , 0      }, /* 0x4b */ \
+    {0     , 0      }, /* 0x4c */ \
+    {0     , 0      }, /* 0x4d */ \
+    {0     , 0      }, /* 0x4e */ \
+    {0     , 0      }, /* 0x4f */ \
+    {0     , 0      }, /* 0x50 */ \
+    {0     , 0      }, /* 0x51 */ \
+    {0     , 0      }, /* 0x52 */ \
+    {0     , 0      }, /* 0x53 */ \
+                                  \
+    {'/'   , '/'    }, /* 0x54 */ \
+    {'*'   , '*'    }, /* 0x55 */ \
+    {'-'   , '-'    }, /* 0x56 */ \
+    {'+'   , '+'    }, /* 0x57 */ \
+    {'\r'  , '\r'   }, /* 0x58 */ \
+    {'1'   , 0      }, /* 0x59 */ \
+    {'2'   , 0      }, /* 0x5a */ \
+    {'3'   , 0      }, /* 0x5b */ \
+    {'4'   , 0      }, /* 0x5c */ \
+    {'5'   , '5'    }, /* 0x5d */ \
+    {'6'   , 0      }, /* 0x5e */ \
+    {'7'   , 0      }, /* 0x5f */ \
+    {'8'   , 0      }, /* 0x60 */ \
+    {'9'   , 0      }, /* 0x61 */ \
+    {'0'   , 0      }, /* 0x62 */ \
+    {'0'   , 0      }, /* 0x63 */ \
+    {'='   , '='    }, /* 0x67 */ \
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_HID_H__ */
+
+/// @}
diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c
new file mode 100644
index 0000000..588b612
--- /dev/null
+++ b/src/class/hid/hid_device.c
@@ -0,0 +1,417 @@
+/*
+ * 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 (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_HID)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "hid_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_in;
+  uint8_t ep_out;        // optional Out endpoint
+  uint8_t itf_protocol;  // Boot mouse or keyboard
+
+  uint8_t protocol_mode; // Boot (0) or Report protocol (1)
+  uint8_t idle_rate;     // up to application to handle idle rate
+  uint16_t report_desc_len;
+
+  CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE];
+  CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE];
+
+  // TODO save hid descriptor since host can specifically request this after enumeration
+  // Note: HID descriptor may be not available from application after enumeration
+  tusb_hid_descriptor_hid_t const * hid_descriptor;
+} hidd_interface_t;
+
+CFG_TUSB_MEM_SECTION static hidd_interface_t _hidd_itf[CFG_TUD_HID];
+
+/*------------- Helpers -------------*/
+static inline uint8_t get_index_by_itfnum(uint8_t itf_num)
+{
+	for (uint8_t i=0; i < CFG_TUD_HID; i++ )
+	{
+		if ( itf_num == _hidd_itf[i].itf_num ) return i;
+	}
+
+	return 0xFF;
+}
+
+//--------------------------------------------------------------------+
+// APPLICATION API
+//--------------------------------------------------------------------+
+bool tud_hid_n_ready(uint8_t instance)
+{
+  uint8_t const ep_in = _hidd_itf[instance].ep_in;
+  return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(TUD_OPT_RHPORT, ep_in);
+}
+
+bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint8_t len)
+{
+  uint8_t const rhport = 0;
+  hidd_interface_t * p_hid = &_hidd_itf[instance];
+
+  // claim endpoint
+  TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) );
+
+  // prepare data
+  if (report_id)
+  {
+    len = tu_min8(len, CFG_TUD_HID_EP_BUFSIZE-1);
+
+    p_hid->epin_buf[0] = report_id;
+    memcpy(p_hid->epin_buf+1, report, len);
+    len++;
+  }else
+  {
+    // If report id = 0, skip ID field
+    len = tu_min8(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);
+}
+
+uint8_t tud_hid_n_interface_protocol(uint8_t instance)
+{
+  return _hidd_itf[instance].itf_protocol;
+}
+
+uint8_t tud_hid_n_get_protocol(uint8_t instance)
+{
+  return _hidd_itf[instance].protocol_mode;
+}
+
+bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
+{
+  hid_keyboard_report_t report;
+
+  report.modifier = modifier;
+  report.reserved = 0;
+
+  if ( keycode )
+  {
+    memcpy(report.keycode, keycode, 6);
+  }else
+  {
+    tu_memclr(report.keycode, 6);
+  }
+
+  return tud_hid_n_report(instance, report_id, &report, sizeof(report));
+}
+
+bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id,
+                            uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
+{
+  hid_mouse_report_t report =
+  {
+    .buttons = buttons,
+    .x       = x,
+    .y       = y,
+    .wheel   = vertical,
+    .pan     = horizontal
+  };
+
+  return tud_hid_n_report(instance, report_id, &report, sizeof(report));
+}
+
+bool tud_hid_n_gamepad_report(uint8_t instance, 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)
+{
+  hid_gamepad_report_t report =
+  {
+    .x       = x,
+    .y       = y,
+    .z       = z,
+    .rz      = rz,
+    .rx      = rx,
+    .ry      = ry,
+    .hat     = hat,
+    .buttons = buttons,
+  };
+
+  return tud_hid_n_report(instance, report_id, &report, sizeof(report));
+}
+
+//--------------------------------------------------------------------+
+// USBD-CLASS API
+//--------------------------------------------------------------------+
+void hidd_init(void)
+{
+  hidd_reset(TUD_OPT_RHPORT);
+}
+
+void hidd_reset(uint8_t rhport)
+{
+  (void) rhport;
+  tu_memclr(_hidd_itf, sizeof(_hidd_itf));
+}
+
+uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len)
+{
+  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);
+  TU_ASSERT(max_len >= drv_len, 0);
+
+  // Find available interface
+  hidd_interface_t * p_hid = NULL;
+  uint8_t hid_id;
+  for(hid_id=0; hid_id<CFG_TUD_HID; hid_id++)
+  {
+    if ( _hidd_itf[hid_id].ep_in == 0 )
+    {
+      p_hid = &_hidd_itf[hid_id];
+      break;
+    }
+  }
+  TU_ASSERT(p_hid, 0);
+
+  uint8_t const *p_desc = (uint8_t const *) desc_itf;
+
+  //------------- HID descriptor -------------//
+  p_desc = tu_desc_next(p_desc);
+  TU_ASSERT(HID_DESC_TYPE_HID == tu_desc_type(p_desc), 0);
+  p_hid->hid_descriptor = (tusb_hid_descriptor_hid_t const *) p_desc;
+
+  //------------- Endpoint Descriptor -------------//
+  p_desc = tu_desc_next(p_desc);
+  TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0);
+
+  if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol;
+
+  p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode
+  p_hid->itf_num       = desc_itf->bInterfaceNumber;
+
+  // Use offsetof to avoid pointer to the odd/misaligned address
+  p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*) p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength));
+
+  // Prepare for output endpoint
+  if (p_hid->ep_out)
+  {
+    if ( !usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)) )
+    {
+      TU_LOG_FAILED();
+      TU_BREAKPOINT();
+    }
+  }
+
+  return drv_len;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
+
+  uint8_t const hid_itf = get_index_by_itfnum((uint8_t) request->wIndex);
+  TU_VERIFY(hid_itf < CFG_TUD_HID);
+
+  hidd_interface_t* p_hid = &_hidd_itf[hid_itf];
+
+  if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
+  {
+    //------------- STD Request -------------//
+    if ( stage == CONTROL_STAGE_SETUP )
+    {
+      uint8_t const desc_type  = tu_u16_high(request->wValue);
+      //uint8_t const desc_index = tu_u16_low (request->wValue);
+
+      if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID)
+      {
+        TU_VERIFY(p_hid->hid_descriptor);
+        TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) p_hid->hid_descriptor, p_hid->hid_descriptor->bLength));
+      }
+      else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT)
+      {
+        uint8_t const * desc_report = tud_hid_descriptor_report_cb(hid_itf);
+        tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_report, p_hid->report_desc_len);
+      }
+      else
+      {
+        return false; // stall unsupported request
+      }
+    }
+  }
+  else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
+  {
+    //------------- Class Specific Request -------------//
+    switch( request->bRequest )
+    {
+      case HID_REQ_CONTROL_GET_REPORT:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          uint8_t const report_type = tu_u16_high(request->wValue);
+          uint8_t const report_id   = tu_u16_low(request->wValue);
+
+          uint8_t* report_buf = p_hid->epin_buf;
+          uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
+
+          uint16_t xferlen = 0;
+
+          // If host request a specific Report ID, add ID to as 1 byte of response
+          if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) )
+          {
+            *report_buf++ = report_id;
+            req_len--;
+
+            xferlen++;
+          }
+
+          xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len);
+          TU_ASSERT( xferlen > 0 );
+
+          tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen);
+        }
+      break;
+
+      case  HID_REQ_CONTROL_SET_REPORT:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          TU_VERIFY(request->wLength <= sizeof(p_hid->epout_buf));
+          tud_control_xfer(rhport, request, p_hid->epout_buf, request->wLength);
+        }
+        else if ( stage == CONTROL_STAGE_ACK )
+        {
+          uint8_t const report_type = tu_u16_high(request->wValue);
+          uint8_t const report_id   = tu_u16_low(request->wValue);
+
+          uint8_t const* report_buf = p_hid->epout_buf;
+          uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
+
+          // If host request a specific Report ID, extract report ID in buffer before invoking callback
+          if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) )
+          {
+            report_buf++;
+            report_len--;
+          }
+
+          tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len);
+        }
+      break;
+
+      case HID_REQ_CONTROL_SET_IDLE:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          p_hid->idle_rate = tu_u16_high(request->wValue);
+          if ( tud_hid_set_idle_cb )
+          {
+            // stall request if callback return false
+            TU_VERIFY( tud_hid_set_idle_cb( hid_itf, p_hid->idle_rate) );
+          }
+
+          tud_control_status(rhport, request);
+        }
+      break;
+
+      case HID_REQ_CONTROL_GET_IDLE:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          // TODO idle rate of report
+          tud_control_xfer(rhport, request, &p_hid->idle_rate, 1);
+        }
+      break;
+
+      case HID_REQ_CONTROL_GET_PROTOCOL:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1);
+        }
+      break;
+
+      case HID_REQ_CONTROL_SET_PROTOCOL:
+        if ( stage == CONTROL_STAGE_SETUP )
+        {
+          tud_control_status(rhport, request);
+        }
+        else if ( stage == CONTROL_STAGE_ACK )
+        {
+          p_hid->protocol_mode = (uint8_t) request->wValue;
+          if (tud_hid_set_protocol_cb)
+          {
+            tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode);
+          }
+        }
+      break;
+
+      default: return false; // stall unsupported request
+    }
+  }else
+  {
+    return false; // stall unsupported request
+  }
+
+  return true;
+}
+
+bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) result;
+
+  uint8_t instance = 0;
+  hidd_interface_t * p_hid = _hidd_itf;
+
+  // Identify which interface to use
+  for (instance = 0; instance < CFG_TUD_HID; instance++)
+  {
+    p_hid = &_hidd_itf[instance];
+    if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break;
+  }
+  TU_ASSERT(instance < CFG_TUD_HID);
+
+  // Sent report successfully
+  if (ep_addr == p_hid->ep_in)
+  {
+    if (tud_hid_report_complete_cb)
+    {
+      tud_hid_report_complete_cb(instance, p_hid->epin_buf, (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);
+    TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
+  }
+
+  return true;
+}
+
+#endif
diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h
new file mode 100644
index 0000000..078b673
--- /dev/null
+++ b/src/class/hid/hid_device.h
@@ -0,0 +1,393 @@
+/*
+ * 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.
+ */
+
+#ifndef _TUSB_HID_DEVICE_H_
+#define _TUSB_HID_DEVICE_H_
+
+#include "hid.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Class Driver Default Configure & Validation
+//--------------------------------------------------------------------+
+
+#if !defined(CFG_TUD_HID_EP_BUFSIZE) & defined(CFG_TUD_HID_BUFSIZE)
+  // TODO warn user to use new name later on
+  // #warning CFG_TUD_HID_BUFSIZE is renamed to CFG_TUD_HID_EP_BUFSIZE, please update to use the new name
+  #define CFG_TUD_HID_EP_BUFSIZE  CFG_TUD_HID_BUFSIZE
+#endif
+
+#ifndef CFG_TUD_HID_EP_BUFSIZE
+  #define CFG_TUD_HID_EP_BUFSIZE     64
+#endif
+
+//--------------------------------------------------------------------+
+// Application API (Multiple Instances)
+// CFG_TUD_HID > 1
+//--------------------------------------------------------------------+
+
+// Check if the interface is ready to use
+bool tud_hid_n_ready(uint8_t instance);
+
+// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values
+uint8_t tud_hid_n_interface_protocol(uint8_t instance);
+
+// Get current active protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
+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);
+
+// KEYBOARD: convenient helper to send keyboard report if application
+// use template layout report as defined by hid_keyboard_report_t
+bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
+
+// MOUSE: convenient helper to send mouse report if application
+// use template layout report as defined by hid_mouse_report_t
+bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
+
+// Gamepad: convenient helper to send gamepad report if application
+// use template layout report TUD_HID_REPORT_DESC_GAMEPAD
+bool tud_hid_n_gamepad_report(uint8_t instance, 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);
+
+//--------------------------------------------------------------------+
+// Application API (Single Port)
+//--------------------------------------------------------------------+
+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_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);
+
+//--------------------------------------------------------------------+
+// Callbacks (Weak is optional)
+//--------------------------------------------------------------------+
+
+// Invoked when received GET HID REPORT DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance);
+
+// Invoked when received GET_REPORT control request
+// Application must fill buffer report's content and return its length.
+// Return zero will cause the stack to STALL request
+uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen);
+
+// Invoked when received SET_REPORT control request or
+// received data on OUT endpoint ( Report ID = 0, Type = 0 )
+void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize);
+
+// Invoked when received SET_PROTOCOL request
+// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
+TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol);
+
+// Invoked when received SET_IDLE request. return false will stall the request
+// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication
+// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms).
+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);
+
+
+//--------------------------------------------------------------------+
+// Inline Functions
+//--------------------------------------------------------------------+
+static inline bool tud_hid_ready(void)
+{
+  return tud_hid_n_ready(0);
+}
+
+static inline uint8_t tud_hid_interface_protocol(void)
+{
+  return tud_hid_n_interface_protocol(0);
+}
+
+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)
+{
+  return tud_hid_n_report(0, report_id, report, len);
+}
+
+static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
+{
+  return tud_hid_n_keyboard_report(0, report_id, modifier, keycode);
+}
+
+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)
+{
+  return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, 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)
+{
+  return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons);
+}
+
+/* --------------------------------------------------------------------+
+ * HID Report Descriptor Template
+ *
+ * Convenient for declaring popular HID device (keyboard, mouse, consumer,
+ * gamepad etc...). Templates take "HID_REPORT_ID(n)" as input, leave
+ * empty if multiple reports is not used
+ *
+ * - Only 1 report: no parameter
+ *      uint8_t const report_desc[] = { TUD_HID_REPORT_DESC_KEYBOARD() };
+ *
+ * - Multiple Reports: "HID_REPORT_ID(ID)" must be passed to template
+ *      uint8_t const report_desc[] =
+ *      {
+ *          TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1) ) ,
+ *          TUD_HID_REPORT_DESC_MOUSE   ( HID_REPORT_ID(2) )
+ *      };
+ *--------------------------------------------------------------------*/
+
+// Keyboard Report Descriptor Template
+#define TUD_HID_REPORT_DESC_KEYBOARD(...) \
+  HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP     )                    ,\
+  HID_USAGE      ( HID_USAGE_DESKTOP_KEYBOARD )                    ,\
+  HID_COLLECTION ( HID_COLLECTION_APPLICATION )                    ,\
+    /* Report ID if any */\
+    __VA_ARGS__ \
+    /* 8 bits Modifier Keys (Shfit, Control, Alt) */ \
+    HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD )                     ,\
+      HID_USAGE_MIN    ( 224                                    )  ,\
+      HID_USAGE_MAX    ( 231                                    )  ,\
+      HID_LOGICAL_MIN  ( 0                                      )  ,\
+      HID_LOGICAL_MAX  ( 1                                      )  ,\
+      HID_REPORT_COUNT ( 8                                      )  ,\
+      HID_REPORT_SIZE  ( 1                                      )  ,\
+      HID_INPUT        ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE )  ,\
+      /* 8 bit reserved */ \
+      HID_REPORT_COUNT ( 1                                      )  ,\
+      HID_REPORT_SIZE  ( 8                                      )  ,\
+      HID_INPUT        ( HID_CONSTANT                           )  ,\
+    /* Output 5-bit LED Indicator Kana | Compose | ScrollLock | CapsLock | NumLock */ \
+    HID_USAGE_PAGE  ( HID_USAGE_PAGE_LED                   )       ,\
+      HID_USAGE_MIN    ( 1                                       ) ,\
+      HID_USAGE_MAX    ( 5                                       ) ,\
+      HID_REPORT_COUNT ( 5                                       ) ,\
+      HID_REPORT_SIZE  ( 1                                       ) ,\
+      HID_OUTPUT       ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE  ) ,\
+      /* led padding */ \
+      HID_REPORT_COUNT ( 1                                       ) ,\
+      HID_REPORT_SIZE  ( 3                                       ) ,\
+      HID_OUTPUT       ( HID_CONSTANT                            ) ,\
+    /* 6-byte Keycodes */ \
+    HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD )                     ,\
+      HID_USAGE_MIN    ( 0                                   )     ,\
+      HID_USAGE_MAX_N  ( 255, 2                              )     ,\
+      HID_LOGICAL_MIN  ( 0                                   )     ,\
+      HID_LOGICAL_MAX_N( 255, 2                              )     ,\
+      HID_REPORT_COUNT ( 6                                   )     ,\
+      HID_REPORT_SIZE  ( 8                                   )     ,\
+      HID_INPUT        ( HID_DATA | HID_ARRAY | HID_ABSOLUTE )     ,\
+  HID_COLLECTION_END \
+
+// Mouse Report Descriptor Template
+#define TUD_HID_REPORT_DESC_MOUSE(...) \
+  HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP      )                   ,\
+  HID_USAGE      ( HID_USAGE_DESKTOP_MOUSE     )                   ,\
+  HID_COLLECTION ( HID_COLLECTION_APPLICATION  )                   ,\
+    /* Report ID if any */\
+    __VA_ARGS__ \
+    HID_USAGE      ( HID_USAGE_DESKTOP_POINTER )                   ,\
+    HID_COLLECTION ( HID_COLLECTION_PHYSICAL   )                   ,\
+      HID_USAGE_PAGE  ( HID_USAGE_PAGE_BUTTON  )                   ,\
+        HID_USAGE_MIN   ( 1                                      ) ,\
+        HID_USAGE_MAX   ( 5                                      ) ,\
+        HID_LOGICAL_MIN ( 0                                      ) ,\
+        HID_LOGICAL_MAX ( 1                                      ) ,\
+        /* Left, Right, Middle, Backward, Forward buttons */ \
+        HID_REPORT_COUNT( 5                                      ) ,\
+        HID_REPORT_SIZE ( 1                                      ) ,\
+        HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
+        /* 3 bit padding */ \
+        HID_REPORT_COUNT( 1                                      ) ,\
+        HID_REPORT_SIZE ( 3                                      ) ,\
+        HID_INPUT       ( HID_CONSTANT                           ) ,\
+      HID_USAGE_PAGE  ( HID_USAGE_PAGE_DESKTOP )                   ,\
+        /* X, Y position [-127, 127] */ \
+        HID_USAGE       ( HID_USAGE_DESKTOP_X                    ) ,\
+        HID_USAGE       ( HID_USAGE_DESKTOP_Y                    ) ,\
+        HID_LOGICAL_MIN ( 0x81                                   ) ,\
+        HID_LOGICAL_MAX ( 0x7f                                   ) ,\
+        HID_REPORT_COUNT( 2                                      ) ,\
+        HID_REPORT_SIZE ( 8                                      ) ,\
+        HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
+        /* Verital wheel scroll [-127, 127] */ \
+        HID_USAGE       ( HID_USAGE_DESKTOP_WHEEL                )  ,\
+        HID_LOGICAL_MIN ( 0x81                                   )  ,\
+        HID_LOGICAL_MAX ( 0x7f                                   )  ,\
+        HID_REPORT_COUNT( 1                                      )  ,\
+        HID_REPORT_SIZE ( 8                                      )  ,\
+        HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_RELATIVE )  ,\
+      HID_USAGE_PAGE  ( HID_USAGE_PAGE_CONSUMER ), \
+       /* Horizontal wheel scroll [-127, 127] */ \
+        HID_USAGE_N     ( HID_USAGE_CONSUMER_AC_PAN, 2           ), \
+        HID_LOGICAL_MIN ( 0x81                                   ), \
+        HID_LOGICAL_MAX ( 0x7f                                   ), \
+        HID_REPORT_COUNT( 1                                      ), \
+        HID_REPORT_SIZE ( 8                                      ), \
+        HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \
+    HID_COLLECTION_END                                            , \
+  HID_COLLECTION_END \
+
+// Consumer Control Report Descriptor Template
+#define TUD_HID_REPORT_DESC_CONSUMER(...) \
+  HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER    )              ,\
+  HID_USAGE      ( HID_USAGE_CONSUMER_CONTROL )              ,\
+  HID_COLLECTION ( HID_COLLECTION_APPLICATION )              ,\
+    /* Report ID if any */\
+    __VA_ARGS__ \
+    HID_LOGICAL_MIN  ( 0x00                                ) ,\
+    HID_LOGICAL_MAX_N( 0x03FF, 2                           ) ,\
+    HID_USAGE_MIN    ( 0x00                                ) ,\
+    HID_USAGE_MAX_N  ( 0x03FF, 2                           ) ,\
+    HID_REPORT_COUNT ( 1                                   ) ,\
+    HID_REPORT_SIZE  ( 16                                  ) ,\
+    HID_INPUT        ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
+  HID_COLLECTION_END \
+
+/* System Control Report Descriptor Template
+ * 0x00 - do nothing
+ * 0x01 - Power Off
+ * 0x02 - Standby
+ * 0x03 - Wake Host
+ */
+#define TUD_HID_REPORT_DESC_SYSTEM_CONTROL(...) \
+  HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP           )        ,\
+  HID_USAGE      ( HID_USAGE_DESKTOP_SYSTEM_CONTROL )        ,\
+  HID_COLLECTION ( HID_COLLECTION_APPLICATION       )        ,\
+    /* Report ID if any */\
+    __VA_ARGS__ \
+    /* 2 bit system power control */ \
+    HID_LOGICAL_MIN  ( 1                                   ) ,\
+    HID_LOGICAL_MAX  ( 3                                   ) ,\
+    HID_REPORT_COUNT ( 1                                   ) ,\
+    HID_REPORT_SIZE  ( 2                                   ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_SYSTEM_SLEEP      ) ,\
+    HID_USAGE        ( HID_USAGE_DESKTOP_SYSTEM_WAKE_UP    ) ,\
+    HID_INPUT        ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
+    /* 6 bit padding */ \
+    HID_REPORT_COUNT ( 1                                   ) ,\
+    HID_REPORT_SIZE  ( 6                                   ) ,\
+    HID_INPUT        ( HID_CONSTANT                        ) ,\
+  HID_COLLECTION_END \
+
+// Gamepad Report Descriptor Template
+// 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  )                 ,\
+  HID_COLLECTION ( HID_COLLECTION_APPLICATION )                 ,\
+    /* 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 ) ,\
+    /* 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 ) ,\
+    /* 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
+// - 1st parameter is report size (mandatory)
+// - 2nd parameter is report id HID_REPORT_ID(n) (optional)
+#define TUD_HID_REPORT_DESC_GENERIC_INOUT(report_size, ...) \
+    HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2   ),\
+    HID_USAGE        ( 0x01                       ),\
+    HID_COLLECTION   ( HID_COLLECTION_APPLICATION ),\
+      /* Report ID if any */\
+      __VA_ARGS__ \
+      /* Input */ \
+      HID_USAGE       ( 0x02                                   ),\
+      HID_LOGICAL_MIN ( 0x00                                   ),\
+      HID_LOGICAL_MAX_N ( 0xff, 2                              ),\
+      HID_REPORT_SIZE ( 8                                      ),\
+      HID_REPORT_COUNT( report_size                            ),\
+      HID_INPUT       ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+      /* Output */ \
+      HID_USAGE       ( 0x03                                    ),\
+      HID_LOGICAL_MIN ( 0x00                                    ),\
+      HID_LOGICAL_MAX_N ( 0xff, 2                               ),\
+      HID_REPORT_SIZE ( 8                                       ),\
+      HID_REPORT_COUNT( report_size                             ),\
+      HID_OUTPUT      ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE  ),\
+    HID_COLLECTION_END \
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void     hidd_init            (void);
+void     hidd_reset           (uint8_t rhport);
+uint16_t hidd_open            (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+bool     hidd_xfer_cb         (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_HID_DEVICE_H_ */
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
new file mode 100644
index 0000000..f19f1ba
--- /dev/null
+++ b/src/class/hid/hid_host.c
@@ -0,0 +1,636 @@
+/* 
+ * 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 (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID)
+
+#include "host/usbh.h"
+#include "host/usbh_classdriver.h"
+
+#include "hid_host.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_in;
+  uint8_t ep_out;
+
+  uint8_t itf_protocol;   // None, Keyboard, Mouse
+  uint8_t protocol_mode;  // Boot (0) or Report protocol (1)
+
+  uint8_t  report_desc_type;
+  uint16_t report_desc_len;
+
+  uint16_t epin_size;
+  uint16_t epout_size;
+
+  uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE];
+  uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE];
+} hidh_interface_t;
+
+typedef struct
+{
+  uint8_t inst_count;
+  hidh_interface_t instances[CFG_TUH_HID];
+} hidh_device_t;
+
+static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX];
+
+//------------- Internal prototypes -------------//
+
+// Get HID device & interface
+TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr);
+TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance);
+static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf);
+static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr);
+
+//--------------------------------------------------------------------+
+// Interface API
+//--------------------------------------------------------------------+
+
+uint8_t tuh_hid_instance_count(uint8_t dev_addr)
+{
+  return get_dev(dev_addr)->inst_count;
+}
+
+bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance)
+{
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+  return (hid_itf->ep_in != 0) || (hid_itf->ep_out != 0);
+}
+
+uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance)
+{
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+  return hid_itf->itf_protocol;
+}
+
+//--------------------------------------------------------------------+
+// Control Endpoint API
+//--------------------------------------------------------------------+
+
+uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
+{
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+  return hid_itf->protocol_mode;
+}
+
+static bool set_protocol_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  uint8_t const itf_num     = (uint8_t) request->wIndex;
+  uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+
+  if (XFER_RESULT_SUCCESS == result) hid_itf->protocol_mode = (uint8_t) request->wValue;
+
+  if (tuh_hid_set_protocol_complete_cb)
+  {
+    tuh_hid_set_protocol_complete_cb(dev_addr, 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);
+
+  TU_LOG2("HID Set Protocol = %d\r\n", protocol);
+
+  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_PROTOCOL,
+    .wValue   = protocol,
+    .wIndex   = hid_itf->itf_num,
+    .wLength  = 0
+  };
+
+  TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, set_protocol_complete) );
+  return true;
+}
+
+static bool set_report_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  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 report_type = tu_u16_high(request->wValue);
+    uint8_t const report_id   = tu_u16_low(request->wValue);
+
+    tuh_hid_set_report_complete_cb(dev_addr, instance, report_id, report_type, (result == XFER_RESULT_SUCCESS) ? request->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)
+{
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+  TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len);
+
+  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_REPORT,
+    .wValue   = tu_u16(report_type, report_id),
+    .wIndex   = hid_itf->itf_num,
+    .wLength  = len
+  };
+
+  TU_ASSERT( tuh_control_xfer(dev_addr, &request, report, set_report_complete) );
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// Interrupt Endpoint API
+//--------------------------------------------------------------------+
+
+bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance)
+{
+  hidh_interface_t* hid_itf = get_instance(dev_addr, 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);
+}
+
+//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance)
+//{
+//  TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance));
+//
+//  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+//  return !usbh_edpt_busy(dev_addr, hid_itf->ep_in);
+//}
+
+//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len);
+
+//--------------------------------------------------------------------+
+// USBH API
+//--------------------------------------------------------------------+
+void hidh_init(void)
+{
+  tu_memclr(_hidh_dev, sizeof(_hidh_dev));
+}
+
+bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) result;
+
+  uint8_t const dir = tu_edpt_dir(ep_addr);
+  uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr);
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+
+  if ( dir == TUSB_DIR_IN )
+  {
+    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);
+  }else
+  {
+    if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, xferred_bytes);
+  }
+
+  return true;
+}
+
+void hidh_close(uint8_t dev_addr)
+{
+  TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
+
+  hidh_device_t* hid_dev = get_dev(dev_addr);
+
+  if (tuh_hid_umount_cb)
+  {
+    for (uint8_t inst = 0; inst < hid_dev->inst_count; inst++ ) tuh_hid_umount_cb(dev_addr, inst);
+  }
+
+  tu_memclr(hid_dev, sizeof(hidh_device_t));
+}
+
+//--------------------------------------------------------------------+
+// 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) 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);
+
+  // 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);
+  TU_ASSERT(max_len >= drv_len);
+
+  uint8_t const *p_desc = (uint8_t const *) desc_itf;
+
+  //------------- HID descriptor -------------//
+  p_desc = tu_desc_next(p_desc);
+  tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
+  TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType);
+
+  // not enough interface, try to increase CFG_TUH_HID
+  // TODO multiple devices
+  hidh_device_t* hid_dev = get_dev(dev_addr);
+  TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0);
+
+  //------------- Endpoint Descriptor -------------//
+  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)
+  {
+    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;
+  hid_itf->report_desc_len  = tu_unaligned_read16(&desc_hid->wReportLength);
+
+  // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config
+  hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
+  if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol;
+
+  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
+  };
+
+  TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc) );
+
+  return true;
+}
+
+// Force device to work in BOOT protocol
+static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  // Stall is a valid response for SET_IDLE, therefore we could ignore its result
+  (void) result;
+
+  uint8_t const itf_num     = (uint8_t) request->wIndex;
+  uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+
+  TU_LOG2("HID 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
+  };
+
+  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)
+{
+  // We can be here after SET_IDLE or SET_PROTOCOL (boot device)
+  // Trigger assert if result is not successful with set protocol
+  if ( request->bRequest != HID_REQ_CONTROL_SET_IDLE )
+  {
+    TU_ASSERT(result == XFER_RESULT_SUCCESS);
+  }
+
+  uint8_t const itf_num     = (uint8_t) request->wIndex;
+  uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+
+  // 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);
+
+    // Driver is mounted without report descriptor
+    config_driver_mount_complete(dev_addr, instance, NULL, 0);
+  }else
+  {
+    TU_LOG2("HID Get Report Descriptor\r\n");
+    tusb_control_request_t const new_request =
+    {
+      .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));
+  }
+
+  return true;
+}
+
+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);
+
+  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* desc_report = usbh_get_enum_buf();
+  uint16_t const desc_len    = request->wLength;
+
+  config_driver_mount_complete(dev_addr, instance, desc_report, desc_len);
+
+  return true;
+}
+
+static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
+{
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+
+  // enumeration is complete
+  tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len);
+
+  // notify usbh that driver enumeration is complete
+  usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num);
+}
+
+//--------------------------------------------------------------------+
+// Report Descriptor Parser
+//--------------------------------------------------------------------+
+
+uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len)
+{
+  // Report Item 6.2.2.2 USB HID 1.11
+  union TU_ATTR_PACKED
+  {
+    uint8_t byte;
+    struct TU_ATTR_PACKED
+    {
+        uint8_t size : 2;
+        uint8_t type : 2;
+        uint8_t tag  : 4;
+    };
+  } header;
+
+  tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t));
+
+  uint8_t report_num = 0;
+  tuh_hid_report_info_t* info = report_info_arr;
+
+  // current parsed report count & size from descriptor
+//  uint8_t ri_report_count = 0;
+//  uint8_t ri_report_size = 0;
+
+  uint8_t ri_collection_depth = 0;
+
+  while(desc_len && report_num < arr_count)
+  {
+    header.byte = *desc_report++;
+    desc_len--;
+
+    uint8_t const tag  = header.tag;
+    uint8_t const type = header.type;
+    uint8_t const size = header.size;
+
+    uint8_t const data8 = desc_report[0];
+
+    TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size);
+    for(uint32_t i=0; i<size; i++) TU_LOG(3, "%02X ", desc_report[i]);
+    TU_LOG(3, "\r\n");
+
+    switch(type)
+    {
+      case RI_TYPE_MAIN:
+        switch (tag)
+        {
+          case RI_MAIN_INPUT: break;
+          case RI_MAIN_OUTPUT: break;
+          case RI_MAIN_FEATURE: break;
+
+          case RI_MAIN_COLLECTION:
+            ri_collection_depth++;
+          break;
+
+          case RI_MAIN_COLLECTION_END:
+            ri_collection_depth--;
+            if (ri_collection_depth == 0)
+            {
+              info++;
+              report_num++;
+            }
+          break;
+
+          default: break;
+        }
+      break;
+
+      case RI_TYPE_GLOBAL:
+        switch(tag)
+        {
+          case RI_GLOBAL_USAGE_PAGE:
+            // only take in account the "usage page" before REPORT ID
+            if ( ri_collection_depth == 0 ) memcpy(&info->usage_page, desc_report, size);
+          break;
+
+          case RI_GLOBAL_LOGICAL_MIN   : break;
+          case RI_GLOBAL_LOGICAL_MAX   : break;
+          case RI_GLOBAL_PHYSICAL_MIN  : break;
+          case RI_GLOBAL_PHYSICAL_MAX  : break;
+
+          case RI_GLOBAL_REPORT_ID:
+            info->report_id = data8;
+          break;
+
+          case RI_GLOBAL_REPORT_SIZE:
+//            ri_report_size = data8;
+          break;
+
+          case RI_GLOBAL_REPORT_COUNT:
+//            ri_report_count = data8;
+          break;
+
+          case RI_GLOBAL_UNIT_EXPONENT : break;
+          case RI_GLOBAL_UNIT          : break;
+          case RI_GLOBAL_PUSH          : break;
+          case RI_GLOBAL_POP           : break;
+
+          default: break;
+        }
+      break;
+
+      case RI_TYPE_LOCAL:
+        switch(tag)
+        {
+          case RI_LOCAL_USAGE:
+            // only take in account the "usage" before starting REPORT ID
+            if ( ri_collection_depth == 0 ) info->usage = data8;
+          break;
+
+          case RI_LOCAL_USAGE_MIN        : break;
+          case RI_LOCAL_USAGE_MAX        : break;
+          case RI_LOCAL_DESIGNATOR_INDEX : break;
+          case RI_LOCAL_DESIGNATOR_MIN   : break;
+          case RI_LOCAL_DESIGNATOR_MAX   : break;
+          case RI_LOCAL_STRING_INDEX     : break;
+          case RI_LOCAL_STRING_MIN       : break;
+          case RI_LOCAL_STRING_MAX       : break;
+          case RI_LOCAL_DELIMITER        : break;
+          default: break;
+        }
+      break;
+
+      // error
+      default: break;
+    }
+
+    desc_report += size;
+    desc_len    -= size;
+  }
+
+  for ( uint8_t i = 0; i < report_num; i++ )
+  {
+    info = report_info_arr+i;
+    TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage);
+  }
+
+  return report_num;
+}
+
+//--------------------------------------------------------------------+
+// Helper
+//--------------------------------------------------------------------+
+
+// Get Device by address
+TU_ATTR_ALWAYS_INLINE static inline hidh_device_t* get_dev(uint8_t dev_addr)
+{
+  return &_hidh_dev[dev_addr-1];
+}
+
+// Get Interface by instance number
+TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_addr, uint8_t instance)
+{
+  return &_hidh_dev[dev_addr-1].instances[instance];
+}
+
+// Get instance ID by interface number
+static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf)
+{
+  for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ )
+  {
+    hidh_interface_t *hid = get_instance(dev_addr, inst);
+
+    if ( (hid->itf_num == itf) && (hid->ep_in || hid->ep_out) ) return inst;
+  }
+
+  return 0xff;
+}
+
+// Get instance ID by endpoint address
+static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr)
+{
+  for ( uint8_t inst = 0; inst < CFG_TUH_HID; inst++ )
+  {
+    hidh_interface_t *hid = get_instance(dev_addr, inst);
+
+    if ( (ep_addr == hid->ep_in) || ( ep_addr == hid->ep_out) ) return inst;
+  }
+
+  return 0xff;
+}
+
+#endif
diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h
new file mode 100644
index 0000000..fe09b03
--- /dev/null
+++ b/src/class/hid/hid_host.h
@@ -0,0 +1,152 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_HID_HOST_H_
+#define _TUSB_HID_HOST_H_
+
+#include "hid.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Class Driver Configuration
+//--------------------------------------------------------------------+
+
+// TODO Highspeed interrupt can be up to 512 bytes
+#ifndef CFG_TUH_HID_EPIN_BUFSIZE
+#define CFG_TUH_HID_EPIN_BUFSIZE 64
+#endif
+
+#ifndef CFG_TUH_HID_EPOUT_BUFSIZE
+#define CFG_TUH_HID_EPOUT_BUFSIZE 64
+#endif
+
+
+typedef struct
+{
+  uint8_t  report_id;
+  uint8_t  usage;
+  uint16_t usage_page;
+
+  // TODO still use the endpoint size for now
+//  uint8_t in_len;      // length of IN report
+//  uint8_t out_len;     // length of OUT report
+} tuh_hid_report_info_t;
+
+//--------------------------------------------------------------------+
+// Interface API
+//--------------------------------------------------------------------+
+
+// Get the number of HID instances
+uint8_t tuh_hid_instance_count(uint8_t dev_addr);
+
+// Check if HID instance is mounted
+bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance);
+
+// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values
+uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance);
+
+// Parse report descriptor into array of report_info struct and return number of reports.
+// For complicated report, application should write its own parser.
+uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED;
+
+//--------------------------------------------------------------------+
+// Control Endpoint API
+//--------------------------------------------------------------------+
+
+// Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
+// Note: Device will be initialized in Boot protocol for simplicity.
+//       Application can use set_protocol() to switch back to Report protocol.
+uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance);
+
+// Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
+// This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE)
+bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol);
+
+// Set Report using control endpoint
+// report_type is either Intput, Output or Feature, (value from hid_report_type_t)
+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);
+
+//--------------------------------------------------------------------+
+// Interrupt Endpoint API
+//--------------------------------------------------------------------+
+
+// Check if the interface is ready to use
+//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance);
+
+// Try to receive next report on Interrupt Endpoint. Immediately return
+// - true If succeeded, tuh_hid_report_received_cb() callback will be invoked when report is available
+// - false if failed to queue the transfer e.g endpoint is busy
+bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance);
+
+// Send report using interrupt endpoint
+// If report_id > 0 (composite), it will be sent as 1st byte, then report contents. Otherwise only report content is sent.
+//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len);
+
+//--------------------------------------------------------------------+
+// Callbacks (Weak is optional)
+//--------------------------------------------------------------------+
+
+// Invoked when device with hid interface is mounted
+// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
+// can be used to parse common/simple enough descriptor.
+// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
+// therefore report_desc = NULL, desc_len = 0
+void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report_desc, uint16_t desc_len);
+
+// Invoked when device with hid interface is un-mounted
+TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance);
+
+// Invoked when received report from device via interrupt endpoint
+// Note: if there is report ID (composite), it is 1st byte of report
+void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
+
+// Invoked when sent report to device successfully via interrupt endpoint
+TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
+
+// Invoked when Sent Report to device via either control endpoint
+// len = 0 indicate there is error in the transfer e.g stalled response
+TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
+
+// Invoked when Set Protocol request is complete
+TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t protocol);
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void hidh_init       (void);
+bool hidh_open       (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
+bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool hidh_xfer_cb    (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+void hidh_close      (uint8_t dev_addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_HID_HOST_H_ */
diff --git a/src/class/midi/midi.h b/src/class/midi/midi.h
new file mode 100644
index 0000000..74dc417
--- /dev/null
+++ b/src/class/midi/midi.h
@@ -0,0 +1,212 @@
+/* 
+ * 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_class
+ *  \defgroup ClassDriver_CDC Communication Device Class (CDC)
+ *            Currently only Abstract Control Model subclass is supported
+ *  @{ */
+
+#ifndef _TUSB_MIDI_H__
+#define _TUSB_MIDI_H__
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Class Specific Descriptor
+//--------------------------------------------------------------------+
+
+typedef enum
+{
+  MIDI_CS_INTERFACE_HEADER    = 0x01,
+  MIDI_CS_INTERFACE_IN_JACK   = 0x02,
+  MIDI_CS_INTERFACE_OUT_JACK  = 0x03,
+  MIDI_CS_INTERFACE_ELEMENT   = 0x04,
+} midi_cs_interface_subtype_t;
+
+typedef enum
+{
+  MIDI_CS_ENDPOINT_GENERAL = 0x01
+} midi_cs_endpoint_subtype_t;
+
+typedef enum
+{
+  MIDI_JACK_EMBEDDED = 0x01,
+  MIDI_JACK_EXTERNAL = 0x02
+} midi_jack_type_t;
+
+typedef enum
+{
+  MIDI_CIN_MISC              = 0,
+  MIDI_CIN_CABLE_EVENT       = 1,
+  MIDI_CIN_SYSCOM_2BYTE      = 2, // 2 byte system common message e.g MTC, SongSelect
+  MIDI_CIN_SYSCOM_3BYTE      = 3, // 3 byte system common message e.g SPP
+  MIDI_CIN_SYSEX_START       = 4, // SysEx starts or continue
+  MIDI_CIN_SYSEX_END_1BYTE   = 5, // SysEx ends with 1 data, or 1 byte system common message
+  MIDI_CIN_SYSEX_END_2BYTE   = 6, // SysEx ends with 2 data
+  MIDI_CIN_SYSEX_END_3BYTE   = 7, // SysEx ends with 3 data
+  MIDI_CIN_NOTE_ON           = 8,
+  MIDI_CIN_NOTE_OFF          = 9,
+  MIDI_CIN_POLY_KEYPRESS     = 10,
+  MIDI_CIN_CONTROL_CHANGE    = 11,
+  MIDI_CIN_PROGRAM_CHANGE    = 12,
+  MIDI_CIN_CHANNEL_PRESSURE  = 13,
+  MIDI_CIN_PITCH_BEND_CHANGE = 14,
+  MIDI_CIN_1BYTE_DATA = 15
+} midi_code_index_number_t;
+
+// MIDI 1.0 status byte
+enum
+{
+  //------------- System Exclusive -------------//
+  MIDI_STATUS_SYSEX_START                    = 0xF0,
+  MIDI_STATUS_SYSEX_END                      = 0xF7,
+
+  //------------- System Common -------------//
+  MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME = 0xF1,
+  MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER   = 0xF2,
+  MIDI_STATUS_SYSCOM_SONG_SELECT             = 0xF3,
+  // F4, F5 is undefined
+  MIDI_STATUS_SYSCOM_TUNE_REQUEST            = 0xF6,
+
+  //------------- System RealTime  -------------//
+  MIDI_STATUS_SYSREAL_TIMING_CLOCK           = 0xF8,
+  // 0xF9 is undefined
+  MIDI_STATUS_SYSREAL_START                  = 0xFA,
+  MIDI_STATUS_SYSREAL_CONTINUE               = 0xFB,
+  MIDI_STATUS_SYSREAL_STOP                   = 0xFC,
+  // 0xFD is undefined
+  MIDI_STATUS_SYSREAL_ACTIVE_SENSING         = 0xFE,
+  MIDI_STATUS_SYSREAL_SYSTEM_RESET           = 0xFF,
+};
+
+/// MIDI Interface Header Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType
+  uint16_t bcdMSC            ; ///< MidiStreaming SubClass release number in Binary-Coded Decimal
+  uint16_t wTotalLength      ;
+} midi_desc_header_t;
+
+/// MIDI In Jack Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType
+  uint8_t bJackType          ; ///< Embedded or External
+  uint8_t bJackID            ; ///< Unique ID for MIDI IN Jack
+  uint8_t iJack              ; ///< string descriptor
+} midi_desc_in_jack_t;
+
+
+/// MIDI Out Jack Descriptor with single pin
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType
+  uint8_t bJackType          ; ///< Embedded or External
+  uint8_t bJackID            ; ///< Unique ID for MIDI IN Jack
+  uint8_t bNrInputPins;
+
+  uint8_t baSourceID;
+  uint8_t baSourcePin;
+
+  uint8_t iJack              ; ///< string descriptor
+} midi_desc_out_jack_t ;
+
+/// MIDI Out Jack Descriptor with multiple pins
+#define midi_desc_out_jack_n_t(input_num) \
+  struct TU_ATTR_PACKED { \
+    uint8_t bLength            ; \
+    uint8_t bDescriptorType    ; \
+    uint8_t bDescriptorSubType ; \
+    uint8_t bJackType          ; \
+    uint8_t bJackID            ; \
+    uint8_t bNrInputPins       ; \
+    struct TU_ATTR_PACKED {      \
+        uint8_t baSourceID;      \
+        uint8_t baSourcePin;     \
+    } pins[input_num];           \
+   uint8_t iJack              ;  \
+  }
+
+/// MIDI Element Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType
+  uint8_t bElementID;
+
+  uint8_t bNrInputPins;
+  uint8_t baSourceID;
+  uint8_t baSourcePin;
+
+  uint8_t bNrOutputPins;
+  uint8_t bInTerminalLink;
+  uint8_t bOutTerminalLink;
+  uint8_t bElCapsSize;
+
+  uint16_t bmElementCaps;
+  uint8_t  iElement;
+} midi_desc_element_t;
+
+/// MIDI Element Descriptor with multiple pins
+#define midi_desc_element_n_t(input_num) \
+  struct TU_ATTR_PACKED {       \
+    uint8_t bLength;            \
+    uint8_t bDescriptorType;    \
+    uint8_t bDescriptorSubType; \
+    uint8_t bElementID;         \
+    uint8_t bNrInputPins;       \
+    struct TU_ATTR_PACKED {     \
+        uint8_t baSourceID;     \
+        uint8_t baSourcePin;    \
+    } pins[input_num];          \
+    uint8_t bNrOutputPins;      \
+    uint8_t bInTerminalLink;    \
+    uint8_t bOutTerminalLink;   \
+    uint8_t bElCapsSize;        \
+    uint16_t bmElementCaps;     \
+    uint8_t  iElement;          \
+ }
+
+/** @} */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+
+/** @} */
diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c
new file mode 100644
index 0000000..b08b362
--- /dev/null
+++ b/src/class/midi/midi_device.c
@@ -0,0 +1,545 @@
+/* 
+ * 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 (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MIDI)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "midi_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+typedef struct
+{
+  uint8_t buffer[4];
+  uint8_t index;
+  uint8_t total;
+}midid_stream_t;
+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_in;
+  uint8_t ep_out;
+
+  // For Stream read()/write() API
+  // Messages are always 4 bytes long, queue them for reading and writing so the
+  // callers can use the Stream interface with single-byte read/write calls.
+  midid_stream_t stream_write;
+  midid_stream_t stream_read;
+
+  /*------------- From this point, data is not cleared by bus reset -------------*/
+  // FIFO
+  tu_fifo_t rx_ff;
+  tu_fifo_t tx_ff;
+  uint8_t rx_ff_buf[CFG_TUD_MIDI_RX_BUFSIZE];
+  uint8_t tx_ff_buf[CFG_TUD_MIDI_TX_BUFSIZE];
+
+  #if CFG_FIFO_MUTEX
+  osal_mutex_def_t rx_ff_mutex;
+  osal_mutex_def_t tx_ff_mutex;
+  #endif
+
+  // Endpoint Transfer buffer
+  CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE];
+  CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EP_BUFSIZE];
+
+} midid_interface_t;
+
+#define ITF_MEM_RESET_SIZE   offsetof(midid_interface_t, rx_ff)
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+CFG_TUSB_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI];
+
+bool tud_midi_n_mounted (uint8_t itf)
+{
+  midid_interface_t* midi = &_midid_itf[itf];
+  return midi->ep_in && midi->ep_out;
+}
+
+static void _prep_out_transaction (midid_interface_t* p_midi)
+{
+  uint8_t const rhport = TUD_OPT_RHPORT;
+  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.
+  // 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_midi->epout_buf), );
+
+  // claim endpoint
+  TU_VERIFY(usbd_edpt_claim(rhport, p_midi->ep_out), );
+
+  // fifo can be changed before endpoint is claimed
+  available = tu_fifo_remaining(&p_midi->rx_ff);
+
+  if ( available >= sizeof(p_midi->epout_buf) )  {
+    usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, sizeof(p_midi->epout_buf));
+  }else
+  {
+    // Release endpoint since we don't make any transfer
+    usbd_edpt_release(rhport, p_midi->ep_out);
+  }
+}
+
+//--------------------------------------------------------------------+
+// READ API
+//--------------------------------------------------------------------+
+uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num)
+{
+  (void) cable_num;
+
+  midid_interface_t* midi = &_midid_itf[itf];
+  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);
+}
+
+uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize)
+{
+  (void) cable_num;
+  TU_VERIFY(bufsize, 0);
+
+  uint8_t* buf8 = (uint8_t*) buffer;
+
+  midid_interface_t* midi = &_midid_itf[itf];
+  midid_stream_t* stream = &midi->stream_read;
+
+  uint32_t total_read = 0;
+  while( bufsize )
+  {
+    // Get new packet from fifo, then set packet expected bytes
+    if ( stream->total == 0 )
+    {
+      // return if there is no more data from fifo
+      if ( !tud_midi_n_packet_read(itf, stream->buffer) ) return total_read;
+
+      uint8_t const code_index = stream->buffer[0] & 0x0f;
+
+      // MIDI 1.0 Table 4-1: Code Index Number Classifications
+      switch(code_index)
+      {
+        case MIDI_CIN_MISC:
+        case MIDI_CIN_CABLE_EVENT:
+          // These are reserved and unused, possibly issue somewhere, skip this packet
+          return 0;
+        break;
+
+        case MIDI_CIN_SYSEX_END_1BYTE:
+        case MIDI_CIN_1BYTE_DATA:
+          stream->total = 1;
+        break;
+
+        case MIDI_CIN_SYSCOM_2BYTE     :
+        case MIDI_CIN_SYSEX_END_2BYTE  :
+        case MIDI_CIN_PROGRAM_CHANGE   :
+        case MIDI_CIN_CHANNEL_PRESSURE :
+          stream->total = 2;
+        break;
+
+        default:
+          stream->total = 3;
+        break;
+      }
+    }
+
+    // Copy data up to bufsize
+    uint32_t const count = tu_min32(stream->total - stream->index, bufsize);
+
+    // Skip the header (1st byte) in the buffer
+    memcpy(buf8, stream->buffer + 1 + stream->index, count);
+
+    total_read += count;
+    stream->index += count;
+    buf8 += count;
+    bufsize -= count;
+
+    // complete current event packet, reset stream
+    if ( stream->total == stream->index )
+    {
+      stream->index = 0;
+      stream->total = 0;
+    }
+  }
+
+  return total_read;
+}
+
+bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4])
+{
+  midid_interface_t* midi = &_midid_itf[itf];
+  TU_VERIFY(midi->ep_out);
+
+  uint32_t const num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4);
+  _prep_out_transaction(midi);
+  return (num_read == 4);
+}
+
+//--------------------------------------------------------------------+
+// WRITE API
+//--------------------------------------------------------------------+
+
+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;
+
+  // skip if previous transfer not complete
+  TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 );
+
+  uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EP_BUFSIZE);
+
+  if (count)
+  {
+    TU_ASSERT( usbd_edpt_xfer(rhport, midi->ep_in, midi->epin_buf, count), 0 );
+    return count;
+  }else
+  {
+    // Release endpoint since we don't make any transfer
+    usbd_edpt_release(rhport, midi->ep_in);
+    return 0;
+  }
+}
+
+uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
+{
+  midid_interface_t* midi = &_midid_itf[itf];
+  TU_VERIFY(midi->ep_in, 0);
+
+  midid_stream_t* stream = &midi->stream_write;
+
+  uint32_t i = 0;
+  while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) )
+  {
+    uint8_t const data = buffer[i];
+    i++;
+
+    if ( stream->index == 0 )
+    {
+      //------------- New event packet -------------//
+
+      uint8_t const msg = data >> 4;
+
+      stream->index = 2;
+      stream->buffer[1] = data;
+
+      // Check to see if we're still in a SysEx transmit.
+      if ( stream->buffer[0] == MIDI_CIN_SYSEX_START )
+      {
+        if ( data == MIDI_STATUS_SYSEX_END )
+        {
+          stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE;
+          stream->total = 2;
+        }
+        else
+        {
+          stream->total = 4;
+        }
+      }
+      else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE )
+      {
+        // Channel Voice Messages
+        stream->buffer[0] = (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->total = 3;
+      }
+      else if ( msg == 0xf )
+      {
+        // System message
+        if ( data == MIDI_STATUS_SYSEX_START )
+        {
+          stream->buffer[0] = MIDI_CIN_SYSEX_START;
+          stream->total = 4;
+        }
+        else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT )
+        {
+          stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE;
+          stream->total = 3;
+        }
+        else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER )
+        {
+          stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE;
+          stream->total = 4;
+        }
+        else
+        {
+          stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE;
+          stream->total = 2;
+        }
+      }
+      else
+      {
+        // Pack individual bytes if we don't support packing them into words.
+        stream->buffer[0] = cable_num << 4 | 0xf;
+        stream->buffer[2] = 0;
+        stream->buffer[3] = 0;
+        stream->index = 2;
+        stream->total = 2;
+      }
+    }
+    else
+    {
+      //------------- On-going (buffering) packet -------------//
+
+      TU_ASSERT(stream->index < 4, i);
+      stream->buffer[stream->index] = data;
+      stream->index++;
+
+      // See if this byte ends a SysEx.
+      if ( stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END )
+      {
+        stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1);
+        stream->total = stream->index;
+      }
+    }
+
+    // Send out packet
+    if ( stream->index == stream->total )
+    {
+      // zeroes unused bytes
+      for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0;
+
+      uint16_t const count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4);
+
+      // complete current event packet, reset stream
+      stream->index = stream->total = 0;
+
+      // FIFO overflown, since we already check fifo remaining. It is probably race condition
+      TU_ASSERT(count == 4, i);
+    }
+  }
+
+  write_flush(midi);
+
+  return i;
+}
+
+bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4])
+{
+  midid_interface_t* midi = &_midid_itf[itf];
+  TU_VERIFY(midi->ep_in);
+
+  if (tu_fifo_remaining(&midi->tx_ff) < 4) return false;
+
+  tu_fifo_write_n(&midi->tx_ff, packet, 4);
+  write_flush(midi);
+
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void midid_init(void)
+{
+  tu_memclr(_midid_itf, sizeof(_midid_itf));
+
+  for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
+  {
+    midid_interface_t* midi = &_midid_itf[i];
+
+    // config fifo
+    tu_fifo_config(&midi->rx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, false); // true, true
+    tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS.
+
+    #if CFG_FIFO_MUTEX
+    tu_fifo_config_mutex(&midi->rx_ff, NULL, osal_mutex_create(&midi->rx_ff_mutex));
+    tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex), NULL);
+    #endif
+  }
+}
+
+void midid_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
+  {
+    midid_interface_t* midi = &_midid_itf[i];
+    tu_memclr(midi, ITF_MEM_RESET_SIZE);
+    tu_fifo_clear(&midi->rx_ff);
+    tu_fifo_clear(&midi->tx_ff);
+  }
+}
+
+uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len)
+{
+  // 1st Interface is Audio Control v1
+  TU_VERIFY(TUSB_CLASS_AUDIO               == desc_itf->bInterfaceClass    &&
+            AUDIO_SUBCLASS_CONTROL         == desc_itf->bInterfaceSubClass &&
+            AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol, 0);
+
+  uint16_t drv_len = tu_desc_len(desc_itf);
+  uint8_t const * p_desc = tu_desc_next(desc_itf);
+
+  // Skip Class Specific descriptors
+  while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
+  {
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  // 2nd Interface is MIDI Streaming
+  TU_VERIFY(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0);
+  tusb_desc_interface_t const * desc_midi = (tusb_desc_interface_t const *) p_desc;
+
+  TU_VERIFY(TUSB_CLASS_AUDIO               == desc_midi->bInterfaceClass    &&
+            AUDIO_SUBCLASS_MIDI_STREAMING  == desc_midi->bInterfaceSubClass &&
+            AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_midi->bInterfaceProtocol, 0);
+
+  // Find available interface
+  midid_interface_t * p_midi = NULL;
+  for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
+  {
+    if ( _midid_itf[i].ep_in == 0 && _midid_itf[i].ep_out == 0 )
+    {
+      p_midi = &_midid_itf[i];
+      break;
+    }
+  }
+  TU_ASSERT(p_midi);
+
+  p_midi->itf_num = desc_midi->bInterfaceNumber;
+  (void) p_midi->itf_num;
+
+  // next descriptor
+  drv_len += tu_desc_len(p_desc);
+  p_desc   = tu_desc_next(p_desc);
+
+  // Find and open endpoint descriptors
+  uint8_t found_endpoints = 0;
+  while ( (found_endpoints < desc_midi->bNumEndpoints) && (drv_len <= max_len)  )
+  {
+    if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
+    {
+      TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0);
+      uint8_t ep_addr = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
+
+      if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN)
+      {
+        p_midi->ep_in = ep_addr;
+      } else {
+        p_midi->ep_out = ep_addr;
+      }
+
+      // Class Specific MIDI Stream endpoint descriptor
+      drv_len += tu_desc_len(p_desc);
+      p_desc   = tu_desc_next(p_desc);
+
+      found_endpoints += 1;
+    }
+
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  // Prepare for incoming data
+  _prep_out_transaction(p_midi);
+
+  return drv_len;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  (void) rhport;
+  (void) stage;
+  (void) request;
+
+  // driver doesn't support any request yet
+  return false;
+}
+
+bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) result;
+  (void) rhport;
+
+  uint8_t itf;
+  midid_interface_t* p_midi;
+
+  // Identify which interface to use
+  for (itf = 0; itf < CFG_TUD_MIDI; itf++)
+  {
+    p_midi = &_midid_itf[itf];
+    if ( ( ep_addr == p_midi->ep_out ) || ( ep_addr == p_midi->ep_in ) ) break;
+  }
+  TU_ASSERT(itf < CFG_TUD_MIDI);
+
+  // receive new data
+  if ( ep_addr == p_midi->ep_out )
+  {
+    tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, xferred_bytes);
+
+    // invoke receive callback if available
+    if (tud_midi_rx_cb) tud_midi_rx_cb(itf);
+
+    // prepare for next
+    // TODO for now ep_out is not used by public API therefore there is no race condition,
+    // and does not need to claim like ep_in
+    _prep_out_transaction(p_midi);
+  }
+  else if ( ep_addr == p_midi->ep_in )
+  {
+    if (0 == write_flush(p_midi))
+    {
+      // If there is no data left, a ZLP should be sent if
+      // xferred_bytes is multiple of EP size and not zero
+      if ( !tu_fifo_count(&p_midi->tx_ff) && xferred_bytes && (0 == (xferred_bytes % CFG_TUD_MIDI_EP_BUFSIZE)) )
+      {
+        if ( usbd_edpt_claim(rhport, p_midi->ep_in) )
+        {
+          usbd_edpt_xfer(rhport, p_midi->ep_in, NULL, 0);
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+#endif
diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h
new file mode 100644
index 0000000..211edc8
--- /dev/null
+++ b/src/class/midi/midi_device.h
@@ -0,0 +1,173 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_MIDI_DEVICE_H_
+#define _TUSB_MIDI_DEVICE_H_
+
+#include "class/audio/audio.h"
+#include "midi.h"
+
+//--------------------------------------------------------------------+
+// Class Driver Configuration
+//--------------------------------------------------------------------+
+
+#if !defined(CFG_TUD_MIDI_EP_BUFSIZE) && defined(CFG_TUD_MIDI_EPSIZE)
+  #warning CFG_TUD_MIDI_EPSIZE is renamed to CFG_TUD_MIDI_EP_BUFSIZE, please update to use the new name
+  #define CFG_TUD_MIDI_EP_BUFSIZE    CFG_TUD_MIDI_EPSIZE
+#endif
+
+#ifndef CFG_TUD_MIDI_EP_BUFSIZE
+  #define CFG_TUD_MIDI_EP_BUFSIZE     (TUD_OPT_HIGH_SPEED ? 512 : 64)
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/** \addtogroup MIDI_Serial Serial
+ *  @{
+ *  \defgroup   MIDI_Serial_Device Device
+ *  @{ */
+
+//--------------------------------------------------------------------+
+// Application API (Multiple Interfaces)
+// CFG_TUD_MIDI > 1
+//--------------------------------------------------------------------+
+
+// Check if midi interface is mounted
+bool     tud_midi_n_mounted      (uint8_t itf);
+
+// Get the number of bytes available for reading
+uint32_t tud_midi_n_available    (uint8_t itf, uint8_t cable_num);
+
+// Read byte stream              (legacy)
+uint32_t tud_midi_n_stream_read  (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize);
+
+// Write byte Stream             (legacy)
+uint32_t tud_midi_n_stream_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize);
+
+// Read event packet             (4 bytes)
+bool     tud_midi_n_packet_read  (uint8_t itf, uint8_t packet[4]);
+
+// Write event packet            (4 bytes)
+bool     tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]);
+
+//--------------------------------------------------------------------+
+// Application API (Single Interface)
+//--------------------------------------------------------------------+
+static inline bool     tud_midi_mounted      (void);
+static inline uint32_t tud_midi_available    (void);
+
+static inline uint32_t tud_midi_stream_read  (void* buffer, uint32_t bufsize);
+static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize);
+
+static inline bool     tud_midi_packet_read  (uint8_t packet[4]);
+static inline bool     tud_midi_packet_write (uint8_t const packet[4]);
+
+//------------- Deprecated API name  -------------//
+// TODO remove after 0.10.0 release
+
+TU_ATTR_DEPRECATED("tud_midi_read() is renamed to tud_midi_stream_read()")
+static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize)
+{
+  return tud_midi_stream_read(buffer, bufsize);
+}
+
+TU_ATTR_DEPRECATED("tud_midi_write() is renamed to tud_midi_stream_write()")
+static inline uint32_t tud_midi_write(uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
+{
+  return tud_midi_stream_write(cable_num, buffer, bufsize);
+}
+
+
+TU_ATTR_DEPRECATED("tud_midi_send() is renamed to tud_midi_packet_write()")
+static inline bool tud_midi_send(uint8_t packet[4])
+{
+  return tud_midi_packet_write(packet);
+}
+
+TU_ATTR_DEPRECATED("tud_midi_receive() is renamed to tud_midi_packet_read()")
+static inline bool tud_midi_receive(uint8_t packet[4])
+{
+  return tud_midi_packet_read(packet);
+}
+
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf);
+
+//--------------------------------------------------------------------+
+// Inline Functions
+//--------------------------------------------------------------------+
+
+static inline bool tud_midi_mounted (void)
+{
+  return tud_midi_n_mounted(0);
+}
+
+static inline uint32_t tud_midi_available (void)
+{
+  return tud_midi_n_available(0, 0);
+}
+
+static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize)
+{
+  return tud_midi_n_stream_read(0, 0, buffer, bufsize);
+}
+
+static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
+{
+  return tud_midi_n_stream_write(0, cable_num, buffer, bufsize);
+}
+
+static inline bool tud_midi_packet_read (uint8_t packet[4])
+{
+  return tud_midi_n_packet_read(0, packet);
+}
+
+static inline bool tud_midi_packet_write (uint8_t const packet[4])
+{
+  return tud_midi_n_packet_write(0, packet);
+}
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void     midid_init            (void);
+void     midid_reset           (uint8_t rhport);
+uint16_t midid_open            (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     midid_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+bool     midid_xfer_cb         (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_MIDI_DEVICE_H_ */
+
+/** @} */
+/** @} */
diff --git a/src/class/msc/msc.h b/src/class/msc/msc.h
new file mode 100644
index 0000000..84b6e4d
--- /dev/null
+++ b/src/class/msc/msc.h
@@ -0,0 +1,382 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_MSC_H_
+#define _TUSB_MSC_H_
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Mass Storage Class Constant
+//--------------------------------------------------------------------+
+/// MassStorage Subclass
+typedef enum
+{
+  MSC_SUBCLASS_RBC = 1 , ///< Reduced Block Commands (RBC) T10 Project 1240-D
+  MSC_SUBCLASS_SFF_MMC , ///< SFF-8020i, MMC-2 (ATAPI). Typically used by a CD/DVD device
+  MSC_SUBCLASS_QIC     , ///< QIC-157. Typically used by a tape device
+  MSC_SUBCLASS_UFI     , ///< UFI. Typically used by Floppy Disk Drive (FDD) device
+  MSC_SUBCLASS_SFF     , ///< SFF-8070i. Can be used by Floppy Disk Drive (FDD) device
+  MSC_SUBCLASS_SCSI      ///< SCSI transparent command set
+}msc_subclass_type_t;
+
+enum {
+  MSC_CBW_SIGNATURE = 0x43425355, ///< Constant value of 43425355h (little endian)
+  MSC_CSW_SIGNATURE = 0x53425355  ///< Constant value of 53425355h (little endian)
+};
+
+/// \brief MassStorage Protocol.
+/// \details CBI only approved to use with full-speed floopy disk & should not used with highspeed or device other than floopy
+typedef enum
+{
+  MSC_PROTOCOL_CBI              = 0 ,  ///< Control/Bulk/Interrupt protocol (with command completion interrupt)
+  MSC_PROTOCOL_CBI_NO_INTERRUPT = 1 ,  ///< Control/Bulk/Interrupt protocol (without command completion interrupt)
+  MSC_PROTOCOL_BOT              = 0x50 ///< Bulk-Only Transport
+}msc_protocol_type_t;
+
+/// MassStorage Class-Specific Control Request
+typedef enum
+{
+  MSC_REQ_GET_MAX_LUN = 254, ///< The Get Max LUN device request is used to determine the number of logical units supported by the device. Logical Unit Numbers on the device shall be numbered contiguously starting from LUN 0 to a maximum LUN of 15
+  MSC_REQ_RESET       = 255  ///< This request is used to reset the mass storage device and its associated interface. This class-specific request shall ready the device for the next CBW from the host.
+}msc_request_type_t;
+
+/// \brief Command Block Status Values
+/// \details Indicates the success or failure of the command. The device shall set this byte to zero if the command completed
+/// successfully. A non-zero value shall indicate a failure during command execution according to the following
+typedef enum
+{
+  MSC_CSW_STATUS_PASSED = 0 , ///< MSC_CSW_STATUS_PASSED
+  MSC_CSW_STATUS_FAILED     , ///< MSC_CSW_STATUS_FAILED
+  MSC_CSW_STATUS_PHASE_ERROR  ///< MSC_CSW_STATUS_PHASE_ERROR
+}msc_csw_status_t;
+
+/// Command Block Wrapper
+typedef struct TU_ATTR_PACKED
+{
+  uint32_t signature;   ///< Signature that helps identify this data packet as a CBW. The signature field shall contain the value 43425355h (little endian), indicating a CBW.
+  uint32_t tag;         ///< Tag sent by the host. The device shall echo the contents of this field back to the host in the dCSWTagfield of the associated CSW. The dCSWTagpositively associates a CSW with the corresponding CBW.
+  uint32_t total_bytes; ///< The number of bytes of data that the host expects to transfer on the Bulk-In or Bulk-Out endpoint (as indicated by the Direction bit) during the execution of this command. If this field is zero, the device and the host shall transfer no data between the CBW and the associated CSW, and the device shall ignore the value of the Direction bit in bmCBWFlags.
+  uint8_t dir;          ///< Bit 7 of this field define transfer direction \n - 0 : Data-Out from host to the device. \n - 1 : Data-In from the device to the host.
+  uint8_t lun;          ///< The device Logical Unit Number (LUN) to which the command block is being sent. For devices that support multiple LUNs, the host shall place into this field the LUN to which this command block is addressed. Otherwise, the host shall set this field to zero.
+  uint8_t cmd_len;      ///< The valid length of the CBWCBin bytes. This defines the valid length of the command block. The only legal values are 1 through 16
+  uint8_t command[16];  ///< The command block to be executed by the device. The device shall interpret the first cmd_len bytes in this field as a command block
+}msc_cbw_t;
+
+TU_VERIFY_STATIC(sizeof(msc_cbw_t) == 31, "size is not correct");
+
+/// Command Status Wrapper
+typedef struct TU_ATTR_PACKED
+{
+  uint32_t signature    ; ///< Signature that helps identify this data packet as a CSW. The signature field shall contain the value 53425355h (little endian), indicating CSW.
+  uint32_t tag          ; ///< The device shall set this field to the value received in the dCBWTag of the associated CBW.
+  uint32_t data_residue ; ///< For Data-Out the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLength, and the actual amount of data processed by the device. For Data-In the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLengthand the actual amount of relevant data sent by the device
+  uint8_t  status       ; ///< indicates the success or failure of the command. Values from \ref msc_csw_status_t
+}msc_csw_t;
+
+TU_VERIFY_STATIC(sizeof(msc_csw_t) == 13, "size is not correct");
+
+//--------------------------------------------------------------------+
+// SCSI Constant
+//--------------------------------------------------------------------+
+
+/// SCSI Command Operation Code
+typedef enum
+{
+  SCSI_CMD_TEST_UNIT_READY              = 0x00, ///< The SCSI Test Unit Ready command is used to determine if a device is ready to transfer data (read/write), i.e. if a disk has spun up, if a tape is loaded and ready etc. The device does not perform a self-test operation.
+  SCSI_CMD_INQUIRY                      = 0x12, ///< The SCSI Inquiry command is used to obtain basic information from a target device.
+  SCSI_CMD_MODE_SELECT_6                = 0x15, ///<  provides a means for the application client to specify medium, logical unit, or peripheral device parameters to the device server. Device servers that implement the MODE SELECT(6) command shall also implement the MODE SENSE(6) command. Application clients should issue MODE SENSE(6) prior to each MODE SELECT(6) to determine supported mode pages, page lengths, and other parameters.
+  SCSI_CMD_MODE_SENSE_6                 = 0x1A, ///< provides a means for a device server to report parameters to an application client. It is a complementary command to the MODE SELECT(6) command. Device servers that implement the MODE SENSE(6) command shall also implement the MODE SELECT(6) command.
+  SCSI_CMD_START_STOP_UNIT              = 0x1B,
+  SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E,
+  SCSI_CMD_READ_CAPACITY_10             = 0x25, ///< The SCSI Read Capacity command is used to obtain data capacity information from a target device.
+  SCSI_CMD_REQUEST_SENSE                = 0x03, ///< The SCSI Request Sense command is part of the SCSI computer protocol standard. This command is used to obtain sense data -- status/error information -- from a target device.
+  SCSI_CMD_READ_FORMAT_CAPACITY         = 0x23, ///< The command allows the Host to request a list of the possible format capacities for an installed writable media. This command also has the capability to report the writable capacity for a media when it is installed
+  SCSI_CMD_READ_10                      = 0x28, ///< The READ (10) command requests that the device server read the specified logical block(s) and transfer them to the data-in buffer.
+  SCSI_CMD_WRITE_10                     = 0x2A, ///< The WRITE (10) command requests thatthe device server transfer the specified logical block(s) from the data-out buffer and write them.
+}scsi_cmd_type_t;
+
+/// SCSI Sense Key
+typedef enum
+{
+  SCSI_SENSE_NONE            = 0x00, ///< no specific Sense Key. This would be the case for a successful command
+  SCSI_SENSE_RECOVERED_ERROR = 0x01, ///< ndicates the last command completed successfully with some recovery action performed by the disc drive.
+  SCSI_SENSE_NOT_READY       = 0x02, ///< Indicates the logical unit addressed cannot be accessed.
+  SCSI_SENSE_MEDIUM_ERROR    = 0x03, ///< Indicates the command terminated with a non-recovered error condition.
+  SCSI_SENSE_HARDWARE_ERROR  = 0x04, ///< Indicates the disc drive detected a nonrecoverable hardware failure while performing the command or during a self test.
+  SCSI_SENSE_ILLEGAL_REQUEST = 0x05, ///< Indicates an illegal parameter in the command descriptor block or in the additional parameters
+  SCSI_SENSE_UNIT_ATTENTION  = 0x06, ///< Indicates the disc drive may have been reset.
+  SCSI_SENSE_DATA_PROTECT    = 0x07, ///< Indicates that a command that reads or writes the medium was attempted on a block that is protected from this operation. The read or write operation is not performed.
+  SCSI_SENSE_FIRMWARE_ERROR  = 0x08, ///< Vendor specific sense key.
+  SCSI_SENSE_ABORTED_COMMAND = 0x0b, ///< Indicates the disc drive aborted the command.
+  SCSI_SENSE_EQUAL           = 0x0c, ///< Indicates a SEARCH DATA command has satisfied an equal comparison.
+  SCSI_SENSE_VOLUME_OVERFLOW = 0x0d, ///< Indicates a buffered peripheral device has reached the end of medium partition and data remains in the buffer that has not been written to the medium.
+  SCSI_SENSE_MISCOMPARE      = 0x0e  ///< ndicates that the source data did not match the data read from the medium.
+}scsi_sense_key_type_t;
+
+//--------------------------------------------------------------------+
+// SCSI Primary Command (SPC-4)
+//--------------------------------------------------------------------+
+
+/// SCSI Test Unit Ready Command
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t cmd_code    ; ///< SCSI OpCode for \ref SCSI_CMD_TEST_UNIT_READY
+  uint8_t lun         ; ///< Logical Unit
+  uint8_t reserved[3] ;
+  uint8_t control     ;
+} scsi_test_unit_ready_t;
+
+TU_VERIFY_STATIC(sizeof(scsi_test_unit_ready_t) == 6, "size is not correct");
+
+/// SCSI Inquiry Command
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t cmd_code     ; ///< SCSI OpCode for \ref SCSI_CMD_INQUIRY
+  uint8_t reserved1    ;
+  uint8_t page_code    ;
+  uint8_t reserved2    ;
+  uint8_t alloc_length ; ///< specifies the maximum number of bytes that USB host has allocated in the Data-In Buffer. An allocation length of zero specifies that no data shall be transferred.
+  uint8_t control      ;
+} scsi_inquiry_t, scsi_request_sense_t;
+
+TU_VERIFY_STATIC(sizeof(scsi_inquiry_t) == 6, "size is not correct");
+
+/// SCSI Inquiry Response Data
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t peripheral_device_type     : 5;
+  uint8_t peripheral_qualifier       : 3;
+
+  uint8_t                            : 7;
+  uint8_t is_removable               : 1;
+
+  uint8_t version;
+
+  uint8_t response_data_format       : 4;
+  uint8_t hierarchical_support       : 1;
+  uint8_t normal_aca                 : 1;
+  uint8_t                            : 2;
+
+  uint8_t additional_length;
+
+  uint8_t protect                    : 1;
+  uint8_t                            : 2;
+  uint8_t third_party_copy           : 1;
+  uint8_t target_port_group_support  : 2;
+  uint8_t access_control_coordinator : 1;
+  uint8_t scc_support                : 1;
+
+  uint8_t addr16                     : 1;
+  uint8_t                            : 3;
+  uint8_t multi_port                 : 1;
+  uint8_t                            : 1; // vendor specific
+  uint8_t enclosure_service          : 1;
+  uint8_t                            : 1;
+
+  uint8_t                            : 1; // vendor specific
+  uint8_t cmd_que                    : 1;
+  uint8_t                            : 2;
+  uint8_t sync                       : 1;
+  uint8_t wbus16                     : 1;
+  uint8_t                            : 2;
+
+  uint8_t vendor_id[8]  ; ///< 8 bytes of ASCII data identifying the vendor of the product.
+  uint8_t product_id[16]; ///< 16 bytes of ASCII data defined by the vendor.
+  uint8_t product_rev[4]; ///< 4 bytes of ASCII data defined by the vendor.
+} scsi_inquiry_resp_t;
+
+TU_VERIFY_STATIC(sizeof(scsi_inquiry_resp_t) == 36, "size is not correct");
+
+
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t response_code : 7; ///< 70h - current errors, Fixed Format 71h - deferred errors, Fixed Format
+  uint8_t valid         : 1;
+
+  uint8_t reserved;
+
+  uint8_t sense_key     : 4;
+  uint8_t               : 1;
+  uint8_t ili           : 1; ///< Incorrect length indicator
+  uint8_t end_of_medium : 1;
+  uint8_t filemark      : 1;
+
+  uint32_t information;
+  uint8_t  add_sense_len;
+  uint32_t command_specific_info;
+  uint8_t  add_sense_code;
+  uint8_t  add_sense_qualifier;
+  uint8_t  field_replaceable_unit_code;
+
+  uint8_t  sense_key_specific[3]; ///< sense key specific valid bit is bit 7 of key[0], aka MSB in Big Endian layout
+
+} scsi_sense_fixed_resp_t;
+
+TU_VERIFY_STATIC(sizeof(scsi_sense_fixed_resp_t) == 18, "size is not correct");
+
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t cmd_code     ; ///< SCSI OpCode for \ref SCSI_CMD_MODE_SENSE_6
+
+  uint8_t : 3;
+  uint8_t disable_block_descriptor : 1;
+  uint8_t : 4;
+
+  uint8_t page_code : 6;
+  uint8_t page_control : 2;
+
+  uint8_t subpage_code;
+  uint8_t alloc_length;
+  uint8_t control;
+} scsi_mode_sense6_t;
+
+TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_t) == 6, "size is not correct");
+
+// This is only a Mode parameter header(6).
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t data_len;
+  uint8_t medium_type;
+
+  uint8_t reserved : 7;
+  bool write_protected : 1;
+
+  uint8_t block_descriptor_len;
+} scsi_mode_sense6_resp_t;
+
+TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_resp_t) == 4, "size is not correct");
+
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t cmd_code; ///< SCSI OpCode for \ref SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
+  uint8_t reserved[3];
+  uint8_t prohibit_removal;
+  uint8_t control;
+} scsi_prevent_allow_medium_removal_t;
+
+TU_VERIFY_STATIC( sizeof(scsi_prevent_allow_medium_removal_t) == 6, "size is not correct");
+
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t cmd_code;
+
+  uint8_t immded : 1;
+  uint8_t        : 7;
+
+  uint8_t TU_RESERVED;
+
+  uint8_t power_condition_mod : 4;
+  uint8_t                     : 4;
+
+  uint8_t start           : 1;
+  uint8_t load_eject      : 1;
+  uint8_t no_flush        : 1;
+  uint8_t                 : 1;
+  uint8_t power_condition : 4;
+
+  uint8_t control;
+} scsi_start_stop_unit_t;
+
+TU_VERIFY_STATIC( sizeof(scsi_start_stop_unit_t) == 6, "size is not correct");
+
+//--------------------------------------------------------------------+
+// SCSI MMC
+//--------------------------------------------------------------------+
+/// SCSI Read Format Capacity: Write Capacity
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t cmd_code;
+  uint8_t reserved[6];
+  uint16_t alloc_length;
+  uint8_t control;
+} scsi_read_format_capacity_t;
+
+TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_t) == 10, "size is not correct");
+
+typedef struct TU_ATTR_PACKED{
+  uint8_t reserved[3];
+  uint8_t list_length; /// must be 8*n, length in bytes of formattable capacity descriptor followed it.
+
+  uint32_t block_num; /// Number of Logical Blocks
+  uint8_t  descriptor_type; // 00: reserved, 01 unformatted media , 10 Formatted media, 11 No media present
+
+  uint8_t  reserved2;
+  uint16_t block_size_u16;
+
+} scsi_read_format_capacity_data_t;
+
+TU_VERIFY_STATIC( sizeof(scsi_read_format_capacity_data_t) == 12, "size is not correct");
+
+//--------------------------------------------------------------------+
+// SCSI Block Command (SBC-3)
+// NOTE: All data in SCSI command are in Big Endian
+//--------------------------------------------------------------------+
+
+/// SCSI Read Capacity 10 Command: Read Capacity
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  cmd_code                 ; ///< SCSI OpCode for \ref SCSI_CMD_READ_CAPACITY_10
+  uint8_t  reserved1                ;
+  uint32_t lba                      ; ///< The first Logical Block Address (LBA) accessed by this command
+  uint16_t reserved2                ;
+  uint8_t  partial_medium_indicator ;
+  uint8_t  control                  ;
+} scsi_read_capacity10_t;
+
+TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_t) == 10, "size is not correct");
+
+/// SCSI Read Capacity 10 Response Data
+typedef struct {
+  uint32_t last_lba   ; ///< The last Logical Block Address of the device
+  uint32_t block_size ; ///< Block size in bytes
+} scsi_read_capacity10_resp_t;
+
+TU_VERIFY_STATIC(sizeof(scsi_read_capacity10_resp_t) == 8, "size is not correct");
+
+/// SCSI Read 10 Command
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  cmd_code    ; ///< SCSI OpCode
+  uint8_t  reserved    ; // has LUN according to wiki
+  uint32_t lba         ; ///< The first Logical Block Address (LBA) accessed by this command
+  uint8_t  reserved2   ;
+  uint16_t block_count ; ///< Number of Blocks used by this command
+  uint8_t  control     ;
+} scsi_read10_t, scsi_write10_t;
+
+TU_VERIFY_STATIC(sizeof(scsi_read10_t) == 10, "size is not correct");
+TU_VERIFY_STATIC(sizeof(scsi_write10_t) == 10, "size is not correct");
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_MSC_H_ */
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
new file mode 100644
index 0000000..97837b1
--- /dev/null
+++ b/src/class/msc/msc_device.c
@@ -0,0 +1,939 @@
+/*
+ * 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 (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MSC)
+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+#include "device/dcd.h"         // for faking dcd_event_xfer_complete
+
+#include "msc_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+// Can be selectively disabled to reduce logging when troubleshooting other driver
+#define MSC_DEBUG   2
+
+enum
+{
+  MSC_STAGE_CMD  = 0,
+  MSC_STAGE_DATA,
+  MSC_STAGE_STATUS,
+  MSC_STAGE_STATUS_SENT,
+  MSC_STAGE_NEED_RESET,
+};
+
+typedef struct
+{
+  // TODO optimize alignment
+  CFG_TUSB_MEM_ALIGN msc_cbw_t cbw;
+  CFG_TUSB_MEM_ALIGN msc_csw_t csw;
+
+  uint8_t  itf_num;
+  uint8_t  ep_in;
+  uint8_t  ep_out;
+
+  // Bulk Only Transfer (BOT) Protocol
+  uint8_t  stage;
+  uint32_t total_len;   // byte to be transferred, can be smaller than total_bytes in cbw
+  uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage
+
+  // Sense Response Data
+  uint8_t sense_key;
+  uint8_t add_sense_code;
+  uint8_t add_sense_qualifier;
+}mscd_interface_t;
+
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf;
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE];
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize);
+static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
+
+static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
+static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes);
+
+TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir)
+{
+  return tu_bit_test(dir, 7);
+}
+
+static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc)
+{
+  // Data residue is always = host expect - actual transferred
+  p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
+
+  p_msc->stage = MSC_STAGE_STATUS_SENT;
+  return usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t));
+}
+
+static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc)
+{
+  p_msc->stage = MSC_STAGE_CMD;
+  return usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t));
+}
+
+static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status)
+{
+  msc_cbw_t const * p_cbw = &p_msc->cbw;
+  msc_csw_t       * p_csw = &p_msc->csw;
+
+  p_csw->status       = status;
+  p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
+  p_msc->stage        = MSC_STAGE_STATUS;
+
+  // failed but sense key is not set: default to Illegal Request
+  if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
+
+  // If there is data stage and not yet complete, stall it
+  if ( p_cbw->total_bytes && p_csw->data_residue )
+  {
+    if ( is_data_in(p_cbw->dir) )
+    {
+      usbd_edpt_stall(rhport, p_msc->ep_in);
+    }
+    else
+    {
+      usbd_edpt_stall(rhport, p_msc->ep_out);
+    }
+  }
+}
+
+static inline uint32_t rdwr10_get_lba(uint8_t const command[])
+{
+  // use offsetof to avoid pointer to the odd/unaligned address
+  uint32_t const lba = tu_unaligned_read32(command + offsetof(scsi_write10_t, lba));
+
+  // lba is in Big Endian
+  return tu_ntohl(lba);
+}
+
+static inline uint16_t rdwr10_get_blockcount(msc_cbw_t const* cbw)
+{
+  uint16_t const block_count = tu_unaligned_read16(cbw->command + offsetof(scsi_write10_t, block_count));
+  return tu_ntohs(block_count);
+}
+
+static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw)
+{
+  // first extract block count in the command
+  uint16_t const block_count = rdwr10_get_blockcount(cbw);
+
+  // invalid block count
+  if (block_count == 0) return 0;
+
+  return (uint16_t) (cbw->total_bytes / block_count);
+}
+
+uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw)
+{
+  uint8_t status = MSC_CSW_STATUS_PASSED;
+  uint16_t const block_count = rdwr10_get_blockcount(cbw);
+
+  if ( cbw->total_bytes == 0 )
+  {
+    if ( block_count )
+    {
+      TU_LOG(MSC_DEBUG, "  SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n");
+      status = MSC_CSW_STATUS_PHASE_ERROR;
+    }else
+    {
+      // no data transfer, only exist in complaint test suite
+    }
+  }else
+  {
+    if ( SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir) )
+    {
+      TU_LOG(MSC_DEBUG, "  SCSI case 10 (Ho <> Di)\r\n");
+      status = MSC_CSW_STATUS_PHASE_ERROR;
+    }
+    else if ( SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir) )
+    {
+      TU_LOG(MSC_DEBUG, "  SCSI case 8 (Hi <> Do)\r\n");
+      status = MSC_CSW_STATUS_PHASE_ERROR;
+    }
+    else if ( 0 == block_count )
+    {
+      TU_LOG(MSC_DEBUG, "  SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n");
+      status =  MSC_CSW_STATUS_FAILED;
+    }
+    else if ( cbw->total_bytes / block_count == 0 )
+    {
+      TU_LOG(MSC_DEBUG, " Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n");
+      status = MSC_CSW_STATUS_PHASE_ERROR;
+    }
+  }
+
+  return status;
+}
+
+//--------------------------------------------------------------------+
+// Debug
+//--------------------------------------------------------------------+
+#if CFG_TUSB_DEBUG >= 2
+
+TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
+{
+  { .key = SCSI_CMD_TEST_UNIT_READY              , .data = "Test Unit Ready" },
+  { .key = SCSI_CMD_INQUIRY                      , .data = "Inquiry" },
+  { .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_READ_CAPACITY_10             , .data = "Read Capacity10" },
+  { .key = SCSI_CMD_REQUEST_SENSE                , .data = "Request Sense" },
+  { .key = SCSI_CMD_READ_FORMAT_CAPACITY         , .data = "Read Format Capacity" },
+  { .key = SCSI_CMD_READ_10                      , .data = "Read10" },
+  { .key = SCSI_CMD_WRITE_10                     , .data = "Write10" }
+};
+
+TU_ATTR_UNUSED static tu_lookup_table_t const _msc_scsi_cmd_table =
+{
+  .count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup),
+  .items = _msc_scsi_cmd_lookup
+};
+
+#endif
+
+//--------------------------------------------------------------------+
+// APPLICATION API
+//--------------------------------------------------------------------+
+bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier)
+{
+  (void) lun;
+
+  _mscd_itf.sense_key           = sense_key;
+  _mscd_itf.add_sense_code      = add_sense_code;
+  _mscd_itf.add_sense_qualifier = add_sense_qualifier;
+
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void mscd_init(void)
+{
+  tu_memclr(&_mscd_itf, sizeof(mscd_interface_t));
+}
+
+void mscd_reset(uint8_t rhport)
+{
+  (void) rhport;
+  tu_memclr(&_mscd_itf, sizeof(mscd_interface_t));
+}
+
+uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
+{
+  // only support SCSI's BOT protocol
+  TU_VERIFY(TUSB_CLASS_MSC    == itf_desc->bInterfaceClass &&
+            MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass &&
+            MSC_PROTOCOL_BOT  == itf_desc->bInterfaceProtocol, 0);
+
+  // msc driver length is fixed
+  uint16_t const drv_len = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
+
+  // Max length must be at least 1 interface + 2 endpoints
+  TU_ASSERT(max_len >= drv_len, 0);
+
+  mscd_interface_t * p_msc = &_mscd_itf;
+  p_msc->itf_num = itf_desc->bInterfaceNumber;
+
+  // Open endpoint pair
+  TU_ASSERT( usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0 );
+
+  // Prepare for Command Block Wrapper
+  TU_ASSERT( prepare_cbw(rhport, p_msc), drv_len);
+
+  return drv_len;
+}
+
+static void proc_bot_reset(mscd_interface_t* p_msc)
+{
+  p_msc->stage       = MSC_STAGE_CMD;
+  p_msc->total_len   = 0;
+  p_msc->xferred_len = 0;
+
+  p_msc->sense_key           = 0;
+  p_msc->add_sense_code      = 0;
+  p_msc->add_sense_qualifier = 0;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  // nothing to do with DATA & ACK stage
+  if (stage != CONTROL_STAGE_SETUP) return true;
+
+  mscd_interface_t* p_msc = &_mscd_itf;
+
+  // Clear Endpoint Feature (stall) for recovery
+  if ( TUSB_REQ_TYPE_STANDARD     == request->bmRequestType_bit.type      &&
+       TUSB_REQ_RCPT_ENDPOINT     == request->bmRequestType_bit.recipient &&
+       TUSB_REQ_CLEAR_FEATURE     == request->bRequest                    &&
+       TUSB_REQ_FEATURE_EDPT_HALT == request->wValue )
+  {
+    uint8_t const ep_addr = tu_u16_low(request->wIndex);
+
+    if ( p_msc->stage == MSC_STAGE_NEED_RESET )
+    {
+      // reset recovery is required to recover from this stage
+      // Clear Stall request cannot resolve this -> continue to stall endpoint
+      usbd_edpt_stall(rhport, ep_addr);
+    }
+    else
+    {
+      if ( ep_addr == p_msc->ep_in )
+      {
+        if ( p_msc->stage == MSC_STAGE_STATUS )
+        {
+          // resume sending SCSI status if we are in this stage previously before stalled
+          TU_ASSERT( send_csw(rhport, p_msc) );
+        }
+      }
+      else if ( ep_addr == p_msc->ep_out )
+      {
+        if ( p_msc->stage == MSC_STAGE_CMD )
+        {
+          // part of reset recovery (probably due to invalid CBW) -> prepare for new command
+          // Note: skip if already queued previously
+          if ( usbd_edpt_ready(rhport, p_msc->ep_out) )
+          {
+            TU_ASSERT( prepare_cbw(rhport, p_msc) );
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  // From this point only handle class request only
+  TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
+
+  switch ( request->bRequest )
+  {
+    case MSC_REQ_RESET:
+      TU_LOG(MSC_DEBUG, "  MSC BOT Reset\r\n");
+      TU_VERIFY(request->wValue == 0 && request->wLength == 0);
+
+      // driver state reset
+      proc_bot_reset(p_msc);
+
+      tud_control_status(rhport, request);
+    break;
+
+    case MSC_REQ_GET_MAX_LUN:
+    {
+      TU_LOG(MSC_DEBUG, "  MSC Get Max Lun\r\n");
+      TU_VERIFY(request->wValue == 0 && request->wLength == 1);
+
+      uint8_t maxlun = 1;
+      if (tud_msc_get_maxlun_cb) maxlun = tud_msc_get_maxlun_cb();
+      TU_VERIFY(maxlun);
+
+      // MAX LUN is minus 1 by specs
+      maxlun--;
+
+      tud_control_xfer(rhport, request, &maxlun, 1);
+    }
+    break;
+
+    default: return false; // stall unsupported request
+  }
+
+  return true;
+}
+
+bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
+{
+  (void) event;
+
+  mscd_interface_t* p_msc = &_mscd_itf;
+  msc_cbw_t const * p_cbw = &p_msc->cbw;
+  msc_csw_t       * p_csw = &p_msc->csw;
+
+  switch (p_msc->stage)
+  {
+    case MSC_STAGE_CMD:
+      //------------- new CBW received -------------//
+      // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it
+      if(ep_addr != p_msc->ep_out) return true;
+
+      if ( !(xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE) )
+      {
+        TU_LOG(MSC_DEBUG, "  SCSI CBW is not valid\r\n");
+
+        // BOT 6.6.1 If CBW is not valid stall both endpoints until reset recovery
+        p_msc->stage = MSC_STAGE_NEED_RESET;
+
+        // invalid CBW stall both endpoints
+        usbd_edpt_stall(rhport, p_msc->ep_in);
+        usbd_edpt_stall(rhport, p_msc->ep_out);
+
+        return false;
+      }
+
+      TU_LOG(MSC_DEBUG, "  SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
+      //TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2);
+
+      p_csw->signature    = MSC_CSW_SIGNATURE;
+      p_csw->tag          = p_cbw->tag;
+      p_csw->data_residue = 0;
+      p_csw->status       = MSC_CSW_STATUS_PASSED;
+
+      /*------------- Parse command and prepare DATA -------------*/
+      p_msc->stage = MSC_STAGE_DATA;
+      p_msc->total_len = p_cbw->total_bytes;
+      p_msc->xferred_len = 0;
+
+      // Read10 or Write10
+      if ( (SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0]) )
+      {
+        uint8_t const status = rdwr10_validate_cmd(p_cbw);
+
+        if ( status != MSC_CSW_STATUS_PASSED)
+        {
+          fail_scsi_op(rhport, p_msc, status);
+        }else if ( p_cbw->total_bytes )
+        {
+          if (SCSI_CMD_READ_10 == p_cbw->command[0])
+          {
+            proc_read10_cmd(rhport, p_msc);
+          }else
+          {
+            proc_write10_cmd(rhport, p_msc);
+          }
+        }else
+        {
+          // no data transfer, only exist in complaint test suite
+          p_msc->stage = MSC_STAGE_STATUS;
+        }
+      }
+      else
+      {
+        // For other SCSI commands
+        // 1. OUT : queue transfer (invoke app callback after done)
+        // 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length
+        if ( (p_cbw->total_bytes > 0 ) && !is_data_in(p_cbw->dir) )
+        {
+          if (p_cbw->total_bytes > sizeof(_mscd_buf))
+          {
+            TU_LOG(MSC_DEBUG, "  SCSI reject non READ10/WRITE10 with large data\r\n");
+            fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+          }else
+          {
+            // 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) );
+          }
+        }else
+        {
+          // First process if it is a built-in commands
+          int32_t resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf));
+
+          // 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);
+          }
+
+          if ( resplen < 0 )
+          {
+            // unsupported command
+            TU_LOG(MSC_DEBUG, "  SCSI unsupported command\r\n");
+            fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+          }
+          else if (resplen == 0)
+          {
+            if (p_cbw->total_bytes)
+            {
+              // 6.7 The 13 Cases: case 4 (Hi > Dn)
+              // TU_LOG(MSC_DEBUG, "  SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes);
+              fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+            }else
+            {
+              // case 1 Hn = Dn: all good
+              p_msc->stage = MSC_STAGE_STATUS;
+            }
+          }
+          else
+          {
+            if ( p_cbw->total_bytes == 0 )
+            {
+              // 6.7 The 13 Cases: case 2 (Hn < Di)
+              // TU_LOG(MSC_DEBUG, "  SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes);
+              fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+            }else
+            {
+              // 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) );
+            }
+          }
+        }
+      }
+    break;
+
+    case MSC_STAGE_DATA:
+      TU_LOG(MSC_DEBUG, "  SCSI Data\r\n");
+      //TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2);
+
+      if (SCSI_CMD_READ_10 == p_cbw->command[0])
+      {
+        p_msc->xferred_len += xferred_bytes;
+
+        if ( p_msc->xferred_len >= p_msc->total_len )
+        {
+          // Data Stage is complete
+          p_msc->stage = MSC_STAGE_STATUS;
+        }else
+        {
+          proc_read10_cmd(rhport, p_msc);
+        }
+      }
+      else if (SCSI_CMD_WRITE_10 == p_cbw->command[0])
+      {
+        proc_write10_new_data(rhport, p_msc, xferred_bytes);
+      }
+      else
+      {
+        p_msc->xferred_len += xferred_bytes;
+
+        // 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);
+
+          if ( cb_result < 0 )
+          {
+            // unsupported command
+            TU_LOG(MSC_DEBUG, "  SCSI unsupported command\r\n");
+            fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+          }else
+          {
+            // TODO haven't implement this scenario any further yet
+          }
+        }
+
+        if ( p_msc->xferred_len >= p_msc->total_len )
+        {
+          // Data Stage is complete
+          p_msc->stage = MSC_STAGE_STATUS;
+        }
+        else
+        {
+          // This scenario with command that take more than one transfer is already rejected at Command stage
+          TU_BREAKPOINT();
+        }
+      }
+    break;
+
+    case MSC_STAGE_STATUS:
+      // processed immediately after this switch, supposedly to be empty
+    break;
+
+    case MSC_STAGE_STATUS_SENT:
+      // 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_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2);
+
+        // Invoke complete callback if defined
+        // Note: There is racing issue with samd51 + qspi flash testing with arduino
+        // if complete_cb() is invoked after queuing the status.
+        switch(p_cbw->command[0])
+        {
+          case SCSI_CMD_READ_10:
+            if ( tud_msc_read10_complete_cb ) tud_msc_read10_complete_cb(p_cbw->lun);
+          break;
+
+          case SCSI_CMD_WRITE_10:
+            if ( tud_msc_write10_complete_cb ) tud_msc_write10_complete_cb(p_cbw->lun);
+          break;
+
+          default:
+            if ( tud_msc_scsi_complete_cb ) tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command);
+          break;
+        }
+
+        TU_ASSERT( prepare_cbw(rhport, p_msc) );
+      }else
+      {
+        // Any xfer ended here is consider unknown error, ignore it
+        TU_LOG1("  Warning expect SCSI Status but received unknown data\r\n");
+      }
+    break;
+
+    default : break;
+  }
+
+  if ( p_msc->stage == MSC_STAGE_STATUS )
+  {
+    // skip status if epin is currently stalled, will do it when received Clear Stall request
+    if ( !usbd_edpt_stalled(rhport,  p_msc->ep_in) )
+    {
+      if ( (p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir) )
+      {
+        // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status
+        // TU_LOG(MSC_DEBUG, "  SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len);
+        usbd_edpt_stall(rhport, p_msc->ep_in);
+      }else
+      {
+        TU_ASSERT( send_csw(rhport, p_msc) );
+      }
+    }
+
+    #if TU_CHECK_MCU(OPT_MCU_CXD56)
+    // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD.
+    // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and
+    // hope everything will work
+    if ( usbd_edpt_stalled(rhport, p_msc->ep_in) )
+    {
+      usbd_edpt_clear_stall(rhport, p_msc->ep_in);
+      send_csw(rhport, p_msc);
+    }
+    #endif
+  }
+
+  return true;
+}
+
+/*------------------------------------------------------------------*/
+/* SCSI Command Process
+ *------------------------------------------------------------------*/
+
+// return response's length (copied to buffer). Negative if it is not an built-in command or indicate Failed status (CSW)
+// In case of a failed status, sense key must be set for reason of failure
+static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize)
+{
+  (void) bufsize; // TODO refractor later
+  int32_t resplen;
+
+  mscd_interface_t* p_msc = &_mscd_itf;
+
+  switch ( scsi_cmd[0] )
+  {
+    case SCSI_CMD_TEST_UNIT_READY:
+      resplen = 0;
+      if ( !tud_msc_test_unit_ready_cb(lun) )
+      {
+        // 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);
+      }
+    break;
+
+    case SCSI_CMD_START_STOP_UNIT:
+      resplen = 0;
+
+      if (tud_msc_start_stop_cb)
+      {
+        scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
+        if ( !tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject) )
+        {
+          // 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);
+        }
+      }
+    break;
+
+    case SCSI_CMD_READ_CAPACITY_10:
+    {
+      uint32_t block_count;
+      uint32_t block_size;
+      uint16_t block_size_u16;
+
+      tud_msc_capacity_cb(lun, &block_count, &block_size_u16);
+      block_size = (uint32_t) block_size_u16;
+
+      // Invalid block size/count from callback, possibly unit is not ready
+      // stall this request, set sense key to NOT READY
+      if (block_count == 0 || block_size == 0)
+      {
+        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);
+      }else
+      {
+        scsi_read_capacity10_resp_t read_capa10;
+
+        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);
+      }
+    }
+    break;
+
+    case SCSI_CMD_READ_FORMAT_CAPACITY:
+    {
+      scsi_read_format_capacity_data_t read_fmt_capa =
+      {
+          .list_length     = 8,
+          .block_num       = 0,
+          .descriptor_type = 2, // formatted media
+          .block_size_u16  = 0
+      };
+
+      uint32_t block_count;
+      uint16_t block_size;
+
+      tud_msc_capacity_cb(lun, &block_count, &block_size);
+
+      // Invalid block size/count from callback, possibly unit is not ready
+      // stall this request, set sense key to NOT READY
+      if (block_count == 0 || block_size == 0)
+      {
+        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);
+      }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);
+      }
+    }
+    break;
+
+    case SCSI_CMD_INQUIRY:
+    {
+      scsi_inquiry_resp_t inquiry_rsp =
+      {
+          .is_removable         = 1,
+          .version              = 2,
+          .response_data_format = 2,
+      };
+
+      // vendor_id, product_id, product_rev is space padded string
+      memset(inquiry_rsp.vendor_id  , ' ', sizeof(inquiry_rsp.vendor_id));
+      memset(inquiry_rsp.product_id , ' ', sizeof(inquiry_rsp.product_id));
+      memset(inquiry_rsp.product_rev, ' ', sizeof(inquiry_rsp.product_rev));
+
+      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);
+    }
+    break;
+
+    case SCSI_CMD_MODE_SENSE_6:
+    {
+      scsi_mode_sense6_resp_t mode_resp =
+      {
+          .data_len = 3,
+          .medium_type = 0,
+          .write_protected = false,
+          .reserved = 0,
+          .block_descriptor_len = 0  // no block descriptor are included
+      };
+
+      bool writable = true;
+      if ( tud_msc_is_writable_cb )
+      {
+        writable = tud_msc_is_writable_cb(lun);
+      }
+
+      mode_resp.write_protected = !writable;
+
+      resplen = sizeof(mode_resp);
+      memcpy(buffer, &mode_resp, resplen);
+    }
+    break;
+
+    case SCSI_CMD_REQUEST_SENSE:
+    {
+      scsi_sense_fixed_resp_t sense_rsp =
+      {
+          .response_code = 0x70,
+          .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_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);
+
+      // Clear sense data after copy
+      tud_msc_set_sense(lun, 0, 0, 0);
+    }
+    break;
+
+    default: resplen = -1; break;
+  }
+
+  return resplen;
+}
+
+static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
+{
+  msc_cbw_t const * p_cbw = &p_msc->cbw;
+
+  // block size already verified not zero
+  uint16_t const block_sz = rdwr10_get_blocksize(p_cbw);
+
+  // Adjust lba with transferred bytes
+  uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
+
+  // remaining bytes capped at class buffer
+  int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len);
+
+  // Application can consume smaller bytes
+  uint32_t const offset = p_msc->xferred_len % block_sz;
+  nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_buf, (uint32_t) nbytes);
+
+  if ( nbytes < 0 )
+  {
+    // negative means error -> endpoint is stalled & status in CSW set to failed
+    TU_LOG(MSC_DEBUG, "  tud_msc_read10_cb() return -1\r\n");
+
+    // Sense = Flash not ready for access
+    tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_MEDIUM_ERROR, 0x33, 0x00);
+
+    fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+  }
+  else if ( nbytes == 0 )
+  {
+    // zero means not ready -> simulate an transfer complete so that this driver callback will fired again
+    dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false);
+  }
+  else
+  {
+    TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, nbytes), );
+  }
+}
+
+static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
+{
+  msc_cbw_t const * p_cbw = &p_msc->cbw;
+  bool writable = true;
+
+  if ( tud_msc_is_writable_cb )
+  {
+    writable = tud_msc_is_writable_cb(p_cbw->lun);
+  }
+
+  if ( !writable )
+  {
+    // Not writable, complete this SCSI op with error
+    // Sense = Write protected
+    tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00);
+    fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+    return;
+  }
+
+  // remaining bytes capped at class buffer
+  int32_t nbytes = (int32_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), );
+}
+
+// process new data arrived from WRITE10
+static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes)
+{
+  msc_cbw_t const * p_cbw = &p_msc->cbw;
+
+  // block size already verified not zero
+  uint16_t const block_sz = rdwr10_get_blocksize(p_cbw);
+
+  // Adjust lba with transferred bytes
+  uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
+
+  // Invoke callback to consume new data
+  uint32_t const offset = p_msc->xferred_len % block_sz;
+  int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_buf, xferred_bytes);
+
+  if ( nbytes < 0 )
+  {
+    // negative means error -> failed this scsi op
+    TU_LOG(MSC_DEBUG, "  tud_msc_write10_cb() return -1\r\n");
+
+    // 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);
+
+    fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+  }else
+  {
+    // Application consume less than what we got (including zero)
+    if ( (uint32_t) nbytes < xferred_bytes )
+    {
+      if ( nbytes > 0 )
+      {
+        p_msc->xferred_len += nbytes;
+        memmove(_mscd_buf, _mscd_buf+nbytes, xferred_bytes-nbytes);
+      }
+
+      // 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);
+    }
+    else
+    {
+      // Application consume all bytes in our buffer
+      p_msc->xferred_len += xferred_bytes;
+
+      if ( p_msc->xferred_len >= p_msc->total_len )
+      {
+        // Data Stage is complete
+        p_msc->stage = MSC_STAGE_STATUS;
+      }else
+      {
+        // prepare to receive more data from host
+        proc_write10_cmd(rhport, p_msc);
+      }
+    }
+  }
+}
+
+#endif
diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h
new file mode 100644
index 0000000..d326943
--- /dev/null
+++ b/src/class/msc/msc_device.h
@@ -0,0 +1,159 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_MSC_DEVICE_H_
+#define _TUSB_MSC_DEVICE_H_
+
+#include "common/tusb_common.h"
+#include "msc.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Class Driver Configuration
+//--------------------------------------------------------------------+
+
+#if !defined(CFG_TUD_MSC_EP_BUFSIZE) & defined(CFG_TUD_MSC_BUFSIZE)
+  // TODO warn user to use new name later on
+  // #warning CFG_TUD_MSC_BUFSIZE is renamed to CFG_TUD_MSC_EP_BUFSIZE, please update to use the new name
+  #define CFG_TUD_MSC_EP_BUFSIZE  CFG_TUD_MSC_BUFSIZE
+#endif
+
+#ifndef CFG_TUD_MSC_EP_BUFSIZE
+  #error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better
+#endif
+
+TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct");
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
+// Set SCSI sense response
+bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier);
+
+//--------------------------------------------------------------------+
+// Application Callbacks (WEAK is optional)
+//--------------------------------------------------------------------+
+
+// Invoked when received SCSI READ10 command
+// - Address = lba * BLOCK_SIZE + offset
+//   - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE.
+//
+// - Application fill the buffer (up to bufsize) with address contents and return number of read byte. If
+//   - read < bufsize : These bytes are transferred first and callback invoked again for remaining data.
+//
+//   - read == 0      : Indicate application is not ready yet e.g disk I/O busy.
+//                      Callback invoked again with the same parameters later on.
+//
+//   - read < 0       : Indicate application error e.g invalid address. This request will be STALLed
+//                      and return failed status in command status wrapper phase.
+int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
+
+// Invoked when received SCSI WRITE10 command
+// - Address = lba * BLOCK_SIZE + offset
+//   - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE.
+//
+// - Application write data from buffer to address contents (up to bufsize) and return number of written byte. If
+//   - write < bufsize : callback invoked again with remaining data later on.
+//
+//   - write == 0      : Indicate application is not ready yet e.g disk I/O busy.
+//                       Callback invoked again with the same parameters later on.
+//
+//   - write < 0       : Indicate application error e.g invalid address. This request will be STALLed
+//                       and return failed status in command status wrapper phase.
+//
+// TODO change buffer to const uint8_t*
+int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
+
+// Invoked when received SCSI_CMD_INQUIRY
+// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]);
+
+// Invoked when received Test Unit Ready command.
+// return true allowing host to read/write this LUN e.g SD card inserted
+bool tud_msc_test_unit_ready_cb(uint8_t lun);
+
+// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
+// Application update block count and block size
+void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size);
+
+/**
+ * Invoked when received an SCSI command not in built-in list below.
+ * - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE
+ * - READ10 and WRITE10 has their own callbacks
+ *
+ * \param[in]   lun         Logical unit number
+ * \param[in]   scsi_cmd    SCSI command contents which application must examine to response accordingly
+ * \param[out]  buffer      Buffer for SCSI Data Stage.
+ *                            - For INPUT: application must fill this with response.
+ *                            - For OUTPUT it holds the Data from host
+ * \param[in]   bufsize     Buffer's length.
+ *
+ * \return      Actual bytes processed, can be zero for no-data command.
+ * \retval      negative    Indicate error e.g unsupported command, tinyusb will \b STALL the corresponding
+ *                          endpoint and return failed status in command status wrapper phase.
+ */
+int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize);
+
+/*------------- Optional callbacks -------------*/
+
+// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation
+TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void);
+
+// Invoked when received Start Stop Unit command
+// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
+// - 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 Read10 command is complete
+TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);
+
+// Invoke when Write10 command is complete, can be used to flush flash caching
+TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun);
+
+// Invoked when command in tud_msc_scsi_cb is complete
+TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]);
+
+// Invoked to check if device is writable as part of SCSI WRITE10
+TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun);
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void     mscd_init            (void);
+void     mscd_reset           (uint8_t rhport);
+uint16_t mscd_open            (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     mscd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * p_request);
+bool     mscd_xfer_cb         (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_MSC_DEVICE_H_ */
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
new file mode 100644
index 0000000..fa65199
--- /dev/null
+++ b/src/class/msc/msc_host.c
@@ -0,0 +1,491 @@
+/* 
+ * 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 TUSB_OPT_HOST_ENABLED & CFG_TUH_MSC
+
+#include "host/usbh.h"
+#include "host/usbh_classdriver.h"
+
+#include "msc_host.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+enum
+{
+  MSC_STAGE_IDLE = 0,
+  MSC_STAGE_CMD,
+  MSC_STAGE_DATA,
+  MSC_STAGE_STATUS,
+};
+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_in;
+  uint8_t ep_out;
+
+  uint8_t max_lun;
+
+  volatile bool configured; // Receive SET_CONFIGURE
+  volatile bool mounted;    // Enumeration is complete
+
+  struct {
+    uint32_t block_size;
+    uint32_t block_count;
+  } capacity[CFG_TUH_MSC_MAXLUN];
+
+  //------------- SCSI -------------//
+  uint8_t stage;
+  void*   buffer;
+  tuh_msc_complete_cb_t complete_cb;
+
+  msc_cbw_t cbw;
+  msc_csw_t csw;
+}msch_interface_t;
+
+CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX];
+
+// buffer used to read scsi information when mounted
+// largest response data currently is inquiry TODO Inquiry is not part of enum anymore
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4)
+static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)];
+
+TU_ATTR_ALWAYS_INLINE
+static inline msch_interface_t* get_itf(uint8_t dev_addr)
+{
+  return &_msch_itf[dev_addr-1];
+}
+
+//--------------------------------------------------------------------+
+// PUBLIC API
+//--------------------------------------------------------------------+
+uint8_t tuh_msc_get_maxlun(uint8_t dev_addr)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  return p_msc->max_lun;
+}
+
+uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  return p_msc->capacity[lun].block_count;
+}
+
+uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  return p_msc->capacity[lun].block_size;
+}
+
+bool tuh_msc_mounted(uint8_t dev_addr)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  return p_msc->mounted;
+}
+
+bool tuh_msc_ready(uint8_t dev_addr)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in);
+}
+
+//--------------------------------------------------------------------+
+// PUBLIC API: SCSI COMMAND
+//--------------------------------------------------------------------+
+static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun)
+{
+  tu_memclr(cbw, sizeof(msc_cbw_t));
+  cbw->signature = MSC_CBW_SIGNATURE;
+  cbw->tag       = 0x54555342; // TUSB
+  cbw->lun       = lun;
+}
+
+bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  TU_VERIFY(p_msc->configured);
+
+  // TODO claim endpoint
+
+  p_msc->cbw = *cbw;
+  p_msc->stage = MSC_STAGE_CMD;
+  p_msc->buffer = data;
+  p_msc->complete_cb = complete_cb;
+
+  TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)));
+
+  return true;
+}
+
+bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb)
+{
+   msch_interface_t* p_msc = get_itf(dev_addr);
+   TU_VERIFY(p_msc->configured);
+
+  msc_cbw_t cbw;
+  cbw_init(&cbw, lun);
+
+  cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t);
+  cbw.dir        = TUSB_DIR_IN_MASK;
+  cbw.cmd_len    = sizeof(scsi_read_capacity10_t);
+  cbw.command[0] = SCSI_CMD_READ_CAPACITY_10;
+
+  return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb);
+}
+
+bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  TU_VERIFY(p_msc->mounted);
+
+  msc_cbw_t cbw;
+  cbw_init(&cbw, lun);
+
+  cbw.total_bytes = sizeof(scsi_inquiry_resp_t);
+  cbw.dir         = TUSB_DIR_IN_MASK;
+  cbw.cmd_len     = sizeof(scsi_inquiry_t);
+
+  scsi_inquiry_t const cmd_inquiry =
+  {
+    .cmd_code     = SCSI_CMD_INQUIRY,
+    .alloc_length = sizeof(scsi_inquiry_resp_t)
+  };
+  memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len);
+
+  return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb);
+}
+
+bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  TU_VERIFY(p_msc->configured);
+
+  msc_cbw_t cbw;
+  cbw_init(&cbw, lun);
+
+  cbw.total_bytes = 0;
+  cbw.dir         = TUSB_DIR_OUT;
+  cbw.cmd_len     = sizeof(scsi_test_unit_ready_t);
+  cbw.command[0]  = SCSI_CMD_TEST_UNIT_READY;
+  cbw.command[1]  = lun; // according to wiki TODO need verification
+
+  return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb);
+}
+
+bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb)
+{
+  msc_cbw_t cbw;
+  cbw_init(&cbw, lun);
+
+  cbw.total_bytes = 18; // TODO sense response
+  cbw.dir         = TUSB_DIR_IN_MASK;
+  cbw.cmd_len     = sizeof(scsi_request_sense_t);
+
+  scsi_request_sense_t const cmd_request_sense =
+  {
+    .cmd_code     = SCSI_CMD_REQUEST_SENSE,
+    .alloc_length = 18
+  };
+
+  memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len);
+
+  return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb);
+}
+
+bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  TU_VERIFY(p_msc->mounted);
+
+  msc_cbw_t cbw;
+  cbw_init(&cbw, lun);
+ 
+  cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
+  cbw.dir         = TUSB_DIR_IN_MASK;
+  cbw.cmd_len     = sizeof(scsi_read10_t);
+ 
+  scsi_read10_t const cmd_read10 =
+  {
+    .cmd_code    = SCSI_CMD_READ_10,
+    .lba         = tu_htonl(lba),
+    .block_count = tu_htons(block_count)
+  };
+ 
+  memcpy(cbw.command, &cmd_read10, cbw.cmd_len);
+ 
+  return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb);
+}
+ 
+bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  TU_VERIFY(p_msc->mounted);
+
+  msc_cbw_t cbw;
+  cbw_init(&cbw, lun);
+
+  cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
+  cbw.dir         = TUSB_DIR_OUT;
+  cbw.cmd_len     = sizeof(scsi_write10_t);
+
+  scsi_write10_t const cmd_write10 =
+  {
+    .cmd_code    = SCSI_CMD_WRITE_10,
+    .lba         = tu_htonl(lba),
+    .block_count = tu_htons(block_count)
+  };
+
+  memcpy(cbw.command, &cmd_write10, cbw.cmd_len);
+
+  return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb);
+}
+
+#if 0
+// MSC interface Reset (not used now)
+bool tuh_msc_reset(uint8_t dev_addr)
+{
+  tusb_control_request_t const new_request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_INTERFACE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
+    },
+    .bRequest = MSC_REQ_RESET,
+    .wValue   = 0,
+    .wIndex   = p_msc->itf_num,
+    .wLength  = 0
+  };
+  TU_ASSERT( usbh_control_xfer( dev_addr, &new_request, NULL ) );
+}
+#endif
+
+//--------------------------------------------------------------------+
+// CLASS-USBH API
+//--------------------------------------------------------------------+
+void msch_init(void)
+{
+  tu_memclr(_msch_itf, sizeof(_msch_itf));
+}
+
+void msch_close(uint8_t dev_addr)
+{
+  TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
+
+  msch_interface_t* p_msc = get_itf(dev_addr);
+
+  // invoke Application Callback
+  if (p_msc->mounted && tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr);
+
+  tu_memclr(p_msc, sizeof(msch_interface_t));
+}
+
+bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  msc_cbw_t const * cbw = &p_msc->cbw;
+  msc_csw_t       * csw = &p_msc->csw;
+
+  switch (p_msc->stage)
+  {
+    case MSC_STAGE_CMD:
+      // Must be Command Block
+      TU_ASSERT(ep_addr == p_msc->ep_out &&  event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t));
+
+      if ( cbw->total_bytes && p_msc->buffer )
+      {
+        // Data stage if any
+        p_msc->stage = MSC_STAGE_DATA;
+
+        uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out;
+        TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, 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)));
+      }
+    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)));
+    break;
+
+    case MSC_STAGE_STATUS:
+      // SCSI op is complete
+      p_msc->stage = MSC_STAGE_IDLE;
+
+      if (p_msc->complete_cb) p_msc->complete_cb(dev_addr, cbw, csw);
+    break;
+
+    // unknown state
+    default: break;
+  }
+
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// MSC Enumeration
+//--------------------------------------------------------------------+
+
+static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+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)
+{
+  TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
+             MSC_PROTOCOL_BOT  == desc_itf->bInterfaceProtocol);
+
+  // msc driver length is fixed
+  uint16_t const drv_len = sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+  TU_ASSERT(drv_len <= max_len);
+
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf);
+
+  for(uint32_t i=0; i<2; i++)
+  {
+    TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
+    TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
+
+    if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
+    {
+      p_msc->ep_in = ep_desc->bEndpointAddress;
+    }else
+    {
+      p_msc->ep_out = ep_desc->bEndpointAddress;
+    }
+
+    ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc);
+  }
+
+  p_msc->itf_num = desc_itf->bInterfaceNumber;
+
+  return true;
+}
+
+bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  TU_ASSERT(p_msc->itf_num == itf_num);
+
+  p_msc->configured = true;
+
+  //------------- Get Max Lun -------------//
+  TU_LOG2("MSC Get Max Lun\r\n");
+  tusb_control_request_t request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_INTERFACE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_IN
+    },
+    .bRequest = MSC_REQ_GET_MAX_LUN,
+    .wValue   = 0,
+    .wIndex   = itf_num,
+    .wLength  = 1
+  };
+  TU_ASSERT(tuh_control_xfer(dev_addr, &request, &p_msc->max_lun, config_get_maxlun_complete));
+
+  return true;
+}
+
+static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  (void) request;
+
+  msch_interface_t* p_msc = get_itf(dev_addr);
+
+  // STALL means zero
+  p_msc->max_lun = (XFER_RESULT_SUCCESS == 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;
+}
+
+static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
+{
+  if (csw->status == 0)
+  {
+    // Unit is ready, read its capacity
+    TU_LOG2("SCSI Read Capacity\r\n");
+    tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete);
+  }else
+  {
+    // Note: During enumeration, some device fails Test Unit Ready and require a few retries
+    // with Request Sense to start working !!
+    // TODO limit number of retries
+    TU_LOG2("SCSI Request Sense\r\n");
+    TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete));
+  }
+
+  return true;
+}
+
+static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
+{
+  TU_ASSERT(csw->status == 0);
+  TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete));
+  return true;
+}
+
+static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
+{
+  TU_ASSERT(csw->status == 0);
+
+  msch_interface_t* p_msc = get_itf(dev_addr);
+
+  // 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);
+
+  // Mark enumeration is complete
+  p_msc->mounted = true;
+  if (tuh_msc_mount_cb) tuh_msc_mount_cb(dev_addr);
+
+  // notify usbh that driver enumeration is complete
+  usbh_driver_set_config_complete(dev_addr, p_msc->itf_num);
+
+  return true;
+}
+
+#endif
diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h
new file mode 100644
index 0000000..7718ad4
--- /dev/null
+++ b/src/class/msc/msc_host.h
@@ -0,0 +1,119 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_MSC_HOST_H_
+#define _TUSB_MSC_HOST_H_
+
+#include "msc.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Class Driver Configuration
+//--------------------------------------------------------------------+
+
+#ifndef CFG_TUH_MSC_MAXLUN
+#define CFG_TUH_MSC_MAXLUN  4
+#endif
+
+typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
+// Check if device supports MassStorage interface.
+// This function true after tuh_msc_mounted_cb() and false after tuh_msc_unmounted_cb()
+bool tuh_msc_mounted(uint8_t dev_addr);
+
+// Check if the interface is currently ready or busy transferring data
+bool tuh_msc_ready(uint8_t dev_addr);
+
+// Get Max Lun
+uint8_t tuh_msc_get_maxlun(uint8_t dev_addr);
+
+// Get number of block
+uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun);
+
+// Get block size in bytes
+uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun);
+
+// Perform a full SCSI command (cbw, data, csw) in non-blocking manner.
+// Complete callback is invoked when SCSI op is complete.
+// return true if success, false if there is already pending operation.
+bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb);
+
+// Perform SCSI Inquiry command
+// Complete callback is invoked when SCSI op is complete.
+bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb);
+
+// Perform SCSI Test Unit Ready command
+// Complete callback is invoked when SCSI op is complete.
+bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb);
+
+// Perform SCSI Request Sense 10 command
+// Complete callback is invoked when SCSI op is complete.
+bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb);
+
+// Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer
+// Complete callback is invoked when SCSI op is complete.
+bool  tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb);
+
+// Perform SCSI Write 10 command. Write n blocks starting from LBA to device
+// Complete callback is invoked when SCSI op is complete.
+bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb);
+
+// Perform SCSI Read Capacity 10 command
+// Complete callback is invoked when SCSI op is complete.
+// Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by
+// simply call tuh_msc_get_block_count() and tuh_msc_get_block_size()
+bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb);
+
+//------------- Application Callback -------------//
+
+// Invoked when a device with MassStorage interface is mounted
+TU_ATTR_WEAK void tuh_msc_mount_cb(uint8_t dev_addr);
+
+// Invoked when a device with MassStorage interface is unmounted
+TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr);
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+
+void msch_init       (void);
+bool msch_open       (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
+bool msch_set_config (uint8_t dev_addr, uint8_t itf_num);
+void msch_close      (uint8_t dev_addr);
+bool msch_xfer_cb    (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_MSC_HOST_H_ */
diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c
new file mode 100644
index 0000000..c6cd388
--- /dev/null
+++ b/src/class/net/ecm_rndis_device.c
@@ -0,0 +1,445 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Peter Lawrence
+ * 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 ( TUSB_OPT_DEVICE_ENABLED && CFG_TUD_ECM_RNDIS )
+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "net_device.h"
+#include "rndis_protocol.h"
+
+void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networking/rndis_reports.c */
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef struct
+{
+  uint8_t itf_num;      // Index number of Management Interface, +1 for Data Interface
+  uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active
+
+  uint8_t ep_notif;
+  uint8_t ep_in;
+  uint8_t ep_out;
+
+  bool ecm_mode;
+
+  // Endpoint descriptor use to open/close when receving SetInterface
+  // TODO since configuration descriptor may not be long-lived memory, we should
+  // keep a copy of endpoint attribute instead
+  uint8_t const * ecm_desc_epdata;
+
+} netd_interface_t;
+
+#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t)
+#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0
+
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN];
+
+struct ecm_notify_struct
+{
+  tusb_control_request_t header;
+  uint32_t downlink, uplink;
+};
+
+static const struct ecm_notify_struct ecm_notify_nc =
+{
+  .header = {
+    .bmRequestType = 0xA1,
+    .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */,
+    .wValue = 1 /* Connected */,
+    .wLength = 0,
+  },
+};
+
+static const struct ecm_notify_struct ecm_notify_csc =
+{
+  .header = {
+    .bmRequestType = 0xA1,
+    .bRequest = 0x2A /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */,
+    .wLength = 8,
+  },
+  .downlink = 9728000,
+  .uplink = 9728000,
+};
+
+// TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union
+{
+  uint8_t rndis_buf[120];
+  struct ecm_notify_struct ecm_buf;
+} notify;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// TODO remove CFG_TUSB_MEM_SECTION
+CFG_TUSB_MEM_SECTION static netd_interface_t _netd_itf;
+
+static bool can_xmit;
+
+void tud_network_recv_renew(void)
+{
+  usbd_edpt_xfer(TUD_OPT_RHPORT, _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);
+}
+
+void netd_report(uint8_t *buf, uint16_t len)
+{
+  // 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);
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void netd_init(void)
+{
+  tu_memclr(&_netd_itf, sizeof(_netd_itf));
+}
+
+void netd_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  netd_init();
+}
+
+uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
+{
+  bool const is_rndis = (TUD_RNDIS_ITF_CLASS    == itf_desc->bInterfaceClass    &&
+                         TUD_RNDIS_ITF_SUBCLASS == itf_desc->bInterfaceSubClass &&
+                         TUD_RNDIS_ITF_PROTOCOL == itf_desc->bInterfaceProtocol);
+
+  bool const is_ecm = (TUSB_CLASS_CDC                           == itf_desc->bInterfaceClass &&
+                       CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL == itf_desc->bInterfaceSubClass &&
+                       0x00                                     == itf_desc->bInterfaceProtocol);
+
+  TU_VERIFY(is_rndis || is_ecm, 0);
+
+  // confirm interface hasn't already been allocated
+  TU_ASSERT(0 == _netd_itf.ep_notif, 0);
+
+  // sanity check the descriptor
+  _netd_itf.ecm_mode = is_ecm;
+
+  //------------- Management Interface -------------//
+  _netd_itf.itf_num = itf_desc->bInterfaceNumber;
+
+  uint16_t drv_len = sizeof(tusb_desc_interface_t);
+  uint8_t const * p_desc = tu_desc_next( itf_desc );
+
+  // Communication Functional Descriptors
+  while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
+  {
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  // notification endpoint (if any)
+  if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
+  {
+    TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 );
+
+    _netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
+
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  //------------- Data Interface -------------//
+  // - RNDIS Data followed immediately by a pair of endpoints
+  // - CDC-ECM data interface has 2 alternate settings
+  //   - 0 : zero endpoints for inactive (default)
+  //   - 1 : IN & OUT endpoints for active networking
+  TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0);
+
+  do
+  {
+    tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc;
+    TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0);
+
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len) );
+
+  // Pair of endpoints
+  TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0);
+
+  if ( _netd_itf.ecm_mode )
+  {
+    // ECM by default is in-active, save the endpoint attribute
+    // to open later when received setInterface
+    _netd_itf.ecm_desc_epdata = p_desc;
+  }else
+  {
+    // Open endpoint pair for RNDIS
+    TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0 );
+
+    tud_network_init_cb();
+
+    // we are ready to transmit a packet
+    can_xmit = true;
+
+    // prepare for incoming packets
+    tud_network_recv_renew();
+  }
+
+  drv_len += 2*sizeof(tusb_desc_endpoint_t);
+
+  return drv_len;
+}
+
+static void ecm_report(bool nc)
+{
+  notify.ecm_buf = (nc) ? ecm_notify_nc : ecm_notify_csc;
+  notify.ecm_buf.header.wIndex = _netd_itf.itf_num;
+  netd_report((uint8_t *)&notify.ecm_buf, (nc) ? sizeof(notify.ecm_buf.header) : sizeof(notify.ecm_buf));
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  if ( stage == CONTROL_STAGE_SETUP )
+  {
+    switch ( request->bmRequestType_bit.type )
+    {
+      case TUSB_REQ_TYPE_STANDARD:
+        switch ( request->bRequest )
+        {
+          case TUSB_REQ_GET_INTERFACE:
+          {
+            uint8_t const req_itfnum = (uint8_t) request->wIndex;
+            TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum);
+
+            tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1);
+          }
+          break;
+
+          case TUSB_REQ_SET_INTERFACE:
+          {
+            uint8_t const req_itfnum = (uint8_t) request->wIndex;
+            uint8_t const req_alt    = (uint8_t) request->wValue;
+
+            // Only valid for Data Interface with Alternate is either 0 or 1
+            TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2);
+
+            // ACM-ECM only: qequest to enable/disable network activities
+            TU_VERIFY(_netd_itf.ecm_mode);
+
+            _netd_itf.itf_data_alt = req_alt;
+
+            if ( _netd_itf.itf_data_alt )
+            {
+              // TODO since we don't actually close endpoint
+              // hack here to not re-open it
+              if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 )
+              {
+                TU_ASSERT(_netd_itf.ecm_desc_epdata);
+                TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) );
+
+                // TODO should be merge with RNDIS's after endpoint opened
+                // Also should have opposite callback for application to disable network !!
+                tud_network_init_cb();
+                can_xmit = true; // we are ready to transmit a packet
+                tud_network_recv_renew(); // prepare for incoming packets
+              }
+            }else
+            {
+              // TODO close the endpoint pair
+              // For now pretend that we did, this should have no harm since host won't try to
+              // communicate with the endpoints again
+              // _netd_itf.ep_in = _netd_itf.ep_out = 0
+            }
+
+            tud_control_status(rhport, request);
+          }
+          break;
+
+          // unsupported request
+          default: return false;
+        }
+      break;
+
+      case TUSB_REQ_TYPE_CLASS:
+        TU_VERIFY (_netd_itf.itf_num == request->wIndex);
+
+        if (_netd_itf.ecm_mode)
+        {
+          /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */
+          if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest)
+          {
+            tud_control_xfer(rhport, request, NULL, 0);
+            ecm_report(true);
+          }
+        }
+        else
+        {
+          if (request->bmRequestType_bit.direction == TUSB_DIR_IN)
+          {
+            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);
+          }
+          else
+          {
+            tud_control_xfer(rhport, request, notify.rndis_buf, sizeof(notify.rndis_buf));
+          }
+        }
+      break;
+
+      // unsupported request
+      default: return false;
+    }
+  }
+  else if ( stage == CONTROL_STAGE_DATA )
+  {
+    // Handle RNDIS class control OUT only
+    if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
+        request->bmRequestType_bit.direction == TUSB_DIR_OUT   &&
+        _netd_itf.itf_num == request->wIndex)
+    {
+      if ( !_netd_itf.ecm_mode )
+      {
+        rndis_class_set_handler(notify.rndis_buf, request->wLength);
+      }
+    }
+  }
+
+  return true;
+}
+
+static void handle_incoming_packet(uint32_t len)
+{
+  uint8_t *pnt = received;
+  uint32_t size = 0;
+
+  if (_netd_itf.ecm_mode)
+  {
+    size = len;
+  }
+  else
+  {
+    rndis_data_packet_t *r = (rndis_data_packet_t *) ((void*) pnt);
+    if (len >= sizeof(rndis_data_packet_t))
+      if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len))
+        if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len)
+        {
+          pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)];
+          size = r->DataLength;
+        }
+  }
+
+  if (!tud_network_recv_cb(pnt, size))
+  {
+    /* if a buffer was never handled by user code, we must renew on the user's behalf */
+    tud_network_recv_renew();
+  }
+}
+
+bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) rhport;
+  (void) result;
+
+  /* new packet received */
+  if ( ep_addr == _netd_itf.ep_out )
+  {
+    handle_incoming_packet(xferred_bytes);
+  }
+
+  /* data transmission finished */
+  if ( ep_addr == _netd_itf.ep_in )
+  {
+    /* TinyUSB requires the class driver to implement ZLP (since ZLP usage is class-specific) */
+
+    if ( xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE)) )
+    {
+      do_in_xfer(NULL, 0); /* a ZLP is needed */
+    }
+    else
+    {
+      /* we're finally finished */
+      can_xmit = true;
+    }
+  }
+
+  if ( _netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif) )
+  {
+    if (sizeof(notify.ecm_buf.header) == xferred_bytes) ecm_report(false);
+  }
+
+  return true;
+}
+
+bool tud_network_can_xmit(uint16_t size)
+{
+  (void)size;
+
+  return can_xmit;
+}
+
+void tud_network_xmit(void *ref, uint16_t arg)
+{
+  uint8_t *data;
+  uint16_t len;
+
+  if (!can_xmit)
+    return;
+
+  len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN;
+  data = transmitted + len;
+
+  len += tud_network_xmit_cb(data, ref, arg);
+
+  if (!_netd_itf.ecm_mode)
+  {
+    rndis_data_packet_t *hdr = (rndis_data_packet_t *) ((void*) transmitted);
+    memset(hdr, 0, sizeof(rndis_data_packet_t));
+    hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
+    hdr->MessageLength = len;
+    hdr->DataOffset = sizeof(rndis_data_packet_t) - offsetof(rndis_data_packet_t, DataOffset);
+    hdr->DataLength = len - sizeof(rndis_data_packet_t);
+  }
+
+  do_in_xfer(transmitted, len);
+}
+
+#endif
diff --git a/src/class/net/ncm.h b/src/class/net/ncm.h
new file mode 100644
index 0000000..96ba11f
--- /dev/null
+++ b/src/class/net/ncm.h
@@ -0,0 +1,69 @@
+/*
+ * 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_NCM_H_
+#define _TUSB_NCM_H_
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// Table 4.3 Data Class Interface Protocol Codes
+typedef enum
+{
+  NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01
+} ncm_data_interface_protocol_code_t;
+
+
+// Table 6.2 Class-Specific Request Codes for Network Control Model subclass
+typedef enum
+{
+  NCM_SET_ETHERNET_MULTICAST_FILTERS               = 0x40,
+  NCM_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41,
+  NCM_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42,
+  NCM_SET_ETHERNET_PACKET_FILTER                   = 0x43,
+  NCM_GET_ETHERNET_STATISTIC                       = 0x44,
+  NCM_GET_NTB_PARAMETERS                           = 0x80,
+  NCM_GET_NET_ADDRESS                              = 0x81,
+  NCM_SET_NET_ADDRESS                              = 0x82,
+  NCM_GET_NTB_FORMAT                               = 0x83,
+  NCM_SET_NTB_FORMAT                               = 0x84,
+  NCM_GET_NTB_INPUT_SIZE                           = 0x85,
+  NCM_SET_NTB_INPUT_SIZE                           = 0x86,
+  NCM_GET_MAX_DATAGRAM_SIZE                        = 0x87,
+  NCM_SET_MAX_DATAGRAM_SIZE                        = 0x88,
+  NCM_GET_CRC_MODE                                 = 0x89,
+  NCM_SET_CRC_MODE                                 = 0x8A,
+} ncm_request_code_t;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c
new file mode 100644
index 0000000..3e131a8
--- /dev/null
+++ b/src/class/net/ncm_device.c
@@ -0,0 +1,510 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jacob Berg Potter
+ * Copyright (c) 2020 Peter Lawrence
+ * 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 ( TUSB_OPT_DEVICE_ENABLED && CFG_TUD_NCM )
+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+#include "net_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+#define NTH16_SIGNATURE      0x484D434E
+#define NDP16_SIGNATURE_NCM0 0x304D434E
+#define NDP16_SIGNATURE_NCM1 0x314D434E
+
+typedef struct TU_ATTR_PACKED
+{
+  uint16_t wLength;
+  uint16_t bmNtbFormatsSupported;
+  uint32_t dwNtbInMaxSize;
+  uint16_t wNdbInDivisor;
+  uint16_t wNdbInPayloadRemainder;
+  uint16_t wNdbInAlignment;
+  uint16_t wReserved;
+  uint32_t dwNtbOutMaxSize;
+  uint16_t wNdbOutDivisor;
+  uint16_t wNdbOutPayloadRemainder;
+  uint16_t wNdbOutAlignment;
+  uint16_t wNtbOutMaxDatagrams;
+} ntb_parameters_t;
+
+typedef struct TU_ATTR_PACKED
+{
+  uint32_t dwSignature;
+  uint16_t wHeaderLength;
+  uint16_t wSequence;
+  uint16_t wBlockLength;
+  uint16_t wNdpIndex;
+} nth16_t;
+
+typedef struct TU_ATTR_PACKED
+{
+  uint16_t wDatagramIndex;
+  uint16_t wDatagramLength;
+} ndp16_datagram_t;
+
+typedef struct TU_ATTR_PACKED
+{
+  uint32_t dwSignature;
+  uint16_t wLength;
+  uint16_t wNextNdpIndex;
+  ndp16_datagram_t datagram[];
+} ndp16_t;
+
+typedef union TU_ATTR_PACKED {
+  struct {
+    nth16_t nth;
+    ndp16_t ndp;
+  };
+  uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE];
+} transmit_ntb_t;
+
+struct ecm_notify_struct
+{
+  tusb_control_request_t header;
+  uint32_t downlink, uplink;
+};
+
+typedef struct
+{
+  uint8_t itf_num;      // Index number of Management Interface, +1 for Data Interface
+  uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active
+
+  uint8_t ep_notif;
+  uint8_t ep_in;
+  uint8_t ep_out;
+
+  const ndp16_t *ndp;
+  uint8_t num_datagrams, current_datagram_index;
+
+  enum {
+    REPORT_SPEED,
+    REPORT_CONNECTED,
+    REPORT_DONE
+  } report_state;
+  bool report_pending;
+
+  uint8_t  current_ntb;           // Index in transmit_ntb[] that is currently being filled with datagrams
+  uint8_t  datagram_count;        // Number of datagrams in transmit_ntb[current_ntb]
+  uint16_t next_datagram_offset;  // Offset in transmit_ntb[current_ntb].data to place the next datagram
+  uint16_t ntb_in_size;           // Maximum size of transmitted (IN to host) NTBs; initially CFG_TUD_NCM_IN_NTB_MAX_SIZE
+  uint8_t  max_datagrams_per_ntb; // Maximum number of datagrams per NTB; initially CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB
+
+  uint16_t nth_sequence;          // Sequence number counter for transmitted NTBs
+
+  bool transferring;
+
+} ncm_interface_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static const ntb_parameters_t ntb_parameters = {
+    .wLength                 = sizeof(ntb_parameters_t),
+    .bmNtbFormatsSupported   = 0x01,
+    .dwNtbInMaxSize          = CFG_TUD_NCM_IN_NTB_MAX_SIZE,
+    .wNdbInDivisor           = 4,
+    .wNdbInPayloadRemainder  = 0,
+    .wNdbInAlignment         = CFG_TUD_NCM_ALIGNMENT,
+    .wReserved               = 0,
+    .dwNtbOutMaxSize         = CFG_TUD_NCM_OUT_NTB_MAX_SIZE,
+    .wNdbOutDivisor          = 4,
+    .wNdbOutPayloadRemainder = 0,
+    .wNdbOutAlignment        = CFG_TUD_NCM_ALIGNMENT,
+    .wNtbOutMaxDatagrams     = 0
+};
+
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static transmit_ntb_t transmit_ntb[2];
+
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE];
+
+static ncm_interface_t ncm_interface;
+
+/*
+ * Set up the NTB state in ncm_interface to be ready to add datagrams.
+ */
+static void ncm_prepare_for_tx(void) {
+  ncm_interface.datagram_count = 0;
+  // datagrams start after all the headers
+  ncm_interface.next_datagram_offset = sizeof(nth16_t) + sizeof(ndp16_t)
+      + ((CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1) * sizeof(ndp16_datagram_t));
+}
+
+/*
+ * If not already transmitting, start sending the current NTB to the host and swap buffers
+ * to start filling the other one with datagrams.
+ */
+static void ncm_start_tx(void) {
+  if (ncm_interface.transferring) {
+    return;
+  }
+
+  transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb];
+  size_t ntb_length = ncm_interface.next_datagram_offset;
+
+  // Fill in NTB header
+  ntb->nth.dwSignature = NTH16_SIGNATURE;
+  ntb->nth.wHeaderLength = sizeof(nth16_t);
+  ntb->nth.wSequence = ncm_interface.nth_sequence++;
+  ntb->nth.wBlockLength = ntb_length;
+  ntb->nth.wNdpIndex = sizeof(nth16_t);
+
+  // Fill in NDP16 header and terminator
+  ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0;
+  ntb->ndp.wLength = sizeof(ndp16_t) + (ncm_interface.datagram_count + 1) * sizeof(ndp16_datagram_t);
+  ntb->ndp.wNextNdpIndex = 0;
+  ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = 0;
+  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);
+  ncm_interface.transferring = true;
+
+  // Swap to the other NTB and clear it out
+  ncm_interface.current_ntb = 1 - ncm_interface.current_ntb;
+  ncm_prepare_for_tx();
+}
+
+static struct ecm_notify_struct ncm_notify_connected =
+{
+    .header = {
+        .bmRequestType_bit = {
+          .recipient = TUSB_REQ_RCPT_INTERFACE,
+          .type      = TUSB_REQ_TYPE_CLASS,
+          .direction = TUSB_DIR_IN
+        },
+        .bRequest      = CDC_NOTIF_NETWORK_CONNECTION,
+        .wValue        = 1 /* Connected */,
+        .wLength       = 0,
+    },
+};
+
+static struct ecm_notify_struct ncm_notify_speed_change =
+{
+    .header = {
+        .bmRequestType_bit = {
+          .recipient = TUSB_REQ_RCPT_INTERFACE,
+          .type      = TUSB_REQ_TYPE_CLASS,
+          .direction = TUSB_DIR_IN
+        },
+        .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE,
+        .wLength = 8,
+    },
+    .downlink = 10000000,
+    .uplink = 10000000,
+};
+
+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));
+    return;
+  }
+
+  const ndp16_t *ndp = ncm_interface.ndp;
+  const int i = ncm_interface.current_datagram_index;
+  ncm_interface.current_datagram_index++;
+  ncm_interface.num_datagrams--;
+
+  tud_network_recv_cb(receive_ntb + ndp->datagram[i].wDatagramIndex, ndp->datagram[i].wDatagramLength);
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+
+void netd_init(void)
+{
+  tu_memclr(&ncm_interface, sizeof(ncm_interface));
+  ncm_interface.ntb_in_size = CFG_TUD_NCM_IN_NTB_MAX_SIZE;
+  ncm_interface.max_datagrams_per_ntb = CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB;
+  ncm_prepare_for_tx();
+}
+
+void netd_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  netd_init();
+}
+
+uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
+{
+  // confirm interface hasn't already been allocated
+  TU_ASSERT(0 == ncm_interface.ep_notif, 0);
+
+  //------------- Management Interface -------------//
+  ncm_interface.itf_num = itf_desc->bInterfaceNumber;
+
+  uint16_t drv_len = sizeof(tusb_desc_interface_t);
+  uint8_t const * p_desc = tu_desc_next( itf_desc );
+
+  // Communication Functional Descriptors
+  while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
+  {
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  // notification endpoint (if any)
+  if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
+  {
+    TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 );
+
+    ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
+
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  //------------- Data Interface -------------//
+  // - CDC-NCM data interface has 2 alternate settings
+  //   - 0 : zero endpoints for inactive (default)
+  //   - 1 : IN & OUT endpoints for transfer of NTBs
+  TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0);
+
+  do
+  {
+    tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc;
+    TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0);
+
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  } while((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len));
+
+  // Pair of endpoints
+  TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0);
+
+  TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in) );
+
+  drv_len += 2*sizeof(tusb_desc_endpoint_t);
+
+  return drv_len;
+}
+
+static void ncm_report(void)
+{
+  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));
+    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));
+    ncm_interface.report_state = REPORT_DONE;
+    ncm_interface.report_pending = true;
+  }
+}
+
+TU_ATTR_WEAK void tud_network_link_state_cb(bool state)
+{
+  (void)state;
+}
+
+// Handle class control request
+// return false to stall control endpoint (e.g unsupported request)
+bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  if ( stage != CONTROL_STAGE_SETUP ) return true;
+
+  switch ( request->bmRequestType_bit.type )
+  {
+    case TUSB_REQ_TYPE_STANDARD:
+      switch ( request->bRequest )
+      {
+        case TUSB_REQ_GET_INTERFACE:
+        {
+          uint8_t const req_itfnum = (uint8_t) request->wIndex;
+          TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum);
+
+          tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1);
+        }
+          break;
+
+        case TUSB_REQ_SET_INTERFACE:
+        {
+          uint8_t const req_itfnum = (uint8_t) request->wIndex;
+          uint8_t const req_alt    = (uint8_t) request->wValue;
+
+          // Only valid for Data Interface with Alternate is either 0 or 1
+          TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum && req_alt < 2);
+
+          if (req_alt != ncm_interface.itf_data_alt) {
+            ncm_interface.itf_data_alt = req_alt;
+
+            if (ncm_interface.itf_data_alt) {
+              if (!usbd_edpt_busy(rhport, ncm_interface.ep_out)) {
+                tud_network_recv_renew(); // prepare for incoming datagrams
+              }
+              if (!ncm_interface.report_pending) {
+                ncm_report();
+              }
+            }
+
+            tud_network_link_state_cb(ncm_interface.itf_data_alt);
+          }
+
+          tud_control_status(rhport, request);
+        }
+          break;
+
+          // unsupported request
+        default: return false;
+      }
+      break;
+
+    case TUSB_REQ_TYPE_CLASS:
+      TU_VERIFY (ncm_interface.itf_num == request->wIndex);
+
+      if (NCM_GET_NTB_PARAMETERS == request->bRequest)
+      {
+        tud_control_xfer(rhport, request, (void*)&ntb_parameters, sizeof(ntb_parameters));
+      }
+
+      break;
+
+      // unsupported request
+    default: return false;
+  }
+
+  return true;
+}
+
+static void handle_incoming_datagram(uint32_t len)
+{
+  uint32_t size = len;
+
+  if (len == 0) {
+    return;
+  }
+
+  TU_ASSERT(size >= sizeof(nth16_t), );
+
+  const nth16_t *hdr = (const nth16_t *)receive_ntb;
+  TU_ASSERT(hdr->dwSignature == NTH16_SIGNATURE, );
+  TU_ASSERT(hdr->wNdpIndex >= sizeof(nth16_t) && (hdr->wNdpIndex + sizeof(ndp16_t)) <= len, );
+
+  const ndp16_t *ndp = (const ndp16_t *)(receive_ntb + hdr->wNdpIndex);
+  TU_ASSERT(ndp->dwSignature == NDP16_SIGNATURE_NCM0 || ndp->dwSignature == NDP16_SIGNATURE_NCM1, );
+  TU_ASSERT(hdr->wNdpIndex + ndp->wLength <= len, );
+
+  int num_datagrams = (ndp->wLength - 12) / 4;
+  ncm_interface.current_datagram_index = 0;
+  ncm_interface.num_datagrams = 0;
+  ncm_interface.ndp = ndp;
+  for (int i = 0; i < num_datagrams && ndp->datagram[i].wDatagramIndex && ndp->datagram[i].wDatagramLength; i++)
+  {
+    ncm_interface.num_datagrams++;
+  }
+  
+  tud_network_recv_renew();
+}
+
+bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) rhport;
+  (void) result;
+
+  /* new datagram receive_ntb */
+  if (ep_addr == ncm_interface.ep_out )
+  {
+    handle_incoming_datagram(xferred_bytes);
+  }
+
+  /* data transmission finished */
+  if (ep_addr == ncm_interface.ep_in )
+  {
+    if (ncm_interface.transferring) {
+      ncm_interface.transferring = false;
+    }
+
+    // If there are datagrams queued up that we tried to send while this NTB was being emitted, send them now
+    if (ncm_interface.datagram_count && ncm_interface.itf_data_alt == 1) {
+      ncm_start_tx();
+    }
+  }
+
+  if (ep_addr == ncm_interface.ep_notif )
+  {
+    ncm_interface.report_pending = false;
+    ncm_report();
+  }
+
+  return true;
+}
+
+// poll network driver for its ability to accept another packet to transmit
+bool tud_network_can_xmit(uint16_t size)
+{
+  TU_VERIFY(ncm_interface.itf_data_alt == 1);
+
+  if (ncm_interface.datagram_count >= ncm_interface.max_datagrams_per_ntb) {
+    TU_LOG2("NTB full [by count]\r\n");
+    return false;
+  }
+
+  size_t next_datagram_offset = ncm_interface.next_datagram_offset;
+  if (next_datagram_offset + size > ncm_interface.ntb_in_size) {
+    TU_LOG2("ntb full [by size]\r\n");
+    return false;
+  }
+
+  return true;
+}
+
+void tud_network_xmit(void *ref, uint16_t arg)
+{
+  transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb];
+  size_t next_datagram_offset = ncm_interface.next_datagram_offset;
+
+  uint16_t size = tud_network_xmit_cb(ntb->data + next_datagram_offset, ref, arg);
+
+  ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = ncm_interface.next_datagram_offset;
+  ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = size;
+
+  ncm_interface.datagram_count++;
+  next_datagram_offset += size;
+
+  // round up so the next datagram is aligned correctly
+  next_datagram_offset += (CFG_TUD_NCM_ALIGNMENT - 1);
+  next_datagram_offset -= (next_datagram_offset % CFG_TUD_NCM_ALIGNMENT);
+
+  ncm_interface.next_datagram_offset = next_datagram_offset;
+
+  ncm_start_tx();
+}
+
+#endif
diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h
new file mode 100644
index 0000000..6e29446
--- /dev/null
+++ b/src/class/net/net_device.h
@@ -0,0 +1,118 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Peter Lawrence
+ * 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_NET_DEVICE_H_
+#define _TUSB_NET_DEVICE_H_
+
+#include "class/cdc/cdc.h"
+
+#if CFG_TUD_ECM_RNDIS && CFG_TUD_NCM
+#error "Cannot enable both ECM_RNDIS and NCM network drivers"
+#endif
+
+#include "ncm.h"
+
+/* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */
+#define CFG_TUD_NET_ENDPOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
+/* Maximum Transmission Unit (in bytes) of the network, including Ethernet header */
+#ifndef CFG_TUD_NET_MTU
+#define CFG_TUD_NET_MTU           1514
+#endif
+
+#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE
+#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200
+#endif
+
+#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE
+#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200
+#endif
+
+#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB
+#define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8
+#endif
+
+#ifndef CFG_TUD_NCM_ALIGNMENT
+#define CFG_TUD_NCM_ALIGNMENT 4
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
+// indicate to network driver that client has finished with the packet provided to network_recv_cb()
+void tud_network_recv_renew(void);
+
+// poll network driver for its ability to accept another packet to transmit
+bool tud_network_can_xmit(uint16_t size);
+
+// if network_can_xmit() returns true, network_xmit() can be called once
+void tud_network_xmit(void *ref, uint16_t arg);
+
+//--------------------------------------------------------------------+
+// Application Callbacks (WEAK is optional)
+//--------------------------------------------------------------------+
+
+// client must provide this: return false if the packet buffer was not accepted
+bool tud_network_recv_cb(const uint8_t *src, uint16_t size);
+
+// client must provide this: copy from network stack packet pointer to dst
+uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg);
+
+//------------- ECM/RNDIS -------------//
+
+// client must provide this: initialize any network state back to the beginning
+void tud_network_init_cb(void);
+
+// client must provide this: 48-bit MAC address
+// TODO removed later since it is not part of tinyusb stack
+extern const uint8_t tud_network_mac_address[6];
+
+//------------- NCM -------------//
+
+// callback to client providing optional indication of internal state of network driver
+void tud_network_link_state_cb(bool state);
+
+//--------------------------------------------------------------------+
+// INTERNAL USBD-CLASS DRIVER API
+//--------------------------------------------------------------------+
+void     netd_init            (void);
+void     netd_reset           (uint8_t rhport);
+uint16_t netd_open            (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+bool     netd_xfer_cb         (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+void     netd_report          (uint8_t *buf, uint16_t len);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_NET_DEVICE_H_ */
diff --git a/src/class/usbtmc/usbtmc.h b/src/class/usbtmc/usbtmc.h
new file mode 100644
index 0000000..7d7005c
--- /dev/null
+++ b/src/class/usbtmc/usbtmc.h
@@ -0,0 +1,316 @@
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 N Conrad
+ *
+ * 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_USBTMC_H__
+#define _TUSB_USBTMC_H__
+
+#include "common/tusb_common.h"
+
+
+/* Implements USBTMC Revision 1.0, April 14, 2003
+
+ String descriptors must have a "LANGID=0x409"/US English string.
+ Characters must be 0x20 (' ') to 0x7E ('~') ASCII,
+   But MUST not contain: "/:?\*
+   Also must not have leading or trailing space (' ')
+ Device descriptor must state USB version 0x0200 or greater
+
+ If USB488DeviceCapabilites.D2 = 1 (SR1), then there must be a INT endpoint.
+*/
+
+#define USBTMC_VERSION 0x0100
+#define USBTMC_488_VERSION 0x0100
+
+typedef enum {
+  USBTMC_MSGID_DEV_DEP_MSG_OUT = 1u,
+  USBTMC_MSGID_DEV_DEP_MSG_IN = 2u,
+  USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT = 126u,
+  USBTMC_MSGID_VENDOR_SPECIFIC_IN = 127u,
+  USBTMC_MSGID_USB488_TRIGGER = 128u,
+} usbtmc_msgid_enum;
+
+/// \brief Message header (For BULK OUT and BULK IN); 4 bytes
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t MsgID              ; ///< Message type ID (usbtmc_msgid_enum)
+  uint8_t bTag    		       ; ///< Transfer ID 1<=bTag<=255
+  uint8_t bTagInverse        ; ///< Complement of the tag
+  uint8_t _reserved           ; ///< Must be 0x00
+} usbtmc_msg_header_t;
+
+typedef struct TU_ATTR_PACKED
+{
+  usbtmc_msg_header_t header;
+  uint8_t data[8];
+} usbtmc_msg_generic_t;
+
+/* Uses on the bulk-out endpoint: */
+// Next 8 bytes are message-specific
+typedef struct TU_ATTR_PACKED {
+	usbtmc_msg_header_t header ; ///< Header
+	uint32_t TransferSize      ; ///< Transfer size; LSB first
+	struct TU_ATTR_PACKED
+	{
+	  unsigned int EOM  : 1         ; ///< EOM set on last byte
+  } bmTransferAttributes;
+  uint8_t _reserved[3];
+} usbtmc_msg_request_dev_dep_out;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_out) == 12u, "struct wrong length");
+
+// Next 8 bytes are message-specific
+typedef struct TU_ATTR_PACKED
+{
+  usbtmc_msg_header_t header ; ///< Header
+  uint32_t TransferSize      ; ///< Transfer size; LSB first
+  struct TU_ATTR_PACKED
+  {
+    unsigned int TermCharEnabled  : 1 ; ///< "The Bulk-IN transfer must terminate on the specified TermChar."; CAPABILITIES must list TermChar
+  } bmTransferAttributes;
+  uint8_t TermChar;
+  uint8_t _reserved[2];
+} usbtmc_msg_request_dev_dep_in;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_in) == 12u, "struct wrong length");
+
+/* Bulk-in headers */
+
+typedef struct TU_ATTR_PACKED
+{
+  usbtmc_msg_header_t header;
+  uint32_t TransferSize;
+  struct TU_ATTR_PACKED
+  {
+    uint8_t EOM: 1;           ///< Last byte of transfer is the end of the message
+    uint8_t UsingTermChar: 1; ///< Support TermChar && Request.TermCharEnabled && last char in transfer is TermChar
+  } bmTransferAttributes;
+  uint8_t _reserved[3];
+} usbtmc_msg_dev_dep_msg_in_header_t;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_msg_dev_dep_msg_in_header_t) == 12u, "struct wrong length");
+
+/* Unsupported vendor things.... Are these ever used?*/
+
+typedef struct TU_ATTR_PACKED
+{
+  usbtmc_msg_header_t header ; ///< Header
+  uint32_t TransferSize      ; ///< Transfer size; LSB first
+  uint8_t _reserved[4];
+} usbtmc_msg_request_vendor_specific_out;
+
+
+TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_out) == 12u, "struct wrong length");
+
+typedef struct TU_ATTR_PACKED
+{
+  usbtmc_msg_header_t header ; ///< Header
+  uint32_t TransferSize      ; ///< Transfer size; LSB first
+  uint8_t _reserved[4];
+} usbtmc_msg_request_vendor_specific_in;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_in) == 12u, "struct wrong length");
+
+// Control request type should use tusb_control_request_t
+
+/*
+typedef struct TU_ATTR_PACKED {
+  struct {
+    unsigned int Recipient  : 5         ; ///< EOM set on last byte
+    unsigned int Type       : 2         ; ///< EOM set on last byte
+    unsigned int DirectionToHost  : 1   ; ///< 0 is OUT, 1 is IN
+  } bmRequestType;
+  uint8_t bRequest                 ; ///< If bmRequestType.Type = Class, see usmtmc_request_type_enum
+  uint16_t wValue                  ;
+  uint16_t wIndex                  ;
+  uint16_t wLength                 ; // Number of bytes in data stage
+} usbtmc_class_specific_control_req;
+
+*/
+// bulk-in protocol errors
+enum {
+  USBTMC_BULK_IN_ERR_INCOMPLETE_HEADER = 1u,
+  USBTMC_BULK_IN_ERR_UNSUPPORTED = 2u,
+  USBTMC_BULK_IN_ERR_BAD_PARAMETER = 3u,
+  USBTMC_BULK_IN_ERR_DATA_TOO_SHORT = 4u,
+  USBTMC_BULK_IN_ERR_DATA_TOO_LONG = 5u,
+};
+// bult-in halt errors
+enum {
+  USBTMC_BULK_IN_ERR = 1u, ///< receives a USBTMC command message that expects a response while a
+                           /// Bulk-IN transfer is in progress
+};
+
+typedef enum {
+  USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT      = 1u,
+  USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS  = 2u,
+  USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN       = 3u,
+  USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS   = 4u,
+  USBTMC_bREQUEST_INITIATE_CLEAR               = 5u,
+  USBTMC_bREQUEST_CHECK_CLEAR_STATUS           = 6u,
+  USBTMC_bREQUEST_GET_CAPABILITIES             = 7u,
+
+  USBTMC_bREQUEST_INDICATOR_PULSE               = 64u, // Optional
+
+  /****** USBTMC 488 *************/
+  USB488_bREQUEST_READ_STATUS_BYTE  = 128u,
+  USB488_bREQUEST_REN_CONTROL       = 160u,
+  USB488_bREQUEST_GO_TO_LOCAL       = 161u,
+  USB488_bREQUEST_LOCAL_LOCKOUT     = 162u,
+
+} usmtmc_request_type_enum;
+
+typedef enum {
+  USBTMC_STATUS_SUCCESS = 0x01,
+  USBTMC_STATUS_PENDING = 0x02,
+  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_enum;
+
+/************************************************************
+ * Control Responses
+ */
+
+typedef struct TU_ATTR_PACKED {
+  uint8_t USBTMC_status;                 ///< usbtmc_status_enum
+  uint8_t _reserved;
+  uint16_t bcdUSBTMC;                    ///< USBTMC_VERSION
+
+  struct TU_ATTR_PACKED
+  {
+    unsigned int listenOnly :1;
+    unsigned int talkOnly :1;
+    unsigned int supportsIndicatorPulse :1;
+  } bmIntfcCapabilities;
+  struct TU_ATTR_PACKED
+  {
+    unsigned int canEndBulkInOnTermChar :1;
+  } bmDevCapabilities;
+  uint8_t _reserved2[6];
+  uint8_t _reserved3[12];
+} usbtmc_response_capabilities_t;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_t) == 0x18, "struct wrong length");
+
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t USBTMC_status;
+  struct TU_ATTR_PACKED
+  {
+    unsigned int BulkInFifoBytes :1;
+  } bmClear;
+} usbtmc_get_clear_status_rsp_t;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length");
+
+// Used for both abort bulk IN and bulk OUT
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t USBTMC_status;
+  uint8_t bTag;
+} usbtmc_initiate_abort_rsp_t;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length");
+
+// Used for both check_abort_bulk_in_status and check_abort_bulk_out_status
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t USBTMC_status;
+  struct TU_ATTR_PACKED
+  {
+    unsigned int BulkInFifoBytes : 1; ///< Has queued data or a short packet that is queued
+  } bmAbortBulkIn;
+  uint8_t _reserved[2];               ///< Must be zero
+  uint32_t NBYTES_RXD_TXD;
+} usbtmc_check_abort_bulk_rsp_t;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_check_abort_bulk_rsp_t) == 8u, "struct wrong length");
+
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t USBTMC_status;                 ///< usbtmc_status_enum
+  uint8_t _reserved;
+  uint16_t bcdUSBTMC;                    ///< USBTMC_VERSION
+
+  struct TU_ATTR_PACKED
+  {
+    unsigned int listenOnly :1;
+    unsigned int talkOnly :1;
+    unsigned int supportsIndicatorPulse :1;
+  } bmIntfcCapabilities;
+
+  struct TU_ATTR_PACKED
+  {
+    unsigned int canEndBulkInOnTermChar :1;
+  } bmDevCapabilities;
+
+  uint8_t _reserved2[6];
+  uint16_t bcdUSB488;
+
+  struct TU_ATTR_PACKED
+  {
+    unsigned int is488_2 :1;
+    unsigned int supportsREN_GTL_LLO :1;
+    unsigned int supportsTrigger :1;
+  } bmIntfcCapabilities488;
+
+  struct TU_ATTR_PACKED
+  {
+    unsigned int SCPI :1;
+    unsigned int SR1 :1;
+    unsigned int RL1 :1;
+    unsigned int DT1 :1;
+  } bmDevCapabilities488;
+  uint8_t _reserved3[8];
+} usbtmc_response_capabilities_488_t;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_488_t) == 0x18, "struct wrong length");
+
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t USBTMC_status;
+  uint8_t bTag;
+  uint8_t statusByte;
+} usbtmc_read_stb_rsp_488_t;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length");
+
+typedef struct TU_ATTR_PACKED
+{
+  struct TU_ATTR_PACKED
+  {
+      unsigned int bTag : 7;
+      unsigned int one  : 1;
+  } bNotify1;
+  uint8_t StatusByte;
+} usbtmc_read_stb_interrupt_488_t;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_interrupt_488_t) == 2u, "struct wrong length");
+
+#endif
+
diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c
new file mode 100644
index 0000000..4bd1edf
--- /dev/null
+++ b/src/class/usbtmc/usbtmc_device.c
@@ -0,0 +1,856 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Nathan Conrad
+ *
+ * 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.
+ */
+
+/*
+ * This library is not fully reentrant, though it is reentrant from the view
+ * of either the application layer or the USB stack. Due to its locking,
+ * it is not safe to call its functions from interrupts.
+ *
+ * The one exception is that its functions may not be called from the application
+ * until the USB stack is initialized. This should not be a problem since the
+ * device shouldn't be sending messages until it receives a request from the
+ * host.
+ */
+
+
+/*
+ * In the case of single-CPU "no OS", this task is never preempted other than by
+ * interrupts, and the USBTMC code isn't called by interrupts, so all is OK. For "no OS",
+ * the mutex structure's main effect is to disable the USB interrupts.
+ * With an OS, this class driver uses the OSAL to perform locking. The code uses a single lock
+ * and does not call outside of this class with a lock held, so deadlocks won't happen.
+ */
+
+//Limitations:
+// "vendor-specific" commands are not handled.
+// Dealing with "termchar" must be handled by the application layer,
+//    though additional error checking is does in this module.
+// talkOnly and listenOnly are NOT supported. They're not permitted
+// in USB488, anyway.
+
+/* Supported:
+ *
+ * Notification pulse
+ * Trigger
+ * Read status byte (both by interrupt endpoint and control message)
+ *
+ */
+
+
+// TODO:
+// 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)
+
+
+#include "tusb_option.h"
+
+#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_USBTMC)
+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "usbtmc_device.h"
+
+#ifdef xDEBUG
+#include "uart_util.h"
+static char logMsg[150];
+#endif
+
+/*
+ * The state machine does not allow simultaneous reading and writing. This is
+ * consistent with USBTMC.
+ */
+
+typedef enum
+{
+  STATE_CLOSED,  // Endpoints have not yet been opened since USB reset
+  STATE_NAK,     // Bulk-out endpoint is in NAK state.
+  STATE_IDLE,    // Bulk-out endpoint is waiting for CMD.
+  STATE_RCV,     // Bulk-out is receiving DEV_DEP message
+  STATE_TX_REQUESTED,
+  STATE_TX_INITIATED,
+  STATE_TX_SHORTED,
+  STATE_CLEARING,
+  STATE_ABORTING_BULK_IN,
+  STATE_ABORTING_BULK_IN_SHORTED, // aborting, and short packet has been queued for transmission
+  STATE_ABORTING_BULK_IN_ABORTED, // aborting, and short packet has been transmitted
+  STATE_ABORTING_BULK_OUT,
+  STATE_NUM_STATES
+} usbtmcd_state_enum;
+
+#if (CFG_TUD_USBTMC_ENABLE_488)
+  typedef usbtmc_response_capabilities_488_t usbtmc_capabilities_specific_t;
+#else
+  typedef usbtmc_response_capabilities_t usbtmc_capabilities_specific_t;
+#endif
+
+
+typedef struct
+{
+  volatile usbtmcd_state_enum state;
+
+  uint8_t itf_id;
+  uint8_t rhport;
+  uint8_t ep_bulk_in;
+  uint8_t ep_bulk_out;
+  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];
+  // OUT buffer receives one packet at a time
+  CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_MAX_PACKET_SIZE];
+  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)
+
+  uint8_t lastBulkOutTag; // used for aborts (mostly)
+  uint8_t lastBulkInTag; // used for aborts (mostly)
+
+  uint8_t const * devInBuffer; // pointer to application-layer used for transmissions
+
+  usbtmc_capabilities_specific_t const * capabilities;
+} usbtmc_interface_state_t;
+
+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");
+
+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);
+
+static uint8_t termChar;
+static uint8_t termCharRequested = false;
+
+
+osal_mutex_def_t usbtmcLockBuffer;
+static osal_mutex_t usbtmcLock;
+
+// Our own private lock, mostly for the state variable.
+#define criticalEnter() do {osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0)
+#define criticalLeave() do {osal_mutex_unlock(usbtmcLock); } while (0)
+
+bool atomicChangeState(usbtmcd_state_enum expectedState, usbtmcd_state_enum newState)
+{
+  bool ret = true;
+  criticalEnter();
+  usbtmcd_state_enum oldState = usbtmc_state.state;
+  if (oldState == expectedState)
+  {
+    usbtmc_state.state = newState;
+  }
+  else
+  {
+    ret = false;
+  }
+  criticalLeave();
+  return ret;
+}
+
+// called from app
+// We keep a reference to the buffer, so it MUST not change until the app is
+// notified that the transfer is complete.
+// length of data is specified in the hdr.
+
+// We can't just send the whole thing at once because we need to concatanate the
+// header with the data.
+bool tud_usbtmc_transmit_dev_msg_data(
+    const void * data, size_t len,
+    bool endOfMessage,
+    bool usingTermChar)
+{
+  const unsigned int txBufLen = sizeof(usbtmc_state.ep_bulk_in_buf);
+
+#ifndef NDEBUG
+  TU_ASSERT(len > 0u);
+  TU_ASSERT(len <= usbtmc_state.transfer_size_remaining);
+  TU_ASSERT(usbtmc_state.transfer_size_sent == 0u);
+  if(usingTermChar)
+  {
+    TU_ASSERT(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar);
+    TU_ASSERT(termCharRequested);
+    TU_ASSERT(((uint8_t const*)data)[len-1u] == termChar);
+  }
+#endif
+
+  TU_VERIFY(usbtmc_state.state == STATE_TX_REQUESTED);
+  usbtmc_msg_dev_dep_msg_in_header_t *hdr = (usbtmc_msg_dev_dep_msg_in_header_t*)usbtmc_state.ep_bulk_in_buf;
+  tu_varclr(hdr);
+  hdr->header.MsgID = USBTMC_MSGID_DEV_DEP_MSG_IN;
+  hdr->header.bTag = usbtmc_state.lastBulkInTag;
+  hdr->header.bTagInverse = (uint8_t)~(usbtmc_state.lastBulkInTag);
+  hdr->TransferSize = len;
+  hdr->bmTransferAttributes.EOM = endOfMessage;
+  hdr->bmTransferAttributes.UsingTermChar = usingTermChar;
+
+  // Copy in the header
+  const size_t headerLen = sizeof(*hdr);
+  const size_t dataLen = ((headerLen + hdr->TransferSize) <= txBufLen) ?
+                            len : (txBufLen - headerLen);
+  const size_t packetLen = headerLen + dataLen;
+
+  memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + headerLen, data, dataLen);
+  usbtmc_state.transfer_size_remaining = len - dataLen;
+  usbtmc_state.transfer_size_sent = dataLen;
+  usbtmc_state.devInBuffer = (uint8_t const*) data + (dataLen);
+
+  bool stateChanged =
+      atomicChangeState(STATE_TX_REQUESTED, (packetLen >= txBufLen) ? STATE_TX_INITIATED : STATE_TX_SHORTED);
+  TU_VERIFY(stateChanged);
+  TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen));
+  return true;
+}
+
+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,);
+# endif
+    if(usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse)
+      TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL,);
+#endif
+
+    usbtmcLock = osal_mutex_create(&usbtmcLockBuffer);
+}
+
+uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
+{
+  (void)rhport;
+
+  uint16_t drv_len;
+  uint8_t const * p_desc;
+  uint8_t found_endpoints = 0;
+
+  TU_VERIFY(itf_desc->bInterfaceClass    == TUD_USBTMC_APP_CLASS   , 0);
+  TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_USBTMC_APP_SUBCLASS, 0);
+
+#ifndef NDEBUG
+  // Only 2 or 3 endpoints are allowed for USBTMC.
+  TU_ASSERT((itf_desc->bNumEndpoints == 2) || (itf_desc->bNumEndpoints ==3), 0);
+#endif
+
+  TU_ASSERT(usbtmc_state.state == STATE_CLOSED, 0);
+
+  // Interface
+  drv_len = 0u;
+  p_desc = (uint8_t const *) itf_desc;
+
+  usbtmc_state.itf_id = itf_desc->bInterfaceNumber;
+  usbtmc_state.rhport = rhport;
+
+  while (found_endpoints < itf_desc->bNumEndpoints && drv_len <= max_len)
+  {
+    if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
+    {
+      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);
+          if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN)
+          {
+            usbtmc_state.ep_bulk_in = ep_desc->bEndpointAddress;
+          } else {
+            usbtmc_state.ep_bulk_out = ep_desc->bEndpointAddress;
+          }
+
+          break;
+        case TUSB_XFER_INTERRUPT:
+#ifndef NDEBUG
+          TU_ASSERT(tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN, 0);
+          TU_ASSERT(usbtmc_state.ep_int_in == 0, 0);
+#endif
+          usbtmc_state.ep_int_in = ep_desc->bEndpointAddress;
+          break;
+        default:
+          TU_ASSERT(false, 0);
+      }
+      TU_ASSERT( usbd_edpt_open(rhport, ep_desc), 0);
+      found_endpoints++;
+    }
+
+    drv_len += tu_desc_len(p_desc);
+    p_desc   = tu_desc_next(p_desc);
+  }
+
+  // bulk endpoints are required, but interrupt IN is optional
+#ifndef NDEBUG
+  TU_ASSERT(usbtmc_state.ep_bulk_in  != 0, 0);
+  TU_ASSERT(usbtmc_state.ep_bulk_out != 0, 0);
+  if (itf_desc->bNumEndpoints == 2)
+  {
+    TU_ASSERT(usbtmc_state.ep_int_in == 0, 0);
+  }
+  else if (itf_desc->bNumEndpoints == 3)
+  {
+    TU_ASSERT(usbtmc_state.ep_int_in != 0, 0);
+  }
+#if (CFG_TUD_USBTMC_ENABLE_488)
+  if(usbtmc_state.capabilities->bmIntfcCapabilities488.is488_2 ||
+      usbtmc_state.capabilities->bmDevCapabilities488.SR1)
+  {
+    TU_ASSERT(usbtmc_state.ep_int_in != 0, 0);
+  }
+#endif
+#endif
+  atomicChangeState(STATE_CLOSED, STATE_NAK);
+  tud_usbtmc_open_cb(itf_desc->iInterface);
+
+  return drv_len;
+}
+// Tell USBTMC class to set its bulk-in EP to ACK so that it can
+// receive USBTMC commands.
+// Returns false if it was already in an ACK state or is busy
+// processing a command (such as a clear). Returns true if it was
+// in the NAK state and successfully transitioned to the ACK wait
+// state.
+bool tud_usbtmc_start_bus_read()
+{
+  usbtmcd_state_enum oldState = usbtmc_state.state;
+  switch(oldState)
+  {
+  // These may transition to IDLE
+  case STATE_NAK:
+  case STATE_ABORTING_BULK_IN_ABORTED:
+    TU_VERIFY(atomicChangeState(oldState, STATE_IDLE));
+    break;
+  // When receiving, let it remain receiving
+  case STATE_RCV:
+    break;
+  default:
+    TU_VERIFY(false);
+  }
+  TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, 64));
+  return true;
+}
+
+void usbtmcd_reset_cb(uint8_t rhport)
+{
+  (void)rhport;
+  usbtmc_capabilities_specific_t const * capabilities = tud_usbtmc_get_capabilities_cb();
+
+  criticalEnter();
+  tu_varclr(&usbtmc_state);
+  usbtmc_state.capabilities = capabilities;
+  usbtmc_state.itf_id = 0xFFu;
+  criticalLeave();
+}
+
+static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len)
+{
+  (void)rhport;
+  // return true upon failure, as we can assume error is being handled elsewhere.
+  TU_VERIFY(atomicChangeState(STATE_IDLE, STATE_RCV), true);
+  usbtmc_state.transfer_size_sent = 0u;
+
+  // must be a header, should have been confirmed before calling here.
+  usbtmc_msg_request_dev_dep_out *msg = (usbtmc_msg_request_dev_dep_out*)data;
+  usbtmc_state.transfer_size_remaining = msg->TransferSize;
+  TU_VERIFY(tud_usbtmc_msgBulkOut_start_cb(msg));
+
+  TU_VERIFY(handle_devMsgOut(rhport, (uint8_t*)data + sizeof(*msg), len - sizeof(*msg), len));
+  usbtmc_state.lastBulkOutTag = msg->header.bTag;
+  return true;
+}
+
+static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen)
+{
+  (void)rhport;
+  // 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);
+
+  // Packet is to be considered complete when we get enough data or at a short packet.
+  bool atEnd = false;
+  if(len >= usbtmc_state.transfer_size_remaining || shortPacket)
+  {
+    atEnd = true;
+    TU_VERIFY(atomicChangeState(STATE_RCV, STATE_NAK));
+  }
+
+  len = tu_min32(len, usbtmc_state.transfer_size_remaining);
+
+  usbtmc_state.transfer_size_remaining -= len;
+  usbtmc_state.transfer_size_sent += len;
+
+  // App may (should?) call the wait_for_bus() command at this point
+  if(!tud_usbtmc_msg_data_cb(data, len, atEnd))
+  {
+    // TODO: Go to an error state upon failure other than just stalling the EP?
+    return false;
+  }
+
+
+  return true;
+}
+
+static bool handle_devMsgIn(void *data, size_t len)
+{
+  TU_VERIFY(len == sizeof(usbtmc_msg_request_dev_dep_in));
+  usbtmc_msg_request_dev_dep_in *msg = (usbtmc_msg_request_dev_dep_in*)data;
+  bool stateChanged = atomicChangeState(STATE_IDLE, STATE_TX_REQUESTED);
+  TU_VERIFY(stateChanged);
+  usbtmc_state.lastBulkInTag = msg->header.bTag;
+  usbtmc_state.transfer_size_remaining = msg->TransferSize;
+  usbtmc_state.transfer_size_sent = 0u;
+
+  termCharRequested = msg->bmTransferAttributes.TermCharEnabled;
+  termChar = msg->TermChar;
+
+  if(termCharRequested)
+    TU_VERIFY(usbtmc_state.capabilities->bmDevCapabilities.canEndBulkInOnTermChar);
+
+  TU_VERIFY(tud_usbtmc_msgBulkIn_request_cb(msg));
+  return true;
+}
+
+bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  TU_VERIFY(result == XFER_RESULT_SUCCESS);
+  //uart_tx_str_sync("TMC XFER CB\r\n");
+  if(usbtmc_state.state == STATE_CLEARING) {
+    return true; /* I think we can ignore everything here */
+  }
+
+  if(ep_addr == usbtmc_state.ep_bulk_out)
+  {
+    usbtmc_msg_generic_t *msg = NULL;
+
+    switch(usbtmc_state.state)
+    {
+    case STATE_IDLE:
+      TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t));
+      msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf);
+      uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse);
+      TU_VERIFY(msg->header.bTag == invInvTag);
+      TU_VERIFY(msg->header.bTag != 0x00);
+
+      switch(msg->header.MsgID) {
+      case USBTMC_MSGID_DEV_DEP_MSG_OUT:
+        if(!handle_devMsgOutStart(rhport, msg, xferred_bytes))
+        {
+          usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
+          TU_VERIFY(false);
+        }
+        break;
+
+      case USBTMC_MSGID_DEV_DEP_MSG_IN:
+        TU_VERIFY(handle_devMsgIn(msg, xferred_bytes));
+        break;
+
+#if (CFG_TUD_USBTMC_ENABLE_488)
+      case USBTMC_MSGID_USB488_TRIGGER:
+        // Spec says we halt the EP if we didn't declare we support it.
+        TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger);
+        TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg));
+
+        break;
+#endif
+      case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT:
+      case USBTMC_MSGID_VENDOR_SPECIFIC_IN:
+      default:
+        usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
+        TU_VERIFY(false);
+        return false;
+      }
+      return true;
+
+    case STATE_RCV:
+      if(!handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes))
+      {
+        usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
+        TU_VERIFY(false);
+      }
+      return true;
+
+    case STATE_ABORTING_BULK_OUT:
+      TU_VERIFY(false);
+      return false; // Should be stalled by now, shouldn't have received a packet.
+
+    case STATE_TX_REQUESTED:
+    case STATE_TX_INITIATED:
+    case STATE_ABORTING_BULK_IN:
+    case STATE_ABORTING_BULK_IN_SHORTED:
+    case STATE_ABORTING_BULK_IN_ABORTED:
+    default:
+      TU_VERIFY(false);
+    }
+  }
+  else if(ep_addr == usbtmc_state.ep_bulk_in)
+  {
+    switch(usbtmc_state.state) {
+    case STATE_TX_SHORTED:
+      TU_VERIFY(atomicChangeState(STATE_TX_SHORTED, STATE_NAK));
+      TU_VERIFY(tud_usbtmc_msgBulkIn_complete_cb());
+      break;
+
+    case STATE_TX_INITIATED:
+      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,
+            (void*)(uintptr_t) usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf)));
+        usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf);
+        usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf);
+        usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf);
+      }
+      else // last packet
+      {
+        size_t packetLen = usbtmc_state.transfer_size_remaining;
+        memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining);
+          usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.transfer_size_remaining);
+        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 ))
+        {
+          usbtmc_state.state = STATE_TX_SHORTED;
+        }
+      }
+      return true;
+
+    case STATE_ABORTING_BULK_IN:
+      // need to send short packet  (ZLP?)
+      TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u));
+      usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED;
+      return true;
+
+    case STATE_ABORTING_BULK_IN_SHORTED:
+      /* Done. :)*/
+      usbtmc_state.state = STATE_ABORTING_BULK_IN_ABORTED;
+      return true;
+
+    default:
+      TU_ASSERT(false);
+      return false;
+    }
+  }
+  else if (ep_addr == usbtmc_state.ep_int_in) {
+    // Good?
+    return true;
+  }
+  return false;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  // nothing to do with DATA and ACK stage
+  if ( stage != CONTROL_STAGE_SETUP ) return true;
+
+  uint8_t tmcStatusCode = USBTMC_STATUS_FAILED;
+#if (CFG_TUD_USBTMC_ENABLE_488)
+  uint8_t bTag;
+#endif
+
+  if((request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) &&
+      (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT) &&
+      (request->bRequest == TUSB_REQ_CLEAR_FEATURE) &&
+      (request->wValue == TUSB_REQ_FEATURE_EDPT_HALT))
+  {
+    uint32_t ep_addr = (request->wIndex);
+
+    if(ep_addr == usbtmc_state.ep_bulk_out)
+    {
+      criticalEnter();
+      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)
+    {
+      tud_usbtmc_bulkIn_clearFeature_cb();
+    }
+    else
+    {
+      return false;
+    }
+    return true;
+  }
+
+  // Otherwise, we only handle class requests.
+  if(request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS)
+  {
+    return false;
+  }
+
+  // Verification that we own the interface is unneeded since it's been routed to us specifically.
+
+  switch(request->bRequest)
+  {
+  // USBTMC required requests
+  case USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT:
+  {
+    usbtmc_initiate_abort_rsp_t rsp = {
+        .bTag = usbtmc_state.lastBulkOutTag,
+    };
+    TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface
+    TU_VERIFY(request->wLength == sizeof(rsp));
+    TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out);
+
+    // wValue is the requested bTag to abort
+    if(usbtmc_state.state != STATE_RCV)
+    {
+      rsp.USBTMC_status = USBTMC_STATUS_FAILED;
+    }
+    else if(usbtmc_state.lastBulkOutTag == (request->wValue & 0x7Fu))
+    {
+      rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS;
+    }
+    else
+    {
+      rsp.USBTMC_status = USBTMC_STATUS_SUCCESS;
+      // Check if we've queued a short packet
+      criticalEnter();
+      usbtmc_state.state = STATE_ABORTING_BULK_OUT;
+      criticalLeave();
+      TU_VERIFY(tud_usbtmc_initiate_abort_bulk_out_cb(&(rsp.USBTMC_status)));
+      usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
+    }
+    TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp)));
+    return true;
+  }
+
+  case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS:
+  {
+    usbtmc_check_abort_bulk_rsp_t rsp = {
+        .USBTMC_status = USBTMC_STATUS_SUCCESS,
+        .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent
+    };
+    TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP
+    TU_VERIFY(request->wLength == sizeof(rsp));
+    TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out);
+    TU_VERIFY(tud_usbtmc_check_abort_bulk_out_cb(&rsp));
+    TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp)));
+    return true;
+  }
+
+  case USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN:
+  {
+    usbtmc_initiate_abort_rsp_t rsp = {
+        .bTag = usbtmc_state.lastBulkInTag,
+    };
+    TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface
+    TU_VERIFY(request->wLength == sizeof(rsp));
+    TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_in);
+    // wValue is the requested bTag to abort
+    if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED) &&
+        usbtmc_state.lastBulkInTag == (request->wValue & 0x7Fu))
+    {
+      rsp.USBTMC_status = USBTMC_STATUS_SUCCESS;
+    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) ?
+              STATE_ABORTING_BULK_IN : STATE_ABORTING_BULK_IN_SHORTED;
+      criticalLeave();
+      if(usbtmc_state.transfer_size_sent  == 0)
+      {
+        // Send short packet, nothing is in the buffer yet
+        TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u));
+        usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED;
+      }
+      TU_VERIFY(tud_usbtmc_initiate_abort_bulk_in_cb(&(rsp.USBTMC_status)));
+    }
+    else if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED))
+    { // FIXME: Unsure how to check  if the OUT endpoint fifo is non-empty....
+      rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS;
+    }
+    else
+    {
+      rsp.USBTMC_status = USBTMC_STATUS_FAILED;
+    }
+    TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp)));
+    return true;
+  }
+
+  case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS:
+  {
+    TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP
+    TU_VERIFY(request->wLength == 8u);
+
+    usbtmc_check_abort_bulk_rsp_t rsp =
+    {
+        .USBTMC_status = USBTMC_STATUS_FAILED,
+        .bmAbortBulkIn =
+        {
+            .BulkInFifoBytes = (usbtmc_state.state != STATE_ABORTING_BULK_IN_ABORTED)
+        },
+        .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent,
+    };
+    TU_VERIFY(tud_usbtmc_check_abort_bulk_in_cb(&rsp));
+    criticalEnter();
+    switch(usbtmc_state.state)
+    {
+    case STATE_ABORTING_BULK_IN_ABORTED:
+      rsp.USBTMC_status = USBTMC_STATUS_SUCCESS;
+      usbtmc_state.state = STATE_IDLE;
+      break;
+    case STATE_ABORTING_BULK_IN:
+    case STATE_ABORTING_BULK_OUT:
+      rsp.USBTMC_status = USBTMC_STATUS_PENDING;
+      break;
+    default:
+      break;
+    }
+    criticalLeave();
+    TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp)));
+
+    return true;
+  }
+
+  case USBTMC_bREQUEST_INITIATE_CLEAR:
+    {
+      TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
+      TU_VERIFY(request->wLength == sizeof(tmcStatusCode));
+      // After receiving an INITIATE_CLEAR request, the device must Halt the Bulk-OUT endpoint, queue the
+      // control endpoint response shown in Table 31, and clear all input buffers and output buffers.
+      usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
+      usbtmc_state.transfer_size_remaining = 0;
+      criticalEnter();
+      usbtmc_state.state = STATE_CLEARING;
+      criticalLeave();
+      TU_VERIFY(tud_usbtmc_initiate_clear_cb(&tmcStatusCode));
+      TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode,sizeof(tmcStatusCode)));
+      return true;
+    }
+
+  case USBTMC_bREQUEST_CHECK_CLEAR_STATUS:
+    {
+      TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
+      usbtmc_get_clear_status_rsp_t clearStatusRsp = {0};
+      TU_VERIFY(request->wLength == sizeof(clearStatusRsp));
+
+      if(usbd_edpt_busy(rhport, usbtmc_state.ep_bulk_in))
+      {
+        // Stuff stuck in TX buffer?
+        clearStatusRsp.bmClear.BulkInFifoBytes = 1;
+        clearStatusRsp.USBTMC_status = USBTMC_STATUS_PENDING;
+      }
+      else
+      {
+        // Let app check if it's clear
+        TU_VERIFY(tud_usbtmc_check_clear_cb(&clearStatusRsp));
+      }
+      if(clearStatusRsp.USBTMC_status == USBTMC_STATUS_SUCCESS)
+      {
+        criticalEnter();
+        usbtmc_state.state = STATE_IDLE;
+        criticalLeave();
+      }
+      TU_VERIFY(tud_control_xfer(rhport, request, (void*)&clearStatusRsp,sizeof(clearStatusRsp)));
+      return true;
+    }
+
+  case USBTMC_bREQUEST_GET_CAPABILITIES:
+    {
+      TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
+      TU_VERIFY(request->wLength == sizeof(*(usbtmc_state.capabilities)));
+      TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) usbtmc_state.capabilities, sizeof(*usbtmc_state.capabilities)));
+      return true;
+    }
+  // USBTMC Optional Requests
+
+  case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional
+    {
+      TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
+      TU_VERIFY(request->wLength == sizeof(tmcStatusCode));
+      TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse);
+      TU_VERIFY(tud_usbtmc_indicator_pulse_cb(request, &tmcStatusCode));
+      TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode, sizeof(tmcStatusCode)));
+      return true;
+    }
+#if (CFG_TUD_USBTMC_ENABLE_488)
+
+    // USB488 required requests
+  case USB488_bREQUEST_READ_STATUS_BYTE:
+    {
+      usbtmc_read_stb_rsp_488_t rsp;
+      TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
+      TU_VERIFY(request->wLength == sizeof(rsp)); // in,class,interface
+
+      bTag = request->wValue & 0x7F;
+      TU_VERIFY(request->bmRequestType == 0xA1);
+      TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero
+      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 =
+        {
+          .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));
+      }
+      else
+      {
+        rsp.statusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status));
+      }
+      TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp, sizeof(rsp)));
+      return true;
+    }
+    // USB488 optional requests
+  case USB488_bREQUEST_REN_CONTROL:
+  case USB488_bREQUEST_GO_TO_LOCAL:
+  case USB488_bREQUEST_LOCAL_LOCKOUT:
+    {
+      TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
+      TU_VERIFY(false);
+      return false;
+    }
+#endif
+
+  default:
+    TU_VERIFY(false);
+    return false;
+  }
+  TU_VERIFY(false);
+}
+
+#endif /* CFG_TUD_TSMC */
diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h
new file mode 100644
index 0000000..0549a15
--- /dev/null
+++ b/src/class/usbtmc/usbtmc_device.h
@@ -0,0 +1,116 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 N Conrad
+ *
+ * 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 CLASS_USBTMC_USBTMC_DEVICE_H_
+#define CLASS_USBTMC_USBTMC_DEVICE_H_
+
+#include "usbtmc.h"
+
+// Enable 488 mode by default
+#if !defined(CFG_TUD_USBTMC_ENABLE_488)
+#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
+ */
+
+// In order to proceed, app must call call tud_usbtmc_start_bus_read(rhport) during or soon after:
+// * tud_usbtmc_open_cb
+// * tud_usbtmc_msg_data_cb
+// * tud_usbtmc_msgBulkIn_complete_cb
+// * tud_usbtmc_msg_trigger_cb
+// * (successful) tud_usbtmc_check_abort_bulk_out_cb
+// * (successful) tud_usbtmc_check_abort_bulk_in_cb
+// * (successful) tud_usmtmc_bulkOut_clearFeature_cb
+
+#if (CFG_TUD_USBTMC_ENABLE_488)
+usbtmc_response_capabilities_488_t const * tud_usbtmc_get_capabilities_cb(void);
+#else
+usbtmc_response_capabilities_t const * tud_usbtmc_get_capabilities_cb(void);
+#endif
+
+void tud_usbtmc_open_cb(uint8_t interface_id);
+
+bool tud_usbtmc_msgBulkOut_start_cb(usbtmc_msg_request_dev_dep_out const * msgHeader);
+// transfer_complete does not imply that a message is complete.
+bool tud_usbtmc_msg_data_cb( void *data, size_t len, bool transfer_complete);
+void tud_usbtmc_bulkOut_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer
+
+bool tud_usbtmc_msgBulkIn_request_cb(usbtmc_msg_request_dev_dep_in const * request);
+bool tud_usbtmc_msgBulkIn_complete_cb(void);
+void tud_usbtmc_bulkIn_clearFeature_cb(void); // Notice to clear and abort the pending BULK out transfer
+
+bool tud_usbtmc_initiate_abort_bulk_in_cb(uint8_t *tmcResult);
+bool tud_usbtmc_initiate_abort_bulk_out_cb(uint8_t *tmcResult);
+bool tud_usbtmc_initiate_clear_cb(uint8_t *tmcResult);
+
+bool tud_usbtmc_check_abort_bulk_in_cb(usbtmc_check_abort_bulk_rsp_t *rsp);
+bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp);
+bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp);
+
+// Indicator pulse should be 0.5 to 1.0 seconds long
+TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult);
+
+#if (CFG_TUD_USBTMC_ENABLE_488)
+uint8_t tud_usbtmc_get_stb_cb(uint8_t *tmcResult);
+TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg);
+//TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb();
+#endif
+
+/*******************************************
+ * Called from app
+ *
+ * We keep a reference to the buffer, so it MUST not change until the app is
+ * notified that the transfer is complete.
+ ******************************************/
+
+bool tud_usbtmc_transmit_dev_msg_data(
+    const void * data, size_t len,
+    bool endOfMessage, bool usingTermChar);
+
+bool tud_usbtmc_start_bus_read(void);
+
+
+/* "callbacks" from USB device core */
+
+uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+void     usbtmcd_reset_cb(uint8_t rhport);
+bool     usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+bool     usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+void     usbtmcd_init_cb(void);
+
+/************************************************************
+ * USBTMC Descriptor Templates
+ *************************************************************/
+
+
+#endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */
diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c
new file mode 100644
index 0000000..8a4ca1d
--- /dev/null
+++ b/src/class/vendor/vendor_device.c
@@ -0,0 +1,257 @@
+/*
+ * 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 (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_VENDOR)
+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "vendor_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_in;
+  uint8_t ep_out;
+
+  /*------------- From this point, data is not cleared by bus reset -------------*/
+  tu_fifo_t rx_ff;
+  tu_fifo_t tx_ff;
+
+  uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
+  uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
+
+#if CFG_FIFO_MUTEX
+  osal_mutex_def_t rx_ff_mutex;
+  osal_mutex_def_t tx_ff_mutex;
+#endif
+
+  // Endpoint Transfer buffer
+  CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE];
+  CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE];
+} vendord_interface_t;
+
+CFG_TUSB_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
+
+#define ITF_MEM_RESET_SIZE   offsetof(vendord_interface_t, rx_ff)
+
+
+bool tud_vendor_n_mounted (uint8_t itf)
+{
+  return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out;
+}
+
+uint32_t tud_vendor_n_available (uint8_t itf)
+{
+  return tu_fifo_count(&_vendord_itf[itf].rx_ff);
+}
+
+bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8)
+{
+  return tu_fifo_peek(&_vendord_itf[itf].rx_ff, u8);
+}
+
+//--------------------------------------------------------------------+
+// Read API
+//--------------------------------------------------------------------+
+static void _prep_out_transaction (vendord_interface_t* p_itf)
+{
+  // skip if previous transfer not complete
+  if ( usbd_edpt_busy(TUD_OPT_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);
+  }
+}
+
+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);
+  _prep_out_transaction(p_itf);
+  return num_read;
+}
+
+void tud_vendor_n_read_flush (uint8_t itf)
+{
+  vendord_interface_t* p_itf = &_vendord_itf[itf];
+  tu_fifo_clear(&p_itf->rx_ff);
+  _prep_out_transaction(p_itf);
+}
+
+//--------------------------------------------------------------------+
+// Write API
+//--------------------------------------------------------------------+
+static bool maybe_transmit(vendord_interface_t* p_itf)
+{
+  // skip if previous transfer not complete
+  TU_VERIFY( !usbd_edpt_busy(TUD_OPT_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) );
+  }
+  return true;
+}
+
+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);
+  return ret;
+}
+
+uint32_t tud_vendor_n_write_available (uint8_t itf)
+{
+  return tu_fifo_remaining(&_vendord_itf[itf].tx_ff);
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void vendord_init(void)
+{
+  tu_memclr(_vendord_itf, sizeof(_vendord_itf));
+
+  for(uint8_t i=0; i<CFG_TUD_VENDOR; i++)
+  {
+    vendord_interface_t* p_itf = &_vendord_itf[i];
+
+    // config fifo
+    tu_fifo_config(&p_itf->rx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false);
+    tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false);
+
+#if CFG_FIFO_MUTEX
+    tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex));
+    tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL);
+#endif
+  }
+}
+
+void vendord_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  for(uint8_t i=0; i<CFG_TUD_VENDOR; i++)
+  {
+    vendord_interface_t* p_itf = &_vendord_itf[i];
+
+    tu_memclr(p_itf, ITF_MEM_RESET_SIZE);
+    tu_fifo_clear(&p_itf->rx_ff);
+    tu_fifo_clear(&p_itf->tx_ff);
+  }
+}
+
+uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len)
+{
+  TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0);
+
+  uint8_t const * p_desc = tu_desc_next(desc_itf);
+  uint8_t const * desc_end = p_desc + max_len;
+
+  // Find available interface
+  vendord_interface_t* p_vendor = NULL;
+  for(uint8_t i=0; i<CFG_TUD_VENDOR; i++)
+  {
+    if ( _vendord_itf[i].ep_in == 0 && _vendord_itf[i].ep_out == 0 )
+    {
+      p_vendor = &_vendord_itf[i];
+      break;
+    }
+  }
+  TU_VERIFY(p_vendor, 0);
+
+  p_vendor->itf_num = desc_itf->bInterfaceNumber;
+  if (desc_itf->bNumEndpoints)
+  {
+    // skip non-endpoint descriptors
+    while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) )
+    {
+      p_desc = tu_desc_next(p_desc);
+    }
+
+    // Open endpoint pair with usbd helper
+    TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_BULK, &p_vendor->ep_out, &p_vendor->ep_in), 0);
+
+    p_desc += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+
+    // Prepare for incoming data
+    if ( p_vendor->ep_out )
+    {
+      TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, sizeof(p_vendor->epout_buf)), 0);
+    }
+
+    if ( p_vendor->ep_in ) maybe_transmit(p_vendor);
+  }
+
+  return (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)
+{
+  (void) rhport;
+  (void) result;
+
+  uint8_t itf = 0;
+  vendord_interface_t* p_itf = _vendord_itf;
+
+  for ( ; ; itf++, p_itf++)
+  {
+    if (itf >= TU_ARRAY_SIZE(_vendord_itf)) return false;
+
+    if ( ( ep_addr == p_itf->ep_out ) || ( ep_addr == p_itf->ep_in ) ) break;
+  }
+
+  if ( ep_addr == p_itf->ep_out )
+  {
+    // Receive new data
+    tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, xferred_bytes);
+
+    // Invoked callback if any
+    if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf);
+
+    _prep_out_transaction(p_itf);
+  }
+  else if ( ep_addr == p_itf->ep_in )
+  {
+    // Send complete, try to send more if possible
+    maybe_transmit(p_itf);
+  }
+
+  return true;
+}
+
+#endif
diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h
new file mode 100644
index 0000000..d71c2a3
--- /dev/null
+++ b/src/class/vendor/vendor_device.h
@@ -0,0 +1,136 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_VENDOR_DEVICE_H_
+#define _TUSB_VENDOR_DEVICE_H_
+
+#include "common/tusb_common.h"
+
+#ifndef CFG_TUD_VENDOR_EPSIZE
+#define CFG_TUD_VENDOR_EPSIZE     64
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Application API (Multiple Interfaces)
+//--------------------------------------------------------------------+
+bool     tud_vendor_n_mounted         (uint8_t itf);
+
+uint32_t tud_vendor_n_available       (uint8_t itf);
+uint32_t tud_vendor_n_read            (uint8_t itf, void* buffer, uint32_t bufsize);
+bool     tud_vendor_n_peek            (uint8_t itf, uint8_t* ui8);
+void     tud_vendor_n_read_flush      (uint8_t itf);
+
+uint32_t tud_vendor_n_write           (uint8_t itf, void const* buffer, uint32_t bufsize);
+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);
+
+//--------------------------------------------------------------------+
+// Application API (Single Port)
+//--------------------------------------------------------------------+
+static inline bool     tud_vendor_mounted         (void);
+static inline uint32_t tud_vendor_available       (void);
+static inline uint32_t tud_vendor_read            (void* buffer, uint32_t bufsize);
+static inline bool     tud_vendor_peek            (uint8_t* ui8);
+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);
+
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+
+// Invoked when received new data
+TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf);
+
+//--------------------------------------------------------------------+
+// Inline Functions
+//--------------------------------------------------------------------+
+
+static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str)
+{
+  return tud_vendor_n_write(itf, str, strlen(str));
+}
+
+static inline bool tud_vendor_mounted (void)
+{
+  return tud_vendor_n_mounted(0);
+}
+
+static inline uint32_t tud_vendor_available (void)
+{
+  return tud_vendor_n_available(0);
+}
+
+static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize)
+{
+  return tud_vendor_n_read(0, buffer, bufsize);
+}
+
+static inline bool tud_vendor_peek (uint8_t* ui8)
+{
+  return tud_vendor_n_peek(0, ui8);
+}
+
+static inline void tud_vendor_read_flush(void)
+{
+    tud_vendor_n_read_flush(0);
+}
+
+static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize)
+{
+  return tud_vendor_n_write(0, buffer, bufsize);
+}
+
+static inline uint32_t tud_vendor_write_str (char const* str)
+{
+  return tud_vendor_n_write_str(0, str);
+}
+
+static inline uint32_t tud_vendor_write_available (void)
+{
+  return tud_vendor_n_write_available(0);
+}
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void     vendord_init(void);
+void     vendord_reset(uint8_t rhport);
+uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_VENDOR_DEVICE_H_ */
diff --git a/src/class/vendor/vendor_host.c b/src/class/vendor/vendor_host.c
new file mode 100644
index 0000000..1e28e9a
--- /dev/null
+++ b/src/class/vendor/vendor_host.c
@@ -0,0 +1,146 @@
+/* 
+ * 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 (TUSB_OPT_HOST_ENABLED && CFG_TUH_VENDOR)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "host/usbh.h"
+#include "vendor_host.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+custom_interface_info_t custom_interface[CFG_TUH_DEVICE_MAX];
+
+static tusb_error_t cush_validate_paras(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length)
+{
+  if ( !tusbh_custom_is_mounted(dev_addr, vendor_id, product_id) )
+  {
+    return TUSB_ERROR_DEVICE_NOT_READY;
+  }
+
+  TU_ASSERT( p_buffer != NULL && length != 0, TUSB_ERROR_INVALID_PARA);
+
+  return TUSB_ERROR_NONE;
+}
+//--------------------------------------------------------------------+
+// APPLICATION API (need to check parameters)
+//--------------------------------------------------------------------+
+tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length)
+{
+  TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_buffer, length) );
+
+  if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_in) )
+  {
+    return TUSB_ERROR_INTERFACE_IS_BUSY;
+  }
+
+  (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_in, p_buffer, length);
+
+  return TUSB_ERROR_NONE;
+}
+
+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)
+{
+  TU_ASSERT_ERR( cush_validate_paras(dev_addr, vendor_id, product_id, p_data, length) );
+
+  if ( !hcd_pipe_is_idle(custom_interface[dev_addr-1].pipe_out) )
+  {
+    return TUSB_ERROR_INTERFACE_IS_BUSY;
+  }
+
+  (void) usbh_edpt_xfer( custom_interface[dev_addr-1].pipe_out, p_data, length);
+
+  return TUSB_ERROR_NONE;
+}
+
+//--------------------------------------------------------------------+
+// USBH-CLASS API
+//--------------------------------------------------------------------+
+void cush_init(void)
+{
+  tu_memclr(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUH_DEVICE_MAX);
+}
+
+tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length)
+{
+  // FIXME quick hack to test lpc1k custom class with 2 bulk endpoints
+  uint8_t const *p_desc = (uint8_t const *) p_interface_desc;
+  p_desc = tu_desc_next(p_desc);
+
+  //------------- Bulk Endpoints Descriptor -------------//
+  for(uint32_t i=0; i<2; i++)
+  {
+    tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc;
+    TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_INVALID_PARA);
+
+    pipe_handle_t * p_pipe_hdl =  ( p_endpoint->bEndpointAddress &  TUSB_DIR_IN_MASK ) ?
+                         &custom_interface[dev_addr-1].pipe_in : &custom_interface[dev_addr-1].pipe_out;
+    *p_pipe_hdl = usbh_edpt_open(dev_addr, p_endpoint, TUSB_CLASS_VENDOR_SPECIFIC);
+    TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED );
+
+    p_desc = tu_desc_next(p_desc);
+  }
+
+  (*p_length) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
+  return TUSB_ERROR_NONE;
+}
+
+void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event)
+{
+
+}
+
+void cush_close(uint8_t dev_addr)
+{
+  tusb_error_t err1, err2;
+  custom_interface_info_t * p_interface = &custom_interface[dev_addr-1];
+
+  // TODO re-consider to check pipe valid before calling pipe_close
+  if( pipehandle_is_valid( p_interface->pipe_in ) )
+  {
+    err1 = hcd_pipe_close( p_interface->pipe_in );
+  }
+
+  if ( pipehandle_is_valid( p_interface->pipe_out ) )
+  {
+    err2 = hcd_pipe_close( p_interface->pipe_out );
+  }
+
+  tu_memclr(p_interface, sizeof(custom_interface_info_t));
+
+  TU_ASSERT(err1 == TUSB_ERROR_NONE && err2 == TUSB_ERROR_NONE, (void) 0 );
+}
+
+#endif
diff --git a/src/class/vendor/vendor_host.h b/src/class/vendor/vendor_host.h
new file mode 100644
index 0000000..07fa56c
--- /dev/null
+++ b/src/class/vendor/vendor_host.h
@@ -0,0 +1,67 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_VENDOR_HOST_H_
+#define _TUSB_VENDOR_HOST_H_
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef struct {
+  pipe_handle_t pipe_in;
+  pipe_handle_t pipe_out;
+}custom_interface_info_t;
+
+//--------------------------------------------------------------------+
+// USBH-CLASS DRIVER API
+//--------------------------------------------------------------------+
+static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id)
+{
+  (void) vendor_id; // TODO check this later
+  (void) product_id;
+//  return (tusbh_device_get_mounted_class_flag(dev_addr) & TU_BIT(TUSB_CLASS_MAPPED_INDEX_END-1) ) != 0;
+  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);
+
+//--------------------------------------------------------------------+
+// 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);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_VENDOR_HOST_H_ */
diff --git a/src/class/video/video.h b/src/class/video/video.h
new file mode 100644
index 0000000..8447465
--- /dev/null
+++ b/src/class/video/video.h
@@ -0,0 +1,480 @@
+/*
+ * 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.
+ */
+
+#ifndef TUSB_VIDEO_H_
+#define TUSB_VIDEO_H_
+
+#include "common/tusb_common.h"
+
+// Table 3-19 Color Matching Descriptor
+typedef enum {
+  VIDEO_COLOR_PRIMARIES_UNDEFINED = 0x00,
+  VIDEO_COLOR_PRIMARIES_BT709, // sRGB (default)
+  VIDEO_COLOR_PRIMARIES_BT470_2M,
+  VIDEO_COLOR_PRIMARIES_BT470_2BG,
+  VIDEO_COLOR_PRIMARIES_SMPTE170M,
+  VIDEO_COLOR_PRIMARIES_SMPTE240M,
+} video_color_primaries_t;
+
+// Table 3-19 Color Matching Descriptor
+typedef enum {
+  VIDEO_COLOR_XFER_CH_UNDEFINED = 0x00,
+  VIDEO_COLOR_XFER_CH_BT709, // default
+  VIDEO_COLOR_XFER_CH_BT470_2M,
+  VIDEO_COLOR_XFER_CH_BT470_2BG,
+  VIDEO_COLOR_XFER_CH_SMPTE170M,
+  VIDEO_COLOR_XFER_CH_SMPTE240M,
+  VIDEO_COLOR_XFER_CH_LINEAR,
+  VIDEO_COLOR_XFER_CH_SRGB,
+} video_color_transfer_characteristics_t;
+
+// Table 3-19 Color Matching Descriptor
+typedef enum {
+  VIDEO_COLOR_COEF_UNDEFINED = 0x00,
+  VIDEO_COLOR_COEF_BT709,
+  VIDEO_COLOR_COEF_FCC,
+  VIDEO_COLOR_COEF_BT470_2BG,
+  VIDEO_COLOR_COEF_SMPTE170M, // BT.601 default
+  VIDEO_COLOR_COEF_SMPTE240M,
+} video_color_matrix_coefficients_t;
+
+/* 4.2.1.2 Request Error Code Control */
+typedef enum {
+  VIDEO_ERROR_NONE = 0, /* The request succeeded. */
+  VIDEO_ERROR_NOT_READY,
+  VIDEO_ERROR_WRONG_STATE,
+  VIDEO_ERROR_POWER,
+  VIDEO_ERROR_OUT_OF_RANGE,
+  VIDEO_ERROR_INVALID_UNIT,
+  VIDEO_ERROR_INVALID_CONTROL,
+  VIDEO_ERROR_INVALID_REQUEST,
+  VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE,
+  VIDEO_ERROR_UNKNOWN = 0xFF,
+} video_error_code_t;
+
+/* A.2 Interface Subclass */
+typedef enum {
+  VIDEO_SUBCLASS_UNDEFINED = 0x00,
+  VIDEO_SUBCLASS_CONTROL,
+  VIDEO_SUBCLASS_STREAMING,
+  VIDEO_SUBCLASS_INTERFACE_COLLECTION,
+} video_subclass_type_t;
+
+/* A.3 Interface Protocol */
+typedef enum {
+  VIDEO_ITF_PROTOCOL_UNDEFINED = 0x00,
+  VIDEO_ITF_PROTOCOL_15,
+} video_interface_protocol_code_t;
+
+/* A.5 Class-Specific VideoControl Interface Descriptor Subtypes */
+typedef enum {
+  VIDEO_CS_ITF_VC_UNDEFINED = 0x00,
+  VIDEO_CS_ITF_VC_HEADER,
+  VIDEO_CS_ITF_VC_INPUT_TERMINAL,
+  VIDEO_CS_ITF_VC_OUTPUT_TERMINAL,
+  VIDEO_CS_ITF_VC_SELECTOR_UNIT,
+  VIDEO_CS_ITF_VC_PROCESSING_UNIT,
+  VIDEO_CS_ITF_VC_EXTENSION_UNIT,
+  VIDEO_CS_ITF_VC_ENCODING_UNIT,
+  VIDEO_CS_ITF_VC_MAX,
+} video_cs_vc_interface_subtype_t;
+
+/* A.6 Class-Specific VideoStreaming Interface Descriptor Subtypes */
+typedef enum {
+  VIDEO_CS_ITF_VS_UNDEFINED             = 0x00,
+  VIDEO_CS_ITF_VS_INPUT_HEADER          = 0x01,
+  VIDEO_CS_ITF_VS_OUTPUT_HEADER         = 0x02,
+  VIDEO_CS_ITF_VS_STILL_IMAGE_FRAME     = 0x03,
+  VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED   = 0x04,
+  VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED    = 0x05,
+  VIDEO_CS_ITF_VS_FORMAT_MJPEG          = 0x06,
+  VIDEO_CS_ITF_VS_FRAME_MJPEG           = 0x07,
+  VIDEO_CS_ITF_VS_FORMAT_MPEG2TS        = 0x0A,
+  VIDEO_CS_ITF_VS_FORMAT_DV             = 0x0C,
+  VIDEO_CS_ITF_VS_COLORFORMAT           = 0x0D,
+  VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED    = 0x10,
+  VIDEO_CS_ITF_VS_FRAME_FRAME_BASED     = 0x11,
+  VIDEO_CS_ITF_VS_FORMAT_STREAM_BASED   = 0x12,
+  VIDEO_CS_ITF_VS_FORMAT_H264           = 0x13,
+  VIDEO_CS_ITF_VS_FRAME_H264            = 0x14,
+  VIDEO_CS_ITF_VS_FORMAT_H264_SIMULCAST = 0x15,
+  VIDEO_CS_ITF_VS_FORMAT_VP8            = 0x16,
+  VIDEO_CS_ITF_VS_FRAME_VP8             = 0x17,
+  VIDEO_CS_ITF_VS_FORMAT_VP8_SIMULCAST  = 0x18,
+} video_cs_vs_interface_subtype_t;
+
+/* A.7. Class-Specific Endpoint Descriptor Subtypes */
+typedef enum {
+  VIDEO_CS_EP_UNDEFINED = 0x00,
+  VIDEO_CS_EP_GENERAL,
+  VIDEO_CS_EP_ENDPOINT,
+  VIDEO_CS_EP_INTERRUPT
+} video_cs_ep_subtype_t;
+
+/* A.8 Class-Specific Request Codes */
+typedef enum {
+  VIDEO_REQUEST_UNDEFINED   = 0x00,
+  VIDEO_REQUEST_SET_CUR     = 0x01,
+  VIDEO_REQUEST_SET_CUR_ALL = 0x11,
+  VIDEO_REQUEST_GET_CUR     = 0x81,
+  VIDEO_REQUEST_GET_MIN     = 0x82,
+  VIDEO_REQUEST_GET_MAX     = 0x83,
+  VIDEO_REQUEST_GET_RES     = 0x84,
+  VIDEO_REQUEST_GET_LEN     = 0x85,
+  VIDEO_REQUEST_GET_INFO    = 0x86,
+  VIDEO_REQUEST_GET_DEF     = 0x87,
+  VIDEO_REQUEST_GET_CUR_ALL = 0x91,
+  VIDEO_REQUEST_GET_MIN_ALL = 0x92,
+  VIDEO_REQUEST_GET_MAX_ALL = 0x93,
+  VIDEO_REQUEST_GET_RES_ALL = 0x94,
+  VIDEO_REQUEST_GET_DEF_ALL = 0x97
+} video_control_request_t;
+
+/* A.9.1 VideoControl Interface Control Selectors */
+typedef enum {
+  VIDEO_VC_CTL_UNDEFINED = 0x00,
+  VIDEO_VC_CTL_VIDEO_POWER_MODE,
+  VIDEO_VC_CTL_REQUEST_ERROR_CODE,
+} video_interface_control_selector_t;
+
+/* A.9.8 VideoStreaming Interface Control Selectors */
+typedef enum {
+  VIDEO_VS_CTL_UNDEFINED = 0x00,
+  VIDEO_VS_CTL_PROBE,
+  VIDEO_VS_CTL_COMMIT,
+  VIDEO_VS_CTL_STILL_PROBE,
+  VIDEO_VS_CTL_STILL_COMMIT,
+  VIDEO_VS_CTL_STILL_IMAGE_TRIGGER,
+  VIDEO_VS_CTL_STREAM_ERROR_CODE,
+  VIDEO_VS_CTL_GENERATE_KEY_FRAME,
+  VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT,
+  VIDEO_VS_CTL_SYNCH_DELAY_CONTROL,
+} video_interface_streaming_selector_t;
+
+/* B. Terminal Types */
+typedef enum {
+  // Terminal
+  VIDEO_TT_VENDOR_SPECIFIC         = 0x0100,
+  VIDEO_TT_STREAMING               = 0x0101,
+
+  // Input
+  VIDEO_ITT_VENDOR_SPECIFIC        = 0x0200,
+  VIDEO_ITT_CAMERA                 = 0x0201,
+  VIDEO_ITT_MEDIA_TRANSPORT_INPUT  = 0x0202,
+
+  // Output
+  VIDEO_OTT_VENDOR_SPECIFIC        = 0x0300,
+  VIDEO_OTT_DISPLAY                = 0x0301,
+  VIDEO_OTT_MEDIA_TRANSPORT_OUTPUT = 0x0302,
+
+  // External
+  VIDEO_ETT_VENDOR_SPEIFIC         = 0x0400,
+  VIDEO_ETT_COMPOSITE_CONNECTOR    = 0x0401,
+  VIDEO_ETT_SVIDEO_CONNECTOR       = 0x0402,
+  VIDEO_ETT_COMPONENT_CONNECTOR    = 0x0403,
+} video_terminal_type_t;
+
+//--------------------------------------------------------------------+
+// Descriptors
+//--------------------------------------------------------------------+
+
+/* 2.3.4.2 */
+typedef struct TU_ATTR_PACKED {
+  uint8_t  bLength;
+  uint8_t  bDescriptorType;
+  uint8_t  bDescriptorSubType;
+  uint16_t bcdUVC;
+  uint16_t wTotalLength;
+  uint32_t dwClockFrequency;
+  uint8_t  bInCollection;
+  uint8_t  baInterfaceNr[];
+} tusb_desc_cs_video_ctl_itf_hdr_t;
+
+/* 2.4.3.3 */
+typedef struct TU_ATTR_PACKED {
+  uint8_t bHeaderLength;
+  union {
+    uint8_t bmHeaderInfo;
+    struct {
+      uint8_t FrameID:              1;
+      uint8_t EndOfFrame:           1;
+      uint8_t PresentationTime:     1;
+      uint8_t SourceClockReference: 1;
+      uint8_t PayloadSpecific:      1;
+      uint8_t StillImage:           1;
+      uint8_t Error:                1;
+      uint8_t EndOfHeader:          1;
+    };
+  };
+} tusb_video_payload_header_t;
+
+/* 3.9.2.1 */
+typedef struct TU_ATTR_PACKED {
+  uint8_t  bLength;
+  uint8_t  bDescriptorType;
+  uint8_t  bDescriptorSubType;
+  uint8_t  bNumFormats;
+  uint16_t wTotalLength;
+  uint8_t  bEndpointAddress;
+  uint8_t  bmInfo;
+  uint8_t  bTerminalLink;
+  uint8_t  bStillCaptureMethod;
+  uint8_t  bTriggerSupport;
+  uint8_t  bTriggerUsage;
+  uint8_t  bControlSize;
+  uint8_t  bmaControls[];
+} tusb_desc_cs_video_stm_itf_in_hdr_t;
+
+/* 3.9.2.2 */
+typedef struct TU_ATTR_PACKED {
+  uint8_t  bLength;
+  uint8_t  bDescriptorType;
+  uint8_t  bDescriptorSubType;
+  uint8_t  bNumFormats;
+  uint16_t wTotalLength;
+  uint8_t  bEndpointAddress;
+  uint8_t  bTerminalLink;
+  uint8_t  bControlSize;
+  uint8_t  bmaControls[];
+} tusb_desc_cs_video_stm_itf_out_hdr_t;
+
+typedef struct TU_ATTR_PACKED {
+  uint8_t  bLength;
+  uint8_t  bDescriptorType;
+  uint8_t  bDescriptorSubType;
+  uint8_t  bNumFormats;
+  uint16_t wTotalLength;
+  uint8_t  bEndpointAddress;
+  union {
+    struct {
+      uint8_t  bmInfo;
+      uint8_t  bTerminalLink;
+      uint8_t  bStillCaptureMethod;
+      uint8_t  bTriggerSupport;
+      uint8_t  bTriggerUsage;
+      uint8_t  bControlSize;
+      uint8_t  bmaControls[];
+    } input;
+    struct {
+      uint8_t  bEndpointAddress;
+      uint8_t  bTerminalLink;
+      uint8_t  bControlSize;
+      uint8_t  bmaControls[];
+    } output;
+  };
+} tusb_desc_cs_video_stm_itf_hdr_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;
+} tusb_desc_cs_video_fmt_uncompressed_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 dwMaxVideoFrameBufferSize; /* deprecated */
+  uint32_t dwDefaultFrameInterval;
+  uint8_t  bFrameIntervalType;
+  uint32_t dwFrameInterval[];
+} tusb_desc_cs_video_frm_uncompressed_t;
+
+//--------------------------------------------------------------------+
+// Requests
+//--------------------------------------------------------------------+
+
+/* 4.3.1.1 */
+typedef struct TU_ATTR_PACKED {
+  union {
+    uint8_t bmHint;
+    struct TU_ATTR_PACKED {
+      uint16_t dwFrameInterval: 1;
+      uint16_t wKeyFrameRatel : 1;
+      uint16_t wPFrameRate    : 1;
+      uint16_t wCompQuality   : 1;
+      uint16_t wCompWindowSize: 1;
+      uint16_t                : 0;
+    } Hint;
+  };
+  uint8_t  bFormatIndex;
+  uint8_t  bFrameIndex;
+  uint32_t dwFrameInterval;
+  uint16_t wKeyFrameRate;
+  uint16_t wPFrameRate;
+  uint16_t wCompQuality;
+  uint16_t wCompWindowSize;
+  uint16_t wDelay;
+  uint32_t dwMaxVideoFrameSize;
+  uint32_t dwMaxPayloadTransferSize;
+  uint32_t dwClockFrequency;
+  union {
+    uint8_t bmFramingInfo;
+    struct TU_ATTR_PACKED {
+      uint8_t FrameID   : 1;
+      uint8_t EndOfFrame: 1;
+      uint8_t EndOfSlice: 1;
+      uint8_t           : 0;
+    } FramingInfo;
+  };
+  uint8_t  bPreferedVersion;
+  uint8_t  bMinVersion;
+  uint8_t  bMaxVersion;
+  uint8_t  bUsage;
+  uint8_t  bBitDepthLuma;
+  uint8_t  bmSettings;
+  uint8_t  bMaxNumberOfRefFramesPlus1;
+  uint16_t bmRateControlModes;
+  uint64_t bmLayoutPerStream;
+} video_probe_and_commit_control_t;
+
+TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not correct");
+
+#define TUD_VIDEO_DESC_IAD_LEN                    8
+#define TUD_VIDEO_DESC_STD_VC_LEN                 9
+#define TUD_VIDEO_DESC_CS_VC_LEN                  12
+#define TUD_VIDEO_DESC_INPUT_TERM_LEN             8
+#define TUD_VIDEO_DESC_OUTPUT_TERM_LEN            9
+#define TUD_VIDEO_DESC_CAMERA_TERM_LEN            18
+#define TUD_VIDEO_DESC_STD_VS_LEN                 9
+#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_FRM_UNCOMPR_CONT_LEN 38
+#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26
+#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN   6
+
+/* 2.2 compression formats */
+#define TUD_VIDEO_GUID_YUY2   0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
+#define TUD_VIDEO_GUID_NV12   0x4E,0x56,0x31,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
+#define TUD_VIDEO_GUID_M420   0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
+#define TUD_VIDEO_GUID_I420   0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
+
+#define TUD_VIDEO_DESC_IAD(_firstitfs, _nitfs, _stridx) \
+  TUD_VIDEO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, \
+  _firstitfs, _nitfs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_INTERFACE_COLLECTION, \
+  VIDEO_ITF_PROTOCOL_UNDEFINED, _stridx
+
+#define TUD_VIDEO_DESC_STD_VC(_itfnum, _nEPs, _stridx) \
+  TUD_VIDEO_DESC_STD_VC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, \
+  _nEPs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_CONTROL, VIDEO_ITF_PROTOCOL_15, _stridx
+
+/* 3.7.2 */
+#define TUD_VIDEO_DESC_CS_VC(_bcdUVC, _totallen, _clkfreq, ...)	\
+  TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_HEADER, \
+  U16_TO_U8S_LE(_bcdUVC), U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VC_LEN + (TU_ARGS_NUM(__VA_ARGS__))), \
+  U32_TO_U8S_LE(_clkfreq), TU_ARGS_NUM(__VA_ARGS__), __VA_ARGS__
+
+/* 3.7.2.1 */
+#define TUD_VIDEO_DESC_INPUT_TERM(_tid, _tt, _at, _stridx) \
+  TUD_VIDEO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \
+    _tid, U16_TO_U8S_LE(_tt), _at, _stridx
+
+/* 3.7.2.2 */
+#define TUD_VIDEO_DESC_OUTPUT_TERM(_tid, _tt, _at, _srcid, _stridx) \
+  TUD_VIDEO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, \
+    _tid, U16_TO_U8S_LE(_tt), _at, _srcid, _stridx
+
+/* 3.7.2.3 */
+#define TUD_VIDEO_DESC_CAMERA_TERM(_tid, _at, _stridx, _focal_min, _focal_max, _focal, _ctls) \
+  TUD_VIDEO_DESC_CAMERA_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \
+    _tid, U16_TO_U8S_LE(VIDEO_ITT_CAMERA), _at, _stridx, \
+    U16_TO_U8S_LE(_focal_min), U16_TO_U8S_LE(_focal_max), U16_TO_U8S_LE(_focal), 3, \
+    TU_U32_BYTE0(_ctls), TU_U32_BYTE1(_ctls), TU_U32_BYTE2(_ctls)
+
+/* 3.9.1 */
+#define TUD_VIDEO_DESC_STD_VS(_itfnum, _alt, _epn, _stridx) \
+  TUD_VIDEO_DESC_STD_VS_LEN, TUSB_DESC_INTERFACE, _itfnum, _alt, \
+  _epn, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_STREAMING, VIDEO_ITF_PROTOCOL_15, _stridx
+
+/* 3.9.2.1 */
+#define TUD_VIDEO_DESC_CS_VS_INPUT(_numfmt, _totallen, _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, ...) \
+  TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \
+  VIDEO_CS_ITF_VS_INPUT_HEADER, _numfmt, \
+  U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \
+  _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
+
+/* 3.9.2.2 */
+#define TUD_VIDEO_DESC_CS_VS_OUTPUT(_numfmt, _totallen, _ep, _inf, _termlnk, ...) \
+  TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, \
+  VIDEO_CS_ITF_VS_OUTPUT_HEADER, _numfmt, \
+  U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (TU_ARGS_NUM(__VA_ARGS__))), \
+  _ep, _inf, _termlnk, (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
+
+/* Uncompressed 3.1.1 */
+#define TUD_VIDEO_GUID(_g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15) _g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15
+
+#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfrmdesc, \
+  _guid, _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp) \
+  TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, \
+  _fmtidx, _numfrmdesc, TUD_VIDEO_GUID(_guid), \
+  _bitsperpix, _frmidx, _asrx,  _asry, _interlace, _cp
+
+/* Uncompressed 3.1.2 Table 3-3 */
+#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \
+  TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \
+  _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)
+
+/* Uncompressed 3.1.2 Table 3-4 */
+#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \
+  TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \
+  TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, \
+  _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, \
+  TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_COLORFORMAT, \
+  _color, _trns, _mat
+
+/* 3.10.1.1 */
+#define TUD_VIDEO_DESC_EP_ISO(_ep, _epsize, _ep_interval) \
+  7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS,\
+  U16_TO_U8S_LE(_epsize), _ep_interval
+
+/* 3.10.1.2 */
+#define TUD_VIDEO_DESC_EP_BULK(_ep, _epsize, _ep_interval) \
+  7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), _ep_interval
+
+#endif
diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c
new file mode 100644
index 0000000..eeb0681
--- /dev/null
+++ b/src/class/video/video_device.c
@@ -0,0 +1,1149 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ * 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 (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING)
+
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "video_device.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef struct {
+  tusb_desc_interface_t            std;
+  tusb_desc_cs_video_ctl_itf_hdr_t ctl;
+} tusb_desc_vc_itf_t;
+
+typedef struct {
+  tusb_desc_interface_t            std;
+  tusb_desc_cs_video_stm_itf_hdr_t stm;
+} tusb_desc_vs_itf_t;
+
+typedef union {
+  tusb_desc_cs_video_ctl_itf_hdr_t ctl;
+  tusb_desc_cs_video_stm_itf_hdr_t stm;
+} tusb_desc_video_itf_hdr_t;
+
+typedef struct TU_ATTR_PACKED {
+  uint8_t bLength;
+  uint8_t bDescriptorType;
+  uint8_t bDescriptorSubtype;
+  uint8_t bEntityId;
+} tusb_desc_cs_video_entity_itf_t;
+
+/* video streaming interface */
+typedef struct TU_ATTR_PACKED {
+  uint8_t index_vc;  /* index of bound video control interface */
+  uint8_t index_vs;  /* index from the video control interface */
+  struct {
+    uint16_t beg;    /* Offset of the begging of video streaming interface descriptor */
+    uint16_t end;    /* Offset of the end of video streaming interface descriptor */
+    uint16_t cur;    /* Offset of the current settings */
+    uint16_t ep[2];  /* Offset of endpoint descriptors. 0: streaming, 1: still capture */
+  } desc;
+  uint8_t *buffer;   /* frame buffer. assume linear buffer. no support for stride access */
+  uint32_t bufsize;  /* frame buffer size */
+  uint32_t offset;   /* offset for the next payload transfer */
+  uint32_t max_payload_transfer_size;
+  uint8_t  error_code;/* error code */
+  /*------------- From this point, data is not cleared by bus reset -------------*/
+  CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */
+} videod_streaming_interface_t;
+
+/* video control interface */
+typedef struct TU_ATTR_PACKED {
+  void const *beg;  /* The head of the first video control interface descriptor */
+  uint16_t    len;  /* Byte length of the descriptors */
+  uint16_t    cur;  /* offset for current video control interface */
+  uint8_t     stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */
+  uint8_t error_code;  /* error code */
+  uint8_t power_mode;
+
+  /*------------- From this point, data is not cleared by bus reset -------------*/
+  // CFG_TUSB_MEM_ALIGN uint8_t ctl_buf[64]; /* EP transfer buffer for interrupt transfer */
+
+} videod_interface_t;
+
+#define ITF_STM_MEM_RESET_SIZE   offsetof(videod_streaming_interface_t, ep_buf)
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+CFG_TUSB_MEM_SECTION static videod_interface_t _videod_itf[CFG_TUD_VIDEO];
+CFG_TUSB_MEM_SECTION static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING];
+
+static uint8_t const _cap_get     = 0x1u; /* support for GET */
+static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */
+
+/** Get interface number from the interface descriptor
+ *
+ * @param[in] desc    interface descriptor
+ *
+ * @return bInterfaceNumber */
+static inline uint8_t _desc_itfnum(void const *desc)
+{
+  return ((uint8_t const*)desc)[2];
+}
+
+/** Get endpoint address from the endpoint descriptor
+ *
+ * @param[in] desc    endpoint descriptor
+ *
+ * @return bEndpointAddress */
+static inline uint8_t _desc_ep_addr(void const *desc)
+{
+  return ((uint8_t const*)desc)[2];
+}
+
+/** Get instance of streaming interface
+ *
+ * @param[in] ctl_idx    instance number of video control
+ * @param[in] stm_idx    index number of streaming interface
+ *
+ * @return instance */
+static videod_streaming_interface_t* _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
+{
+  videod_interface_t *ctl = &_videod_itf[ctl_idx];
+  if (!ctl->beg) return NULL;
+  videod_streaming_interface_t *stm = &_videod_streaming_itf[ctl->stm[stm_idx]];
+  if (!stm->desc.beg) return NULL;
+  return stm;
+}
+
+static tusb_desc_vc_itf_t const* _get_desc_vc(videod_interface_t const *self)
+{
+  return (tusb_desc_vc_itf_t const *)(self->beg + self->cur);
+}
+
+static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const *self)
+{
+  if (!self->desc.cur) return NULL;
+  void const *desc = _videod_itf[self->index_vc].beg;
+  return (tusb_desc_vs_itf_t const*)(desc + self->desc.cur);
+}
+
+/** Find the first descriptor of a given type
+ *
+ * @param[in] beg        The head of descriptor byte array.
+ * @param[in] end        The tail of descriptor byte array.
+ * @param[in] desc_type  The target descriptor type.
+ *
+ * @return The pointer for interface descriptor.
+ * @retval end   did not found interface descriptor */
+static void const* _find_desc(void const *beg, void const *end, uint_fast8_t desc_type)
+{
+  void const *cur = beg;
+  while ((cur < end) && (desc_type != tu_desc_type(cur))) {
+    cur = tu_desc_next(cur);
+  }
+  return cur;
+}
+
+/** Find the first descriptor specified by the arguments
+ *
+ * @param[in] beg        The head of descriptor byte array.
+ * @param[in] end        The tail of descriptor byte array.
+ * @param[in] desc_type  The target descriptor type
+ * @param[in] element_0  The target element following the desc_type
+ * @param[in] element_1  The target element following the element_0
+ *
+ * @return The pointer for interface descriptor.
+ * @retval end   did not found interface descriptor */
+static void const* _find_desc_3(void const *beg, void const *end,
+                                uint_fast8_t desc_type,
+                                uint_fast8_t element_0,
+                                uint_fast8_t element_1)
+{
+  for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, desc_type)) {
+    uint8_t const *p = (uint8_t const *)cur;
+    if ((p[2] == element_0) && (p[3] == element_1)) {
+      return cur;
+    }
+    cur = tu_desc_next(cur);
+  }
+  return end;
+}
+
+/** Return the next interface descriptor which has another interface number.
+ *
+ * @param[in] beg     The head of descriptor byte array.
+ * @param[in] end     The tail of descriptor byte array.
+ *
+ * @return The pointer for interface descriptor.
+ * @retval end   did not found interface descriptor */
+static void const* _next_desc_itf(void const *beg, void const *end)
+{
+  void const *cur = beg;
+  uint_fast8_t itfnum = ((tusb_desc_interface_t const*)cur)->bInterfaceNumber;
+  while ((cur < end) &&
+         (itfnum == ((tusb_desc_interface_t const*)cur)->bInterfaceNumber)) {
+    cur = _find_desc(tu_desc_next(cur), end, TUSB_DESC_INTERFACE);
+  }
+  return cur;
+}
+
+/** Find the first interface descriptor with the specified interface number and alternate setting number.
+ *
+ * @param[in] beg     The head of descriptor byte array.
+ * @param[in] end     The tail of descriptor byte array.
+ * @param[in] itfnum  The target interface number.
+ * @param[in] altnum  The target alternate setting number.
+ *
+ * @return The pointer for interface descriptor.
+ * @retval end   did not found interface descriptor */
+static inline void const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum)
+{
+  return _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum);
+}
+
+/** Find the first endpoint descriptor belonging to the current interface descriptor.
+ *
+ * The search range is from `beg` to `end` or the next interface descriptor.
+ *
+ * @param[in] beg     The head of descriptor byte array.
+ * @param[in] end     The tail of descriptor byte array.
+ *
+ * @return The pointer for endpoint descriptor.
+ * @retval end   did not found endpoint descriptor */
+static void const* _find_desc_ep(void const *beg, void const *end)
+{
+  for (void const *cur = beg; cur < end; cur = tu_desc_next(cur)) {
+    uint_fast8_t desc_type = tu_desc_type(cur);
+    if (TUSB_DESC_ENDPOINT == desc_type) return cur;
+    if (TUSB_DESC_INTERFACE == desc_type) break;
+  }
+  return end;
+}
+
+/** Find the first entity descriptor with the entity ID
+ *  specified by the argument belonging to the current video control descriptor.
+ *
+ * @param[in] desc      The video control interface descriptor.
+ * @param[in] entityid  The target entity id.
+ *
+ * @return The pointer for interface descriptor.
+ * @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)) {
+    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)
+        && itf->bEntityId == entityid) {
+      return itf;
+    }
+    cur = tu_desc_next(cur);
+  }
+  return end;
+}
+
+/** Return the end of the video streaming descriptor. */
+static inline void const* _end_of_streaming_descriptor(void const *desc)
+{
+  tusb_desc_vs_itf_t const *vs = (tusb_desc_vs_itf_t const *)desc;
+  return desc + vs->std.bLength + vs->stm.wTotalLength;
+}
+
+/** 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)
+{
+  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);
+}
+
+/** 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)
+{
+  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);
+}
+
+/** Set uniquely determined values to variables that have not been set
+ *
+ * @param[in,out] param       Target */
+static bool _update_streaming_parameters(videod_streaming_interface_t const *stm,
+                                         video_probe_and_commit_control_t *param)
+{
+  tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
+  uint_fast8_t fmtnum = param->bFormatIndex;
+  TU_ASSERT(fmtnum <= vs->stm.bNumFormats);
+  if (!fmtnum) {
+    if (1 < vs->stm.bNumFormats) return true; /* Need to negotiate all variables. */
+    fmtnum = 1;
+    param->bFormatIndex = 1;
+  }
+
+  /* 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  */
+  param->bmFramingInfo    = 0x3; /* enables FrameID and EndOfFrame */
+  param->bPreferedVersion = 1;
+  param->bMinVersion      = 1;
+  param->bMaxVersion      = 1;
+  param->bUsage           = 0;
+  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);
+  TU_ASSERT(fmt != end);
+  uint_fast8_t frmnum = param->bFrameIndex;
+  TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors);
+  if (!frmnum) {
+    if (1 < fmt->bNumFrameDescriptors) return true;
+    frmnum = 1;
+    param->bFrameIndex = 1;
+  }
+  tusb_desc_cs_video_frm_uncompressed_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;
+    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]))) {
+      return true;
+    }
+    interval = frm->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;
+  param->dwMaxPayloadTransferSize = payload_size;
+  return true;
+}
+
+/** Set the minimum, maximum, default values or resolutions to variables which need to negotiate with the host
+ *
+ * @param[in]     request     GET_MAX, GET_MIN, GET_RES or GET_DEF
+ * @param[in,out] param       Target
+ */
+static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request,
+                                            video_probe_and_commit_control_t *param)
+{
+  uint_fast8_t const fmtnum = param->bFormatIndex;
+  if (!fmtnum) {
+    switch (request) {
+      case VIDEO_REQUEST_GET_MAX:
+        param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats;
+        break;
+      case VIDEO_REQUEST_GET_MIN:
+      case VIDEO_REQUEST_GET_DEF:
+        param->bFormatIndex = 1;
+        break;
+      default: return false;
+    }
+    /* 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  */
+    param->bmFramingInfo    = 0x3; /* enables FrameID and EndOfFrame */
+    param->bPreferedVersion = 1;
+    param->bMinVersion      = 1;
+    param->bMaxVersion      = 1;
+    param->bUsage           = 0;
+    param->bBitDepthLuma    = 8;
+    return true;
+  }
+
+  uint_fast8_t frmnum = param->bFrameIndex;
+  if (!frmnum) {
+    tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
+    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);
+    switch (request) {
+      case VIDEO_REQUEST_GET_MAX:
+        frmnum = fmt->bNumFrameDescriptors;
+        break;
+      case VIDEO_REQUEST_GET_MIN:
+        frmnum = 1;
+        break;
+      case VIDEO_REQUEST_GET_DEF:
+        frmnum = fmt->bDefaultFrameIndex;
+        break;
+      default: return false;
+    }
+    param->bFrameIndex = 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;
+    return true;
+  }
+
+  if (!param->dwFrameInterval) {
+    tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
+    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);
+
+    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];
+          interval = max_interval;
+          interval_ms = min_interval / 10000;
+        }
+        break;
+      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];
+          interval = min_interval;
+          interval_ms = max_interval / 10000;
+        }
+        break;
+      case VIDEO_REQUEST_GET_DEF:
+        interval = frm->dwDefaultFrameInterval;
+        interval_ms = interval / 10000;
+        break;
+      case VIDEO_REQUEST_GET_RES:
+        {
+          uint_fast8_t num_intervals = frm->bFrameIntervalType;
+          if (num_intervals) {
+            interval = 0;
+          } else {
+            interval = frm->dwFrameInterval[2];
+            interval_ms = interval / 10000;
+          }
+        }
+        break;
+      default: return false;
+    }
+    param->dwFrameInterval = interval;
+    if (!interval) {
+      param->dwMaxPayloadTransferSize = 0;
+    } else {
+      uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
+      if (!interval_ms) {
+        param->dwMaxPayloadTransferSize = frame_size + 2;
+      } else {
+        param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2;
+      }
+    }
+    return true;
+  }
+  return true;
+}
+
+/** Close current video control interface.
+ *
+ * @param[in,out] self     Video control interface context.
+ * @param[in]     altnum   The target alternate setting number. */
+static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self)
+{
+  tusb_desc_vc_itf_t const *vc = _get_desc_vc(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;
+  if (vc->std.bNumEndpoints) {
+    /* Find the notification endpoint descriptor. */
+    cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT);
+    TU_ASSERT(cur < end);
+    tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur;
+    usbd_edpt_close(rhport, notif->bEndpointAddress);
+  }
+  self->cur = 0;
+  return true;
+}
+
+/** Set the alternate setting to own video control interface.
+ *
+ * @param[in,out] self     Video control interface context.
+ * @param[in]     altnum   The target alternate setting number. */
+static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum)
+{
+  TU_LOG2("    open VC %d\n", altnum);
+  void const *beg = self->beg;
+  void const *end = beg + self->len;
+  /* The first descriptor is a video control interface descriptor. */
+  void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum);
+  TU_LOG2("    cur %d\n", cur - beg);
+  TU_VERIFY(cur < end);
+
+  tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)cur;
+  TU_LOG2("    bInCollection %d\n", vc->ctl.bInCollection);
+  /* Support for up to 2 streaming interfaces only. */
+  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;
+  /* 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);
+  /* Open the notification endpoint if it exist. */
+  if (vc->std.bNumEndpoints) {
+    /* Support for 1 endpoint only. */
+    TU_VERIFY(1 == vc->std.bNumEndpoints);
+    /* Find the notification endpoint descriptor. */
+    cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT);
+    TU_VERIFY(cur < end);
+    tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur;
+    /* Open the notification endpoint */
+    TU_ASSERT(usbd_edpt_open(rhport, notif));
+  }
+  self->cur = (void const*)vc - beg;
+  return true;
+}
+
+/** Set the alternate setting to own video streaming interface.
+ *
+ * @param[in,out] stm      Streaming interface context.
+ * @param[in]     altnum   The target alternate setting number. */
+static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum)
+{
+  uint_fast8_t i;
+  TU_LOG2("    reopen VS %d\n", altnum);
+  void const *desc = _videod_itf[stm->index_vc].beg;
+
+  /* Close endpoints of previous settings. */
+  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);
+    usbd_edpt_close(rhport, ep_adr);
+    stm->desc.ep[i] = 0;
+    TU_LOG2("    close EP%02x\n", ep_adr);
+  }
+  /* clear transfer management information */
+  stm->buffer  = NULL;
+  stm->bufsize = 0;
+  stm->offset  = 0;
+
+  /* Find a alternate interface */
+  void const *beg = desc + stm->desc.beg;
+  void const *end = desc + stm->desc.end;
+  void const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum);
+  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 */
+  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));
+    return _update_streaming_parameters(stm, param);
+  }
+  /* Open endpoints of the new settings. */
+  for (i = 0, cur = tu_desc_next(cur); i < numeps; ++i, cur = tu_desc_next(cur)) {
+    cur = _find_desc_ep(cur, end);
+    TU_ASSERT(cur < end);
+    tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur;
+    if (!stm->max_payload_transfer_size) {
+      video_probe_and_commit_control_t const *param = (video_probe_and_commit_control_t const*)&stm->ep_buf;
+      uint_fast32_t max_size = param->dwMaxPayloadTransferSize;
+      if ((TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer) &&
+          (tu_edpt_packet_size(ep) < max_size))
+      {
+        /* FS must be less than or equal to max packet size */
+        return false;
+      }
+      /* Set the negotiated value */
+      stm->max_payload_transfer_size = max_size;
+    }
+    TU_ASSERT(usbd_edpt_open(rhport, ep));
+    stm->desc.ep[i] = cur - desc;
+    TU_LOG2("    open EP%02x\n", _desc_ep_addr(cur));
+  }
+  /* initialize payload header */
+  tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf;
+  hdr->bHeaderLength = sizeof(*hdr);
+  hdr->bmHeaderInfo  = 0;
+
+  return true;
+}
+
+/** Prepare the next packet payload. */
+static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm)
+{
+  uint_fast16_t remaining = stm->bufsize - stm->offset;
+  uint_fast16_t hdr_len   = stm->ep_buf[0];
+  uint_fast16_t pkt_len   = stm->max_payload_transfer_size;
+  if (hdr_len + remaining < pkt_len) {
+    pkt_len = hdr_len + remaining;
+  }
+  uint_fast16_t data_len = pkt_len - hdr_len;
+  memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
+  stm->offset += data_len;
+  remaining -= data_len;
+  if (!remaining) {
+    tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf;
+    hdr->EndOfFrame = 1;
+  }
+  return hdr_len + data_len;
+}
+
+/** Handle a standard request to the video control interface. */
+static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage,
+                                    tusb_control_request_t const *request,
+                                    uint_fast8_t ctl_idx)
+{
+  switch (request->bRequest) {
+    case TUSB_REQ_GET_INTERFACE:
+      if (stage == CONTROL_STAGE_SETUP)
+      {
+        TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
+        tusb_desc_vc_itf_t const *vc = _get_desc_vc(&_videod_itf[ctl_idx]);
+        TU_VERIFY(vc, VIDEO_ERROR_UNKNOWN);
+
+        uint8_t alt_num = vc->std.bAlternateSetting;
+
+        TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN);
+      }
+      return VIDEO_ERROR_NONE;
+
+    case TUSB_REQ_SET_INTERFACE:
+      if (stage == CONTROL_STAGE_SETUP)
+      {
+        TU_VERIFY(0 == request->wLength, VIDEO_ERROR_UNKNOWN);
+        TU_VERIFY(_close_vc_itf(rhport, &_videod_itf[ctl_idx]), VIDEO_ERROR_UNKNOWN);
+        TU_VERIFY(_open_vc_itf(rhport, &_videod_itf[ctl_idx], request->wValue), VIDEO_ERROR_UNKNOWN);
+        tud_control_status(rhport, request);
+      }
+      return VIDEO_ERROR_NONE;
+
+    default: /* Unknown/Unsupported request */
+      TU_BREAKPOINT();
+      return VIDEO_ERROR_INVALID_REQUEST;
+  }
+}
+
+static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage,
+                                   tusb_control_request_t const *request,
+                                   uint_fast8_t ctl_idx)
+{
+  videod_interface_t *self = &_videod_itf[ctl_idx];
+
+  /* 4.2.1 Interface Control Request */
+  switch (TU_U16_HIGH(request->wValue)) {
+    case VIDEO_VC_CTL_VIDEO_POWER_MODE:
+      switch (request->bRequest) {
+        case VIDEO_REQUEST_SET_CUR:
+          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) {
+            if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_CUR:
+          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);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_INFO:
+          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);
+          }
+          return VIDEO_ERROR_NONE;
+
+        default: break;
+      }
+      break;
+
+    case VIDEO_VC_CTL_REQUEST_ERROR_CODE:
+      switch (request->bRequest) {
+        case VIDEO_REQUEST_GET_CUR:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_INFO:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN);
+          }
+          return VIDEO_ERROR_NONE;
+
+        default: break;
+      }
+      break;
+
+    default: break;
+  }
+
+  /* Unknown/Unsupported request */
+  TU_BREAKPOINT();
+  return VIDEO_ERROR_INVALID_REQUEST;
+}
+
+static int handle_video_ctl_req(uint8_t rhport, uint8_t stage,
+                                tusb_control_request_t const *request,
+                                uint_fast8_t ctl_idx)
+{
+  uint_fast8_t entity_id;
+  switch (request->bmRequestType_bit.type) {
+    case TUSB_REQ_TYPE_STANDARD:
+      return handle_video_ctl_std_req(rhport, stage, request, ctl_idx);
+
+    case TUSB_REQ_TYPE_CLASS:
+      entity_id = TU_U16_HIGH(request->wIndex);
+      if (!entity_id) {
+        return handle_video_ctl_cs_req(rhport, stage, request, ctl_idx);
+      } else {
+        TU_VERIFY(_find_desc_entity(_get_desc_vc(&_videod_itf[ctl_idx]), entity_id), VIDEO_ERROR_INVALID_REQUEST);
+        return VIDEO_ERROR_NONE;
+      }
+
+    default:
+      return VIDEO_ERROR_INVALID_REQUEST;
+  }
+}
+
+static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage,
+                                    tusb_control_request_t const *request,
+                                    uint_fast8_t stm_idx)
+{
+  videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx];
+  switch (request->bRequest) {
+    case TUSB_REQ_GET_INTERFACE:
+      if (stage == CONTROL_STAGE_SETUP)
+      {
+        TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
+        tusb_desc_vs_itf_t const *vs = _get_desc_vs(self);
+        TU_VERIFY(vs, VIDEO_ERROR_UNKNOWN);
+        uint8_t alt_num = vs->std.bAlternateSetting;
+
+        TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN);
+      }
+      return VIDEO_ERROR_NONE;
+
+    case TUSB_REQ_SET_INTERFACE:
+      if (stage == CONTROL_STAGE_SETUP)
+      {
+        TU_VERIFY(_open_vs_itf(rhport, self, request->wValue), VIDEO_ERROR_UNKNOWN);
+        tud_control_status(rhport, request);
+      }
+      return VIDEO_ERROR_NONE;
+
+    default: /* Unknown/Unsupported request */
+      TU_BREAKPOINT();
+      return VIDEO_ERROR_INVALID_REQUEST;
+  }
+}
+
+static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
+                                   tusb_control_request_t const *request,
+                                   uint_fast8_t stm_idx)
+{
+  (void)rhport;
+  videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx];
+
+  /* 4.2.1 Interface Control Request */
+  switch (TU_U16_HIGH(request->wValue)) {
+    case VIDEO_VS_CTL_STREAM_ERROR_CODE:
+      switch (request->bRequest) {
+        case VIDEO_REQUEST_GET_CUR:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            /* TODO */
+            TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_INFO:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN);
+          }
+          return VIDEO_ERROR_NONE;
+
+        default: break;
+      }
+      break;
+
+    case VIDEO_VS_CTL_PROBE:
+      switch (request->bRequest) {
+        case VIDEO_REQUEST_SET_CUR:
+          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) {
+            TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf),
+                      VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_CUR:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            TU_VERIFY(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);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_MIN:
+        case VIDEO_REQUEST_GET_MAX:
+        case VIDEO_REQUEST_GET_RES:
+        case VIDEO_REQUEST_GET_DEF:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
+            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);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_LEN:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN);
+            uint16_t len = sizeof(video_probe_and_commit_control_t);
+            TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_INFO:
+          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);
+          }
+          return VIDEO_ERROR_NONE;
+
+        default: break;
+      }
+      break;
+
+    case VIDEO_VS_CTL_COMMIT:
+      switch (request->bRequest) {
+        case VIDEO_REQUEST_SET_CUR:
+          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) {
+            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);
+            }
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_CUR:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            TU_VERIFY(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);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_LEN:
+          if (stage == CONTROL_STAGE_SETUP)
+          {
+            TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN);
+            uint16_t len = sizeof(video_probe_and_commit_control_t);
+            TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN);
+          }
+          return VIDEO_ERROR_NONE;
+
+        case VIDEO_REQUEST_GET_INFO:
+          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);
+          }
+          return VIDEO_ERROR_NONE;
+
+        default: break;
+      }
+      break;
+
+    case VIDEO_VS_CTL_STILL_PROBE:
+    case VIDEO_VS_CTL_STILL_COMMIT:
+    case VIDEO_VS_CTL_STILL_IMAGE_TRIGGER:
+    case VIDEO_VS_CTL_GENERATE_KEY_FRAME:
+    case VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT:
+    case VIDEO_VS_CTL_SYNCH_DELAY_CONTROL:
+      /* TODO */
+      break;
+
+    default: break;
+  }
+
+  /* Unknown/Unsupported request */
+  TU_BREAKPOINT();
+  return VIDEO_ERROR_INVALID_REQUEST;
+}
+
+static int handle_video_stm_req(uint8_t rhport, uint8_t stage,
+                                tusb_control_request_t const *request,
+                                uint_fast8_t stm_idx)
+{
+  switch (request->bmRequestType_bit.type) {
+    case TUSB_REQ_TYPE_STANDARD:
+      return handle_video_stm_std_req(rhport, stage, request, stm_idx);
+
+    case TUSB_REQ_TYPE_CLASS:
+      if (TU_U16_HIGH(request->wIndex)) return VIDEO_ERROR_INVALID_REQUEST;
+      return handle_video_stm_cs_req(rhport, stage, request, stm_idx);
+
+    default: return VIDEO_ERROR_INVALID_REQUEST;
+  }
+  return VIDEO_ERROR_UNKNOWN;
+}
+
+//--------------------------------------------------------------------+
+// APPLICATION API
+//--------------------------------------------------------------------+
+
+bool tud_video_n_connected(uint_fast8_t ctl_idx)
+{
+  TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
+  videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, 0);
+  if (stm) return true;
+  return false;
+}
+
+bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
+{
+  TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
+  TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
+  videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx);
+  if (!stm || !stm->desc.ep[0]) return false;
+  return true;
+}
+
+bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize)
+{
+  TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
+  TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
+  if (!buffer || !bufsize) return false;
+  videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx);
+  if (!stm || !stm->desc.ep[0] || stm->buffer) return false;
+
+  /* Find EP address */
+  void const *desc = _videod_itf[stm->index_vc].beg;
+  uint_fast8_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;
+    ep_addr = _desc_ep_addr(desc + ofs_ep);
+    break;
+  }
+  if (!ep_addr) return false;
+
+  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;
+  hdr->EndOfFrame = 0;
+  /* update the packet data */
+  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);
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void videod_init(void)
+{
+  for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) {
+    videod_interface_t* ctl = &_videod_itf[i];
+    tu_memclr(ctl, sizeof(*ctl));
+  }
+  for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
+    videod_streaming_interface_t *stm = &_videod_streaming_itf[i];
+    tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
+  }
+}
+
+void videod_reset(uint8_t rhport)
+{
+  (void) rhport;
+  for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) {
+    videod_interface_t* ctl = &_videod_itf[i];
+    tu_memclr(ctl, sizeof(*ctl));
+  }
+  for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
+    videod_streaming_interface_t *stm = &_videod_streaming_itf[i];
+    tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
+  }
+}
+
+uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
+{
+  TU_VERIFY((TUSB_CLASS_VIDEO       == itf_desc->bInterfaceClass) &&
+            (VIDEO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass) &&
+            (VIDEO_ITF_PROTOCOL_15  == itf_desc->bInterfaceProtocol), 0);
+
+  /* Find available interface */
+  videod_interface_t *self = NULL;
+  uint_fast8_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];
+    break;
+  }
+  TU_ASSERT(ctl_idx < CFG_TUD_VIDEO, 0);
+
+  void const *end = (void const*)itf_desc + max_len;
+  self->beg = itf_desc;
+  self->len = max_len;
+  /*------------- Video Control Interface -------------*/
+  TU_VERIFY(_open_vc_itf(rhport, self, 0), 0);
+  tusb_desc_vc_itf_t const *vc = _get_desc_vc(self);
+  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) {
+    videod_streaming_interface_t *stm = NULL;
+    /* find free streaming interface handle */
+    for (uint_fast8_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;
+      break;
+    }
+    TU_ASSERT(stm, 0);
+    stm->index_vc = ctl_idx;
+    stm->index_vs = stm_idx;
+    stm->desc.beg = (uintptr_t)cur - (uintptr_t)itf_desc;
+    cur = _next_desc_itf(cur, end);
+    stm->desc.end = (uintptr_t)cur - (uintptr_t)itf_desc;
+  }
+  self->len = (uintptr_t)cur - (uintptr_t)itf_desc;
+  return (uintptr_t)cur - (uintptr_t)itf_desc;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+  int err;
+  TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
+  uint_fast8_t itfnum = tu_u16_low(request->wIndex);
+
+  /* Identify which control interface to use */
+  uint_fast8_t itf;
+  for (itf = 0; itf < CFG_TUD_VIDEO; ++itf) {
+    void const *desc = _videod_itf[itf].beg;
+    if (!desc) continue;
+    if (itfnum == _desc_itfnum(desc)) break;
+  }
+
+  if (itf < CFG_TUD_VIDEO) {
+    err = handle_video_ctl_req(rhport, stage, request, itf);
+    _videod_itf[itf].error_code = (uint8_t)err;
+    if (err) return false;
+    return true;
+  }
+
+  /* Identify which streaming interface to use */
+  for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) {
+    videod_streaming_interface_t *stm = &_videod_streaming_itf[itf];
+    if (!stm->desc.beg) continue;
+    void const *desc = _videod_itf[stm->index_vc].beg;
+    if (itfnum == _desc_itfnum(desc + stm->desc.beg)) break;
+  }
+
+  if (itf < CFG_TUD_VIDEO_STREAMING) {
+    err = handle_video_stm_req(rhport, stage, request, itf);
+    _videod_streaming_itf[itf].error_code = (uint8_t)err;
+    if (err) return false;
+    return true;
+  }
+  return false;
+}
+
+bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void)result; (void)xferred_bytes;
+
+  /* find streaming handle */
+  uint_fast8_t itf;
+  videod_interface_t *ctl;
+  videod_streaming_interface_t *stm;
+  for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) {
+    stm = &_videod_streaming_itf[itf];
+    uint_fast16_t const ep_ofs = stm->desc.ep[0];
+    if (!ep_ofs) continue;
+    ctl = &_videod_itf[stm->index_vc];
+    void const *desc = ctl->beg;
+    if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break;
+  }
+
+  TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING);
+  if (stm->offset < stm->bufsize) {
+    /* 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);
+  } else {
+    stm->buffer  = NULL;
+    stm->bufsize = 0;
+    stm->offset  = 0;
+    if (tud_video_frame_xfer_complete_cb) {
+      tud_video_frame_xfer_complete_cb(stm->index_vc, stm->index_vs);
+    }
+  }
+  return true;
+}
+
+#endif
diff --git a/src/class/video/video_device.h b/src/class/video/video_device.h
new file mode 100644
index 0000000..ee2fcb9
--- /dev/null
+++ b/src/class/video/video_device.h
@@ -0,0 +1,97 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * 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.
+ */
+
+#ifndef TUSB_VIDEO_DEVICE_H_
+#define TUSB_VIDEO_DEVICE_H_
+
+#include "common/tusb_common.h"
+#include "video.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Application API (Multiple Ports)
+// CFG_TUD_VIDEO > 1
+//--------------------------------------------------------------------+
+
+/** Return true if streaming
+ *
+ * @param[in] ctl_idx    Destination control interface index
+ * @param[in] stm_idx    Destination streaming interface index */
+bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx);
+
+/** Transfer a frame
+ *
+ * @param[in] ctl_idx    Destination control interface index
+ * @param[in] stm_idx    Destination streaming interface index
+ * @param[in] buffer     Frame buffer. The caller must not use this buffer until the operation is completed.
+ * @param[in] bufsize    Byte size of the frame buffer */
+bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize);
+
+/*------------- Optional callbacks -------------*/
+/** Invoked when compeletion of a frame transfer
+ *
+ * @param[in] ctl_idx    Destination control interface index
+ * @param[in] stm_idx    Destination streaming interface index */
+TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx);
+
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+
+/** Invoked when SET_POWER_MODE request received
+ *
+ * @param[in] ctl_idx    Destination control interface index
+ * @param[in] stm_idx    Destination streaming interface index
+ * @return video_error_code_t */
+TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod);
+
+/** Invoked when VS_COMMIT_CONTROL(SET_CUR) request received
+ *
+ * @param[in] ctl_idx     Destination control interface index
+ * @param[in] stm_idx     Destination streaming interface index
+ * @param[in] parameters  Video streaming parameters
+ * @return video_error_code_t */
+TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
+                                     video_probe_and_commit_control_t const *parameters);
+
+//--------------------------------------------------------------------+
+// INTERNAL USBD-CLASS DRIVER API
+//--------------------------------------------------------------------+
+void     videod_init           (void);
+void     videod_reset          (uint8_t rhport);
+uint16_t videod_open           (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+bool     videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+bool     videod_xfer_cb        (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
new file mode 100644
index 0000000..9b9e2b0
--- /dev/null
+++ b/src/common/tusb_common.h
@@ -0,0 +1,406 @@
+/*
+ * 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.
+ */
+
+#ifndef _TUSB_COMMON_H_
+#define _TUSB_COMMON_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Macros Helper
+//--------------------------------------------------------------------+
+#define TU_ARRAY_SIZE(_arr)   ( sizeof(_arr) / sizeof(_arr[0]) )
+#define TU_MIN(_x, _y)        ( ( (_x) < (_y) ) ? (_x) : (_y) )
+#define TU_MAX(_x, _y)        ( ( (_x) > (_y) ) ? (_x) : (_y) )
+
+#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)
+#define U16_TO_U8S_LE(_u16)   TU_U16_LOW(_u16), TU_U16_HIGH(_u16)
+
+#define TU_U32_BYTE3(_u32)    ((uint8_t) ((((uint32_t) _u32) >> 24) & 0x000000ff)) // MSB
+#define TU_U32_BYTE2(_u32)    ((uint8_t) ((((uint32_t) _u32) >> 16) & 0x000000ff))
+#define TU_U32_BYTE1(_u32)    ((uint8_t) ((((uint32_t) _u32) >>  8) & 0x000000ff))
+#define TU_U32_BYTE0(_u32)    ((uint8_t) (((uint32_t)  _u32)        & 0x000000ff)) // LSB
+
+#define U32_TO_U8S_BE(_u32)   TU_U32_BYTE3(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE0(_u32)
+#define U32_TO_U8S_LE(_u32)   TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32)
+
+#define TU_BIT(n)             (1UL << (n))
+#define TU_GENMASK(h, l)      ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) )
+
+//--------------------------------------------------------------------+
+// Includes
+//--------------------------------------------------------------------+
+
+// Standard Headers
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+// Tinyusb Common Headers
+#include "tusb_option.h"
+#include "tusb_compiler.h"
+#include "tusb_verify.h"
+#include "tusb_types.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
+//--------------------------------------------------------------------+
+
+//------------- Mem -------------//
+#define tu_memclr(buffer, size)  memset((buffer), 0, (size))
+#define tu_varclr(_var)          tu_memclr(_var, sizeof(*(_var)))
+
+//------------- Bytes -------------//
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0)
+{
+  return ( ((uint32_t) b3) << 24) | ( ((uint32_t) b2) << 16) | ( ((uint32_t) b1) << 8) | b0;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low)
+{
+  return (uint16_t) ((((uint16_t) high) << 8) | low);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte3(uint32_t ui32) { return TU_U32_BYTE3(ui32); }
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte2(uint32_t ui32) { return TU_U32_BYTE2(ui32); }
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte1(uint32_t ui32) { return TU_U32_BYTE1(ui32); }
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte0(uint32_t ui32) { return TU_U32_BYTE0(ui32); }
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u32_high16(uint32_t ui32) { return (uint16_t) (ui32 >> 16); }
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u32_low16 (uint32_t ui32) { return (uint16_t) (ui32 & 0x0000ffffu); }
+
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u16_high(uint16_t ui16) { return TU_U16_HIGH(ui16); }
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u16_low (uint16_t ui16) { return TU_U16_LOW(ui16); }
+
+//------------- Bits -------------//
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_set  (uint32_t value, uint8_t pos) { return value | TU_BIT(pos);                  }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_clear(uint32_t value, uint8_t pos) { return value & (~TU_BIT(pos));               }
+TU_ATTR_ALWAYS_INLINE static inline bool     tu_bit_test (uint32_t value, uint8_t pos) { return (value & TU_BIT(pos)) ? true : false; }
+
+//------------- Min -------------//
+TU_ATTR_ALWAYS_INLINE static inline uint8_t  tu_min8  (uint8_t  x, uint8_t y ) { return (x < y) ? x : y; }
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_min16 (uint16_t x, uint16_t y) { return (x < y) ? x : y; }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_min32 (uint32_t x, uint32_t y) { return (x < y) ? x : y; }
+
+//------------- Max -------------//
+TU_ATTR_ALWAYS_INLINE static inline uint8_t  tu_max8  (uint8_t  x, uint8_t y ) { return (x > y) ? x : y; }
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_max16 (uint16_t x, uint16_t y) { return (x > y) ? x : y; }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; }
+
+//------------- Align -------------//
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment)
+{
+  return value & ((uint32_t) ~(alignment-1));
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
+
+//------------- 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)
+{
+  uint8_t result = 0;
+  while (value >>= 1) { result++; }
+  return result;
+}
+
+//------------- Unaligned Access -------------//
+#if TUP_ARCH_STRICT_ALIGN
+
+// Rely on compiler to generate correct code for unaligned access
+typedef struct { uint16_t val; } TU_ATTR_PACKED tu_unaligned_uint16_t;
+typedef struct { uint32_t val; } TU_ATTR_PACKED tu_unaligned_uint32_t;
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void* mem)
+{
+  tu_unaligned_uint32_t const* ua32 = (tu_unaligned_uint32_t const*) mem;
+  return ua32->val;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_t value)
+{
+  tu_unaligned_uint32_t* ua32 = (tu_unaligned_uint32_t*) mem;
+  ua32->val = value;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void* mem)
+{
+  tu_unaligned_uint16_t const* ua16 = (tu_unaligned_uint16_t const*) mem;
+  return ua16->val;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_t value)
+{
+  tu_unaligned_uint16_t* ua16 = (tu_unaligned_uint16_t*) mem;
+  ua16->val = value;
+}
+
+#elif TUP_MCU_STRICT_ALIGN
+
+// MCU such as LPC_IP3511 Highspeed cannot access unaligned memory on USB_RAM although it is ARM M4.
+// We have to manually pick up bytes since tu_unaligned_uint32_t will still generate unaligned code
+// NOTE: volatile cast to memory to prevent compiler to optimize and generate unaligned code
+// TODO Big Endian may need minor changes
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void* mem)
+{
+  volatile uint8_t const* buf8 = (uint8_t const*) mem;
+  return tu_u32(buf8[3], buf8[2], buf8[1], buf8[0]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_t value)
+{
+  volatile uint8_t* buf8 = (uint8_t*) mem;
+  buf8[0] = tu_u32_byte0(value);
+  buf8[1] = tu_u32_byte1(value);
+  buf8[2] = tu_u32_byte2(value);
+  buf8[3] = tu_u32_byte3(value);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void* mem)
+{
+  volatile uint8_t const* buf8 = (uint8_t const*) mem;
+  return tu_u16(buf8[1], buf8[0]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_t value)
+{
+  volatile uint8_t* buf8 = (uint8_t*) mem;
+  buf8[0] = tu_u16_low(value);
+  buf8[1] = tu_u16_high(value);
+}
+
+
+#else
+
+// MCU that could access unaligned memory natively
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32  (const void* mem) { return *((uint32_t const *) mem); }
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16  (const void* mem) { return *((uint16_t const *) mem); }
+
+TU_ATTR_ALWAYS_INLINE static inline void     tu_unaligned_write32 (void* mem, uint32_t value ) { *((uint32_t*) mem) = value; }
+TU_ATTR_ALWAYS_INLINE static inline void     tu_unaligned_write16 (void* mem, uint16_t value ) { *((uint16_t*) mem) = value; }
+
+#endif
+
+// To be removed
+//------------- Binary constant -------------//
+#if defined(__GNUC__) && !defined(__CC_ARM)
+
+#define TU_BIN8(x)               ((uint8_t)  (0b##x))
+#define TU_BIN16(b1, b2)         ((uint16_t) (0b##b1##b2))
+#define TU_BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4))
+
+#else
+
+//  internal macro of B8, B16, B32
+#define _B8__(x) (((x&0x0000000FUL)?1:0) \
+                +((x&0x000000F0UL)?2:0) \
+                +((x&0x00000F00UL)?4:0) \
+                +((x&0x0000F000UL)?8:0) \
+                +((x&0x000F0000UL)?16:0) \
+                +((x&0x00F00000UL)?32:0) \
+                +((x&0x0F000000UL)?64:0) \
+                +((x&0xF0000000UL)?128:0))
+
+#define TU_BIN8(d) ((uint8_t) _B8__(0x##d##UL))
+#define TU_BIN16(dmsb,dlsb) (((uint16_t)TU_BIN8(dmsb)<<8) + TU_BIN8(dlsb))
+#define TU_BIN32(dmsb,db2,db3,dlsb) \
+            (((uint32_t)TU_BIN8(dmsb)<<24) \
+            + ((uint32_t)TU_BIN8(db2)<<16) \
+            + ((uint32_t)TU_BIN8(db3)<<8) \
+            + 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
+
+#endif /* _TUSB_COMMON_H_ */
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
new file mode 100644
index 0000000..d3284c6
--- /dev/null
+++ b/src/common/tusb_compiler.h
@@ -0,0 +1,258 @@
+/* 
+ * 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_Compiler Compiler
+ *  \brief Group_Compiler brief
+ *  @{ */
+
+#ifndef _TUSB_COMPILER_H_
+#define _TUSB_COMPILER_H_
+
+#define TU_TOKEN(x)           x
+#define TU_STRING(x)          #x                  ///< stringify without expand
+#define TU_XSTRING(x)         TU_STRING(x)        ///< expand then stringify
+
+#define TU_STRCAT(a, b)       a##b                ///< concat without expand
+#define TU_STRCAT3(a, b, c)   a##b##c             ///< concat without expand
+
+#define TU_XSTRCAT(a, b)      TU_STRCAT(a, b)     ///< expand then concat
+#define TU_XSTRCAT3(a, b, c)  TU_STRCAT3(a, b, c) ///< expand then concat 3 tokens
+
+#define TU_INCLUDE_PATH(_dir,_file) TU_XSTRING( TU_TOKEN(_dir)TU_TOKEN(_file) )
+
+#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
+  #define _TU_COUNTER_ __COUNTER__
+#else
+  #define _TU_COUNTER_ __LINE__
+#endif
+
+// Compile-time Assert
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+  #define TU_VERIFY_STATIC   _Static_assert
+#elif defined (__cplusplus) && __cplusplus >= 201103L
+  #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
+  #define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) }
+#endif
+
+// for declaration of reserved field, make use of _TU_COUNTER_
+#define TU_RESERVED           TU_XSTRCAT(reserved, _TU_COUNTER_)
+
+#define TU_LITTLE_ENDIAN (0x12u)
+#define TU_BIG_ENDIAN (0x21u)
+
+/*------------------------------------------------------------------*/
+/* Count number of arguments of __VA_ARGS__
+ * - reference https://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments
+ * - _GET_NTH_ARG() takes args >= N (64) but only expand to Nth one (64th)
+ * - _RSEQ_N() is reverse sequential to N to add padding to have
+ * 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())
+
+#define _TU_NARG(...)      _GET_NTH_ARG(__VA_ARGS__)
+#define _GET_NTH_ARG( \
+          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
+         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
+         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
+         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
+         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
+         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
+         _61,_62,_63,N,...) N
+#define _RSEQ_N() \
+         62,61,60,                      \
+         59,58,57,56,55,54,53,52,51,50, \
+         49,48,47,46,45,44,43,42,41,40, \
+         39,38,37,36,35,34,33,32,31,30, \
+         29,28,27,26,25,24,23,22,21,20, \
+         19,18,17,16,15,14,13,12,11,10, \
+         9,8,7,6,5,4,3,2,1,0
+
+// Apply an macro X to each of the arguments with an separated of choice
+#define TU_ARGS_APPLY(_X, _s, ...)   TU_XSTRCAT(_TU_ARGS_APPLY_, TU_ARGS_NUM(__VA_ARGS__))(_X, _s, __VA_ARGS__)
+
+#define _TU_ARGS_APPLY_1(_X, _s, _a1)                                    _X(_a1)
+#define _TU_ARGS_APPLY_2(_X, _s, _a1, _a2)                               _X(_a1) _s _X(_a2)
+#define _TU_ARGS_APPLY_3(_X, _s, _a1, _a2, _a3)                          _X(_a1) _s _TU_ARGS_APPLY_2(_X, _s, _a2, _a3)
+#define _TU_ARGS_APPLY_4(_X, _s, _a1, _a2, _a3, _a4)                     _X(_a1) _s _TU_ARGS_APPLY_3(_X, _s, _a2, _a3, _a4)
+#define _TU_ARGS_APPLY_5(_X, _s, _a1, _a2, _a3, _a4, _a5)                _X(_a1) _s _TU_ARGS_APPLY_4(_X, _s, _a2, _a3, _a4, _a5)
+#define _TU_ARGS_APPLY_6(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6)           _X(_a1) _s _TU_ARGS_APPLY_5(_X, _s, _a2, _a3, _a4, _a5, _a6)
+#define _TU_ARGS_APPLY_7(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7)      _X(_a1) _s _TU_ARGS_APPLY_6(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7)
+#define _TU_ARGS_APPLY_8(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) _X(_a1) _s _TU_ARGS_APPLY_7(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7, _a8)
+
+//--------------------------------------------------------------------+
+// Compiler porting with Attribute and Endian
+//--------------------------------------------------------------------+
+
+// TODO refactor since __attribute__ is supported across many compiler
+#if defined(__GNUC__)
+  #define TU_ATTR_ALIGNED(Bytes)        __attribute__ ((aligned(Bytes)))
+  #define TU_ATTR_SECTION(sec_name)     __attribute__ ((section(#sec_name)))
+  #define TU_ATTR_PACKED                __attribute__ ((packed))
+  #define TU_ATTR_WEAK                  __attribute__ ((weak))
+  #define TU_ATTR_ALWAYS_INLINE         __attribute__ ((always_inline))
+  #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_PACKED_BEGIN
+  #define TU_ATTR_PACKED_END
+  #define TU_ATTR_BIT_FIELD_ORDER_BEGIN
+  #define TU_ATTR_BIT_FIELD_ORDER_END
+
+  // Endian conversion use well-known host to network (big endian) naming
+  #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+    #define TU_BYTE_ORDER TU_LITTLE_ENDIAN
+  #else
+    #define TU_BYTE_ORDER TU_BIG_ENDIAN
+  #endif
+
+  #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
+  #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
+
+  // List of obsolete callback function that is renamed and should not be defined.
+  // Put it here since only gcc support this pragma
+  #pragma GCC poison tud_vendor_control_request_cb
+
+#elif defined(__TI_COMPILER_VERSION__)
+  #define TU_ATTR_ALIGNED(Bytes)        __attribute__ ((aligned(Bytes)))
+  #define TU_ATTR_SECTION(sec_name)     __attribute__ ((section(#sec_name)))
+  #define TU_ATTR_PACKED                __attribute__ ((packed))
+  #define TU_ATTR_WEAK                  __attribute__ ((weak))
+  #define TU_ATTR_ALWAYS_INLINE         __attribute__ ((always_inline))
+  #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_PACKED_BEGIN
+  #define TU_ATTR_PACKED_END
+  #define TU_ATTR_BIT_FIELD_ORDER_BEGIN
+  #define TU_ATTR_BIT_FIELD_ORDER_END
+
+  // __BYTE_ORDER is defined in the TI ARM compiler, but not MSP430 (which is little endian)
+  #if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)) || defined(__MSP430__)
+    #define TU_BYTE_ORDER TU_LITTLE_ENDIAN
+  #else
+    #define TU_BYTE_ORDER TU_BIG_ENDIAN
+  #endif
+
+  #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
+  #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
+
+#elif defined(__ICCARM__)
+  #include <intrinsics.h>
+  #define TU_ATTR_ALIGNED(Bytes)        __attribute__ ((aligned(Bytes)))
+  #define TU_ATTR_SECTION(sec_name)     __attribute__ ((section(#sec_name)))
+  #define TU_ATTR_PACKED                __attribute__ ((packed))
+  #define TU_ATTR_WEAK                  __attribute__ ((weak))
+  #define TU_ATTR_ALWAYS_INLINE         __attribute__ ((always_inline))
+  #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_PACKED_BEGIN
+  #define TU_ATTR_PACKED_END
+  #define TU_ATTR_BIT_FIELD_ORDER_BEGIN
+  #define TU_ATTR_BIT_FIELD_ORDER_END
+
+  // Endian conversion use well-known host to network (big endian) naming
+  #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+    #define TU_BYTE_ORDER TU_LITTLE_ENDIAN
+  #else
+    #define TU_BYTE_ORDER TU_BIG_ENDIAN
+  #endif
+
+  #define TU_BSWAP16(u16) (__iar_builtin_REV16(u16))
+  #define TU_BSWAP32(u32) (__iar_builtin_REV(u32))
+
+#elif defined(__CCRX__)
+  #define TU_ATTR_ALIGNED(Bytes)
+  #define TU_ATTR_SECTION(sec_name)
+  #define TU_ATTR_PACKED
+  #define TU_ATTR_WEAK
+  #define TU_ATTR_ALWAYS_INLINE
+  #define TU_ATTR_DEPRECATED(mess)
+  #define TU_ATTR_UNUSED
+  #define TU_ATTR_USED
+
+  #define TU_ATTR_PACKED_BEGIN          _Pragma("pack")
+  #define TU_ATTR_PACKED_END            _Pragma("packoption")
+  #define TU_ATTR_BIT_FIELD_ORDER_BEGIN _Pragma("bit_order right")
+  #define TU_ATTR_BIT_FIELD_ORDER_END   _Pragma("bit_order")
+
+  // Endian conversion use well-known host to network (big endian) naming
+  #if defined(__LIT)
+    #define TU_BYTE_ORDER TU_LITTLE_ENDIAN
+  #else
+    #define TU_BYTE_ORDER TU_BIG_ENDIAN
+  #endif
+
+  #define TU_BSWAP16(u16) ((unsigned short)_builtin_revw((unsigned long)u16))
+  #define TU_BSWAP32(u32) (_builtin_revl(u32))
+
+#else 
+  #error "Compiler attribute porting is required"
+#endif
+
+#if (TU_BYTE_ORDER == TU_LITTLE_ENDIAN)
+
+  #define tu_htons(u16)  (TU_BSWAP16(u16))
+  #define tu_ntohs(u16)  (TU_BSWAP16(u16))
+
+  #define tu_htonl(u32)  (TU_BSWAP32(u32))
+  #define tu_ntohl(u32)  (TU_BSWAP32(u32))
+
+  #define tu_htole16(u16) (u16)
+  #define tu_le16toh(u16) (u16)
+
+  #define tu_htole32(u32) (u32)
+  #define tu_le32toh(u32) (u32)
+
+#elif (TU_BYTE_ORDER == TU_BIG_ENDIAN)
+
+  #define tu_htons(u16)  (u16)
+  #define tu_ntohs(u16)  (u16)
+
+  #define tu_htonl(u32)  (u32)
+  #define tu_ntohl(u32)  (u32)
+
+  #define tu_htole16(u16) (TU_BSWAP16(u16))
+  #define tu_le16toh(u16) (TU_BSWAP16(u16))
+
+  #define tu_htole32(u32) (TU_BSWAP32(u32))
+  #define tu_le32toh(u32) (TU_BSWAP32(u32))
+
+#else
+  #error Byte order is undefined
+#endif
+
+#endif /* _TUSB_COMPILER_H_ */
+
+/// @}
diff --git a/src/common/tusb_error.h b/src/common/tusb_error.h
new file mode 100644
index 0000000..d7ad8c3
--- /dev/null
+++ b/src/common/tusb_error.h
@@ -0,0 +1,75 @@
+/* 
+ * 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
new file mode 100644
index 0000000..564687e
--- /dev/null
+++ b/src/common/tusb_fifo.c
@@ -0,0 +1,1000 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers
+ *
+ * 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 "osal/osal.h"
+#include "tusb_fifo.h"
+
+// Supress IAR warning
+// Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
+#if defined(__ICCARM__)
+#pragma diag_suppress = Pa082
+#endif
+
+// implement mutex lock and unlock
+#if CFG_FIFO_MUTEX
+
+static inline void _ff_lock(tu_fifo_mutex_t mutex)
+{
+  if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+}
+
+static inline void _ff_unlock(tu_fifo_mutex_t mutex)
+{
+  if (mutex) osal_mutex_unlock(mutex);
+}
+
+#else
+
+#define _ff_lock(_mutex)
+#define _ff_unlock(_mutex)
+
+#endif
+
+/** \enum tu_fifo_copy_mode_t
+ * \brief Write modes intended to allow special read and write functions to be able to
+ *        copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others
+ */
+typedef enum
+{
+  TU_FIFO_COPY_INC,            ///< Copy from/to an increasing source/destination address - default mode
+  TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO
+} tu_fifo_copy_mode_t;
+
+bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable)
+{
+  if (depth > 0x8000) return false;               // Maximum depth is 2^15 items
+
+  _ff_lock(f->mutex_wr);
+  _ff_lock(f->mutex_rd);
+
+  f->buffer = (uint8_t*) buffer;
+  f->depth  = depth;
+  f->item_size = item_size;
+  f->overwritable = overwritable;
+
+  // 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->non_used_index_space = UINT16_MAX - f->max_pointer_idx;
+
+  f->rd_idx = f->wr_idx = 0;
+
+  _ff_unlock(f->mutex_wr);
+  _ff_unlock(f->mutex_rd);
+
+  return true;
+}
+
+// Static functions are intended to work on local variables
+static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth)
+{
+  while ( idx >= depth) idx -= depth;
+  return idx;
+}
+
+// Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address
+// Code adapted from dcd_synopsis.c
+// TODO generalize with configurable 1 byte or 4 byte each read
+static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len)
+{
+  volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf;
+
+  // Reading full available 32 bit words from const app address
+  uint16_t full_words = len >> 2;
+  while(full_words--)
+  {
+    tu_unaligned_write32(ff_buf, *rx_fifo);
+    ff_buf += 4;
+  }
+
+  // Read the remaining 1-3 bytes from const app address
+  uint8_t const bytes_rem = len & 0x03;
+  if ( bytes_rem )
+  {
+    uint32_t tmp32 = *rx_fifo;
+    memcpy(ff_buf, &tmp32, bytes_rem);
+  }
+}
+
+// Intended to be used to write to hardware USB FIFO in e.g. STM32
+// where all data is written to a constant address in full word copies
+static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len)
+{
+  volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf;
+
+  // Pushing full available 32 bit words to const app address
+  uint16_t full_words = len >> 2;
+  while(full_words--)
+  {
+    *tx_fifo = tu_unaligned_read32(ff_buf);
+    ff_buf += 4;
+  }
+
+  // Write the remaining 1-3 bytes into const app address
+  uint8_t const bytes_rem = len & 0x03;
+  if ( bytes_rem )
+  {
+    uint32_t tmp32 = 0;
+    memcpy(&tmp32, ff_buf, bytes_rem);
+
+    *tx_fifo = tmp32;
+  }
+}
+
+// send one item to FIFO WITHOUT updating write pointer
+static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel)
+{
+  memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size);
+}
+
+// send n items to FIFO WITHOUT updating write pointer
+static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode)
+{
+  uint16_t const nLin = f->depth - rel;
+  uint16_t const nWrap = n - nLin;
+
+  uint16_t nLin_bytes = nLin * f->item_size;
+  uint16_t nWrap_bytes = nWrap * f->item_size;
+
+  // current buffer of fifo
+  uint8_t* ff_buf = f->buffer + (rel * f->item_size);
+
+  switch (copy_mode)
+  {
+    case TU_FIFO_COPY_INC:
+      if(n <= nLin)
+      {
+        // Linear only
+        memcpy(ff_buf, app_buf, n*f->item_size);
+      }
+      else
+      {
+        // Wrap around
+
+        // Write data to linear part of buffer
+        memcpy(ff_buf, app_buf, nLin_bytes);
+
+        // Write data wrapped around
+        memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes);
+      }
+      break;
+
+    case TU_FIFO_COPY_CST_FULL_WORDS:
+      // Intended for hardware buffers from which it can be read word by word only
+      if(n <= nLin)
+      {
+        // Linear only
+        _ff_push_const_addr(ff_buf, app_buf, n*f->item_size);
+      }
+      else
+      {
+        // Wrap around case
+
+        // Write full words to linear part of buffer
+        uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC;
+        _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes);
+        ff_buf += nLin_4n_bytes;
+
+        // There could be odd 1-3 bytes before the wrap-around boundary
+        volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf;
+        uint8_t rem = nLin_bytes & 0x03;
+        if (rem > 0)
+        {
+          uint8_t remrem = tu_min16(nWrap_bytes, 4-rem);
+          nWrap_bytes -= remrem;
+
+          uint32_t tmp32 = *rx_fifo;
+          uint8_t * src_u8 = ((uint8_t *) &tmp32);
+
+          // Write 1-3 bytes before wrapped boundary
+          while(rem--) *ff_buf++ = *src_u8++;
+
+          // Read more bytes to beginning to complete a word
+          ff_buf = f->buffer;
+          while(remrem--) *ff_buf++ = *src_u8++;
+        }
+        else
+        {
+          ff_buf = f->buffer; // wrap around to beginning
+        }
+
+        // Write data wrapped part
+        if (nWrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, nWrap_bytes);
+      }
+      break;
+  }
+}
+
+// get one item from FIFO WITHOUT updating read pointer
+static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel)
+{
+  memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size);
+}
+
+// get n items from FIFO WITHOUT updating read pointer
+static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode)
+{
+  uint16_t const nLin = f->depth - rel;
+  uint16_t const nWrap = n - nLin; // only used if wrapped
+
+  uint16_t nLin_bytes = nLin * f->item_size;
+  uint16_t nWrap_bytes = nWrap * f->item_size;
+
+  // current buffer of fifo
+  uint8_t* ff_buf = f->buffer + (rel * f->item_size);
+
+  switch (copy_mode)
+  {
+    case TU_FIFO_COPY_INC:
+      if ( n <= nLin )
+      {
+        // Linear only
+        memcpy(app_buf, ff_buf, n*f->item_size);
+      }
+      else
+      {
+        // Wrap around
+
+        // Read data from linear part of buffer
+        memcpy(app_buf, ff_buf, nLin_bytes);
+
+        // Read data wrapped part
+        memcpy((uint8_t*) app_buf + nLin_bytes, f->buffer, nWrap_bytes);
+      }
+    break;
+
+    case TU_FIFO_COPY_CST_FULL_WORDS:
+      if ( n <= nLin )
+      {
+        // Linear only
+        _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size);
+      }
+      else
+      {
+        // Wrap around case
+
+        // Read full words from linear part of buffer
+        uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC;
+        _ff_pull_const_addr(app_buf, ff_buf, nLin_4n_bytes);
+        ff_buf += nLin_4n_bytes;
+
+        // There could be odd 1-3 bytes before the wrap-around boundary
+        volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf;
+        uint8_t rem = nLin_bytes & 0x03;
+        if (rem > 0)
+        {
+          uint8_t remrem = tu_min16(nWrap_bytes, 4-rem);
+          nWrap_bytes -= remrem;
+
+          uint32_t tmp32=0;
+          uint8_t * dst_u8 = (uint8_t *)&tmp32;
+
+          // Read 1-3 bytes before wrapped boundary
+          while(rem--) *dst_u8++ = *ff_buf++;
+
+          // Read more bytes from beginning to complete a word
+          ff_buf = f->buffer;
+          while(remrem--) *dst_u8++ = *ff_buf++;
+
+          *tx_fifo = tmp32;
+        }
+        else
+        {
+          ff_buf = f->buffer; // wrap around to beginning
+        }
+
+        // Read data wrapped part
+        if (nWrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, nWrap_bytes);
+      }
+    break;
+
+    default: break;
+  }
+}
+
+// Advance an absolute pointer
+static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
+{
+  // We limit the index space of p such that a correct wrap around happens
+  // Check for a wrap around or if we are in unused index space - This has to be checked first!!
+  // We are exploiting the wrap around to the correct index
+  if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx))
+  {
+    p = (p + offset) + f->non_used_index_space;
+  }
+  else
+  {
+    p += offset;
+  }
+  return p;
+}
+
+// Backward an absolute pointer
+static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
+{
+  // We limit the index space of p such that a correct wrap around happens
+  // Check for a wrap around or if we are in unused index space - This has to be checked first!!
+  // We are exploiting the wrap around to the correct index
+  if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx))
+  {
+    p = (p - offset) - f->non_used_index_space;
+  }
+  else
+  {
+    p -= offset;
+  }
+  return p;
+}
+
+// get relative from absolute pointer
+static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p)
+{
+  return _ff_mod(p, f->depth);
+}
+
+// Works on local copies of w and r - return only the difference and as such can be used to determine an overflow
+static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
+{
+  uint16_t cnt = wAbs-rAbs;
+
+  // In case we have non-power of two depth we need a further modification
+  if (rAbs > wAbs) cnt -= f->non_used_index_space;
+
+  return cnt;
+}
+
+// Works on local copies of w and r
+static inline bool _tu_fifo_empty(uint16_t wAbs, uint16_t rAbs)
+{
+  return wAbs == rAbs;
+}
+
+// Works on local copies of w and r
+static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
+{
+  return (_tu_fifo_count(f, wAbs, rAbs) == f->depth);
+}
+
+// Works on local copies of w and r
+// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS"
+// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not
+// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise
+// write pointer wraps and you pointer states are messed up. This can only happen if you
+// use DMAs, write functions do not allow such an error.
+static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
+{
+  return (_tu_fifo_count(f, wAbs, rAbs) > f->depth);
+}
+
+// Works on local copies of w
+// For more details see _tu_fifo_overflow()!
+static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs)
+{
+  f->rd_idx = backward_pointer(f, wAbs, f->depth);
+}
+
+// Works on local copies of w and r
+// Must be protected by mutexes since in case of an overflow read pointer gets modified
+static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wAbs, uint16_t rAbs)
+{
+  uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs);
+
+  // Check overflow and correct if required
+  if (cnt > f->depth)
+  {
+    _tu_fifo_correct_read_pointer(f, wAbs);
+    cnt = f->depth;
+  }
+
+  // Skip beginning of buffer
+  if (cnt == 0) return false;
+
+  uint16_t rRel = get_relative_pointer(f, rAbs);
+
+  // Peek data
+  _ff_pull(f, p_buffer, rRel);
+
+  return true;
+}
+
+// Works on local copies of w and r
+// Must be protected by mutexes since in case of an overflow read pointer gets modified
+static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode)
+{
+  uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs);
+
+  // Check overflow and correct if required
+  if (cnt > f->depth)
+  {
+    _tu_fifo_correct_read_pointer(f, wAbs);
+    rAbs = f->rd_idx;
+    cnt = f->depth;
+  }
+
+  // Skip beginning of buffer
+  if (cnt == 0) return 0;
+
+  // Check if we can read something at and after offset - if too less is available we read what remains
+  if (cnt < n) n = cnt;
+
+  uint16_t rRel = get_relative_pointer(f, rAbs);
+
+  // Peek data
+  _ff_pull_n(f, p_buffer, n, rRel, copy_mode);
+
+  return n;
+}
+
+// Works on local copies of w and r
+static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
+{
+  return f->depth - _tu_fifo_count(f, wAbs, rAbs);
+}
+
+static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode)
+{
+  if ( n == 0 ) return 0;
+
+  _ff_lock(f->mutex_wr);
+
+  uint16_t w = f->wr_idx, r = f->rd_idx;
+  uint8_t const* buf8 = (uint8_t const*) data;
+
+  if (!f->overwritable)
+  {
+    // Not overwritable limit up to full
+    n = tu_min16(n, _tu_fifo_remaining(f, w, r));
+  }
+  else if (n >= f->depth)
+  {
+    // Only copy last part
+    buf8 = buf8 + (n - f->depth) * f->item_size;
+    n = f->depth;
+
+    // We start writing at the read pointer's position since we fill the complete
+    // buffer and we do not want to modify the read pointer within a write function!
+    // This would end up in a race condition with read functions!
+    w = r;
+  }
+
+  uint16_t wRel = get_relative_pointer(f, w);
+
+  // Write data
+  _ff_push_n(f, buf8, n, wRel, copy_mode);
+
+  // Advance pointer
+  f->wr_idx = advance_pointer(f, w, n);
+
+  _ff_unlock(f->mutex_wr);
+
+  return n;
+}
+
+static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode)
+{
+  _ff_lock(f->mutex_rd);
+
+  // Peek the data
+  // f->rd_idx might get modified in case of an overflow so we can not use a local variable
+  n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode);
+
+  // Advance read pointer
+  f->rd_idx = advance_pointer(f, f->rd_idx, n);
+
+  _ff_unlock(f->mutex_rd);
+  return n;
+}
+
+/******************************************************************************/
+/*!
+    @brief Get number of items in FIFO.
+
+    As this function only reads the read and write pointers once, this function is
+    reentrant and thus thread and ISR save without any mutexes. In case an
+    overflow occurred, this function return f.depth at maximum. Overflows are
+    checked and corrected for in the read functions!
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+
+    @returns Number of items in FIFO
+ */
+/******************************************************************************/
+uint16_t tu_fifo_count(tu_fifo_t* f)
+{
+  return tu_min16(_tu_fifo_count(f, f->wr_idx, f->rd_idx), f->depth);
+}
+
+/******************************************************************************/
+/*!
+    @brief Check if FIFO is empty.
+
+    As this function only reads the read and write pointers once, this function is
+    reentrant and thus thread and ISR save without any mutexes.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+
+    @returns Number of items in FIFO
+ */
+/******************************************************************************/
+bool tu_fifo_empty(tu_fifo_t* f)
+{
+  return _tu_fifo_empty(f->wr_idx, f->rd_idx);
+}
+
+/******************************************************************************/
+/*!
+    @brief Check if FIFO is full.
+
+    As this function only reads the read and write pointers once, this function is
+    reentrant and thus thread and ISR save without any mutexes.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+
+    @returns Number of items in FIFO
+ */
+/******************************************************************************/
+bool tu_fifo_full(tu_fifo_t* f)
+{
+  return _tu_fifo_full(f, f->wr_idx, f->rd_idx);
+}
+
+/******************************************************************************/
+/*!
+    @brief Get remaining space in FIFO.
+
+    As this function only reads the read and write pointers once, this function is
+    reentrant and thus thread and ISR save without any mutexes.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+
+    @returns Number of items in FIFO
+ */
+/******************************************************************************/
+uint16_t tu_fifo_remaining(tu_fifo_t* f)
+{
+  return _tu_fifo_remaining(f, f->wr_idx, f->rd_idx);
+}
+
+/******************************************************************************/
+/*!
+    @brief Check if overflow happened.
+
+     BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS"
+     Only one overflow is allowed for this function to work e.g. if depth = 100, you must not
+     write more than 2*depth-1 items in one rush without updating write pointer. Otherwise
+     write pointer wraps and your pointer states are messed up. This can only happen if you
+     use DMAs, write functions do not allow such an error. Avoid such nasty things!
+
+     All reading functions (read, peek) check for overflows and correct read pointer on their own such
+     that latest items are read.
+     If required (e.g. for DMA use) you can also correct the read pointer by
+     tu_fifo_correct_read_pointer().
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+
+    @returns True if overflow happened
+ */
+/******************************************************************************/
+bool tu_fifo_overflowed(tu_fifo_t* f)
+{
+  return _tu_fifo_overflowed(f, f->wr_idx, f->rd_idx);
+}
+
+// Only use in case tu_fifo_overflow() returned true!
+void tu_fifo_correct_read_pointer(tu_fifo_t* f)
+{
+  _ff_lock(f->mutex_rd);
+  _tu_fifo_correct_read_pointer(f, f->wr_idx);
+  _ff_unlock(f->mutex_rd);
+}
+
+/******************************************************************************/
+/*!
+    @brief Read one element out of the buffer.
+
+    This function will return the element located at the array index of the
+    read pointer, and then increment the read pointer index.
+    This function checks for an overflow and corrects read pointer if required.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  buffer
+                Pointer to the place holder for data read from the buffer
+
+    @returns TRUE if the queue is not empty
+ */
+/******************************************************************************/
+bool tu_fifo_read(tu_fifo_t* f, void * buffer)
+{
+  _ff_lock(f->mutex_rd);
+
+  // Peek the data
+  // f->rd_idx might get modified in case of an overflow so we can not use a local variable
+  bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx);
+
+  // Advance pointer
+  f->rd_idx = advance_pointer(f, f->rd_idx, ret);
+
+  _ff_unlock(f->mutex_rd);
+  return ret;
+}
+
+/******************************************************************************/
+/*!
+    @brief This function will read n elements from the array index specified by
+    the read pointer and increment the read index.
+    This function checks for an overflow and corrects read pointer if required.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  buffer
+                The pointer to data location
+    @param[in]  n
+                Number of element that buffer can afford
+
+    @returns number of items read from the FIFO
+ */
+/******************************************************************************/
+uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n)
+{
+  return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC);
+}
+
+uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint16_t n)
+{
+  return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST_FULL_WORDS);
+}
+
+/******************************************************************************/
+/*!
+    @brief Read one item without removing it from the FIFO.
+    This function checks for an overflow and corrects read pointer if required.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  offset
+                Position to read from in the FIFO buffer with respect to read pointer
+    @param[in]  p_buffer
+                Pointer to the place holder for data read from the buffer
+
+    @returns TRUE if the queue is not empty
+ */
+/******************************************************************************/
+bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer)
+{
+  _ff_lock(f->mutex_rd);
+  bool ret = _tu_fifo_peek(f, p_buffer, f->wr_idx, f->rd_idx);
+  _ff_unlock(f->mutex_rd);
+  return ret;
+}
+
+/******************************************************************************/
+/*!
+    @brief Read n items without removing it from the FIFO
+    This function checks for an overflow and corrects read pointer if required.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  p_buffer
+                Pointer to the place holder for data read from the buffer
+    @param[in]  n
+                Number of items to peek
+
+    @returns Number of bytes written to 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);
+  _ff_unlock(f->mutex_rd);
+  return ret;
+}
+
+/******************************************************************************/
+/*!
+    @brief Write one element into the buffer.
+
+    This function will write one element into the array index specified by
+    the write pointer and increment the write index.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  data
+                The byte to add to the FIFO
+
+    @returns TRUE if the data was written to the FIFO (overwrittable
+             FIFO will always return TRUE)
+ */
+/******************************************************************************/
+bool tu_fifo_write(tu_fifo_t* f, const void * data)
+{
+  _ff_lock(f->mutex_wr);
+
+  uint16_t w = f->wr_idx;
+
+  if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable ) return false;
+
+  uint16_t wRel = get_relative_pointer(f, w);
+
+  // Write data
+  _ff_push(f, data, wRel);
+
+  // Advance pointer
+  f->wr_idx = advance_pointer(f, w, 1);
+
+  _ff_unlock(f->mutex_wr);
+
+  return true;
+}
+
+/******************************************************************************/
+/*!
+    @brief This function will write n elements into the array index specified by
+    the write pointer and increment the write index.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  data
+                The pointer to data to add to the FIFO
+    @param[in]  count
+                Number of element
+    @return Number of written elements
+ */
+/******************************************************************************/
+uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n)
+{
+  return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_INC);
+}
+
+/******************************************************************************/
+/*!
+    @brief This function will write n elements into the array index specified by
+    the write pointer and increment the write index. The source address will
+    not be incremented which is useful for reading from registers.
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  data
+                The pointer to data to add to the FIFO
+    @param[in]  count
+                Number of element
+    @return Number of written elements
+ */
+/******************************************************************************/
+uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data, uint16_t n)
+{
+  return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST_FULL_WORDS);
+}
+
+/******************************************************************************/
+/*!
+    @brief Clear the fifo read and write pointers
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+ */
+/******************************************************************************/
+bool tu_fifo_clear(tu_fifo_t *f)
+{
+  _ff_lock(f->mutex_wr);
+  _ff_lock(f->mutex_rd);
+
+  f->rd_idx = f->wr_idx = 0;
+  f->max_pointer_idx = 2*f->depth-1;
+  f->non_used_index_space = UINT16_MAX - f->max_pointer_idx;
+
+  _ff_unlock(f->mutex_wr);
+  _ff_unlock(f->mutex_rd);
+  return true;
+}
+
+/******************************************************************************/
+/*!
+    @brief Change the fifo mode to overwritable or not overwritable
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  overwritable
+                Overwritable mode the fifo is set to
+ */
+/******************************************************************************/
+bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable)
+{
+  _ff_lock(f->mutex_wr);
+  _ff_lock(f->mutex_rd);
+
+  f->overwritable = overwritable;
+
+  _ff_unlock(f->mutex_wr);
+  _ff_unlock(f->mutex_rd);
+
+  return true;
+}
+
+/******************************************************************************/
+/*!
+    @brief Advance write pointer - intended to be used in combination with DMA.
+    It is possible to fill the FIFO by use of a DMA in circular mode. Within
+    DMA ISRs you may update the write pointer to be able to read from the FIFO.
+    As long as the DMA is the only process writing into the FIFO this is safe
+    to use.
+
+    USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE!
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  n
+                Number of items the write pointer moves forward
+ */
+/******************************************************************************/
+void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n)
+{
+  f->wr_idx = advance_pointer(f, f->wr_idx, n);
+}
+
+/******************************************************************************/
+/*!
+    @brief Advance read pointer - intended to be used in combination with DMA.
+    It is possible to read from the FIFO by use of a DMA in linear mode. Within
+    DMA ISRs you may update the read pointer to be able to again write into the
+    FIFO. As long as the DMA is the only process reading from the FIFO this is
+    safe to use.
+
+    USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE!
+
+    @param[in]  f
+                Pointer to the FIFO buffer to manipulate
+    @param[in]  n
+                Number of items the read pointer moves forward
+ */
+/******************************************************************************/
+void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n)
+{
+  f->rd_idx = advance_pointer(f, f->rd_idx, n);
+}
+
+/******************************************************************************/
+/*!
+   @brief Get read info
+
+   Returns the length and pointer from which bytes can be read in a linear manner.
+   This is of major interest for DMA transmissions. If returned length is zero the
+   corresponding pointer is invalid.
+   The read pointer does NOT get advanced, use tu_fifo_advance_read_pointer() to
+   do so!
+   @param[in]       f
+                    Pointer to FIFO
+   @param[out]      *info
+                    Pointer to struct which holds the desired infos
+ */
+/******************************************************************************/
+void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
+{
+  // Operate on temporary values in case they change in between
+  uint16_t w = f->wr_idx, r = f->rd_idx;
+
+  uint16_t cnt = _tu_fifo_count(f, w, r);
+
+  // Check overflow and correct if required - may happen in case a DMA wrote too fast
+  if (cnt > f->depth)
+  {
+    _ff_lock(f->mutex_rd);
+    _tu_fifo_correct_read_pointer(f, w);
+    _ff_unlock(f->mutex_rd);
+    r = f->rd_idx;
+    cnt = f->depth;
+  }
+
+  // Check if fifo is empty
+  if (cnt == 0)
+  {
+    info->len_lin  = 0;
+    info->len_wrap = 0;
+    info->ptr_lin  = NULL;
+    info->ptr_wrap = NULL;
+    return;
+  }
+
+  // Get relative pointers
+  w = get_relative_pointer(f, w);
+  r = get_relative_pointer(f, r);
+
+  // Copy pointer to buffer to start reading from
+  info->ptr_lin = &f->buffer[r];
+
+  // Check if there is a wrap around necessary
+  if (w > r) {
+    // Non wrapping case
+    info->len_lin  = cnt;
+    info->len_wrap = 0;
+    info->ptr_wrap = NULL;
+  }
+  else
+  {
+    info->len_lin  = f->depth - r;         // Also the case if FIFO was full
+    info->len_wrap = cnt - info->len_lin;
+    info->ptr_wrap = f->buffer;
+  }
+}
+
+/******************************************************************************/
+/*!
+   @brief Get linear write info
+
+   Returns the length and pointer to which bytes can be written into FIFO in a linear manner.
+   This is of major interest for DMA transmissions not using circular mode. If a returned length is zero the
+   corresponding pointer is invalid. The returned lengths summed up are the currently free space in the FIFO.
+   The write pointer does NOT get advanced, use tu_fifo_advance_write_pointer() to do so!
+   TAKE CARE TO NOT OVERFLOW THE BUFFER MORE THAN TWO TIMES THE FIFO DEPTH - IT CAN NOT RECOVERE OTHERWISE!
+   @param[in]       f
+                    Pointer to FIFO
+   @param[out]      *info
+                    Pointer to struct which holds the desired infos
+ */
+/******************************************************************************/
+void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
+{
+  uint16_t w = f->wr_idx, r = f->rd_idx;
+  uint16_t free = _tu_fifo_remaining(f, w, r);
+
+  if (free == 0)
+  {
+    info->len_lin = 0;
+    info->len_wrap = 0;
+    info->ptr_lin = NULL;
+    info->ptr_wrap = NULL;
+    return;
+  }
+
+  // Get relative pointers
+  w = get_relative_pointer(f, w);
+  r = get_relative_pointer(f, r);
+
+  // Copy pointer to buffer to start writing to
+  info->ptr_lin = &f->buffer[w];
+
+  if (w < r)
+  {
+    // Non wrapping case
+    info->len_lin = r-w;
+    info->len_wrap = 0;
+    info->ptr_wrap = NULL;
+  }
+  else
+  {
+    info->len_lin = f->depth - w;
+    info->len_wrap = free - info->len_lin; // Remaining length - n already was limited to free or FIFO depth
+    info->ptr_wrap = f->buffer;            // Always start of buffer
+  }
+}
diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h
new file mode 100644
index 0000000..18db289
--- /dev/null
+++ b/src/common/tusb_fifo.h
@@ -0,0 +1,151 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers
+ *
+ * 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_FIFO_H_
+#define _TUSB_FIFO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Due to the use of unmasked pointers, this FIFO does not suffer from loosing
+// one item slice. Furthermore, write and read operations are completely
+// decoupled as write and read functions do not modify a common state. Henceforth,
+// writing or reading from the FIFO within an ISR is safe as long as no other
+// process (thread or ISR) interferes.
+// Also, this FIFO is ready to be used in combination with a DMA as the write and
+// read pointers can be updated from within a DMA ISR. Overflows are detectable
+// within a certain number (see tu_fifo_overflow()).
+
+#include "common/tusb_common.h"
+
+// mutex is only needed for RTOS
+// for OS None, we don't get preempted
+#define CFG_FIFO_MUTEX      (CFG_TUSB_OS != OPT_OS_NONE)
+
+#if CFG_FIFO_MUTEX
+#include "osal/osal.h"
+#define tu_fifo_mutex_t  osal_mutex_t
+#endif
+
+typedef struct
+{
+  uint8_t* buffer               ; ///< buffer pointer
+  uint16_t depth                ; ///< max items
+  uint16_t item_size            ; ///< size of each item
+  bool overwritable             ;
+
+  uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length
+  uint16_t max_pointer_idx      ; ///< maximum absolute pointer index
+
+  volatile uint16_t wr_idx      ; ///< write pointer
+  volatile uint16_t rd_idx      ; ///< read pointer
+
+#if CFG_FIFO_MUTEX
+  tu_fifo_mutex_t mutex_wr;
+  tu_fifo_mutex_t mutex_rd;
+#endif
+
+} tu_fifo_t;
+
+typedef struct
+{
+  uint16_t len_lin  ; ///< linear length in item size
+  uint16_t len_wrap ; ///< wrapped length in item size
+  void * ptr_lin    ; ///< linear part start pointer
+  void * ptr_wrap   ; ///< wrapped part start pointer
+} tu_fifo_buffer_info_t;
+
+#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \
+{                                                           \
+  .buffer               = _buffer,                          \
+  .depth                = _depth,                           \
+  .item_size            = sizeof(_type),                    \
+  .overwritable         = _overwritable,                    \
+  .non_used_index_space = UINT16_MAX - (2*(_depth)-1),      \
+  .max_pointer_idx      = 2*(_depth)-1,                     \
+}
+
+#define TU_FIFO_DEF(_name, _depth, _type, _overwritable)                      \
+    uint8_t _name##_buf[_depth*sizeof(_type)];                                \
+    tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable)
+
+
+bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable);
+bool tu_fifo_clear(tu_fifo_t *f);
+bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
+
+#if CFG_FIFO_MUTEX
+TU_ATTR_ALWAYS_INLINE static inline
+void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mutex_hdl, tu_fifo_mutex_t read_mutex_hdl)
+{
+  f->mutex_wr = write_mutex_hdl;
+  f->mutex_rd = read_mutex_hdl;
+}
+#endif
+
+bool     tu_fifo_write                  (tu_fifo_t* f, void const * p_data);
+uint16_t tu_fifo_write_n                (tu_fifo_t* f, void const * p_data, uint16_t n);
+uint16_t tu_fifo_write_n_const_addr_full_words    (tu_fifo_t* f, const void * data, uint16_t n);
+
+bool     tu_fifo_read                   (tu_fifo_t* f, void * p_buffer);
+uint16_t tu_fifo_read_n                 (tu_fifo_t* f, void * p_buffer, uint16_t n);
+uint16_t tu_fifo_read_n_const_addr_full_words     (tu_fifo_t* f, void * buffer, uint16_t n);
+
+bool     tu_fifo_peek                   (tu_fifo_t* f, void * p_buffer);
+uint16_t tu_fifo_peek_n                 (tu_fifo_t* f, void * p_buffer, uint16_t n);
+
+uint16_t tu_fifo_count                  (tu_fifo_t* f);
+uint16_t tu_fifo_remaining              (tu_fifo_t* f);
+bool     tu_fifo_empty                  (tu_fifo_t* f);
+bool     tu_fifo_full                   (tu_fifo_t* f);
+bool     tu_fifo_overflowed             (tu_fifo_t* f);
+void     tu_fifo_correct_read_pointer   (tu_fifo_t* f);
+
+TU_ATTR_ALWAYS_INLINE static inline
+uint16_t tu_fifo_depth(tu_fifo_t* f)
+{
+  return f->depth;
+}
+
+// Pointer modifications intended to be used in combinations with DMAs.
+// USE WITH CARE - NO SAFTY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED!
+void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n);
+void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n);
+
+// If you want to read/write from/to the FIFO by use of a DMA, you may need to conduct two copies
+// to handle a possible wrapping part. These functions deliver a pointer to start
+// reading/writing from/to and a valid linear length along which no wrap occurs.
+void tu_fifo_get_read_info (tu_fifo_t *f, tu_fifo_buffer_info_t *info);
+void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_FIFO_H_ */
diff --git a/src/common/tusb_timeout.h b/src/common/tusb_timeout.h
new file mode 100644
index 0000000..ce53955
--- /dev/null
+++ b/src/common/tusb_timeout.h
@@ -0,0 +1,80 @@
+/* 
+ * 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 Common Files
+ *  \defgroup Group_TimeoutTimer timeout timer
+ *  @{ */
+
+#ifndef _TUSB_TIMEOUT_H_
+#define _TUSB_TIMEOUT_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  uint32_t start;
+  uint32_t interval;
+}tu_timeout_t;
+
+#if 0
+
+extern uint32_t tusb_hal_millis(void);
+
+static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec)
+{
+  tt->interval = msec;
+  tt->start    = tusb_hal_millis();
+}
+
+static inline bool tu_timeout_expired(tu_timeout_t* tt)
+{
+  return ( tusb_hal_millis() - tt->start ) >= tt->interval;
+}
+
+// For used with periodic event to prevent drift
+static inline void tu_timeout_reset(tu_timeout_t* tt)
+{
+  tt->start += tt->interval;
+}
+
+static inline void tu_timeout_restart(tu_timeout_t* tt)
+{
+  tt->start = tusb_hal_millis();
+}
+
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_TIMEOUT_H_ */
+
+/** @} */
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
new file mode 100644
index 0000000..5b26f5a
--- /dev/null
+++ b/src/common/tusb_types.h
@@ -0,0 +1,546 @@
+/*
+ * 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_usb_definitions
+ *  \defgroup USBDef_Type USB Types
+ *  @{ */
+
+#ifndef _TUSB_TYPES_H_
+#define _TUSB_TYPES_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "tusb_compiler.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*------------------------------------------------------------------*/
+/* CONSTANTS
+ *------------------------------------------------------------------*/
+
+/// defined base on EHCI specs value for Endpoint Speed
+typedef enum
+{
+  TUSB_SPEED_FULL = 0,
+  TUSB_SPEED_LOW  = 1,
+  TUSB_SPEED_HIGH = 2,
+  TUSB_SPEED_INVALID = 0xff,
+}tusb_speed_t;
+
+/// defined base on USB Specs Endpoint's bmAttributes
+typedef enum
+{
+  TUSB_XFER_CONTROL = 0 ,
+  TUSB_XFER_ISOCHRONOUS ,
+  TUSB_XFER_BULK        ,
+  TUSB_XFER_INTERRUPT
+}tusb_xfer_type_t;
+
+typedef enum
+{
+  TUSB_DIR_OUT = 0,
+  TUSB_DIR_IN  = 1,
+
+  TUSB_DIR_IN_MASK = 0x80
+}tusb_dir_t;
+
+/// Isochronous End Point Attributes
+typedef enum
+{
+  TUSB_ISO_EP_ATT_NO_SYNC         = 0x00,
+  TUSB_ISO_EP_ATT_ASYNCHRONOUS    = 0x04,
+  TUSB_ISO_EP_ATT_ADAPTIVE        = 0x08,
+  TUSB_ISO_EP_ATT_SYNCHRONOUS     = 0x0C,
+  TUSB_ISO_EP_ATT_DATA            = 0x00, ///< Data End Point
+  TUSB_ISO_EP_ATT_EXPLICIT_FB     = 0x10, ///< Feedback End Point
+  TUSB_ISO_EP_ATT_IMPLICIT_FB     = 0x20, ///< Data endpoint that also serves as an implicit feedback
+}tusb_iso_ep_attribute_t;
+
+/// USB Descriptor Types
+typedef enum
+{
+  TUSB_DESC_DEVICE                = 0x01,
+  TUSB_DESC_CONFIGURATION         = 0x02,
+  TUSB_DESC_STRING                = 0x03,
+  TUSB_DESC_INTERFACE             = 0x04,
+  TUSB_DESC_ENDPOINT              = 0x05,
+  TUSB_DESC_DEVICE_QUALIFIER      = 0x06,
+  TUSB_DESC_OTHER_SPEED_CONFIG    = 0x07,
+  TUSB_DESC_INTERFACE_POWER       = 0x08,
+  TUSB_DESC_OTG                   = 0x09,
+  TUSB_DESC_DEBUG                 = 0x0A,
+  TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B,
+
+  TUSB_DESC_BOS                   = 0x0F,
+  TUSB_DESC_DEVICE_CAPABILITY     = 0x10,
+
+  TUSB_DESC_FUNCTIONAL            = 0x21,
+
+  // Class Specific Descriptor
+  TUSB_DESC_CS_DEVICE             = 0x21,
+  TUSB_DESC_CS_CONFIGURATION      = 0x22,
+  TUSB_DESC_CS_STRING             = 0x23,
+  TUSB_DESC_CS_INTERFACE          = 0x24,
+  TUSB_DESC_CS_ENDPOINT           = 0x25,
+
+  TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION     = 0x30,
+  TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31
+}tusb_desc_type_t;
+
+typedef enum
+{
+  TUSB_REQ_GET_STATUS        = 0  ,
+  TUSB_REQ_CLEAR_FEATURE     = 1  ,
+  TUSB_REQ_RESERVED          = 2  ,
+  TUSB_REQ_SET_FEATURE       = 3  ,
+  TUSB_REQ_RESERVED2         = 4  ,
+  TUSB_REQ_SET_ADDRESS       = 5  ,
+  TUSB_REQ_GET_DESCRIPTOR    = 6  ,
+  TUSB_REQ_SET_DESCRIPTOR    = 7  ,
+  TUSB_REQ_GET_CONFIGURATION = 8  ,
+  TUSB_REQ_SET_CONFIGURATION = 9  ,
+  TUSB_REQ_GET_INTERFACE     = 10 ,
+  TUSB_REQ_SET_INTERFACE     = 11 ,
+  TUSB_REQ_SYNCH_FRAME       = 12
+}tusb_request_code_t;
+
+typedef enum
+{
+  TUSB_REQ_FEATURE_EDPT_HALT     = 0,
+  TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1,
+  TUSB_REQ_FEATURE_TEST_MODE     = 2
+}tusb_request_feature_selector_t;
+
+typedef enum
+{
+  TUSB_REQ_TYPE_STANDARD = 0,
+  TUSB_REQ_TYPE_CLASS,
+  TUSB_REQ_TYPE_VENDOR,
+  TUSB_REQ_TYPE_INVALID
+} tusb_request_type_t;
+
+typedef enum
+{
+  TUSB_REQ_RCPT_DEVICE =0,
+  TUSB_REQ_RCPT_INTERFACE,
+  TUSB_REQ_RCPT_ENDPOINT,
+  TUSB_REQ_RCPT_OTHER
+} tusb_request_recipient_t;
+
+// https://www.usb.org/defined-class-codes
+typedef enum
+{
+  TUSB_CLASS_UNSPECIFIED          = 0    ,
+  TUSB_CLASS_AUDIO                = 1    ,
+  TUSB_CLASS_CDC                  = 2    ,
+  TUSB_CLASS_HID                  = 3    ,
+  TUSB_CLASS_RESERVED_4           = 4    ,
+  TUSB_CLASS_PHYSICAL             = 5    ,
+  TUSB_CLASS_IMAGE                = 6    ,
+  TUSB_CLASS_PRINTER              = 7    ,
+  TUSB_CLASS_MSC                  = 8    ,
+  TUSB_CLASS_HUB                  = 9    ,
+  TUSB_CLASS_CDC_DATA             = 10   ,
+  TUSB_CLASS_SMART_CARD           = 11   ,
+  TUSB_CLASS_RESERVED_12          = 12   ,
+  TUSB_CLASS_CONTENT_SECURITY     = 13   ,
+  TUSB_CLASS_VIDEO                = 14   ,
+  TUSB_CLASS_PERSONAL_HEALTHCARE  = 15   ,
+  TUSB_CLASS_AUDIO_VIDEO          = 16   ,
+
+  TUSB_CLASS_DIAGNOSTIC           = 0xDC ,
+  TUSB_CLASS_WIRELESS_CONTROLLER  = 0xE0 ,
+  TUSB_CLASS_MISC                 = 0xEF ,
+  TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE ,
+  TUSB_CLASS_VENDOR_SPECIFIC      = 0xFF
+}tusb_class_code_t;
+
+typedef enum
+{
+  MISC_SUBCLASS_COMMON = 2
+}misc_subclass_type_t;
+
+typedef enum
+{
+  MISC_PROTOCOL_IAD = 1
+}misc_protocol_type_t;
+
+typedef enum
+{
+  APP_SUBCLASS_USBTMC = 0x03,
+  APP_SUBCLASS_DFU_RUNTIME = 0x01
+} app_subclass_type_t;
+
+typedef enum
+{
+  DEVICE_CAPABILITY_WIRELESS_USB               = 0x01,
+  DEVICE_CAPABILITY_USB20_EXTENSION            = 0x02,
+  DEVICE_CAPABILITY_SUPERSPEED_USB             = 0x03,
+  DEVICE_CAPABILITY_CONTAINER_id               = 0x04,
+  DEVICE_CAPABILITY_PLATFORM                   = 0x05,
+  DEVICE_CAPABILITY_POWER_DELIVERY             = 0x06,
+  DEVICE_CAPABILITY_BATTERY_INFO               = 0x07,
+  DEVICE_CAPABILITY_PD_CONSUMER_PORT           = 0x08,
+  DEVICE_CAPABILITY_PD_PROVIDER_PORT           = 0x09,
+  DEVICE_CAPABILITY_SUPERSPEED_PLUS            = 0x0A,
+  DEVICE_CAPABILITY_PRECESION_TIME_MEASUREMENT = 0x0B,
+  DEVICE_CAPABILITY_WIRELESS_USB_EXT           = 0x0C,
+  DEVICE_CAPABILITY_BILLBOARD                  = 0x0D,
+  DEVICE_CAPABILITY_AUTHENTICATION             = 0x0E,
+  DEVICE_CAPABILITY_BILLBOARD_EX               = 0x0F,
+  DEVICE_CAPABILITY_CONFIGURATION_SUMMARY      = 0x10
+}device_capability_type_t;
+
+enum {
+  TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5),
+  TUSB_DESC_CONFIG_ATT_SELF_POWERED  = TU_BIT(6),
+};
+
+#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_t;
+
+enum // TODO remove
+{
+  DESC_OFFSET_LEN  = 0,
+  DESC_OFFSET_TYPE = 1
+};
+
+enum
+{
+  INTERFACE_INVALID_NUMBER = 0xff
+};
+
+
+typedef enum
+{
+  MS_OS_20_SET_HEADER_DESCRIPTOR       = 0x00,
+  MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01,
+  MS_OS_20_SUBSET_HEADER_FUNCTION      = 0x02,
+  MS_OS_20_FEATURE_COMPATBLE_ID        = 0x03,
+  MS_OS_20_FEATURE_REG_PROPERTY        = 0x04,
+  MS_OS_20_FEATURE_MIN_RESUME_TIME     = 0x05,
+  MS_OS_20_FEATURE_MODEL_ID            = 0x06,
+  MS_OS_20_FEATURE_CCGP_DEVICE         = 0x07,
+  MS_OS_20_FEATURE_VENDOR_REVISION     = 0x08
+} microsoft_os_20_type_t;
+
+enum
+{
+  CONTROL_STAGE_SETUP,
+  CONTROL_STAGE_DATA,
+  CONTROL_STAGE_ACK
+};
+
+//--------------------------------------------------------------------+
+// USB Descriptors
+//--------------------------------------------------------------------+
+
+// Start of all packed definitions for compiler without per-type packed
+TU_ATTR_PACKED_BEGIN
+TU_ATTR_BIT_FIELD_ORDER_BEGIN
+
+/// USB Device Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t  bDescriptorType    ; ///< DEVICE Descriptor Type.
+  uint16_t bcdUSB             ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant.
+
+  uint8_t  bDeviceClass       ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific.
+  uint8_t  bDeviceSubClass    ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
+  uint8_t  bDeviceProtocol    ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis.
+  uint8_t  bMaxPacketSize0    ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
+
+  uint16_t idVendor           ; ///< Vendor ID (assigned by the USB-IF).
+  uint16_t idProduct          ; ///< Product ID (assigned by the manufacturer).
+  uint16_t bcdDevice          ; ///< Device release number in binary-coded decimal.
+  uint8_t  iManufacturer      ; ///< Index of string descriptor describing manufacturer.
+  uint8_t  iProduct           ; ///< Index of string descriptor describing product.
+  uint8_t  iSerialNumber      ; ///< Index of string descriptor describing the device's serial number.
+
+  uint8_t  bNumConfigurations ; ///< Number of possible configurations.
+} tusb_desc_device_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct");
+
+// USB Binary Device Object Store (BOS) Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength         ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType ; ///< CONFIGURATION Descriptor Type
+  uint16_t wTotalLength    ; ///< Total length of data returned for this descriptor
+  uint8_t  bNumDeviceCaps  ; ///< Number of device capability descriptors in the BOS
+} tusb_desc_bos_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5, "size is not correct");
+
+/// USB Configuration Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength             ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType     ; ///< CONFIGURATION Descriptor Type
+  uint16_t wTotalLength        ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration.
+
+  uint8_t  bNumInterfaces      ; ///< Number of interfaces supported by this configuration
+  uint8_t  bConfigurationValue ; ///< Value to use as an argument to the SetConfiguration() request to select this configuration.
+  uint8_t  iConfiguration      ; ///< Index of string descriptor describing this configuration
+  uint8_t  bmAttributes        ; ///< Configuration characteristics \n D7: Reserved (set to one)\n D6: Self-powered \n D5: Remote Wakeup \n D4...0: Reserved (reset to zero) \n D7 is reserved and must be set to one for historical reasons. \n A device configuration that uses power from the bus and a local source reports a non-zero value in bMaxPower to indicate the amount of bus power required and sets D6. The actual power source at runtime may be determined using the GetStatus(DEVICE) request (see USB 2.0 spec Section 9.4.5). \n If a device configuration supports remote wakeup, D5 is set to one.
+  uint8_t  bMaxPower           ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA).
+} tusb_desc_configuration_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9, "size is not correct");
+
+/// USB Interface Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength            ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType    ; ///< INTERFACE Descriptor Type
+
+  uint8_t  bInterfaceNumber   ; ///< Number of this interface. Zero-based value identifying the index in the array of concurrent interfaces supported by this configuration.
+  uint8_t  bAlternateSetting  ; ///< Value used to select this alternate setting for the interface identified in the prior field
+  uint8_t  bNumEndpoints      ; ///< Number of endpoints used by this interface (excluding endpoint zero). If this value is zero, this interface only uses the Default Control Pipe.
+  uint8_t  bInterfaceClass    ; ///< Class code (assigned by the USB-IF). \li A value of zero is reserved for future standardization. \li If this field is set to FFH, the interface class is vendor-specific. \li All other values are reserved for assignment by the USB-IF.
+  uint8_t  bInterfaceSubClass ; ///< Subclass code (assigned by the USB-IF). \n These codes are qualified by the value of the bInterfaceClass field. \li If the bInterfaceClass field is reset to zero, this field must also be reset to zero. \li If the bInterfaceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
+  uint8_t  bInterfaceProtocol ; ///< Protocol code (assigned by the USB). \n These codes are qualified by the value of the bInterfaceClass and the bInterfaceSubClass fields. If an interface supports class-specific requests, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use a class-specific protocol on this interface. \li If this field is set to FFH, the device uses a vendor-specific protocol for this interface.
+  uint8_t  iInterface         ; ///< Index of string descriptor describing this interface
+} tusb_desc_interface_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9, "size is not correct");
+
+/// USB Endpoint Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength          ; // Size of this descriptor in bytes
+  uint8_t  bDescriptorType  ; // ENDPOINT Descriptor Type
+
+  uint8_t  bEndpointAddress ; // The address of the endpoint
+
+  struct TU_ATTR_PACKED {
+    uint8_t xfer  : 2;        // Control, ISO, Bulk, Interrupt
+    uint8_t sync  : 2;        // None, Asynchronous, Adaptive, Synchronous
+    uint8_t usage : 2;        // Data, Feedback, Implicit feedback
+    uint8_t       : 2;
+  } bmAttributes;
+
+  uint16_t wMaxPacketSize   ; // Bit 10..0 : max packet size, bit 12..11 additional transaction per highspeed micro-frame
+  uint8_t  bInterval        ; // Polling interval, in frames or microframes depending on the operating speed
+} tusb_desc_endpoint_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct");
+
+/// USB Other Speed Configuration Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength             ; ///< Size of descriptor
+  uint8_t  bDescriptorType     ; ///< Other_speed_Configuration Type
+  uint16_t wTotalLength        ; ///< Total length of data returned
+
+  uint8_t  bNumInterfaces      ; ///< Number of interfaces supported by this speed configuration
+  uint8_t  bConfigurationValue ; ///< Value to use to select configuration
+  uint8_t  iConfiguration      ; ///< Index of string descriptor
+  uint8_t  bmAttributes        ; ///< Same as Configuration descriptor
+  uint8_t  bMaxPower           ; ///< Same as Configuration descriptor
+} tusb_desc_other_speed_t;
+
+/// USB Device Qualifier Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength            ; ///< Size of descriptor
+  uint8_t  bDescriptorType    ; ///< Device Qualifier Type
+  uint16_t bcdUSB             ; ///< USB specification version number (e.g., 0200H for V2.00)
+
+  uint8_t  bDeviceClass       ; ///< Class Code
+  uint8_t  bDeviceSubClass    ; ///< SubClass Code
+  uint8_t  bDeviceProtocol    ; ///< Protocol Code
+
+  uint8_t  bMaxPacketSize0    ; ///< Maximum packet size for other speed
+  uint8_t  bNumConfigurations ; ///< Number of Other-speed Configurations
+  uint8_t  bReserved          ; ///< Reserved for future use, must be zero
+} tusb_desc_device_qualifier_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct");
+
+/// USB Interface Association Descriptor (IAD ECN)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength           ; ///< Size of descriptor
+  uint8_t bDescriptorType   ; ///< Other_speed_Configuration Type
+
+  uint8_t bFirstInterface   ; ///< Index of the first associated interface.
+  uint8_t bInterfaceCount   ; ///< Total number of associated interfaces.
+
+  uint8_t bFunctionClass    ; ///< Interface class ID.
+  uint8_t bFunctionSubClass ; ///< Interface subclass ID.
+  uint8_t bFunctionProtocol ; ///< Interface protocol ID.
+
+  uint8_t iFunction         ; ///< Index of the string descriptor describing the interface association.
+} tusb_desc_interface_assoc_t;
+
+// USB String Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength         ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType ; ///< Descriptor Type
+  uint16_t unicode_string[];
+} tusb_desc_string_t;
+
+// USB Binary Device Object Store (BOS)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength;
+  uint8_t bDescriptorType ;
+  uint8_t bDevCapabilityType;
+  uint8_t bReserved;
+  uint8_t PlatformCapabilityUUID[16];
+  uint8_t CapabilityData[];
+} tusb_desc_bos_platform_t;
+
+// USB WebuSB URL Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength;
+  uint8_t bDescriptorType;
+  uint8_t bScheme;
+  char    url[];
+} tusb_desc_webusb_url_t;
+
+// DFU Functional Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength;
+  uint8_t  bDescriptorType;
+
+  union {
+    struct TU_ATTR_PACKED {
+      uint8_t bitCanDnload             : 1;
+      uint8_t bitCanUpload             : 1;
+      uint8_t bitManifestationTolerant : 1;
+      uint8_t bitWillDetach            : 1;
+      uint8_t reserved                 : 4;
+    } bmAttributes;
+
+    uint8_t bAttributes;
+  };
+
+  uint16_t wDetachTimeOut;
+  uint16_t wTransferSize;
+  uint16_t bcdDFUVersion;
+} tusb_desc_dfu_functional_t;
+
+/*------------------------------------------------------------------*/
+/* Types
+ *------------------------------------------------------------------*/
+typedef struct TU_ATTR_PACKED{
+  union {
+    struct TU_ATTR_PACKED {
+      uint8_t recipient :  5; ///< Recipient type tusb_request_recipient_t.
+      uint8_t type      :  2; ///< Request type tusb_request_type_t.
+      uint8_t direction :  1; ///< Direction type. tusb_dir_t
+    } bmRequestType_bit;
+
+    uint8_t bmRequestType;
+  };
+
+  uint8_t  bRequest;
+  uint16_t wValue;
+  uint16_t wIndex;
+  uint16_t wLength;
+} tusb_control_request_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct");
+
+
+TU_ATTR_PACKED_END  // End of all packed definitions
+TU_ATTR_BIT_FIELD_ORDER_END
+
+//--------------------------------------------------------------------+
+// Endpoint helper
+//--------------------------------------------------------------------+
+
+// Get direction from Endpoint address
+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)
+{
+  return (uint8_t)(addr & (~TUSB_DIR_IN_MASK));
+}
+
+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)
+{
+  return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0);
+}
+
+//--------------------------------------------------------------------+
+// Descriptor helper
+//--------------------------------------------------------------------+
+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)
+{
+  return ((uint8_t const*) desc)[DESC_OFFSET_TYPE];
+}
+
+static inline uint8_t tu_desc_len(void const* desc)
+{
+  return ((uint8_t const*) desc)[DESC_OFFSET_LEN];
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_TYPES_H_ */
+
+/** @} */
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
new file mode 100644
index 0000000..56ba8bc
--- /dev/null
+++ b/src/common/tusb_verify.h
@@ -0,0 +1,181 @@
+/* 
+ * 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.
+ */
+#ifndef TUSB_VERIFY_H_
+#define TUSB_VERIFY_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "tusb_option.h"
+#include "tusb_compiler.h"
+
+/*------------------------------------------------------------------*/
+/* This file use an advanced macro technique to mimic the default parameter
+ * as C++ for the sake of code simplicity. Beware of a headache macro
+ * 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
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TU_VERIFY Helper
+//--------------------------------------------------------------------+
+
+#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__)
+  #define TU_BREAKPOINT() do                                                                                \
+  {                                                                                                         \
+    volatile uint32_t* ARM_CM_DHCSR =  ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
+    if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */            \
+  } while(0)
+
+#elif defined(__riscv)
+  #define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0)
+
+#else
+  #define TU_BREAKPOINT() do {} while (0)
+#endif
+
+/*------------------------------------------------------------------*/
+/* Macro Generator
+ *------------------------------------------------------------------*/
+
+// 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
+
+/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/
+#define TU_VERIFY_DEFINE(_cond, _handler, _ret)  do            \
+{                                                              \
+  if ( !(_cond) ) { _handler; return _ret;  }                  \
+} while(0)
+
+/*------------------------------------------------------------------*/
+/* TU_VERIFY
+ * - TU_VERIFY_1ARGS : return false if failed
+ * - TU_VERIFY_2ARGS : return provided value if failed
+ *------------------------------------------------------------------*/
+#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__)
+
+
+/*------------------------------------------------------------------*/
+/* TU_VERIFY WITH HANDLER
+ * - TU_VERIFY_HDLR_2ARGS : execute handler, return false if failed
+ * - TU_VERIFY_HDLR_3ARGS : execute handler, return provided error if failed
+ *------------------------------------------------------------------*/
+#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__)
+
+/*------------------------------------------------------------------*/
+/* ASSERT
+ * basically TU_VERIFY with TU_BREAKPOINT() as handler
+ * - 1 arg : return false if failed
+ * - 2 arg : return error if failed
+ *------------------------------------------------------------------*/
+#define ASSERT_1ARGS(_cond)            TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), false)
+#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__)
+#endif
+
+/*------------------------------------------------------------------*/
+/* ASSERT HDLR
+ *------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* TUSB_VERIFY_H_ */
diff --git a/src/device/dcd.h b/src/device/dcd.h
new file mode 100644
index 0000000..c042cc7
--- /dev/null
+++ b/src/device/dcd.h
@@ -0,0 +1,193 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_DCD_H_
+#define _TUSB_DCD_H_
+
+#include "common/tusb_common.h"
+#include "osal/osal.h"
+#include "common/tusb_fifo.h"
+#include "dcd_attr.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Configuration
+//--------------------------------------------------------------------+
+
+#ifndef CFG_TUD_ENDPPOINT_MAX
+  #define CFG_TUD_ENDPPOINT_MAX   DCD_ATTR_ENDPOINT_MAX
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+typedef enum
+{
+  DCD_EVENT_INVALID = 0,
+  DCD_EVENT_BUS_RESET,
+  DCD_EVENT_UNPLUGGED,
+  DCD_EVENT_SOF,
+  DCD_EVENT_SUSPEND, // TODO LPM Sleep L1 support
+  DCD_EVENT_RESUME,
+
+  DCD_EVENT_SETUP_RECEIVED,
+  DCD_EVENT_XFER_COMPLETE,
+
+  // Not an DCD event, just a convenient way to defer ISR function
+  USBD_EVENT_FUNC_CALL,
+
+  DCD_EVENT_COUNT
+} dcd_eventid_t;
+
+typedef struct TU_ATTR_ALIGNED(4)
+{
+  uint8_t rhport;
+  uint8_t event_id;
+
+  union
+  {
+    // BUS RESET
+    struct {
+      tusb_speed_t speed;
+    } bus_reset;
+
+    // SETUP_RECEIVED
+    tusb_control_request_t setup_received;
+
+    // XFER_COMPLETE
+    struct {
+      uint8_t  ep_addr;
+      uint8_t  result;
+      uint32_t len;
+    }xfer_complete;
+
+    // FUNC_CALL
+    struct {
+      void (*func) (void*);
+      void* param;
+    }func_call;
+  };
+} dcd_event_t;
+
+//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+// Initialize controller to device mode
+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);
+
+// Disable device interrupt
+void dcd_int_disable(uint8_t rhport);
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr);
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport);
+
+// Connect by enabling internal pull-up resistor on D+/D-
+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;
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK;
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open            (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep);
+
+// Close all non-control endpoints, cancel all pending transfers if any.
+// Invoked when switching from a non-zero Configuration by SET_CONFIGURE therefore
+// required for multiple configuration support.
+void dcd_edpt_close_all       (uint8_t rhport);
+
+// Close an endpoint.
+// Since it is weak, caller must TU_ASSERT this function's existence before calling it.
+void dcd_edpt_close           (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK;
+
+// 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);
+
+// Submit an transfer using fifo, When complete dcd_event_xfer_complete() is invoked to notify the stack
+// This API is optional, may be useful for register-based for transferring data.
+bool dcd_edpt_xfer_fifo       (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) TU_ATTR_WEAK;
+
+// Stall endpoint, any queuing transfer should be removed from endpoint
+void dcd_edpt_stall           (uint8_t rhport, uint8_t ep_addr);
+
+// clear stall, data toggle is also reset to DATA0
+// This API never calls with control endpoints, since it is auto cleared when receiving setup packet
+void dcd_edpt_clear_stall     (uint8_t rhport, uint8_t ep_addr);
+
+//--------------------------------------------------------------------+
+// Event API (implemented by stack)
+//--------------------------------------------------------------------+
+
+// Called by DCD to notify device stack
+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);
+
+// helper to send bus reset event
+extern void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr);
+
+// helper to send setup received
+extern void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool 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);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_DCD_H_ */
diff --git a/src/device/dcd_attr.h b/src/device/dcd_attr.h
new file mode 100644
index 0000000..3c5dada
--- /dev/null
+++ b/src/device/dcd_attr.h
@@ -0,0 +1,210 @@
+/*
+ * 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_CONTROLLER_CHIPIDEA_HS
+  #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_CONTROLLER_CHIPIDEA_HS
+  #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
new file mode 100644
index 0000000..6a5210b
--- /dev/null
+++ b/src/device/usbd.c
@@ -0,0 +1,1419 @@
+/*
+ * 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 TUSB_OPT_DEVICE_ENABLED
+
+#include "tusb.h"
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// USBD Configuration
+//--------------------------------------------------------------------+
+
+// Debug level of USBD
+#define USBD_DBG   2
+
+#ifndef CFG_TUD_TASK_QUEUE_SZ
+  #define CFG_TUD_TASK_QUEUE_SZ   16
+#endif
+
+//--------------------------------------------------------------------+
+// Device Data
+//--------------------------------------------------------------------+
+
+// Invalid driver ID in itf2drv[] ep2drv[][] mapping
+enum { DRVID_INVALID = 0xFFu };
+
+typedef struct
+{
+  struct TU_ATTR_PACKED
+  {
+    volatile uint8_t connected    : 1;
+    volatile uint8_t addressed    : 1;
+    volatile uint8_t suspended    : 1;
+
+    uint8_t remote_wakeup_en      : 1; // enable/disable by host
+    uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute
+    uint8_t self_powered          : 1; // configuration descriptor's attribute
+  };
+
+  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;
+
+    // TODO merge ep2drv here, 4-bit should be sufficient
+  }ep_status[CFG_TUD_ENDPPOINT_MAX][2];
+
+}usbd_device_t;
+
+static usbd_device_t _usbd_dev;
+
+//--------------------------------------------------------------------+
+// Class Driver
+//--------------------------------------------------------------------+
+#if CFG_TUSB_DEBUG >= 2
+  #define DRIVER_NAME(_name)    .name = _name,
+#else
+  #define DRIVER_NAME(_name)
+#endif
+
+// Built-in class drivers
+static usbd_class_driver_t const _usbd_driver[] =
+{
+  #if CFG_TUD_CDC
+  {
+    DRIVER_NAME("CDC")
+    .init             = cdcd_init,
+    .reset            = cdcd_reset,
+    .open             = cdcd_open,
+    .control_xfer_cb  = cdcd_control_xfer_cb,
+    .xfer_cb          = cdcd_xfer_cb,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_MSC
+  {
+    DRIVER_NAME("MSC")
+    .init             = mscd_init,
+    .reset            = mscd_reset,
+    .open             = mscd_open,
+    .control_xfer_cb  = mscd_control_xfer_cb,
+    .xfer_cb          = mscd_xfer_cb,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_HID
+  {
+    DRIVER_NAME("HID")
+    .init             = hidd_init,
+    .reset            = hidd_reset,
+    .open             = hidd_open,
+    .control_xfer_cb  = hidd_control_xfer_cb,
+    .xfer_cb          = hidd_xfer_cb,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_AUDIO
+  {
+    DRIVER_NAME("AUDIO")
+    .init             = audiod_init,
+    .reset            = audiod_reset,
+    .open             = audiod_open,
+    .control_xfer_cb  = audiod_control_xfer_cb,
+    .xfer_cb          = audiod_xfer_cb,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_VIDEO
+  {
+    DRIVER_NAME("VIDEO")
+    .init             = videod_init,
+    .reset            = videod_reset,
+    .open             = videod_open,
+    .control_xfer_cb  = videod_control_xfer_cb,
+    .xfer_cb          = videod_xfer_cb,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_MIDI
+  {
+    DRIVER_NAME("MIDI")
+    .init             = midid_init,
+    .open             = midid_open,
+    .reset            = midid_reset,
+    .control_xfer_cb  = midid_control_xfer_cb,
+    .xfer_cb          = midid_xfer_cb,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_VENDOR
+  {
+    DRIVER_NAME("VENDOR")
+    .init             = vendord_init,
+    .reset            = vendord_reset,
+    .open             = vendord_open,
+    .control_xfer_cb  = tud_vendor_control_xfer_cb,
+    .xfer_cb          = vendord_xfer_cb,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_USBTMC
+  {
+    DRIVER_NAME("TMC")
+    .init             = usbtmcd_init_cb,
+    .reset            = usbtmcd_reset_cb,
+    .open             = usbtmcd_open_cb,
+    .control_xfer_cb  = usbtmcd_control_xfer_cb,
+    .xfer_cb          = usbtmcd_xfer_cb,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_DFU_RUNTIME
+  {
+    DRIVER_NAME("DFU-RUNTIME")
+    .init             = dfu_rtd_init,
+    .reset            = dfu_rtd_reset,
+    .open             = dfu_rtd_open,
+    .control_xfer_cb  = dfu_rtd_control_xfer_cb,
+    .xfer_cb          = NULL,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_DFU
+  {
+    DRIVER_NAME("DFU")
+    .init             = dfu_moded_init,
+    .reset            = dfu_moded_reset,
+    .open             = dfu_moded_open,
+    .control_xfer_cb  = dfu_moded_control_xfer_cb,
+    .xfer_cb          = NULL,
+    .sof              = NULL
+  },
+  #endif
+
+  #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM
+  {
+    DRIVER_NAME("NET")
+    .init             = netd_init,
+    .reset            = netd_reset,
+    .open             = netd_open,
+    .control_xfer_cb  = netd_control_xfer_cb,
+    .xfer_cb          = netd_xfer_cb,
+    .sof              = NULL,
+  },
+  #endif
+
+  #if CFG_TUD_BTH
+  {
+    DRIVER_NAME("BTH")
+    .init             = btd_init,
+    .reset            = btd_reset,
+    .open             = btd_open,
+    .control_xfer_cb  = btd_control_xfer_cb,
+    .xfer_cb          = btd_xfer_cb,
+    .sof              = NULL
+  },
+  #endif
+};
+
+enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) };
+
+// Additional class drivers implemented by application
+static usbd_class_driver_t const * _app_driver = NULL;
+static uint8_t _app_driver_count = 0;
+
+// virtually joins built-in and application drivers together.
+// Application is positioned first to allow overwriting built-in ones.
+static inline usbd_class_driver_t const * get_driver(uint8_t drvid)
+{
+  // Application drivers
+  if ( usbd_app_driver_get_cb )
+  {
+    if ( drvid < _app_driver_count ) return &_app_driver[drvid];
+    drvid -= _app_driver_count;
+  }
+
+  // Built-in drivers
+  if (drvid < BUILTIN_DRIVER_COUNT) return &_usbd_driver[drvid];
+
+  return NULL;
+}
+
+#define TOTAL_DRIVER_COUNT    (_app_driver_count + BUILTIN_DRIVER_COUNT)
+
+//--------------------------------------------------------------------+
+// DCD Event
+//--------------------------------------------------------------------+
+
+static bool _usbd_initialized = false;
+
+// 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);
+static osal_queue_t _usbd_q;
+
+// Mutex for claiming endpoint, only needed when using with preempted RTOS
+#if CFG_TUSB_OS != OPT_OS_NONE
+static osal_mutex_def_t _ubsd_mutexdef;
+static osal_mutex_t _usbd_mutex;
+#endif
+
+
+//--------------------------------------------------------------------+
+// Prototypes
+//--------------------------------------------------------------------+
+static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
+static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
+static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// from usbd_control.c
+void usbd_control_reset(void);
+void usbd_control_set_request(tusb_control_request_t const *request);
+void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp );
+bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+
+
+//--------------------------------------------------------------------+
+// Debug
+//--------------------------------------------------------------------+
+#if CFG_TUSB_DEBUG >= 2
+static char const* const _usbd_event_str[DCD_EVENT_COUNT] =
+{
+  "Invalid"        ,
+  "Bus Reset"      ,
+  "Unplugged"      ,
+  "SOF"            ,
+  "Suspend"        ,
+  "Resume"         ,
+  "Setup Received" ,
+  "Xfer Complete"  ,
+  "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 )
+    {
+      TU_LOG2("  %s control complete\r\n", driver->name);
+      return;
+    }
+  }
+}
+
+#endif
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+tusb_speed_t tud_speed_get(void)
+{
+  return (tusb_speed_t) _usbd_dev.speed;
+}
+
+bool tud_connected(void)
+{
+  return _usbd_dev.connected;
+}
+
+bool tud_mounted(void)
+{
+  return _usbd_dev.cfg_num ? true : false;
+}
+
+bool tud_suspended(void)
+{
+  return _usbd_dev.suspended;
+}
+
+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);
+  return true;
+}
+
+bool tud_disconnect(void)
+{
+  TU_VERIFY(dcd_disconnect);
+  dcd_disconnect(TUD_OPT_RHPORT);
+  return true;
+}
+
+bool tud_connect(void)
+{
+  TU_VERIFY(dcd_connect);
+  dcd_connect(TUD_OPT_RHPORT);
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// USBD Task
+//--------------------------------------------------------------------+
+bool tud_inited(void)
+{
+  return _usbd_initialized;
+}
+
+bool tud_init (uint8_t rhport)
+{
+  // skip if already initialized
+  if (_usbd_initialized) return _usbd_initialized;
+
+  TU_LOG2("USBD init\r\n");
+
+  tu_varclr(&_usbd_dev);
+
+#if CFG_TUSB_OS != OPT_OS_NONE
+  // Init device mutex
+  _usbd_mutex = osal_mutex_create(&_ubsd_mutexdef);
+  TU_ASSERT(_usbd_mutex);
+#endif
+
+  // Init device queue & task
+  _usbd_q = osal_queue_create(&_usbd_qdef);
+  TU_ASSERT(_usbd_q);
+
+  // Get application driver if available
+  if ( usbd_app_driver_get_cb )
+  {
+    _app_driver = usbd_app_driver_get_cb(&_app_driver_count);
+  }
+
+  // Init class drivers
+  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);
+    driver->init();
+  }
+
+  // Init device controller driver
+  dcd_init(rhport);
+  dcd_int_enable(rhport);
+
+  _usbd_initialized = true;
+
+  return true;
+}
+
+static void configuration_reset(uint8_t rhport)
+{
+  for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ )
+  {
+    get_driver(i)->reset(rhport);
+  }
+
+  tu_varclr(&_usbd_dev);
+  memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping
+  memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping
+}
+
+static void usbd_reset(uint8_t rhport)
+{
+  configuration_reset(rhport);
+  usbd_control_reset();
+}
+
+bool tud_task_event_ready(void)
+{
+  // Skip if stack is not initialized
+  if ( !tusb_inited() ) return false;
+
+  return !osal_queue_empty(_usbd_q);
+}
+
+/* USB Device Driver task
+ * This top level thread manages all device controller event and delegates events to class-specific drivers.
+ * This should be called periodically within the mainloop or rtos thread.
+ *
+   @code
+    int main(void)
+    {
+      application_init();
+      tusb_init();
+
+      while(1) // the mainloop
+      {
+        application_code();
+        tud_task(); // tinyusb device task
+      }
+    }
+    @endcode
+ */
+void tud_task (void)
+{
+  // Skip if stack is not initialized
+  if ( !tusb_inited() ) return;
+
+  // Loop until there is no more events in the queue
+  while (1)
+  {
+    dcd_event_t event;
+
+    if ( !osal_queue_receive(_usbd_q, &event) ) 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");
+#endif
+
+    switch ( event.event_id )
+    {
+      case DCD_EVENT_BUS_RESET:
+        TU_LOG2(": %s Speed\r\n", _tusb_speed_str[event.bus_reset.speed]);
+        usbd_reset(event.rhport);
+        _usbd_dev.speed = event.bus_reset.speed;
+      break;
+
+      case DCD_EVENT_UNPLUGGED:
+        TU_LOG2("\r\n");
+        usbd_reset(event.rhport);
+
+        // invoke callback
+        if (tud_umount_cb) tud_umount_cb();
+      break;
+
+      case DCD_EVENT_SETUP_RECEIVED:
+        TU_LOG2_VAR(&event.setup_received);
+        TU_LOG2("\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
+        _usbd_dev.connected = 1;
+
+        // mark both in & out control as free
+        _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = false;
+        _usbd_dev.ep_status[0][TUSB_DIR_OUT].claimed = 0;
+        _usbd_dev.ep_status[0][TUSB_DIR_IN ].busy = false;
+        _usbd_dev.ep_status[0][TUSB_DIR_IN ].claimed = 0;
+
+        // Process control request
+        if ( !process_control_request(event.rhport, &event.setup_received) )
+        {
+          TU_LOG2("  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);
+        }
+      break;
+
+      case DCD_EVENT_XFER_COMPLETE:
+      {
+        // Invoke the class callback associated with the endpoint address
+        uint8_t const ep_addr = event.xfer_complete.ep_addr;
+        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);
+
+        _usbd_dev.ep_status[epnum][ep_dir].busy = false;
+        _usbd_dev.ep_status[epnum][ep_dir].claimed = 0;
+
+        if ( 0 == epnum )
+        {
+          usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len);
+        }
+        else
+        {
+          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);
+          driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len);
+        }
+      }
+      break;
+
+      case DCD_EVENT_SUSPEND:
+        // NOTE: When plugging/unplugging device, the D+/D- state are unstable and
+        // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ), which result in a series of event
+        // 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);
+          if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en);
+        }else
+        {
+          TU_LOG2(" Skipped\r\n");
+        }
+      break;
+
+      case DCD_EVENT_RESUME:
+        if ( _usbd_dev.connected )
+        {
+          TU_LOG2("\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);
+        }
+      break;
+
+      case USBD_EVENT_FUNC_CALL:
+        TU_LOG2("\r\n");
+        if ( event.func_call.func ) event.func_call.func(event.func_call.param);
+      break;
+
+      default:
+        TU_BREAKPOINT();
+      break;
+    }
+  }
+}
+
+//--------------------------------------------------------------------+
+// Control Request Parser & Handling
+//--------------------------------------------------------------------+
+
+// Helper to invoke class driver control request handler
+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);
+  return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request);
+}
+
+// This handles the actual request and its response.
+// return false will cause its caller to stall control endpoint
+static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+  usbd_control_set_complete_callback(NULL);
+
+  TU_ASSERT(p_request->bmRequestType_bit.type < TUSB_REQ_TYPE_INVALID);
+
+  // Vendor request
+  if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR )
+  {
+    TU_VERIFY(tud_vendor_control_xfer_cb);
+
+    usbd_control_set_complete_callback(tud_vendor_control_xfer_cb);
+    return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request);
+  }
+
+#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");
+  }
+#endif
+
+  switch ( p_request->bmRequestType_bit.recipient )
+  {
+    //------------- Device Requests e.g in enumeration -------------//
+    case TUSB_REQ_RCPT_DEVICE:
+      if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type )
+      {
+        uint8_t const itf = tu_u16_low(p_request->wIndex);
+        TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv));
+
+        usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]);
+        TU_VERIFY(driver);
+
+        // forward to class driver: "non-STD request to Interface"
+        return invoke_class_control(rhport, driver, p_request);
+      }
+
+      if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type )
+      {
+        // Non standard request is not supported
+        TU_BREAKPOINT();
+        return false;
+      }
+
+      switch ( p_request->bRequest )
+      {
+        case TUSB_REQ_SET_ADDRESS:
+          // Depending on mcu, status phase could be sent either before or after changing device address,
+          // or even require stack to not response with status at all
+          // Therefore DCD must take full responsibility to response and include zlp status packet if needed.
+          usbd_control_set_request(p_request); // set request since DCD has no access to tud_control_status() API
+          dcd_set_address(rhport, (uint8_t) p_request->wValue);
+          // skip tud_control_status()
+          _usbd_dev.addressed = 1;
+        break;
+
+        case TUSB_REQ_GET_CONFIGURATION:
+        {
+          uint8_t cfg_num = _usbd_dev.cfg_num;
+          tud_control_xfer(rhport, p_request, &cfg_num, 1);
+        }
+        break;
+
+        case TUSB_REQ_SET_CONFIGURATION:
+        {
+          uint8_t const cfg_num = (uint8_t) p_request->wValue;
+
+          // Only process if new configure is different
+          if (_usbd_dev.cfg_num != cfg_num)
+          {
+            if ( _usbd_dev.cfg_num )
+            {
+              // already configured: need to clear all endpoints and driver first
+              TU_LOG(USBD_DBG, "  Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num);
+
+              // close all non-control endpoints, cancel all pending transfers if any
+              dcd_edpt_close_all(rhport);
+
+              // close all drivers and current configured state except bus speed
+              uint8_t const speed = _usbd_dev.speed;
+              configuration_reset(rhport);
+
+              _usbd_dev.speed = speed; // restore speed
+            }
+
+            // switch to new configuration if not zero
+            if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) );
+          }
+
+          _usbd_dev.cfg_num = cfg_num;
+          tud_control_status(rhport, p_request);
+        }
+        break;
+
+        case TUSB_REQ_GET_DESCRIPTOR:
+          TU_VERIFY( process_get_descriptor(rhport, p_request) );
+        break;
+
+        case TUSB_REQ_SET_FEATURE:
+          // Only support remote wakeup for device feature
+          TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
+
+          TU_LOG(USBD_DBG, "    Enable Remote Wakeup\r\n");
+
+          // Host may enable remote wake up before suspending especially HID device
+          _usbd_dev.remote_wakeup_en = true;
+          tud_control_status(rhport, p_request);
+        break;
+
+        case TUSB_REQ_CLEAR_FEATURE:
+          // Only support remote wakeup for device feature
+          TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
+
+          TU_LOG(USBD_DBG, "    Disable Remote Wakeup\r\n");
+
+          // Host may disable remote wake up after resuming
+          _usbd_dev.remote_wakeup_en = false;
+          tud_control_status(rhport, p_request);
+        break;
+
+        case TUSB_REQ_GET_STATUS:
+        {
+          // 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);
+          tud_control_xfer(rhport, p_request, &status, 2);
+        }
+        break;
+
+        // Unknown/Unsupported request
+        default: TU_BREAKPOINT(); return false;
+      }
+    break;
+
+    //------------- Class/Interface Specific Request -------------//
+    case TUSB_REQ_RCPT_INTERFACE:
+    {
+      uint8_t const itf = tu_u16_low(p_request->wIndex);
+      TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv));
+
+      usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]);
+      TU_VERIFY(driver);
+
+      // all requests to Interface (STD or Class) is forwarded to class driver.
+      // notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE
+      if ( !invoke_class_control(rhport, driver, p_request) )
+      {
+        // For GET_INTERFACE and SET_INTERFACE, it is mandatory to respond even if the class
+        // driver doesn't use alternate settings or implement this
+        TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type);
+
+        switch(p_request->bRequest)
+        {
+          case TUSB_REQ_GET_INTERFACE:
+          case TUSB_REQ_SET_INTERFACE:
+            // Clear complete callback if driver set since it can also stall the request.
+            usbd_control_set_complete_callback(NULL);
+
+            if (TUSB_REQ_GET_INTERFACE == p_request->bRequest)
+            {
+              uint8_t alternate = 0;
+              tud_control_xfer(rhport, p_request, &alternate, 1);
+            }else
+            {
+              tud_control_status(rhport, p_request);
+            }
+          break;
+
+          default: return false;
+        }
+      }
+    }
+    break;
+
+    //------------- Endpoint Request -------------//
+    case TUSB_REQ_RCPT_ENDPOINT:
+    {
+      uint8_t const ep_addr = tu_u16_low(p_request->wIndex);
+      uint8_t const ep_num  = tu_edpt_number(ep_addr);
+      uint8_t const ep_dir  = tu_edpt_dir(ep_addr);
+
+      TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) );
+
+      usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]);
+
+      if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type )
+      {
+        // Forward class request to its driver
+        TU_VERIFY(driver);
+        return invoke_class_control(rhport, driver, p_request);
+      }
+      else
+      {
+        // Handle STD request to endpoint
+        switch ( p_request->bRequest )
+        {
+          case TUSB_REQ_GET_STATUS:
+          {
+            uint16_t status = usbd_edpt_stalled(rhport, ep_addr) ? 0x0001 : 0x0000;
+            tud_control_xfer(rhport, p_request, &status, 2);
+          }
+          break;
+
+          case TUSB_REQ_CLEAR_FEATURE:
+          case TUSB_REQ_SET_FEATURE:
+          {
+            if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue )
+            {
+              if ( TUSB_REQ_CLEAR_FEATURE ==  p_request->bRequest )
+              {
+                usbd_edpt_clear_stall(rhport, ep_addr);
+              }else
+              {
+                usbd_edpt_stall(rhport, ep_addr);
+              }
+            }
+
+            if (driver)
+            {
+              // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request
+              // We will also forward std request targeted endpoint to class drivers as well
+
+              // STD request must always be ACKed regardless of driver returned value
+              // Also clear complete callback if driver set since it can also stall the request.
+              (void) invoke_class_control(rhport, driver, p_request);
+              usbd_control_set_complete_callback(NULL);
+
+              // skip ZLP status if driver already did that
+              if ( !_usbd_dev.ep_status[0][TUSB_DIR_IN].busy ) tud_control_status(rhport, p_request);
+            }
+          }
+          break;
+
+          // Unknown/Unsupported request
+          default: TU_BREAKPOINT(); return false;
+        }
+      }
+    }
+    break;
+
+    // Unknown recipient
+    default: TU_BREAKPOINT(); return false;
+  }
+
+  return true;
+}
+
+// Process Set Configure Request
+// This function parse configuration descriptor & open drivers accordingly
+static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
+{
+  // index is cfg_num-1
+  tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) tud_descriptor_configuration_cb(cfg_num-1);
+  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;
+
+  // Parse interface descriptor
+  uint8_t const * p_desc   = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t);
+  uint8_t const * desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
+
+  while( p_desc < desc_end )
+  {
+    uint8_t assoc_itf_count = 1;
+
+    // Class will always starts with Interface Association (if any) and then Interface descriptor
+    if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
+    {
+      tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
+      assoc_itf_count = desc_iad->bInterfaceCount;
+
+      p_desc = tu_desc_next(p_desc); // next to Interface
+
+      // IAD's first interface number and class should match with opened interface
+      //TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber &&
+      //          desc_iad->bFunctionClass  == desc_itf->bInterfaceClass);
+    }
+
+    TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) );
+    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;
+    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);
+      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);
+
+        // 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)
+        if ( assoc_itf_count == 1)
+        {
+          #if CFG_TUD_CDC
+          if ( driver->open == cdcd_open ) assoc_itf_count = 2;
+          #endif
+
+          #if CFG_TUD_MIDI
+          if ( driver->open == midid_open ) assoc_itf_count = 2;
+          #endif
+
+          #if CFG_TUD_BTH && CFG_TUD_BTH_ISO_ALT_COUNT
+          if ( driver->open == btd_open ) assoc_itf_count = 2;
+          #endif
+        }
+
+        // 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 == _usbd_dev.itf2drv[itf_num]);
+          _usbd_dev.itf2drv[itf_num] = drv_id;
+        }
+
+        // bind all endpoints to found driver
+        tu_edpt_bind_driver(_usbd_dev.ep2drv, desc_itf, drv_len, drv_id);
+
+        // next Interface
+        p_desc += drv_len;
+
+        break; // exit driver find loop
+      }
+    }
+
+    // Failed if there is no supported drivers
+    TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT);
+  }
+
+  // invoke callback
+  if (tud_mount_cb) tud_mount_cb();
+
+  return true;
+}
+
+// return descriptor's buffer and update desc_len
+static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+  tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
+  uint8_t const desc_index = tu_u16_low( p_request->wValue );
+
+  switch(desc_type)
+  {
+    case TUSB_DESC_DEVICE:
+    {
+      TU_LOG2(" Device\r\n");
+
+      void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb();
+
+      // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has.
+      // This only happens with the very first get device descriptor and EP0 size = 8 or 16.
+      if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed &&
+          ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t))
+      {
+        // Hack here: we modify the request length to prevent usbd_control response with zlp
+        // since we are responding with 1 packet & less data than wLength.
+        tusb_control_request_t mod_request = *p_request;
+        mod_request.wLength = CFG_TUD_ENDPOINT0_SIZE;
+
+        return tud_control_xfer(rhport, &mod_request, desc_device, CFG_TUD_ENDPOINT0_SIZE);
+      }else
+      {
+        return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
+      }
+    }
+    break;
+
+    case TUSB_DESC_BOS:
+    {
+      TU_LOG2(" BOS\r\n");
+
+      // requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
+      if (!tud_descriptor_bos_cb) return false;
+
+      uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb();
+      TU_ASSERT(desc_bos);
+
+      // Use offsetof to avoid pointer to the odd/misaligned address
+      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) );
+
+      return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
+    }
+    break;
+
+    case TUSB_DESC_CONFIGURATION:
+    case TUSB_DESC_OTHER_SPEED_CONFIG:
+    {
+      uintptr_t desc_config;
+
+      if ( desc_type == TUSB_DESC_CONFIGURATION )
+      {
+        TU_LOG2(" 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_VERIFY( tud_descriptor_other_speed_configuration_cb );
+        desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
+      }
+
+      TU_ASSERT(desc_config);
+
+      // Use offsetof to avoid pointer to the odd/misaligned address
+      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) );
+
+      return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
+    }
+    break;
+
+    case TUSB_DESC_STRING:
+    {
+      TU_LOG2(" 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));
+      TU_VERIFY(desc_str);
+
+      // 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;
+
+    case TUSB_DESC_DEVICE_QUALIFIER:
+    {
+      TU_LOG2(" Device Qualifier\r\n");
+
+      TU_VERIFY( tud_descriptor_device_qualifier_cb );
+
+      uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
+      TU_VERIFY(desc_qualifier);
+
+      // 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;
+
+    default: return false;
+  }
+}
+
+//--------------------------------------------------------------------+
+// DCD Event Handler
+//--------------------------------------------------------------------+
+void dcd_event_handler(dcd_event_t const * event, bool in_isr)
+{
+  switch (event->event_id)
+  {
+    case DCD_EVENT_UNPLUGGED:
+      _usbd_dev.connected  = 0;
+      _usbd_dev.addressed  = 0;
+      _usbd_dev.cfg_num    = 0;
+      _usbd_dev.suspended  = 0;
+      osal_queue_send(_usbd_q, event, in_isr);
+    break;
+
+    case DCD_EVENT_SUSPEND:
+      // NOTE: When plugging/unplugging device, the D+/D- state are unstable and
+      // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ).
+      // In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish
+      // suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected
+      if ( _usbd_dev.connected )
+      {
+        _usbd_dev.suspended = 1;
+        osal_queue_send(_usbd_q, event, in_isr);
+      }
+    break;
+
+    case DCD_EVENT_RESUME:
+      // skip event if not connected (especially required for SAMD)
+      if ( _usbd_dev.connected )
+      {
+        _usbd_dev.suspended = 0;
+        osal_queue_send(_usbd_q, event, in_isr);
+      }
+    break;
+
+    case DCD_EVENT_SOF:
+      // 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);
+      }
+    break;
+
+    default:
+      osal_queue_send(_usbd_q, event, in_isr);
+    break;
+  }
+}
+
+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
+//--------------------------------------------------------------------+
+
+// 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)
+{
+  for(int i=0; i<ep_count; i++)
+  {
+    tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+
+    TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && xfer_type == desc_ep->bmAttributes.xfer);
+    TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
+
+    if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
+    {
+      (*ep_in) = desc_ep->bEndpointAddress;
+    }else
+    {
+      (*ep_out) = desc_ep->bEndpointAddress;
+    }
+
+    p_desc = tu_desc_next(p_desc);
+  }
+
+  return true;
+}
+
+// Helper to defer an isr function
+void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr)
+{
+  dcd_event_t event =
+  {
+      .rhport   = 0,
+      .event_id = USBD_EVENT_FUNC_CALL,
+  };
+
+  event.func_call.func  = func;
+  event.func_call.param = param;
+
+  dcd_event_handler(&event, in_isr);
+}
+
+//--------------------------------------------------------------------+
+// USBD Endpoint API
+//--------------------------------------------------------------------+
+
+bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
+{
+  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));
+
+  return dcd_edpt_open(rhport, desc_ep);
+}
+
+bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  // 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;
+  }
+
+#if CFG_TUSB_OS != OPT_OS_NONE
+  osal_mutex_unlock(_usbd_mutex);
+#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;
+  }
+
+#if CFG_TUSB_OS != OPT_OS_NONE
+  osal_mutex_unlock(_usbd_mutex);
+#endif
+
+  return ret;
+}
+
+bool usbd_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);
+
+  // 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);
+
+  // Attempt to transfer on a busy endpoint, sound like an race condition !
+  TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
+
+  // Set busy first since the actual transfer can be complete before dcd_edpt_xfer()
+  // could return and USBD task can preempt and clear the busy
+  _usbd_dev.ep_status[epnum][dir].busy = true;
+
+  if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) )
+  {
+    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_BREAKPOINT();
+    return false;
+  }
+}
+
+// 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 usbd_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);
+
+  TU_LOG2("  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);
+
+  // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return
+  // and usbd task can preempt and clear the busy
+  _usbd_dev.ep_status[epnum][dir].busy = true;
+
+  if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes))
+  {
+    TU_LOG2("OK\r\n");
+    return true;
+  }else
+  {
+    // DCD error, mark endpoint as ready to allow next transfer
+    _usbd_dev.ep_status[epnum][dir].busy = false;
+    _usbd_dev.ep_status[epnum][dir].claimed = 0;
+    TU_LOG2("failed\r\n");
+    TU_BREAKPOINT();
+    return false;
+  }
+}
+
+bool usbd_edpt_busy(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);
+
+  return _usbd_dev.ep_status[epnum][dir].busy;
+}
+
+void usbd_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);
+
+  // only stalled if currently cleared
+  if ( !_usbd_dev.ep_status[epnum][dir].stalled )
+  {
+    TU_LOG(USBD_DBG, "    Stall EP %02X\r\n", ep_addr);
+    dcd_edpt_stall(rhport, ep_addr);
+    _usbd_dev.ep_status[epnum][dir].stalled = true;
+    _usbd_dev.ep_status[epnum][dir].busy = true;
+  }
+}
+
+void usbd_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);
+
+  // only clear if currently stalled
+  if ( _usbd_dev.ep_status[epnum][dir].stalled )
+  {
+    TU_LOG(USBD_DBG, "    Clear Stall EP %02X\r\n", ep_addr);
+    dcd_edpt_clear_stall(rhport, ep_addr);
+    _usbd_dev.ep_status[epnum][dir].stalled = false;
+    _usbd_dev.ep_status[epnum][dir].busy = false;
+  }
+}
+
+bool usbd_edpt_stalled(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);
+
+  return _usbd_dev.ep_status[epnum][dir].stalled;
+}
+
+/**
+ * usbd_edpt_close will disable an endpoint.
+ *
+ * In progress transfers on this EP may be delivered after this call.
+ *
+ */
+void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+  TU_ASSERT(dcd_edpt_close, /**/);
+  TU_LOG2("  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);
+
+  dcd_edpt_close(rhport, ep_addr);
+  _usbd_dev.ep_status[epnum][dir].stalled = false;
+  _usbd_dev.ep_status[epnum][dir].busy = false;
+  _usbd_dev.ep_status[epnum][dir].claimed = false;
+
+  return;
+}
+
+#endif
diff --git a/src/device/usbd.h b/src/device/usbd.h
new file mode 100644
index 0000000..ec34817
--- /dev/null
+++ b/src/device/usbd.h
@@ -0,0 +1,853 @@
+/*
+ * 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.
+ */
+
+#ifndef _TUSB_USBD_H_
+#define _TUSB_USBD_H_
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
+// Init device stack
+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
+void tud_task (void);
+
+// Check if there is pending events need proccessing by tud_task()
+bool tud_task_event_ready(void);
+
+// Interrupt handler, name alias to DCD
+extern void dcd_int_handler(uint8_t rhport);
+#define tud_int_handler   dcd_int_handler
+
+// Get current bus speed
+tusb_speed_t tud_speed_get(void);
+
+// Check if device is connected (may not mounted/configured yet)
+// True if just got out of Bus Reset and received the very first data from host
+bool tud_connected(void);
+
+// Check if device is connected and configured
+bool tud_mounted(void);
+
+// Check if device is suspended
+bool tud_suspended(void);
+
+// Check if device is ready to transfer
+TU_ATTR_ALWAYS_INLINE static inline
+bool tud_ready(void)
+{
+  return tud_mounted() && !tud_suspended();
+}
+
+// Remote wake up host, only if suspended and enabled by host
+bool tud_remote_wakeup(void);
+
+// Enable pull-up resistor on D+ D-
+// Return false on unsupported MCUs
+bool tud_disconnect(void);
+
+// Disable pull-up resistor on D+ D-
+// Return false on unsupported MCUs
+bool tud_connect(void);
+
+// Carry out Data and Status stage of control transfer
+// - If len = 0, it is equivalent to sending status only
+// - If len > wLength : it will be truncated
+bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len);
+
+// Send STATUS (zero length) packet
+bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request);
+
+//--------------------------------------------------------------------+
+// Application Callbacks (WEAK is optional)
+//--------------------------------------------------------------------+
+
+// Invoked when received GET DEVICE DESCRIPTOR request
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void);
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index);
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid);
+
+// Invoked when received GET BOS DESCRIPTOR request
+// Application return pointer to descriptor
+TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void);
+
+// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
+// device_qualifier descriptor describes information about a high-speed capable device that would
+// change if the device were operating at the other speed. If not highspeed capable stall this request.
+TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void);
+
+// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
+TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index);
+
+// Invoked when device is mounted (configured)
+TU_ATTR_WEAK void tud_mount_cb(void);
+
+// Invoked when device is unmounted
+TU_ATTR_WEAK void tud_umount_cb(void);
+
+// Invoked when usb bus is suspended
+// Within 7ms, device must draw an average of current less than 2.5 mA from bus
+TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en);
+
+// Invoked when usb bus is resumed
+TU_ATTR_WEAK void tud_resume_cb(void);
+
+// Invoked when received control request with VENDOR TYPE
+TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+
+//--------------------------------------------------------------------+
+// Binary Device Object Store (BOS) Descriptor Templates
+//--------------------------------------------------------------------+
+
+#define TUD_BOS_DESC_LEN      5
+
+// total length, number of device caps
+#define TUD_BOS_DESCRIPTOR(_total_len, _caps_num) \
+  5, TUSB_DESC_BOS, U16_TO_U8S_LE(_total_len), _caps_num
+
+// Device Capability Platform 128-bit UUID + Data
+#define TUD_BOS_PLATFORM_DESCRIPTOR(...) \
+  4+TU_ARGS_NUM(__VA_ARGS__), TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_PLATFORM, 0x00, __VA_ARGS__
+
+//------------- WebUSB BOS Platform -------------//
+
+// Descriptor Length
+#define TUD_BOS_WEBUSB_DESC_LEN         24
+
+// Vendor Code, iLandingPage
+#define TUD_BOS_WEBUSB_DESCRIPTOR(_vendor_code, _ipage) \
+  TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_WEBUSB_UUID, U16_TO_U8S_LE(0x0100), _vendor_code, _ipage)
+
+#define TUD_BOS_WEBUSB_UUID   \
+  0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, \
+  0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65
+
+//------------- Microsoft OS 2.0 Platform -------------//
+#define TUD_BOS_MICROSOFT_OS_DESC_LEN   28
+
+// Total Length of descriptor set, vendor code
+#define TUD_BOS_MS_OS_20_DESCRIPTOR(_desc_set_len, _vendor_code) \
+  TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_MS_OS_20_UUID, U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(_desc_set_len), _vendor_code, 0)
+
+#define TUD_BOS_MS_OS_20_UUID \
+    0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, \
+  0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor Templates
+//--------------------------------------------------------------------+
+
+#define TUD_CONFIG_DESC_LEN   (9)
+
+// Config number, interface count, string index, total length, attribute, power in mA
+#define TUD_CONFIG_DESCRIPTOR(config_num, _itfcount, _stridx, _total_len, _attribute, _power_ma) \
+  9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, config_num, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2
+
+//--------------------------------------------------------------------+
+// CDC Descriptor Templates
+//--------------------------------------------------------------------+
+
+// Length of template descriptor: 66 bytes
+#define TUD_CDC_DESC_LEN  (8+9+5+5+4+5+7+9+7+7)
+
+// CDC Descriptor Template
+// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
+#define TUD_CDC_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \
+  /* Interface Associate */\
+  8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, 0,\
+  /* CDC Control Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, _stridx,\
+  /* CDC Header */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
+  /* CDC Call */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
+  /* CDC ACM: support line request */\
+  4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\
+  /* CDC Union */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
+  /* Endpoint Notification */\
+  7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\
+  /* CDC Data Interface */\
+  9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+//--------------------------------------------------------------------+
+// MSC Descriptor Templates
+//--------------------------------------------------------------------+
+
+// Length of template descriptor: 23 bytes
+#define TUD_MSC_DESC_LEN    (9 + 7 + 7)
+
+// Interface number, string index, EP Out & EP In address, EP size
+#define TUD_MSC_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
+  /* Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_MSC, MSC_SUBCLASS_SCSI, MSC_PROTOCOL_BOT, _stridx,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+
+//--------------------------------------------------------------------+
+// HID Descriptor Templates
+//--------------------------------------------------------------------+
+
+// Length of template descriptor: 25 bytes
+#define TUD_HID_DESC_LEN    (9 + 9 + 7)
+
+// HID Input only descriptor
+// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
+#define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \
+  /* Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? (uint8_t)HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
+  /* HID descriptor */\
+  9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
+
+// Length of template descriptor: 32 bytes
+#define TUD_HID_INOUT_DESC_LEN    (9 + 9 + 7 + 7)
+
+// HID Input & Output descriptor
+// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval
+#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \
+  /* Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? (uint8_t)HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
+  /* HID descriptor */\
+  9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval, \
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
+
+//--------------------------------------------------------------------+
+// MIDI Descriptor Templates
+// Note: MIDI v1.0 is based on Audio v1.0
+//--------------------------------------------------------------------+
+
+#define TUD_MIDI_DESC_HEAD_LEN (9 + 9 + 9 + 7)
+#define TUD_MIDI_DESC_HEAD(_itfnum,  _stridx, _numcables) \
+  /* Audio Control (AC) Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, _stridx,\
+  /* AC Header */\
+  9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, (uint8_t)((_itfnum) + 1),\
+  /* MIDI Streaming (MS) Interface */\
+  9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\
+  /* MS Header */\
+  7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN)
+
+#define TUD_MIDI_JACKID_IN_EMB(_cablenum) \
+  (uint8_t)(((_cablenum) - 1) * 4 + 1)
+
+#define TUD_MIDI_JACKID_IN_EXT(_cablenum) \
+  (uint8_t)(((_cablenum) - 1) * 4 + 2)
+
+#define TUD_MIDI_JACKID_OUT_EMB(_cablenum) \
+  (uint8_t)(((_cablenum) - 1) * 4 + 3)
+
+#define TUD_MIDI_JACKID_OUT_EXT(_cablenum) \
+  (uint8_t)(((_cablenum) - 1) * 4 + 4)
+
+#define TUD_MIDI_DESC_JACK_LEN (6 + 6 + 9 + 9)
+#define TUD_MIDI_DESC_JACK(_cablenum) \
+  /* MS In Jack (Embedded) */\
+  6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_IN_EMB(_cablenum), 0,\
+  /* MS In Jack (External) */\
+  6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_IN_EXT(_cablenum), 0,\
+  /* MS Out Jack (Embedded), connected to In Jack External */\
+  9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, 0,\
+  /* MS Out Jack (External), connected to In Jack Embedded */\
+  9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, 0
+
+#define TUD_MIDI_DESC_EP_LEN(_numcables) (9 + 4 + (_numcables))
+#define TUD_MIDI_DESC_EP(_epout, _epsize, _numcables) \
+  /* Endpoint: Note Audio v1.0's endpoint has 9 bytes instead of 7 */\
+  9, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0, 0, 0, \
+  /* MS Endpoint (connected to embedded jack) */\
+  (uint8_t)(4 + (_numcables)), TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, _numcables
+
+// Length of template descriptor (88 bytes)
+#define TUD_MIDI_DESC_LEN (TUD_MIDI_DESC_HEAD_LEN + TUD_MIDI_DESC_JACK_LEN + TUD_MIDI_DESC_EP_LEN(1) * 2)
+
+// MIDI simple descriptor
+// - 1 Embedded Jack In connected to 1 External Jack Out
+// - 1 Embedded Jack out connected to 1 External Jack In
+#define TUD_MIDI_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
+  TUD_MIDI_DESC_HEAD(_itfnum, _stridx, 1),\
+  TUD_MIDI_DESC_JACK(1),\
+  TUD_MIDI_DESC_EP(_epout, _epsize, 1),\
+  TUD_MIDI_JACKID_IN_EMB(1),\
+  TUD_MIDI_DESC_EP(_epin, _epsize, 1),\
+  TUD_MIDI_JACKID_OUT_EMB(1)
+
+//--------------------------------------------------------------------+
+// Audio v2.0 Descriptor Templates
+//--------------------------------------------------------------------+
+
+/* Standard Interface Association Descriptor (IAD) */
+#define TUD_AUDIO_DESC_IAD_LEN 8
+#define TUD_AUDIO_DESC_IAD(_firstitfs, _nitfs, _stridx) \
+  TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx
+
+/* Standard AC Interface Descriptor(4.7.1) */
+#define TUD_AUDIO_DESC_STD_AC_LEN 9
+#define TUD_AUDIO_DESC_STD_AC(_itfnum, _nEPs, _stridx) /* _nEPs is 0 or 1 */\
+  TUD_AUDIO_DESC_STD_AC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_INT_PROTOCOL_CODE_V2, _stridx
+
+/* Class-Specific AC Interface Header Descriptor(4.7.2) */
+#define TUD_AUDIO_DESC_CS_AC_LEN 9
+#define TUD_AUDIO_DESC_CS_AC(_bcdADC, _category, _totallen, _ctrl) /* _bcdADC : Audio Device Class Specification Release Number in Binary-Coded Decimal, _category : see audio_function_t, _totallen : Total number of bytes returned for the class-specific AudioControl interface i.e. Clock Source, Unit and Terminal descriptors - Do not include TUD_AUDIO_DESC_CS_AC_LEN, we already do this here*/ \
+  TUD_AUDIO_DESC_CS_AC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(_bcdADC), _category, U16_TO_U8S_LE(_totallen + TUD_AUDIO_DESC_CS_AC_LEN), _ctrl
+
+/* Clock Source Descriptor(4.7.2.1) */
+#define TUD_AUDIO_DESC_CLK_SRC_LEN 8
+#define TUD_AUDIO_DESC_CLK_SRC(_clkid, _attr, _ctrl, _assocTerm, _stridx) \
+  TUD_AUDIO_DESC_CLK_SRC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE, _clkid, _attr, _ctrl, _assocTerm, _stridx
+
+/* Input Terminal Descriptor(4.7.2.4) */
+#define TUD_AUDIO_DESC_INPUT_TERM_LEN 17
+#define TUD_AUDIO_DESC_INPUT_TERM(_termid, _termtype, _assocTerm, _clkid, _nchannelslogical, _channelcfg, _idxchannelnames, _ctrl, _stridx) \
+  TUD_AUDIO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _clkid, _nchannelslogical, U32_TO_U8S_LE(_channelcfg), _idxchannelnames, U16_TO_U8S_LE(_ctrl), _stridx
+
+/* Output Terminal Descriptor(4.7.2.5) */
+#define TUD_AUDIO_DESC_OUTPUT_TERM_LEN 12
+#define TUD_AUDIO_DESC_OUTPUT_TERM(_termid, _termtype, _assocTerm, _srcid, _clkid, _ctrl, _stridx) \
+  TUD_AUDIO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _srcid, _clkid, U16_TO_U8S_LE(_ctrl), _stridx
+
+/* Feature Unit Descriptor(4.7.2.8) */
+// 1 - Channel
+#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN 6+(1+1)*4
+#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _stridx) \
+  TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), _stridx
+
+// 2 - Channels
+#define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN (6+(2+1)*4)
+#define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _stridx) \
+		TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), _stridx
+// 4 - Channels
+#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN (6+(4+1)*4)
+#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _ctrlch3, _ctrlch4, _stridx) \
+                    TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), U32_TO_U8S_LE(_ctrlch3), U32_TO_U8S_LE(_ctrlch4), _stridx
+
+// For more channels, add definitions here
+
+/* Standard AS Interface Descriptor(4.9.1) */
+#define TUD_AUDIO_DESC_STD_AS_INT_LEN 9
+#define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \
+  TUD_AUDIO_DESC_STD_AS_INT_LEN, TUSB_DESC_INTERFACE, _itfnum, _altset, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_INT_PROTOCOL_CODE_V2, _stridx
+
+/* Class-Specific AS Interface Descriptor(4.9.2) */
+#define TUD_AUDIO_DESC_CS_AS_INT_LEN 16
+#define TUD_AUDIO_DESC_CS_AS_INT(_termid, _ctrl, _formattype, _formats, _nchannelsphysical, _channelcfg, _stridx) \
+  TUD_AUDIO_DESC_CS_AS_INT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_AS_GENERAL, _termid, _ctrl, _formattype, U32_TO_U8S_LE(_formats), _nchannelsphysical, U32_TO_U8S_LE(_channelcfg), _stridx
+
+/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */
+#define TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN 6
+#define TUD_AUDIO_DESC_TYPE_I_FORMAT(_subslotsize, _bitresolution) /* _subslotsize is number of bytes per sample (i.e. subslot) and can be 1,2,3, or 4 */\
+  TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_FORMAT_TYPE, AUDIO_FORMAT_TYPE_I, _subslotsize, _bitresolution
+
+/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */
+#define TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN 7
+#define TUD_AUDIO_DESC_STD_AS_ISO_EP(_ep, _attr, _maxEPsize, _interval) \
+  TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN, TUSB_DESC_ENDPOINT, _ep, _attr, U16_TO_U8S_LE(_maxEPsize), _interval
+
+/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */
+#define TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN 8
+#define TUD_AUDIO_DESC_CS_AS_ISO_EP(_attr, _ctrl, _lockdelayunit, _lockdelay) \
+  TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO_CS_EP_SUBTYPE_GENERAL, _attr, _ctrl, _lockdelayunit, U16_TO_U8S_LE(_lockdelay)
+
+/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */
+#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7
+#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \
+  TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval
+
+// AUDIO simple descriptor (UAC2) for 1 microphone input
+// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source
+
+#define TUD_AUDIO_MIC_ONE_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\
+  + TUD_AUDIO_DESC_STD_AC_LEN\
+  + TUD_AUDIO_DESC_CS_AC_LEN\
+  + TUD_AUDIO_DESC_CLK_SRC_LEN\
+  + TUD_AUDIO_DESC_INPUT_TERM_LEN\
+  + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+  + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\
+  + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+  + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+  + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+  + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+  + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+  + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
+
+#define TUD_AUDIO_MIC_ONE_CH_DESC_N_AS_INT 1 	// Number of AS interfaces
+
+#define TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \
+  /* Standard Interface Association Descriptor (IAD) */\
+  TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
+  /* Standard AC Interface Descriptor(4.7.1) */\
+  TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
+  /* Class-Specific AC Interface Header Descriptor(4.7.2) */\
+  TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
+  /* Clock Source Descriptor(4.7.2.1) */\
+  TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01,  /*_stridx*/ 0x00),\
+  /* Input Terminal Descriptor(4.7.2.4) */\
+  TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\
+  /* Output Terminal Descriptor(4.7.2.5) */\
+  TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
+  /* Feature Unit Descriptor(4.7.2.8) */\
+  TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\
+  /* Standard AS Interface Descriptor(4.9.1) */\
+  /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
+  TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\
+  /* Standard AS Interface Descriptor(4.9.1) */\
+  /* Interface 1, Alternate 1 - alternate interface for data streaming */\
+  TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\
+  /* Class-Specific AS Interface Descriptor(4.9.2) */\
+  TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+  /* 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),\
+  /* 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)
+
+// AUDIO simple descriptor (UAC2) for 4 microphone input
+// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source
+
+#define TUD_AUDIO_MIC_FOUR_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\
+  + TUD_AUDIO_DESC_STD_AC_LEN\
+  + TUD_AUDIO_DESC_CS_AC_LEN\
+  + TUD_AUDIO_DESC_CLK_SRC_LEN\
+  + TUD_AUDIO_DESC_INPUT_TERM_LEN\
+  + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+  + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN\
+  + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+  + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+  + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+  + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+  + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+  + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
+
+#define TUD_AUDIO_MIC_FOUR_CH_DESC_N_AS_INT 1   // Number of AS interfaces
+
+#define TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \
+  /* Standard Interface Association Descriptor (IAD) */\
+  TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
+  /* Standard AC Interface Descriptor(4.7.1) */\
+  TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
+  /* Class-Specific AC Interface Header Descriptor(4.7.2) */\
+  TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
+  /* Clock Source Descriptor(4.7.2.1) */\
+  TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01,  /*_stridx*/ 0x00),\
+  /* Input Terminal Descriptor(4.7.2.4) */\
+  TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\
+  /* Output Terminal Descriptor(4.7.2.5) */\
+  TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
+  /* Feature Unit Descriptor(4.7.2.8) */\
+  TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch3*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch4*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\
+  /* Standard AS Interface Descriptor(4.9.1) */\
+  /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
+  TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\
+  /* Standard AS Interface Descriptor(4.9.1) */\
+  /* Interface 1, Alternate 1 - alternate interface for data streaming */\
+  TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\
+  /* Class-Specific AS Interface Descriptor(4.9.2) */\
+  TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+  /* 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),\
+  /* 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)
+
+// AUDIO simple descriptor (UAC2) for mono speaker
+// - 1 Input Terminal, 2 Feature Unit (Mute and Volume Control), 3 Output Terminal, 4 Clock Source
+
+#define TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\
+  + TUD_AUDIO_DESC_STD_AC_LEN\
+  + TUD_AUDIO_DESC_CS_AC_LEN\
+  + TUD_AUDIO_DESC_CLK_SRC_LEN\
+  + TUD_AUDIO_DESC_INPUT_TERM_LEN\
+  + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+  + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\
+  + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+  + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+  + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+  + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+  + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+  + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+  + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN)
+
+#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \
+  /* Standard Interface Association Descriptor (IAD) */\
+  TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
+  /* Standard AC Interface Descriptor(4.7.1) */\
+  TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
+  /* Class-Specific AC Interface Header Descriptor(4.7.2) */\
+  TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
+  /* Clock Source Descriptor(4.7.2.1) */\
+  TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01,  /*_stridx*/ 0x00),\
+  /* Input Terminal Descriptor(4.7.2.4) */\
+  TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\
+  /* Output Terminal Descriptor(4.7.2.5) */\
+  TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
+  /* Feature Unit Descriptor(4.7.2.8) */\
+  TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\
+  /* Standard AS Interface Descriptor(4.9.1) */\
+  /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
+  TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\
+  /* Standard AS Interface Descriptor(4.9.1) */\
+  /* Interface 1, Alternate 1 - alternate interface for data streaming */\
+  TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\
+  /* Class-Specific AS Interface Descriptor(4.9.2) */\
+  TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+  /* 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),\
+  /* 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) */\
+  TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\
+
+//   Calculate wMaxPacketSize of Endpoints
+#define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \
+    ((((_maxFrequency + ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 7999 : 999)) / ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 8000 : 1000)) + 1) * _nBytesPerSample * _nChannels)
+
+
+//--------------------------------------------------------------------+
+// USBTMC/USB488 Descriptor Templates
+//--------------------------------------------------------------------+
+
+#define TUD_USBTMC_APP_CLASS    (TUSB_CLASS_APPLICATION_SPECIFIC)
+#define TUD_USBTMC_APP_SUBCLASS 0x03u
+
+#define TUD_USBTMC_PROTOCOL_STD    0x00u
+#define TUD_USBTMC_PROTOCOL_USB488 0x01u
+
+//   Interface number, number of endpoints, EP string index, USB_TMC_PROTOCOL*, bulk-out endpoint ID,
+//   bulk-in endpoint ID
+#define TUD_USBTMC_IF_DESCRIPTOR(_itfnum, _bNumEndpoints, _stridx, _itfProtocol) \
+  /* Interface */ \
+  0x09, TUSB_DESC_INTERFACE, _itfnum, 0x00, _bNumEndpoints, TUD_USBTMC_APP_CLASS, TUD_USBTMC_APP_SUBCLASS, _itfProtocol, _stridx
+
+#define TUD_USBTMC_IF_DESCRIPTOR_LEN 9u
+
+#define TUD_USBTMC_BULK_DESCRIPTORS(_epout, _epin, _bulk_epsize) \
+  /* Endpoint Out */ \
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u, \
+  /* Endpoint In */ \
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u
+
+#define TUD_USBTMC_BULK_DESCRIPTORS_LEN (7u+7u)
+
+/* optional interrupt endpoint */ \
+// _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number?
+#define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \
+  7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16
+
+#define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u)
+
+//--------------------------------------------------------------------+
+// Vendor Descriptor Templates
+//--------------------------------------------------------------------+
+
+#define TUD_VENDOR_DESC_LEN  (9+7+7)
+
+// Interface number, string index, EP Out & IN address, EP size
+#define TUD_VENDOR_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
+  /* Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _stridx,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+//--------------------------------------------------------------------+
+// DFU Runtime Descriptor Templates
+//--------------------------------------------------------------------+
+
+#define TUD_DFU_APP_CLASS    (TUSB_CLASS_APPLICATION_SPECIFIC)
+#define TUD_DFU_APP_SUBCLASS (APP_SUBCLASS_DFU_RUNTIME)
+
+// Length of template descriptr: 18 bytes
+#define TUD_DFU_RT_DESC_LEN (9 + 9)
+
+// DFU runtime descriptor
+// Interface number, string index, attributes, detach timeout, transfer size
+#define TUD_DFU_RT_DESCRIPTOR(_itfnum, _stridx, _attr, _timeout, _xfer_size) \
+  /* Interface */ \
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_RT, _stridx, \
+  /* Function */ \
+  9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
+
+//--------------------------------------------------------------------+
+// DFU Descriptor Templates
+//--------------------------------------------------------------------+
+
+// Length of template descriptor: 9 bytes + number of alternatives * 9
+#define TUD_DFU_DESC_LEN(_alt_count)    (9 + (_alt_count) * 9)
+
+// Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size
+// Note: Alternate count must be numberic or macro, string index is increased by one for each Alt interface
+#define TUD_DFU_DESCRIPTOR(_itfnum, _alt_count, _stridx, _attr, _timeout, _xfer_size) \
+  TU_XSTRCAT(_TUD_DFU_ALT_,_alt_count)(_itfnum, 0, _stridx), \
+  /* Function */ \
+  9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
+
+#define _TUD_DFU_ALT(_itfnum, _alt, _stridx) \
+  /* Interface */ \
+  9, TUSB_DESC_INTERFACE, _itfnum, _alt, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_DFU, _stridx
+
+#define _TUD_DFU_ALT_1(_itfnum, _alt_count, _stridx) \
+  _TUD_DFU_ALT(_itfnum, _alt_count, _stridx)
+
+#define _TUD_DFU_ALT_2(_itfnum, _alt_count, _stridx) \
+  _TUD_DFU_ALT(_itfnum, _alt_count, _stridx),      \
+  _TUD_DFU_ALT_1(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_3(_itfnum, _alt_count, _stridx) \
+  _TUD_DFU_ALT(_itfnum, _alt_count, _stridx),      \
+  _TUD_DFU_ALT_2(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_4(_itfnum, _alt_count, _stridx) \
+  _TUD_DFU_ALT(_itfnum, _alt_count, _stridx),      \
+  _TUD_DFU_ALT_3(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_5(_itfnum, _alt_count, _stridx) \
+  _TUD_DFU_ALT(_itfnum, _alt_count, _stridx),      \
+  _TUD_DFU_ALT_4(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_6(_itfnum, _alt_count, _stridx) \
+  _TUD_DFU_ALT(_itfnum, _alt_count, _stridx),      \
+  _TUD_DFU_ALT_5(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_7(_itfnum, _alt_count, _stridx) \
+  _TUD_DFU_ALT(_itfnum, _alt_count, _stridx),      \
+  _TUD_DFU_ALT_6(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_8(_itfnum, _alt_count, _stridx) \
+  _TUD_DFU_ALT(_itfnum, _alt_count, _stridx),      \
+  _TUD_DFU_ALT_7(_itfnum, _alt_count+1, _stridx+1)
+
+//--------------------------------------------------------------------+
+// CDC-ECM Descriptor Templates
+//--------------------------------------------------------------------+
+
+// Length of template descriptor: 71 bytes
+#define TUD_CDC_ECM_DESC_LEN  (8+9+5+5+13+7+9+9+7+7)
+
+// CDC-ECM Descriptor Template
+// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
+#define TUD_CDC_ECM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \
+  /* Interface Association */\
+  8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL, 0, 0,\
+  /* CDC Control Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL, 0, _desc_stridx,\
+  /* CDC-ECM Header */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
+  /* CDC-ECM Union */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
+  /* CDC-ECM Functional Descriptor */\
+  13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0,\
+  /* Endpoint Notification */\
+  7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
+  /* CDC Data Interface (default inactive) */\
+  9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
+  /* CDC Data Interface (alternative active) */\
+  9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+//--------------------------------------------------------------------+
+// RNDIS Descriptor Templates
+//--------------------------------------------------------------------+
+
+#if 0
+/* Windows XP */
+#define TUD_RNDIS_ITF_CLASS    TUSB_CLASS_CDC
+#define TUD_RNDIS_ITF_SUBCLASS CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL
+#define TUD_RNDIS_ITF_PROTOCOL 0xFF /* CDC_COMM_PROTOCOL_MICROSOFT_RNDIS */
+#else
+/* Windows 7+ */
+#define TUD_RNDIS_ITF_CLASS    TUSB_CLASS_WIRELESS_CONTROLLER
+#define TUD_RNDIS_ITF_SUBCLASS 0x01
+#define TUD_RNDIS_ITF_PROTOCOL 0x03
+#endif
+
+// Length of template descriptor: 66 bytes
+#define TUD_RNDIS_DESC_LEN  (8+9+5+5+4+5+7+9+7+7)
+
+// RNDIS Descriptor Template
+// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
+#define TUD_RNDIS_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \
+  /* Interface Association */\
+  8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, 0,\
+  /* CDC Control Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, _stridx,\
+  /* CDC-ACM Header */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\
+  /* CDC Call Management */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
+  /* ACM */\
+  4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 0,\
+  /* CDC Union */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
+  /* Endpoint Notification */\
+  7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
+  /* CDC Data Interface */\
+  9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+//--------------------------------------------------------------------+
+// Bluetooth Radio Descriptor Templates
+//--------------------------------------------------------------------+
+
+#define TUD_BT_APP_CLASS                    (TUSB_CLASS_WIRELESS_CONTROLLER)
+#define TUD_BT_APP_SUBCLASS                 0x01
+#define TUD_BT_PROTOCOL_PRIMARY_CONTROLLER  0x01
+#define TUD_BT_PROTOCOL_AMP_CONTROLLER      0x02
+
+#ifndef CFG_TUD_BTH_ISO_ALT_COUNT
+#define CFG_TUD_BTH_ISO_ALT_COUNT 0
+#endif
+
+// Length of template descriptor: 38 bytes + number of ISO alternatives * 23
+#define TUD_BTH_DESC_LEN (8 + 9 + 7 + 7 + 7 + (CFG_TUD_BTH_ISO_ALT_COUNT) * (9 + 7 + 7))
+
+/* Primary Interface */
+#define TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 3, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, _stridx, \
+  /* Endpoint In for events */ \
+  7, TUSB_DESC_ENDPOINT, _ep_evt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_evt_size), _ep_evt_interval, \
+  /* Endpoint In for ACL data */ \
+  7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1, \
+  /* Endpoint Out for ACL data */ \
+  7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1
+
+#define TUD_BTH_ISO_ITF(_itfnum, _alt, _ep_in, _ep_out, _n) ,\
+  /* Interface with 2 endpoints */ \
+  9, TUSB_DESC_INTERFACE, _itfnum, _alt, 2, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0, \
+  /* Isochronous endpoints */ \
+  7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1, \
+  7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1
+
+#define _FIRST(a, ...) a
+#define _REST(a, ...) __VA_ARGS__
+
+#define TUD_BTH_ISO_ITF_0(_itfnum, ...)
+#define TUD_BTH_ISO_ITF_1(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 1, _ep_in, _ep_out, _FIRST(__VA_ARGS__))
+#define TUD_BTH_ISO_ITF_2(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 2, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
+  TUD_BTH_ISO_ITF_1(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
+#define TUD_BTH_ISO_ITF_3(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 3, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
+  TUD_BTH_ISO_ITF_2(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
+#define TUD_BTH_ISO_ITF_4(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 4, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
+  TUD_BTH_ISO_ITF_3(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
+#define TUD_BTH_ISO_ITF_5(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 5, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
+  TUD_BTH_ISO_ITF_4(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
+#define TUD_BTH_ISO_ITF_6(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 6, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
+  TUD_BTH_ISO_ITF_5(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
+
+#define TUD_BTH_ISO_ITFS(_itfnum, _ep_in, _ep_out, ...) \
+  TU_XSTRCAT(TUD_BTH_ISO_ITF_, CFG_TUD_BTH_ISO_ALT_COUNT)(_itfnum, _ep_in, _ep_out, __VA_ARGS__)
+
+// BT Primary controller descriptor
+// Interface number, string index, attributes, event endpoint, event endpoint size, interval, data in, data out, data endpoint size, iso endpoint sizes
+// TODO BTH should also use IAD like CDC for composite device
+#define TUD_BTH_DESCRIPTOR(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size,...) \
+  /* Interface Associate */\
+  8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0,\
+  TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \
+  TUD_BTH_ISO_ITFS(_itfnum + 1, _ep_in + 1, _ep_out + 1, __VA_ARGS__)
+
+//--------------------------------------------------------------------+
+// CDC-NCM Descriptor Templates
+//--------------------------------------------------------------------+
+
+// Length of template descriptor
+#define TUD_CDC_NCM_DESC_LEN  (8+9+5+5+13+6+7+9+9+7+7)
+
+// CDC-ECM Descriptor Template
+// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
+#define TUD_CDC_NCM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \
+  /* Interface Association */\
+  8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, 0,\
+  /* CDC Control Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, _desc_stridx,\
+  /* CDC-NCM Header */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\
+  /* CDC-NCM Union */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
+  /* CDC-NCM Functional Descriptor */\
+  13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0, \
+  /* CDC-NCM Functional Descriptor */\
+  6, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_NCM, U16_TO_U8S_LE(0x0100), 0, \
+  /* Endpoint Notification */\
+  7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 50,\
+  /* CDC Data Interface (default inactive) */\
+  9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\
+  /* CDC Data Interface (alternative active) */\
+  9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_USBD_H_ */
+
+/** @} */
diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c
new file mode 100644
index 0000000..7a82446
--- /dev/null
+++ b/src/device/usbd_control.c
@@ -0,0 +1,233 @@
+/*
+ * 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 TUSB_OPT_DEVICE_ENABLED
+
+#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);
+#endif
+
+enum
+{
+  EDPT_CTRL_OUT = 0x00,
+  EDPT_CTRL_IN  = 0x80
+};
+
+typedef struct
+{
+  tusb_control_request_t request;
+
+  uint8_t* buffer;
+  uint16_t data_len;
+  uint16_t total_xferred;
+
+  usbd_control_xfer_cb_t complete_cb;
+} usbd_control_xfer_t;
+
+static usbd_control_xfer_t _ctrl_xfer;
+
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
+static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE];
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
+// Queue ZLP status transaction
+static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const * request)
+{
+  // Opposite to endpoint in Data Phase
+  uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN;
+  return usbd_edpt_xfer(rhport, ep_addr, NULL, 0);
+}
+
+// Status phase
+bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request)
+{
+  _ctrl_xfer.request       = (*request);
+  _ctrl_xfer.buffer        = NULL;
+  _ctrl_xfer.total_xferred = 0;
+  _ctrl_xfer.data_len      = 0;
+
+  return _status_stage_xact(rhport, request);
+}
+
+// Queue a transaction in Data Stage
+// Each transaction has up to Endpoint0's max packet size.
+// This function can also transfer an zero-length packet
+static bool _data_stage_xact(uint8_t rhport)
+{
+  uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_ENDPOINT0_SIZE);
+
+  uint8_t ep_addr = EDPT_CTRL_OUT;
+
+  if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN )
+  {
+    ep_addr = EDPT_CTRL_IN;
+    if ( xact_len ) memcpy(_usbd_ctrl_buf, _ctrl_xfer.buffer, xact_len);
+  }
+
+  return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len);
+}
+
+// Transmit data to/from the control endpoint.
+// If the request's wLength is zero, a status packet is sent instead.
+bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len)
+{
+  _ctrl_xfer.request       = (*request);
+  _ctrl_xfer.buffer        = (uint8_t*) buffer;
+  _ctrl_xfer.total_xferred = 0U;
+  _ctrl_xfer.data_len      = tu_min16(len, request->wLength);
+
+  if (request->wLength > 0U)
+  {
+    if(_ctrl_xfer.data_len > 0U)
+    {
+      TU_ASSERT(buffer);
+    }
+
+//    TU_LOG2("  Control total data length is %u bytes\r\n", _ctrl_xfer.data_len);
+
+    // Data stage
+    TU_ASSERT( _data_stage_xact(rhport) );
+  }
+  else
+  {
+    // Status stage
+    TU_ASSERT( _status_stage_xact(rhport, request) );
+  }
+
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// USBD API
+//--------------------------------------------------------------------+
+
+void usbd_control_reset(void);
+void usbd_control_set_request(tusb_control_request_t const *request);
+void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp );
+bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+
+void usbd_control_reset(void)
+{
+  tu_varclr(&_ctrl_xfer);
+}
+
+// Set complete callback
+void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp )
+{
+  _ctrl_xfer.complete_cb = fp;
+}
+
+// for dcd_set_address where DCD is responsible for status response
+void usbd_control_set_request(tusb_control_request_t const *request)
+{
+  _ctrl_xfer.request       = (*request);
+  _ctrl_xfer.buffer        = NULL;
+  _ctrl_xfer.total_xferred = 0;
+  _ctrl_xfer.data_len      = 0;
+}
+
+// callback when a transaction complete on
+// - DATA stage of control endpoint or
+// - Status stage
+bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) result;
+
+  // Endpoint Address is opposite to direction bit, this is Status Stage complete event
+  if ( tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction )
+  {
+    TU_ASSERT(0 == xferred_bytes);
+
+    // invoke optional dcd hook if available
+    if (dcd_edpt0_status_complete) dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request);
+
+    if (_ctrl_xfer.complete_cb)
+    {
+      // TODO refactor with usbd_driver_print_control_complete_name
+      _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_ACK, &_ctrl_xfer.request);
+    }
+
+    return true;
+  }
+
+  if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT )
+  {
+    TU_VERIFY(_ctrl_xfer.buffer);
+    memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes);
+    TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2);
+  }
+
+  _ctrl_xfer.total_xferred += xferred_bytes;
+  _ctrl_xfer.buffer += xferred_bytes;
+
+  // Data Stage is complete when all request's length are transferred or
+  // a short packet is sent including zero-length packet.
+  if ( (_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE) )
+  {
+    // DATA stage is complete
+    bool is_ok = true;
+
+    // invoke complete callback if set
+    // callback can still stall control in status phase e.g out data does not make sense
+    if ( _ctrl_xfer.complete_cb )
+    {
+      #if CFG_TUSB_DEBUG >= 2
+      usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb);
+      #endif
+
+      is_ok = _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_DATA, &_ctrl_xfer.request);
+    }
+
+    if ( is_ok )
+    {
+      // Send status
+      TU_ASSERT( _status_stage_xact(rhport, &_ctrl_xfer.request) );
+    }else
+    {
+      // Stall both IN and OUT control endpoint
+      dcd_edpt_stall(rhport, EDPT_CTRL_OUT);
+      dcd_edpt_stall(rhport, EDPT_CTRL_IN);
+    }
+  }
+  else
+  {
+    // More data to transfer
+    TU_ASSERT( _data_stage_xact(rhport) );
+  }
+
+  return true;
+}
+
+#endif
diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h
new file mode 100644
index 0000000..7607b98
--- /dev/null
+++ b/src/device/usbd_pvt.h
@@ -0,0 +1,115 @@
+/* 
+ * 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.
+ */
+#ifndef USBD_PVT_H_
+#define USBD_PVT_H_
+
+#include "osal/osal.h"
+#include "common/tusb_fifo.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Class Driver API
+//--------------------------------------------------------------------+
+
+typedef struct
+{
+  #if CFG_TUSB_DEBUG >= 2
+  char const* name;
+  #endif
+
+  void     (* init             ) (void);
+  void     (* reset            ) (uint8_t rhport);
+  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 */
+} usbd_class_driver_t;
+
+// Invoked when initializing device stack to get additional class drivers.
+// Can optionally implemented by application to extend/overwrite class driver support.
+// Note: The drivers array must be accessible at all time when stack is active
+usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK;
+
+typedef bool (*usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+
+//--------------------------------------------------------------------+
+// USBD Endpoint API
+//--------------------------------------------------------------------+
+
+// Open an endpoint
+bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep);
+
+// Close an endpoint
+void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr);
+
+// Submit a usb transfer
+bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
+
+// Submit a usb ISO transfer by use of a FIFO (ring buffer) - all bytes in FIFO get transmitted
+bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, 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 usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr);
+
+// Release an endpoint without submitting a transfer
+bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr);
+
+// Check if endpoint is busy transferring
+bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr);
+
+// Stall endpoint
+void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr);
+
+// Clear stalled endpoint
+void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr);
+
+// Check if endpoint is stalled
+bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr);
+
+// Check if endpoint is ready (not busy and not stalled)
+TU_ATTR_ALWAYS_INLINE static inline
+bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr)
+{
+  return !usbd_edpt_busy(rhport, ep_addr) && !usbd_edpt_stalled(rhport, ep_addr);
+}
+
+/*------------------------------------------------------------------*/
+/* Helper
+ *------------------------------------------------------------------*/
+
+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);
+void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr );
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* USBD_PVT_H_ */
diff --git a/src/host/hcd.h b/src/host/hcd.h
new file mode 100644
index 0000000..eb53d2e
--- /dev/null
+++ b/src/host/hcd.h
@@ -0,0 +1,179 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_HCD_H_
+#define _TUSB_HCD_H_
+
+#include "common/tusb_common.h"
+#include "osal/osal.h"
+#include "common/tusb_fifo.h"
+#include "hcd_attr.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ //--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef enum
+{
+  HCD_EVENT_DEVICE_ATTACH,
+  HCD_EVENT_DEVICE_REMOVE,
+  HCD_EVENT_XFER_COMPLETE,
+
+  // Not an HCD event, just a convenient way to defer ISR function
+  USBH_EVENT_FUNC_CALL,
+
+  HCD_EVENT_COUNT
+} hcd_eventid_t;
+
+typedef struct
+{
+  uint8_t rhport;
+  uint8_t event_id;
+  uint8_t dev_addr;
+
+  union
+  {
+    // Attach, Remove
+    struct {
+      uint8_t hub_addr;
+      uint8_t hub_port;
+      uint8_t speed;
+    } connection;
+
+    // XFER_COMPLETE
+    struct {
+      uint8_t ep_addr;
+      uint8_t result;
+      uint32_t len;
+    } xfer_complete;
+
+    // FUNC_CALL
+    struct {
+      void (*func) (void*);
+      void* param;
+    }func_call;
+  };
+
+} 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 {
+  uint8_t rhport;
+  uint8_t hub_addr;
+  uint8_t hub_port;
+  uint8_t speed;
+} hcd_devtree_info_t;
+
+#endif
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+// Initialize controller to host mode
+bool hcd_init(uint8_t rhport);
+
+// Interrupt Handler
+void hcd_int_handler(uint8_t rhport);
+
+// Enable USB interrupt
+void hcd_int_enable (uint8_t rhport);
+
+// Disable USB interrupt
+void hcd_int_disable(uint8_t rhport);
+
+// Get frame number (1ms)
+uint32_t hcd_frame_number(uint8_t rhport);
+
+//--------------------------------------------------------------------+
+// Port API
+//--------------------------------------------------------------------+
+
+// Get the current connect status of roothub port
+bool hcd_port_connect_status(uint8_t rhport);
+
+// Reset USB bus on the port
+void hcd_port_reset(uint8_t rhport);
+
+// TODO implement later
+void hcd_port_reset_end(uint8_t rhport);
+
+// Get port link speed
+tusb_speed_t hcd_port_speed_get(uint8_t rhport);
+
+// HCD closes all opened endpoints belong to this device
+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]);
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen);
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr);
+
+//--------------------------------------------------------------------+
+// USBH implemented API
+//--------------------------------------------------------------------+
+
+// Get device tree information of a device
+// USB device tree can be complicated and manged by USBH, this help HCD to retrieve
+// needed topology info to carry out its work
+extern void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info);
+
+//------------- Event API -------------//
+
+// Called by HCD to notify stack
+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);
+
+// Helper to send device removal event
+extern void hcd_event_device_remove(uint8_t rhport, bool 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);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_HCD_H_ */
diff --git a/src/host/hcd_attr.h b/src/host/hcd_attr.h
new file mode 100644
index 0000000..06011c6
--- /dev/null
+++ b/src/host/hcd_attr.h
@@ -0,0 +1,105 @@
+/*
+ * 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
new file mode 100644
index 0000000..fd4dbd0
--- /dev/null
+++ b/src/host/hub.c
@@ -0,0 +1,388 @@
+/* 
+ * 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 (TUSB_OPT_HOST_ENABLED && CFG_TUH_HUB)
+
+#include "usbh.h"
+#include "usbh_classdriver.h"
+#include "hub.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_in;
+  uint8_t port_count;
+  uint8_t status_change; // data from status change interrupt endpoint
+
+  hub_port_status_response_t port_status;
+} hub_interface_t;
+
+CFG_TUSB_MEM_SECTION static hub_interface_t hub_data[CFG_TUH_HUB];
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _hub_buffer[sizeof(descriptor_hub_desc_t)];
+
+TU_ATTR_ALWAYS_INLINE
+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
+static char const* const _hub_feature_str[] =
+{
+  [HUB_FEATURE_PORT_CONNECTION          ] = "PORT_CONNECTION",
+  [HUB_FEATURE_PORT_ENABLE              ] = "PORT_ENABLE",
+  [HUB_FEATURE_PORT_SUSPEND             ] = "PORT_SUSPEND",
+  [HUB_FEATURE_PORT_OVER_CURRENT        ] = "PORT_OVER_CURRENT",
+  [HUB_FEATURE_PORT_RESET               ] = "PORT_RESET",
+  [HUB_FEATURE_PORT_POWER               ] = "PORT_POWER",
+  [HUB_FEATURE_PORT_LOW_SPEED           ] = "PORT_LOW_SPEED",
+  [HUB_FEATURE_PORT_CONNECTION_CHANGE   ] = "PORT_CONNECTION_CHANGE",
+  [HUB_FEATURE_PORT_ENABLE_CHANGE       ] = "PORT_ENABLE_CHANGE",
+  [HUB_FEATURE_PORT_SUSPEND_CHANGE      ] = "PORT_SUSPEND_CHANGE",
+  [HUB_FEATURE_PORT_OVER_CURRENT_CHANGE ] = "PORT_OVER_CURRENT_CHANGE",
+  [HUB_FEATURE_PORT_RESET_CHANGE        ] = "PORT_RESET_CHANGE",
+  [HUB_FEATURE_PORT_TEST                ] = "PORT_TEST",
+  [HUB_FEATURE_PORT_INDICATOR           ] = "PORT_INDICATOR",
+};
+#endif
+
+//--------------------------------------------------------------------+
+// HUB
+//--------------------------------------------------------------------+
+bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb)
+{
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_OTHER,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
+    },
+    .bRequest = HUB_REQUEST_CLEAR_FEATURE,
+    .wValue   = feature,
+    .wIndex   = hub_port,
+    .wLength  = 0
+  };
+
+  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) );
+  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)
+{
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_OTHER,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
+    },
+    .bRequest = HUB_REQUEST_SET_FEATURE,
+    .wValue   = feature,
+    .wIndex   = hub_port,
+    .wLength  = 0
+  };
+
+  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) );
+  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)
+{
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_OTHER,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_IN
+    },
+    .bRequest = HUB_REQUEST_GET_STATUS,
+    .wValue   = 0,
+    .wIndex   = hub_port,
+    .wLength  = 4
+  };
+
+  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) );
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// CLASS-USBH API (don't require to verify parameters)
+//--------------------------------------------------------------------+
+void hub_init(void)
+{
+  tu_memclr(hub_data, sizeof(hub_data));
+}
+
+bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
+{
+  TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
+            0              == itf_desc->bInterfaceSubClass);
+
+  // hub driver does not support multiple TT yet
+  TU_VERIFY(itf_desc->bInterfaceProtocol <= 1);
+
+  // msc driver length is fixed
+  uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
+  TU_ASSERT(drv_len <= max_len);
+
+  //------------- Interrupt Status endpoint -------------//
+  tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+
+  TU_ASSERT(TUSB_DESC_ENDPOINT  == desc_ep->bDescriptorType &&
+            TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
+  
+  TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
+
+  hub_interface_t* p_hub = get_itf(dev_addr);
+
+  p_hub->itf_num = itf_desc->bInterfaceNumber;
+  p_hub->ep_in   = desc_ep->bEndpointAddress;
+
+  return true;
+}
+
+void hub_close(uint8_t dev_addr)
+{
+  TU_VERIFY(dev_addr > CFG_TUH_DEVICE_MAX, );
+  hub_interface_t* p_hub = get_itf(dev_addr);
+
+  if (p_hub->ep_in) tu_memclr(p_hub, sizeof( hub_interface_t));
+}
+
+bool hub_status_pipe_queue(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);
+}
+
+
+//--------------------------------------------------------------------+
+// 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);
+
+bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
+{
+  hub_interface_t* p_hub = get_itf(dev_addr);
+  TU_ASSERT(itf_num == p_hub->itf_num);
+
+  // Get Hub Descriptor
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_DEVICE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_IN
+    },
+    .bRequest = HUB_REQUEST_GET_DESCRIPTOR,
+    .wValue   = 0,
+    .wIndex   = 0,
+    .wLength  = sizeof(descriptor_hub_desc_t)
+  };
+
+  TU_ASSERT( tuh_control_xfer(dev_addr, &request, _hub_buffer, config_set_port_power) );
+
+  return true;
+}
+
+static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  (void) request;
+  TU_ASSERT(XFER_RESULT_SUCCESS == result);
+
+  hub_interface_t* p_hub = get_itf(dev_addr);
+
+  // only use number of ports in hub descriptor
+  descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer;
+  p_hub->port_count = desc_hub->bNbrPorts;
+
+  // May need to GET_STATUS
+
+  // 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);
+}
+
+static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  TU_ASSERT(XFER_RESULT_SUCCESS == result);
+   hub_interface_t* p_hub = get_itf(dev_addr);
+
+  if (request->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) );
+
+    usbh_driver_set_config_complete(dev_addr, 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);
+  }
+
+  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);
+
+// 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)
+{
+  (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
+  (void) ep_addr;
+  TU_ASSERT(result == XFER_RESULT_SUCCESS);
+
+  hub_interface_t* p_hub = get_itf(dev_addr);
+
+  TU_LOG2("  Port 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++)
+  {
+    if ( tu_bit_test(p_hub->status_change, port) )
+    {
+      hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete);
+      break;
+    }
+  }
+
+  // NOTE: next status transfer is queued by usbh.c after handling this request
+
+  return true;
+}
+
+static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  TU_ASSERT(result == XFER_RESULT_SUCCESS);
+
+  hub_interface_t* p_hub = get_itf(dev_addr);
+  uint8_t const port_num = (uint8_t) request->wIndex;
+
+  // Connection change
+  if (p_hub->port_status.change.connection)
+  {
+    // Port is powered and enabled
+    //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);
+  }else
+  {
+    // Other changes are: Enable, Suspend, Over Current, Reset, 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);
+  }
+
+  return true;
+}
+
+static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  TU_ASSERT(result == XFER_RESULT_SUCCESS);
+
+  hub_interface_t* p_hub = get_itf(dev_addr);
+  uint8_t const port_num = (uint8_t) request->wIndex;
+
+  if ( p_hub->port_status.status.connection )
+  {
+    // Reset port if attach event
+    hub_port_reset(dev_addr, port_num, connection_port_reset_complete);
+  }else
+  {
+    // submit detach event
+    hcd_event_t event =
+    {
+      .rhport     = usbh_get_rhport(dev_addr),
+      .event_id   = HCD_EVENT_DEVICE_REMOVE,
+      .connection =
+       {
+         .hub_addr = dev_addr,
+         .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)
+{
+  TU_ASSERT(result == XFER_RESULT_SUCCESS);
+
+  // hub_interface_t* p_hub = get_itf(dev_addr);
+  uint8_t const port_num = (uint8_t) request->wIndex;
+
+  // submit attach event
+  hcd_event_t event =
+  {
+    .rhport     = usbh_get_rhport(dev_addr),
+    .event_id   = HCD_EVENT_DEVICE_ATTACH,
+    .connection =
+    {
+      .hub_addr = dev_addr,
+      .hub_port = port_num
+    }
+  };
+
+  hcd_event_handler(&event, false);
+
+  return true;
+}
+
+#endif
diff --git a/src/host/hub.h b/src/host/hub.h
new file mode 100644
index 0000000..c4d5441
--- /dev/null
+++ b/src/host/hub.h
@@ -0,0 +1,196 @@
+/*
+ * 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_class
+ *  \defgroup ClassDriver_Hub Hub (Host only)
+ *  \details  Like most PC's OS, Hub support is completely hidden from Application. In fact, application cannot determine whether
+ *            a device is mounted directly via roothub or via a hub's port. All Hub-related procedures are performed and managed
+ *            by tinyusb stack. Unless you are trying to develop the stack itself, there are nothing else can be used by Application.
+ *  \note     Due to my laziness, only 1-level of Hub is supported. In other way, the stack cannot mount a hub via another hub.
+ *  @{
+ */
+
+#ifndef _TUSB_HUB_H_
+#define _TUSB_HUB_H_
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//D1...D0: Logical Power Switching Mode
+//00:  Ganged power switching (all ports’power at
+//once)
+//01:  Individual port power switching
+//1X:  Reserved. Used only on 1.0 compliant hubs
+//that implement no power switching
+//D2:  Identifies a Compound Device
+//0: Hub is not part of a compound device.
+//1: Hub is part of a compound device.
+//D4...D3: Over-current Protection Mode
+//00: Global Over-current Protection. The hub
+//reports over-current as a summation of all
+//ports’current draw, without a breakdown of
+//individual port over-current status.
+//01: Individual Port Over-current Protection. The
+//hub reports over-current on a per-port basis.
+//Each port has an over-current status.
+//1X: No Over-current Protection. This option is
+//allowed only for bus-powered hubs that do not
+//implement over-current protection.
+//
+//D6...D5: TT Think TIme
+//00:  TT requires at most 8 FS bit times of inter
+//transaction gap on a full-/low-speed
+//downstream bus.
+//01:  TT requires at most 16 FS bit times.
+//10:  TT requires at most 24 FS bit times.
+//11:  TT requires at most 32 FS bit times.
+//D7: Port Indicators Supported
+//0:  Port Indicators are not supported on its
+//downstream facing ports and the
+//PORT_INDICATOR request has no effect.
+//1:  Port Indicators are supported on its
+//downstream facing ports and the
+//PORT_INDICATOR request controls the
+//indicators. See Section 11.5.3.
+//D15...D8: Reserved
+
+typedef struct TU_ATTR_PACKED{
+  uint8_t  bLength           ; ///< Size of descriptor
+  uint8_t  bDescriptorType   ; ///< Other_speed_Configuration Type
+  uint8_t  bNbrPorts;
+  uint16_t wHubCharacteristics;
+  uint8_t  bPwrOn2PwrGood;
+  uint8_t  bHubContrCurrent;
+  uint8_t  DeviceRemovable; // bitmap each bit for a port (from bit1)
+  uint8_t  PortPwrCtrlMask; // just for compatibility, should be 0xff
+} descriptor_hub_desc_t;
+
+TU_VERIFY_STATIC( sizeof(descriptor_hub_desc_t) == 9, "size is not correct");
+
+enum {
+  HUB_REQUEST_GET_STATUS      = 0  ,
+  HUB_REQUEST_CLEAR_FEATURE   = 1  ,
+
+  HUB_REQUEST_SET_FEATURE     = 3  ,
+
+  HUB_REQUEST_GET_DESCRIPTOR  = 6  ,
+  HUB_REQUEST_SET_DESCRIPTOR  = 7  ,
+  HUB_REQUEST_CLEAR_TT_BUFFER = 8  ,
+  HUB_REQUEST_RESET_TT        = 9  ,
+  HUB_REQUEST_GET_TT_STATE    = 10 ,
+  HUB_REQUEST_STOP_TT         = 11
+};
+
+enum {
+  HUB_FEATURE_HUB_LOCAL_POWER_CHANGE = 0,
+  HUB_FEATURE_HUB_OVER_CURRENT_CHANGE
+};
+
+enum{
+  HUB_FEATURE_PORT_CONNECTION          = 0,
+  HUB_FEATURE_PORT_ENABLE              = 1,
+  HUB_FEATURE_PORT_SUSPEND             = 2,
+  HUB_FEATURE_PORT_OVER_CURRENT        = 3,
+  HUB_FEATURE_PORT_RESET               = 4,
+
+  HUB_FEATURE_PORT_POWER               = 8,
+  HUB_FEATURE_PORT_LOW_SPEED           = 9,
+
+  HUB_FEATURE_PORT_CONNECTION_CHANGE   = 16,
+  HUB_FEATURE_PORT_ENABLE_CHANGE       = 17,
+  HUB_FEATURE_PORT_SUSPEND_CHANGE      = 18,
+  HUB_FEATURE_PORT_OVER_CURRENT_CHANGE = 19,
+  HUB_FEATURE_PORT_RESET_CHANGE        = 20,
+  HUB_FEATURE_PORT_TEST                = 21,
+  HUB_FEATURE_PORT_INDICATOR           = 22
+};
+
+// data in response of HUB_REQUEST_GET_STATUS, wIndex = 0 (hub)
+typedef struct {
+  union{
+    struct TU_ATTR_PACKED {
+      uint16_t local_power_source : 1;
+      uint16_t over_current       : 1;
+      uint16_t : 14;
+    };
+
+    uint16_t value;
+  } status, change;
+} hub_status_response_t;
+
+TU_VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct");
+
+// data in response of HUB_REQUEST_GET_STATUS, wIndex = Port num
+typedef struct {
+  union {
+    struct TU_ATTR_PACKED {
+      uint16_t connection             : 1;
+      uint16_t port_enable            : 1;
+      uint16_t suspend                : 1;
+      uint16_t over_current           : 1;
+      uint16_t reset                  : 1;
+
+      uint16_t                        : 3;
+      uint16_t port_power             : 1;
+      uint16_t low_speed              : 1;
+      uint16_t high_speed             : 1;
+      uint16_t port_test_mode         : 1;
+      uint16_t port_indicator_control : 1;
+      uint16_t TU_RESERVED            : 3;
+    };
+
+    uint16_t value;
+  } status, change;
+} hub_port_status_response_t;
+
+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);
+
+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
+//--------------------------------------------------------------------+
+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);
+bool hub_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool hub_xfer_cb    (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+void hub_close      (uint8_t dev_addr);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_HUB_H_ */
+
+/** @} */
diff --git a/src/host/usbh.c b/src/host/usbh.c
new file mode 100644
index 0000000..b8439ad
--- /dev/null
+++ b/src/host/usbh.c
@@ -0,0 +1,1204 @@
+/* 
+ * 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 TUSB_OPT_HOST_ENABLED
+
+#include "tusb.h"
+#include "host/usbh.h"
+#include "host/usbh_classdriver.h"
+#include "hub.h"
+
+//--------------------------------------------------------------------+
+// 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
+
+// Debug level of USBD
+#define USBH_DBG_LVL   2
+
+//--------------------------------------------------------------------+
+// USBH-HCD common data structure
+//--------------------------------------------------------------------+
+
+// device0 struct must be strictly a subset of normal device struct
+typedef struct
+{
+  // port
+  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;
+  };
+} usbh_dev0_t;
+
+typedef struct {
+  // port
+  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 descriptor -------------//
+  uint16_t vid;
+  uint16_t pid;
+
+  uint8_t  ep0_size;
+  uint8_t  i_manufacturer;
+  uint8_t  i_product;
+  uint8_t  i_serial;
+
+  //------------- configuration descriptor -------------//
+  // uint8_t interface_count; // bNumInterfaces alias
+
+  //------------- device -------------//
+  volatile uint8_t state;            // device state, value from enum tusbh_device_state_t
+
+  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 )
+
+  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;
+#endif
+
+} usbh_device_t;
+
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+// Invalid driver ID in itf2drv[] ep2drv[][] mapping
+enum { DRVID_INVALID = 0xFFu };
+enum { ADDR_INVALID  = 0xFFu };
+
+#if CFG_TUSB_DEBUG >= 2
+  #define DRIVER_NAME(_name)    .name = _name,
+#else
+  #define DRIVER_NAME(_name)
+#endif
+
+static usbh_class_driver_t const usbh_class_drivers[] =
+{
+  #if CFG_TUH_CDC
+    {
+      DRIVER_NAME("CDC")
+      .init       = cdch_init,
+      .open       = cdch_open,
+      .set_config = cdch_set_config,
+      .xfer_cb    = cdch_xfer_cb,
+      .close      = cdch_close
+    },
+  #endif
+
+  #if CFG_TUH_MSC
+    {
+      DRIVER_NAME("MSC")
+      .init       = msch_init,
+      .open       = msch_open,
+      .set_config = msch_set_config,
+      .xfer_cb    = msch_xfer_cb,
+      .close      = msch_close
+    },
+  #endif
+
+  #if CFG_TUH_HID
+    {
+      DRIVER_NAME("HID")
+      .init       = hidh_init,
+      .open       = hidh_open,
+      .set_config = hidh_set_config,
+      .xfer_cb    = hidh_xfer_cb,
+      .close      = hidh_close
+    },
+  #endif
+
+  #if CFG_TUH_HUB
+    {
+      DRIVER_NAME("HUB")
+      .init       = hub_init,
+      .open       = hub_open,
+      .set_config = hub_set_config,
+      .xfer_cb    = hub_xfer_cb,
+      .close      = hub_close
+    },
+  #endif
+
+  #if CFG_TUH_VENDOR
+    {
+      DRIVER_NAME("VENDOR")
+      .init       = cush_init,
+      .open       = cush_open_subtask,
+      .xfer_cb    = cush_isr,
+      .close      = cush_close
+    }
+  #endif
+};
+
+enum { USBH_CLASS_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) };
+
+enum { RESET_DELAY = 500 };  // 200 USB specs say only 50ms but many devices require much longer
+
+enum { CONFIG_NUM = 1 }; // default to use configuration 1
+
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+
+static bool _usbh_initialized = false;
+
+// 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];
+
+// 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);
+static osal_queue_t _usbh_q;
+
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
+
+//------------- Helper Function -------------//
+
+TU_ATTR_ALWAYS_INLINE
+static inline usbh_device_t* get_device(uint8_t dev_addr)
+{
+  TU_ASSERT(dev_addr, 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);
+
+// 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);
+
+//--------------------------------------------------------------------+
+// PUBLIC API (Parameter Verification is required)
+//--------------------------------------------------------------------+
+bool tuh_mounted(uint8_t dev_addr)
+{
+  return get_device(dev_addr)->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);
+
+  *vid = dev->vid;
+  *pid = dev->pid;
+
+  return true;
+}
+
+tusb_speed_t tuh_speed_get (uint8_t dev_addr)
+{
+  return (tusb_speed_t) (dev_addr ? get_device(dev_addr)->speed : _dev0.speed);
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+void osal_task_delay(uint32_t msec)
+{
+  (void) msec;
+
+  const uint32_t start = hcd_frame_number(TUH_OPT_RHPORT);
+  while ( ( hcd_frame_number(TUH_OPT_RHPORT) - start ) < msec ) {}
+}
+#endif
+
+//--------------------------------------------------------------------+
+// CLASS-USBD API (don't require to verify parameters)
+//--------------------------------------------------------------------+
+
+bool tuh_inited(void)
+{
+  return _usbh_initialized;
+}
+
+bool tuh_init(uint8_t rhport)
+{
+  // skip if already initialized
+  if (_usbh_initialized) return _usbh_initialized;
+
+  TU_LOG2("USBH init\r\n");
+
+  tu_memclr(_usbh_devices, sizeof(_usbh_devices));
+  tu_memclr(&_dev0, sizeof(_dev0));
+
+  //------------- Enumeration & Reporter Task init -------------//
+  _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);
+#endif
+
+    memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
+    memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
+  }
+
+  // Class drivers init
+  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_initialized = true;
+  return true;
+}
+
+/* USB Host Driver task
+ * This top level thread manages all host controller event and delegates events to class-specific drivers.
+ * This should be called periodically within the mainloop or rtos thread.
+ *
+   @code
+    int main(void)
+    {
+      application_init();
+      tusb_init();
+
+      while(1) // the mainloop
+      {
+        application_code();
+        tuh_task(); // tinyusb host task
+      }
+    }
+    @endcode
+ */
+void tuh_task(void)
+{
+  // Skip if stack is not initialized
+  if ( !tusb_inited() ) return;
+
+  // Loop until there is no more events in the queue
+  while (1)
+  {
+    hcd_event_t event;
+    if ( !osal_queue_receive(_usbh_q, &event) ) 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");
+        enum_new_device(&event);
+      break;
+
+      case HCD_EVENT_DEVICE_REMOVE:
+        TU_LOG2("USBH DEVICE REMOVED\r\n");
+        process_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port);
+
+        #if CFG_TUH_HUB
+        // TODO remove
+        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 );
+        }
+        #endif
+      break;
+
+      case HCD_EVENT_XFER_COMPLETE:
+      {
+        uint8_t const ep_addr = event.xfer_complete.ep_addr;
+        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);
+
+        if (event.dev_addr == 0)
+        {
+          // device 0 only has control endpoint
+          TU_ASSERT(epnum == 0, );
+          usbh_control_xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
+        }
+        else
+        {
+          usbh_device_t* dev = get_device(event.dev_addr);
+          dev->ep_status[epnum][ep_dir].busy = false;
+          dev->ep_status[epnum][ep_dir].claimed = 0;
+
+          if ( 0 == epnum )
+          {
+            usbh_control_xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
+          }else
+          {
+            uint8_t drv_id = dev->ep2drv[epnum][ep_dir];
+            TU_ASSERT(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);
+          }
+        }
+      }
+      break;
+
+      case USBH_EVENT_FUNC_CALL:
+        if ( event.func_call.func ) event.func_call.func(event.func_call.param);
+      break;
+
+      default: break;
+    }
+  }
+}
+
+//--------------------------------------------------------------------+
+// USBH API For Class Driver
+//--------------------------------------------------------------------+
+
+uint8_t usbh_get_rhport(uint8_t dev_addr)
+{
+  return (dev_addr == 0) ? _dev0.rhport : get_device(dev_addr)->rhport;
+}
+
+uint8_t* usbh_get_enum_buf(void)
+{
+  return _usbh_ctrl_buf;
+}
+
+//--------------------------------------------------------------------+
+// HCD Event Handler
+//--------------------------------------------------------------------+
+
+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);
+
+    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;
+  }
+}
+
+void hcd_event_handler(hcd_event_t const* event, bool in_isr)
+{
+  switch (event->event_id)
+  {
+    default:
+      osal_queue_send(_usbh_q, event, in_isr);
+    break;
+  }
+}
+
+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,
+    .xfer_complete =
+    {
+      .ep_addr = ep_addr,
+      .result  = result,
+      .len     = xferred_bytes
+    }
+  };
+
+  hcd_event_handler(&event, in_isr);
+}
+
+void hcd_event_device_attach(uint8_t rhport, bool in_isr)
+{
+  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);
+}
+
+void hcd_event_device_remove(uint8_t hostid, bool in_isr)
+{
+  hcd_event_t event =
+  {
+    .rhport   = hostid,
+    .event_id = HCD_EVENT_DEVICE_REMOVE
+  };
+
+  event.connection.hub_addr = 0;
+  event.connection.hub_port = 0;
+
+  hcd_event_handler(&event, in_isr);
+}
+
+
+// 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)
+{
+  //------------- 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++ )
+  {
+    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 & hub_port == 0 means roothub
+        (hub_port == 0 || dev->hub_port == hub_port) &&
+        dev->state    != TUSB_DEVICE_STATE_UNPLUG)
+    {
+      // Invoke callback before close driver
+      if (tuh_umount_cb) tuh_umount_cb(dev_addr);
+
+      // 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);
+
+      // release all endpoints associated with the device
+      memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
+      memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
+      tu_memclr(dev->ep_status, sizeof(dev->ep_status));
+
+      dev->state = TUSB_DEVICE_STATE_UNPLUG;
+    }
+  }
+}
+
+//--------------------------------------------------------------------+
+// INTERNAL HELPER
+//--------------------------------------------------------------------+
+static uint8_t get_new_address(bool is_hub)
+{
+  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);
+
+  for (uint8_t i=0; i < count; i++)
+  {
+    uint8_t const addr = start + i;
+    if (get_device(addr)->state == TUSB_DEVICE_STATE_UNPLUG) return addr;
+  }
+  return ADDR_INVALID;
+}
+
+void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
+{
+  usbh_device_t* dev = get_device(dev_addr);
+
+  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;
+    }
+  }
+
+  // all interface are configured
+  if (itf_num == sizeof(dev->itf2drv))
+  {
+    // Invoke callback if available
+    if (tuh_mount_cb) tuh_mount_cb(dev_addr);
+  }
+}
+
+//--------------------------------------------------------------------+
+// 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.
+//--------------------------------------------------------------------+
+
+static bool enum_request_addr0_device_desc(void);
+static bool enum_request_set_addr(void);
+
+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);
+
+#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;
+}
+
+static bool enum_hub_clear_reset1_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_set_addr();
+
+  // done with hub, waiting for next data on status pipe
+  (void) hub_status_pipe_queue( _dev0.hub_addr );
+
+  return true;
+}
+
+static bool enum_hub_get_status1_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);
+
+  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_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) );
+  }
+
+  return true;
+}
+
+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);
+
+  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, queue hub status
+    return hub_status_pipe_queue(dev_addr);
+  }
+
+  _dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH :
+                (port_status.status.low_speed ) ? TUSB_SPEED_LOW  : TUSB_SPEED_FULL;
+
+  // Acknowledge Port Reset Change
+  if (port_status.change.reset)
+  {
+    hub_port_clear_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset0_complete);
+  }
+
+  return true;
+}
+#endif
+
+static bool enum_new_device(hcd_event_t* event)
+{
+  _dev0.rhport   = event->rhport; // TODO refractor integrate to device_pool
+  _dev0.hub_addr = event->connection.hub_addr;
+  _dev0.hub_port = event->connection.hub_port;
+
+  //------------- connected/disconnected directly with roothub -------------//
+  if (_dev0.hub_addr == 0)
+  {
+    // wait until device is stable TODO non blocking
+    osal_task_delay(RESET_DELAY);
+
+    // device unplugged while delaying
+    if ( !hcd_port_connect_status(_dev0.rhport) ) return true;
+
+    _dev0.speed = hcd_port_speed_get(_dev0.rhport );
+
+    enum_request_addr0_device_desc();
+  }
+#if CFG_TUH_HUB
+  //------------- connected/disconnected via hub -------------//
+  else
+  {
+    // 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) );
+  }
+#endif // CFG_TUH_HUB
+
+  return true;
+}
+
+static bool enum_request_addr0_device_desc(void)
+{
+  // 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 to get Control Endpoint Size -------------//
+  TU_LOG2("Get 8 byte of Device Descriptor\r\n");
+  tusb_control_request_t const 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_DEVICE << 8,
+    .wIndex   = 0,
+    .wLength  = 8
+  };
+  TU_ASSERT( tuh_control_xfer(addr0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete) );
+
+  return true;
+}
+
+// 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);
+
+  if (XFER_RESULT_SUCCESS != result)
+  {
+#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;
+  }
+
+  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 );
+
+  // Reset device again before Set Address
+  TU_LOG2("Port reset \r\n");
+
+  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);
+
+    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);
+
+    tuh_task(); // FIXME temporarily to clean up port_reset control transfer
+
+    TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) );
+  }
+#endif
+
+  return true;
+}
+
+static bool enum_request_set_addr(void)
+{
+  uint8_t const addr0 = 0;
+  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 != ADDR_INVALID);
+
+  TU_LOG2("Set Address = %d\r\n", new_addr);
+
+  usbh_device_t* new_dev = get_device(new_addr);
+
+  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 new_request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_DEVICE,
+      .type      = TUSB_REQ_TYPE_STANDARD,
+      .direction = TUSB_DIR_OUT
+    },
+    .bRequest = TUSB_REQ_SET_ADDRESS,
+    .wValue   = new_addr,
+    .wIndex   = 0,
+    .wLength  = 0
+  };
+
+  TU_ASSERT( tuh_control_xfer(addr0, &new_request, NULL, enum_set_address_complete) );
+
+  return true;
+}
+
+// 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)
+{
+  TU_ASSERT(0 == dev_addr);
+  TU_ASSERT(XFER_RESULT_SUCCESS == result);
+
+  uint8_t const new_addr = (uint8_t const) request->wValue;
+
+  usbh_device_t* new_dev = get_device(new_addr);
+  new_dev->addressed = 1;
+
+  // TODO close device 0, may not be needed
+  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");
+  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_DEVICE << 8,
+    .wIndex   = 0,
+    .wLength  = sizeof(tusb_desc_device_t)
+  };
+
+  TU_ASSERT(tuh_control_xfer(new_addr, &new_request, _usbh_ctrl_buf, enum_get_device_desc_complete));
+
+  return true;
+}
+
+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);
+
+  tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
+  usbh_device_t* dev = get_device(dev_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;
+
+//  if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf);
+
+  TU_LOG2("Get 9 bytes of 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  = 9
+  };
+
+  TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_9byte_config_desc_complete) );
+
+  return true;
+}
+
+static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  (void) request;
+  TU_ASSERT(XFER_RESULT_SUCCESS == result);
+
+  // TODO not enough buffer to hold configuration descriptor
+  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)) );
+
+  TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE);
+
+  // 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
+
+  };
+
+  TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_config_desc_complete) );
+
+  return true;
+}
+
+static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+{
+  (void) request;
+  TU_ASSERT(XFER_RESULT_SUCCESS == result);
+
+  // 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) );
+
+  TU_LOG2("Set Configuration = %d\r\n", CONFIG_NUM);
+  tusb_control_request_t const new_request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_DEVICE,
+      .type      = TUSB_REQ_TYPE_STANDARD,
+      .direction = TUSB_DIR_OUT
+    },
+    .bRequest = TUSB_REQ_SET_CONFIGURATION,
+    .wValue   = CONFIG_NUM,
+    .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;
+
+  // 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);
+
+  return true;
+}
+
+static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
+{
+  usbh_device_t* dev = get_device(dev_addr);
+
+  uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
+  uint8_t const* p_desc   = tu_desc_next(desc_cfg);
+
+  // parse each interfaces
+  while( p_desc < desc_end )
+  {
+    uint8_t assoc_itf_count = 1;
+
+    // Class will always starts with Interface Association (if any) and then Interface descriptor
+    if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
+    {
+      tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
+      assoc_itf_count = desc_iad->bInterfaceCount;
+
+      p_desc = tu_desc_next(p_desc); // next to Interface
+
+      // IAD's first interface number and class should match with opened interface
+      //TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber &&
+      //          desc_iad->bFunctionClass  == desc_itf->bInterfaceClass);
+    }
+
+    TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) );
+    tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
+
+#if CFG_TUH_MIDI
+    // MIDI has 2 interfaces (Audio Control v1 + MIDIStreaming) but does not have IAD
+    // manually increase the associated count
+    if (1                              == assoc_itf_count              &&
+        TUSB_CLASS_AUDIO               == desc_itf->bInterfaceClass    &&
+        AUDIO_SUBCLASS_CONTROL         == desc_itf->bInterfaceSubClass &&
+        AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol)
+    {
+      assoc_itf_count = 2;
+    }
+#endif
+
+    uint16_t const drv_len = tu_desc_get_interface_total_len(desc_itf, assoc_itf_count, 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++)
+      {
+        usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
+
+        if ( driver->open(dev->rhport, dev_addr, desc_itf, drv_len) )
+        {
+          // open successfully
+          TU_LOG2("  %s opened\r\n", driver->name);
+
+          // 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;
+          }
+
+          // bind all endpoints to found driver
+          tu_edpt_bind_driver(dev->ep2drv, desc_itf, drv_len, drv_id);
+
+          break; // exit driver find loop
+        }
+      }
+
+      if( drv_id >= USBH_CLASS_DRIVER_COUNT )
+      {
+        TU_LOG(USBH_DBG_LVL, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n",
+               desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol);
+      }
+    }
+
+    // next Interface or IAD descriptor
+    p_desc += drv_len;
+  }
+
+  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)
+{
+  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)
+  {
+    dev->ep_status[epnum][dir].claimed = 1;
+  }
+
+#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)
+  {
+    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;
+
+  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;
+  }
+}
+
+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)
+{
+  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);
+
+  return dev->ep_status[epnum][dir].busy;
+}
+
+
+
+#endif
diff --git a/src/host/usbh.h b/src/host/usbh.h
new file mode 100644
index 0000000..8411cad
--- /dev/null
+++ b/src/host/usbh.h
@@ -0,0 +1,99 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_USBH_H_
+#define _TUSB_USBH_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#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);
+
+//--------------------------------------------------------------------+
+// APPLICATION API
+//--------------------------------------------------------------------+
+
+// Init host stack
+bool tuh_init(uint8_t rhport);
+
+// Check if host stack is already initialized
+bool tuh_inited(void);
+
+// Task function should be called in main/rtos loop
+void tuh_task(void);
+
+// Interrupt handler, name alias to HCD
+extern void hcd_int_handler(uint8_t rhport);
+#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);
+
+// Check if device is connected and configured
+bool tuh_mounted(uint8_t dev_addr);
+
+// Check if device is suspended
+static inline bool tuh_suspended(uint8_t dev_addr)
+{
+  // TODO implement suspend & resume on host
+  (void) dev_addr;
+  return false;
+}
+
+// Check if device is ready to communicate with
+TU_ATTR_ALWAYS_INLINE
+static inline bool tuh_ready(uint8_t dev_addr)
+{
+  return tuh_mounted(dev_addr) && !tuh_suspended(dev_addr);
+}
+
+// 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);
+
+//--------------------------------------------------------------------+
+// 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 dev_addr);
+
+/// Invoked when device is unmounted (bus reset/unplugged)
+TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/host/usbh_classdriver.h b/src/host/usbh_classdriver.h
new file mode 100644
index 0000000..8bc2622
--- /dev/null
+++ b/src/host/usbh_classdriver.h
@@ -0,0 +1,83 @@
+/*
+ * 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_USBH_CLASSDRIVER_H_
+#define _TUSB_USBH_CLASSDRIVER_H_
+
+#include "osal/osal.h"
+#include "common/tusb_fifo.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Class Driver API
+//--------------------------------------------------------------------+
+
+typedef struct {
+  #if CFG_TUSB_DEBUG >= 2
+  char const* name;
+  #endif
+
+  void (* const init       )(void);
+  bool (* const open       )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+  bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
+  bool (* const xfer_cb    )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+  void (* const close      )(uint8_t dev_addr);
+} usbh_class_driver_t;
+
+// Call by class driver to tell USBH that it has complete the enumeration
+void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num);
+
+uint8_t usbh_get_rhport(uint8_t dev_addr);
+
+uint8_t* usbh_get_enum_buf(void);
+
+//--------------------------------------------------------------------+
+// 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
+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);
+
+bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr);
+
+// Check if endpoint transferring is complete
+bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c
new file mode 100644
index 0000000..9204576
--- /dev/null
+++ b/src/host/usbh_control.c
@@ -0,0 +1,138 @@
+/* 
+ * 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
new file mode 100644
index 0000000..c8131d1
--- /dev/null
+++ b/src/osal/osal.h
@@ -0,0 +1,111 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_OSAL_H_
+#define _TUSB_OSAL_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/** \addtogroup group_osal
+ *  @{ */
+
+#include "common/tusb_common.h"
+
+// Return immediately
+#define OSAL_TIMEOUT_NOTIMEOUT     (0)
+// Default timeout
+#define OSAL_TIMEOUT_NORMAL        (10)
+// Wait forever
+#define OSAL_TIMEOUT_WAIT_FOREVER  (UINT32_MAX)
+
+#define OSAL_TIMEOUT_CONTROL_XFER  OSAL_TIMEOUT_WAIT_FOREVER
+
+typedef void (*osal_task_func_t)( void * );
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+  #include "osal_none.h"
+#elif CFG_TUSB_OS == OPT_OS_FREERTOS
+  #include "osal_freertos.h"
+#elif CFG_TUSB_OS == OPT_OS_MYNEWT
+  #include "osal_mynewt.h"
+#elif CFG_TUSB_OS == OPT_OS_PICO
+  #include "osal_pico.h"
+#elif CFG_TUSB_OS == OPT_OS_RTTHREAD
+  #include "osal_rtthread.h"
+#elif CFG_TUSB_OS == OPT_OS_CUSTOM
+  #include "tusb_os_custom.h" // implemented by application
+#else
+  #error OS is not supported yet
+#endif
+
+//--------------------------------------------------------------------+
+// 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
+
+//------------- 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);
+
+//------------- 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
+
+#ifdef __cplusplus
+ }
+#endif
+
+/** @} */
+
+#endif /* _TUSB_OSAL_H_ */
diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h
new file mode 100644
index 0000000..4573e01
--- /dev/null
+++ b/src/osal/osal_freertos.h
@@ -0,0 +1,172 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_OSAL_FREERTOS_H_
+#define _TUSB_OSAL_FREERTOS_H_
+
+// FreeRTOS Headers
+#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,FreeRTOS.h)
+#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,semphr.h)
+#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,queue.h)
+#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,task.h)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TASK API
+//--------------------------------------------------------------------+
+static inline void osal_task_delay(uint32_t msec)
+{
+  vTaskDelay( pdMS_TO_TICKS(msec) );
+}
+
+//--------------------------------------------------------------------+
+// Semaphore API
+//--------------------------------------------------------------------+
+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)
+{
+  return xSemaphoreCreateBinaryStatic(semdef);
+}
+
+static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
+{
+  if ( !in_isr )
+  {
+    return xSemaphoreGive(sem_hdl) != 0;
+  }
+  else
+  {
+    BaseType_t xHigherPriorityTaskWoken;
+    BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken);
+
+#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
+    if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR();
+#else
+    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+#endif
+
+    return res != 0;
+  }
+}
+
+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);
+}
+
+static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
+{
+  xQueueReset(sem_hdl);
+}
+
+//--------------------------------------------------------------------+
+// MUTEX API (priority inheritance)
+//--------------------------------------------------------------------+
+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)
+{
+  return xSemaphoreCreateMutexStatic(mdef);
+}
+
+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)
+{
+  return xSemaphoreGive(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) \
+  static _type _name##_##buf[_depth];\
+  osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf };
+
+typedef struct
+{
+  uint16_t depth;
+  uint16_t item_sz;
+  void*    buf;
+
+  StaticQueue_t sq;
+}osal_queue_def_t;
+
+typedef QueueHandle_t osal_queue_t;
+
+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)
+{
+  return xQueueReceive(qhdl, data, portMAX_DELAY);
+}
+
+static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
+{
+  if ( !in_isr )
+  {
+    return xQueueSendToBack(qhdl, data, OSAL_TIMEOUT_WAIT_FOREVER) != 0;
+  }
+  else
+  {
+    BaseType_t xHigherPriorityTaskWoken;
+    BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken);
+
+#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
+    if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR();
+#else
+    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+#endif
+
+    return res != 0;
+  }
+}
+
+static inline bool osal_queue_empty(osal_queue_t qhdl)
+{
+  return uxQueueMessagesWaiting(qhdl) == 0;
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_OSAL_FREERTOS_H_ */
diff --git a/src/osal/osal_mynewt.h b/src/osal/osal_mynewt.h
new file mode 100644
index 0000000..6882329
--- /dev/null
+++ b/src/osal/osal_mynewt.h
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+#ifndef OSAL_MYNEWT_H_
+#define OSAL_MYNEWT_H_
+
+#include "os/os.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TASK API
+//--------------------------------------------------------------------+
+static inline void osal_task_delay(uint32_t msec)
+{
+  os_time_delay( os_time_ms_to_ticks32(msec) );
+}
+
+//--------------------------------------------------------------------+
+// Semaphore API
+//--------------------------------------------------------------------+
+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)
+{
+  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)
+{
+  (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)
+{
+  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;
+}
+
+static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
+{
+  // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// MUTEX API (priority inheritance)
+//--------------------------------------------------------------------+
+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)
+{
+  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)
+{
+  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)
+{
+  return os_mutex_release(mutex_hdl) == OS_OK;
+}
+
+//--------------------------------------------------------------------+
+// QUEUE API
+//--------------------------------------------------------------------+
+
+// role device/host is used by OS NONE for mutex (disable usb isr) only
+#define OSAL_QUEUE_DEF(_role, _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};\
+
+typedef struct
+{
+  uint16_t depth;
+  uint16_t item_sz;
+  void*    buf;
+  void*    evbuf;
+
+  struct os_mempool mpool;
+  struct os_mempool epool;
+
+  struct os_eventq  evq;
+}osal_queue_def_t;
+
+typedef osal_queue_def_t* osal_queue_t;
+
+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;
+
+  os_eventq_init(&qdef->evq);
+  return (osal_queue_t) qdef;
+}
+
+static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
+{
+  struct os_event* ev;
+  ev = os_eventq_get(&qhdl->evq);
+
+  memcpy(data, ev->ev_arg, qhdl->item_sz); // copy message
+  os_memblock_put(&qhdl->mpool, ev->ev_arg); // put back mem block
+  os_memblock_put(&qhdl->epool, ev);         // put back ev block
+
+  return true;
+}
+
+static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
+{
+  (void) in_isr;
+
+  // get a block from mem pool for data
+  void* ptr = os_memblock_get(&qhdl->mpool);
+  if (!ptr) return false;
+  memcpy(ptr, data, qhdl->item_sz);
+
+  // get a block from event pool to put into queue
+  struct os_event* ev = (struct os_event*) os_memblock_get(&qhdl->epool);
+  if (!ev)
+  {
+    os_memblock_put(&qhdl->mpool, ptr);
+    return false;
+  }
+  tu_memclr(ev, sizeof(struct os_event));
+  ev->ev_arg = ptr;
+
+  os_eventq_put(&qhdl->evq, ev);
+
+  return true;
+}
+
+static inline bool osal_queue_empty(osal_queue_t qhdl)
+{
+  return STAILQ_EMPTY(&qhdl->evq.evq_list);
+}
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* OSAL_MYNEWT_H_ */
diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h
new file mode 100644
index 0000000..a1f997c
--- /dev/null
+++ b/src/osal/osal_none.h
@@ -0,0 +1,204 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_OSAL_NONE_H_
+#define _TUSB_OSAL_NONE_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TASK API
+//--------------------------------------------------------------------+
+
+
+//--------------------------------------------------------------------+
+// Binary Semaphore API
+//--------------------------------------------------------------------+
+typedef struct
+{
+  volatile uint16_t count;
+}osal_semaphore_def_t;
+
+typedef osal_semaphore_def_t* osal_semaphore_t;
+
+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)
+{
+  (void) in_isr;
+  sem_hdl->count++;
+  return true;
+}
+
+// TODO blocking for now
+static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
+{
+  (void) msec;
+
+  while (sem_hdl->count == 0) { }
+  sem_hdl->count--;
+
+  return true;
+}
+
+static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
+{
+  sem_hdl->count = 0;
+}
+
+//--------------------------------------------------------------------+
+// MUTEX API
+// Within tinyusb, mutex is never used in ISR context
+//--------------------------------------------------------------------+
+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)
+{
+  mdef->count = 1;
+  return mdef;
+}
+
+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)
+{
+  return osal_semaphore_post(mutex_hdl, false);
+}
+
+//--------------------------------------------------------------------+
+// QUEUE API
+//--------------------------------------------------------------------+
+#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;
+}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)       \
+  uint8_t _name##_buf[_depth*sizeof(_type)];              \
+  osal_queue_def_t _name = {                              \
+    .role = _role,                                        \
+    .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)
+{
+  (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
+}
+
+// unlock queue
+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
+}
+
+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)
+{
+  _osal_q_lock(qhdl);
+  bool success = tu_fifo_read(&qhdl->ff, data);
+  _osal_q_unlock(qhdl);
+
+  return success;
+}
+
+static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
+{
+  if (!in_isr) {
+    _osal_q_lock(qhdl);
+  }
+
+  bool success = tu_fifo_write(&qhdl->ff, data);
+
+  if (!in_isr) {
+    _osal_q_unlock(qhdl);
+  }
+
+  TU_ASSERT(success);
+
+  return success;
+}
+
+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
+  return tu_fifo_empty(&qhdl->ff);
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_OSAL_NONE_H_ */
diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h
new file mode 100644
index 0000000..1c3366e
--- /dev/null
+++ b/src/osal/osal_pico.h
@@ -0,0 +1,187 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Raspberry Pi (Trading) 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.
+ */
+
+#ifndef _TUSB_OSAL_PICO_H_
+#define _TUSB_OSAL_PICO_H_
+
+#include "pico/time.h"
+#include "pico/sem.h"
+#include "pico/mutex.h"
+#include "pico/critical_section.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TASK API
+//--------------------------------------------------------------------+
+static inline void osal_task_delay(uint32_t msec)
+{
+  sleep_ms(msec);
+}
+
+//--------------------------------------------------------------------+
+// Binary Semaphore API
+//--------------------------------------------------------------------+
+typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t;
+
+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)
+{
+  (void) in_isr;
+  sem_release(sem_hdl);
+  return true;
+}
+
+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)
+{
+  sem_reset(sem_hdl, 0);
+}
+
+//--------------------------------------------------------------------+
+// MUTEX API
+// Within tinyusb, mutex is never used in ISR context
+//--------------------------------------------------------------------+
+typedef struct mutex osal_mutex_def_t, *osal_mutex_t;
+
+static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
+{
+    mutex_init(mdef);
+    return mdef;
+}
+
+static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
+{
+    return mutex_enter_timeout_ms(mutex_hdl, msec);
+}
+
+static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
+{
+    mutex_exit(mutex_hdl);
+    return true;
+}
+
+//--------------------------------------------------------------------+
+// QUEUE API
+//--------------------------------------------------------------------+
+#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;
+    struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section
+} 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)       \
+  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)
+{
+    critical_section_enter_blocking(&qhdl->critsec);
+}
+
+// unlock queue
+static inline void _osal_q_unlock(osal_queue_t qhdl)
+{
+    critical_section_exit(&qhdl->critsec);
+}
+
+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)
+{
+  // 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
+  //assert(!qhdl->ff.mutex);
+
+  _osal_q_lock(qhdl);
+  bool success = tu_fifo_read(&qhdl->ff, data);
+  _osal_q_unlock(qhdl);
+
+  return success;
+}
+
+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
+  //  the fifo mutex is not populated for queues used from an IRQ context
+  //assert(!qhdl->ff.mutex);
+  (void) in_isr;
+
+  _osal_q_lock(qhdl);
+  bool success = tu_fifo_write(&qhdl->ff, data);
+  _osal_q_unlock(qhdl);
+
+  TU_ASSERT(success);
+
+  return success;
+}
+
+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.
+
+  // Skip queue lock/unlock since this function is primarily called
+  // with interrupt disabled before going into low power mode
+  return tu_fifo_empty(&qhdl->ff);
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_OSAL_PICO_H_ */
diff --git a/src/osal/osal_rtthread.h b/src/osal/osal_rtthread.h
new file mode 100644
index 0000000..d5c062a
--- /dev/null
+++ b/src/osal/osal_rtthread.h
@@ -0,0 +1,130 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 tfx2001 (2479727366@qq.com)
+ *
+ * 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_RTTHREAD_H_
+#define _TUSB_OSAL_RTTHREAD_H_
+
+// RT-Thread Headers
+#include "rtthread.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TASK API
+//--------------------------------------------------------------------+
+static inline void osal_task_delay(uint32_t msec) {
+  rt_thread_mdelay(msec);
+}
+
+//--------------------------------------------------------------------+
+// Semaphore API
+//--------------------------------------------------------------------+
+typedef struct rt_semaphore osal_semaphore_def_t;
+typedef rt_sem_t osal_semaphore_t;
+
+static inline osal_semaphore_t
+osal_semaphore_create(osal_semaphore_def_t *semdef) {
+    rt_sem_init(semdef, "tusb", 0, RT_IPC_FLAG_FIFO);
+    return semdef;
+}
+
+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;
+}
+
+static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) {
+    // TODO: implement
+}
+
+//--------------------------------------------------------------------+
+// MUTEX API (priority inheritance)
+//--------------------------------------------------------------------+
+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);
+    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;
+}
+
+static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
+    return rt_mutex_release(mutex_hdl) == RT_EOK;
+}
+
+//--------------------------------------------------------------------+
+// QUEUE API
+//--------------------------------------------------------------------+
+
+// role device/host is used by OS NONE for mutex (disable usb isr) only
+#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
+    static _type _name##_##buf[_depth]; \
+    osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf };
+
+typedef struct {
+    uint16_t depth;
+    uint16_t item_sz;
+    void *buf;
+
+    struct rt_messagequeue sq;
+} osal_queue_def_t;
+
+typedef rt_mq_t osal_queue_t;
+
+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);
+    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;
+}
+
+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) {
+    return (qhdl->entry) == 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_OSAL_RTTHREAD_H_ */
diff --git a/src/portable/broadcom/synopsys/dcd_synopsys.c b/src/portable/broadcom/synopsys/dcd_synopsys.c
new file mode 100644
index 0000000..494bb70
--- /dev/null
+++ b/src/portable/broadcom/synopsys/dcd_synopsys.c
@@ -0,0 +1,1267 @@
+/*
+ * 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
new file mode 100644
index 0000000..81ce3b4
--- /dev/null
+++ b/src/portable/broadcom/synopsys/synopsys_common.h
@@ -0,0 +1,1476 @@
+/**
+  ******************************************************************************
+  * @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 0000000..78ca5a5
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
@@ -0,0 +1,50 @@
+/*
+ * 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"
+
+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 0000000..8c2e7df
--- /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 0000000..728a86b
--- /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 0000000..c943396
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -0,0 +1,637 @@
+/*
+ * 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"
+#include "device/dcd_attr.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && defined(DCD_ATTR_CONTROLLER_CHIPIDEA_HS)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "device/dcd.h"
+#include "ci_hs_type.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+  #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[DCD_ATTR_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
+  dcd_qtd_t qtd[DCD_ATTR_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;
+}
+
+//--------------------------------------------------------------------+
+// 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 < DCD_ATTR_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 0000000..3d028bf
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -0,0 +1,93 @@
+/* 
+ * 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 TUSB_OPT_HOST_ENABLED && \
+    (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "common/tusb_common.h"
+#include "portable/ehci/ehci_api.h"
+#include "ci_hs_type.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+  #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
new file mode 100644
index 0000000..3111197
--- /dev/null
+++ b/src/portable/dialog/da146xx/dcd_da146xx.c
@@ -0,0 +1,1203 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 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 TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_DA1469X
+
+#include "mcu/mcu.h"
+
+#include "device/dcd.h"
+
+/*------------------------------------------------------------------*/
+/* MACRO TYPEDEF CONSTANT ENUM
+ *------------------------------------------------------------------*/
+
+// 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
+
+// Size of RX or TX FIFO.
+#define FIFO_SIZE         64
+
+#ifndef TU_DA1469X_FIFO_READ_THRESHOLD
+// RX FIFO is 64 bytes. When endpoint size is greater then 64, FIFO warning interrupt
+// is enabled to allow read incoming data during frame reception.
+// It is possible to stay in interrupt reading whole packet at once, but it may be
+// more efficient for MCU to read as much data as possible and when FIFO is hardly
+// filled exit interrupt handler waiting for next FIFO warning level interrupt
+// or packet end.
+// When running at 96MHz code that reads FIFO based on number of bytes stored in
+// USB_RXSx_REG.USB_RXCOUNT takes enough time to fill FIFO with two additional bytes.
+// Settings this threshold above this allows to leave interrupt handler and wait
+// for more bytes to before next ISR. This allows reduce overall ISR time to 1/3
+// of time that would be needed if ISR read as fast as possible.
+#define TU_DA1469X_FIFO_READ_THRESHOLD  4
+#endif
+
+#define EP_MAX            4
+
+// Node functional states
+#define NFSR_NODE_RESET         0
+#define NFSR_NODE_RESUME        1
+#define NFSR_NODE_OPERATIONAL   2
+#define NFSR_NODE_SUSPEND       3
+// Those two following states are added to allow going out of sleep mode
+// using frame interrupt.  On remove wakeup RESUME state must be kept for
+// at least 1ms. It is accomplished by using FRAME interrupt that goes
+// through those two fake states before entering OPERATIONAL state.
+#define NFSR_NODE_WAKING        (0x10 | (NFSR_NODE_RESUME))
+#define NFSR_NODE_WAKING2       (0x20 | (NFSR_NODE_RESUME))
+
+static TU_ATTR_ALIGNED(4) uint8_t _setup_packet[8];
+
+typedef struct
+{
+  union
+  {
+    __IOM uint32_t epc_in;
+    __IOM uint32_t USB_EPC0_REG;                 /*!< (@ 0x00000080) Endpoint Control 0 Register  */
+    __IOM uint32_t USB_EPC1_REG;                 /*!< (@ 0x000000A0) Endpoint Control Register 1  */
+    __IOM uint32_t USB_EPC3_REG;                 /*!< (@ 0x000000C0) Endpoint Control Register 3  */
+    __IOM uint32_t USB_EPC5_REG;                 /*!< (@ 0x000000E0) Endpoint Control Register 5  */
+  };
+  union
+  {
+    __IOM uint32_t txd;
+    __IOM uint32_t USB_TXD0_REG;                 /*!< (@ 0x00000084) Transmit Data 0 Register     */
+    __IOM uint32_t USB_TXD1_REG;                 /*!< (@ 0x000000A4) Transmit Data Register 1     */
+    __IOM uint32_t USB_TXD2_REG;                 /*!< (@ 0x000000C4) Transmit Data Register 2     */
+    __IOM uint32_t USB_TXD3_REG;                 /*!< (@ 0x000000E4) Transmit Data Register 3     */
+  };
+  union
+  {
+    __IOM uint32_t txs;
+    __IOM uint32_t USB_TXS0_REG;                 /*!< (@ 0x00000088) Transmit Status 0 Register   */
+    __IOM uint32_t USB_TXS1_REG;                 /*!< (@ 0x000000A8) Transmit Status Register 1   */
+    __IOM uint32_t USB_TXS2_REG;                 /*!< (@ 0x000000C8) Transmit Status Register 2   */
+    __IOM uint32_t USB_TXS3_REG;                 /*!< (@ 0x000000E8) Transmit Status Register 3   */
+  };
+  union
+  {
+    __IOM uint32_t txc;
+    __IOM uint32_t USB_TXC0_REG;                 /*!< (@ 0x0000008C) Transmit command 0 Register  */
+    __IOM uint32_t USB_TXC1_REG;                 /*!< (@ 0x000000AC) Transmit Command Register 1  */
+    __IOM uint32_t USB_TXC2_REG;                 /*!< (@ 0x000000CC) Transmit Command Register 2  */
+    __IOM uint32_t USB_TXC3_REG;                 /*!< (@ 0x000000EC) Transmit Command Register 3  */
+  };
+  union
+  {
+    __IOM uint32_t epc_out;
+    __IOM uint32_t USB_EP0_NAK_REG;              /*!< (@ 0x00000090) EP0 INNAK and OUTNAK Register */
+    __IOM uint32_t USB_EPC2_REG;                 /*!< (@ 0x000000B0) Endpoint Control Register 2   */
+    __IOM uint32_t USB_EPC4_REG;                 /*!< (@ 0x000000D0) Endpoint Control Register 4   */
+    __IOM uint32_t USB_EPC6_REG;                 /*!< (@ 0x000000F0) Endpoint Control Register 6   */
+  };
+  union
+  {
+    __IOM uint32_t rxd;
+    __IOM uint32_t USB_RXD0_REG;                 /*!< (@ 0x00000094) Receive Data 0 Register       */
+    __IOM uint32_t USB_RXD1_REG;                 /*!< (@ 0x000000B4) Receive Data Register,1       */
+    __IOM uint32_t USB_RXD2_REG;                 /*!< (@ 0x000000D4) Receive Data Register 2       */
+    __IOM uint32_t USB_RXD3_REG;                 /*!< (@ 0x000000F4) Receive Data Register 3       */
+  };
+  union
+  {
+    __IOM uint32_t rxs;
+    __IOM uint32_t USB_RXS0_REG;                 /*!< (@ 0x00000098) Receive Status 0 Register     */
+    __IOM uint32_t USB_RXS1_REG;                 /*!< (@ 0x000000B8) Receive Status Register 1     */
+    __IOM uint32_t USB_RXS2_REG;                 /*!< (@ 0x000000D8) Receive Status Register 2     */
+    __IOM uint32_t USB_RXS3_REG;                 /*!< (@ 0x000000F8) Receive Status Register 3     */
+  };
+  union
+  {
+    __IOM uint32_t rxc;
+    __IOM uint32_t USB_RXC0_REG;                 /*!< (@ 0x0000009C) Receive Command 0 Register    */
+    __IOM uint32_t USB_RXC1_REG;                 /*!< (@ 0x000000BC) Receive Command Register 1    */
+    __IOM uint32_t USB_RXC2_REG;                 /*!< (@ 0x000000DC) Receive Command Register 2    */
+    __IOM uint32_t USB_RXC3_REG;                 /*!< (@ 0x000000FC) Receive Command Register 3    */
+  };
+} volatile EPx_REGS;
+
+#define EP_REGS(first_ep_reg) (EPx_REGS*)(&USB->first_ep_reg)
+
+// DMA channel pair to use, channel 6 will be used for RX channel 7 for TX direction.
+#ifndef TU_DA146XX_DMA_RX_CHANNEL
+#define TU_DA146XX_DMA_RX_CHANNEL 6
+#endif
+#define DA146XX_DMA_USB_MUX       (0x6 << (TU_DA146XX_DMA_RX_CHANNEL * 2))
+#define DA146XX_DMA_USB_MUX_MASK  (0xF << (TU_DA146XX_DMA_RX_CHANNEL * 2))
+
+typedef struct
+{
+  __IOM uint32_t DMAx_A_START_REG;
+  __IOM uint32_t DMAx_B_START_REG;
+  __IOM uint32_t DMAx_INT_REG;
+  __IOM uint32_t DMAx_LEN_REG;
+  __IOM uint32_t DMAx_CTRL_REG;
+  __IOM uint32_t DMAx_IDX_REG;
+  __IM uint32_t RESERVED[2]; // Extend structure size for array like usage, registers for each channel are 0x20 bytes apart.
+} da146xx_dma_channel_t;
+
+#define DMA_CHANNEL_REGS(n) ((da146xx_dma_channel_t *)(DMA) + n)
+#define RX_DMA_REGS  DMA_CHANNEL_REGS(TU_DA146XX_DMA_RX_CHANNEL)
+#define TX_DMA_REGS  DMA_CHANNEL_REGS((TU_DA146XX_DMA_RX_CHANNEL) + 1)
+
+#define RX_DMA_START ((1 << DMA_DMA0_CTRL_REG_DMA_ON_Pos) |\
+                      (0 << DMA_DMA0_CTRL_REG_BW_Pos) | \
+                      (1 << DMA_DMA0_CTRL_REG_DREQ_MODE_Pos) | \
+                      (1 << DMA_DMA0_CTRL_REG_BINC_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_AINC_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_CIRCULAR_Pos) | \
+                      (2 << DMA_DMA0_CTRL_REG_DMA_PRIO_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_DMA_IDLE_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_DMA_INIT_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_REQ_SENSE_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_BURST_MODE_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_BUS_ERROR_DETECT_Pos))
+
+#define TX_DMA_START ((1 << DMA_DMA0_CTRL_REG_DMA_ON_Pos) |\
+                      (0 << DMA_DMA0_CTRL_REG_BW_Pos) | \
+                      (1 << DMA_DMA0_CTRL_REG_DREQ_MODE_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_BINC_Pos) | \
+                      (1 << DMA_DMA0_CTRL_REG_AINC_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_CIRCULAR_Pos) | \
+                      (2 << DMA_DMA0_CTRL_REG_DMA_PRIO_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_DMA_IDLE_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_DMA_INIT_Pos) | \
+                      (1 << DMA_DMA0_CTRL_REG_REQ_SENSE_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_BURST_MODE_Pos) | \
+                      (0 << DMA_DMA0_CTRL_REG_BUS_ERROR_DETECT_Pos))
+
+// Dialog register fields and bit mask are very long. Filed masks repeat register names.
+// Those convenience macros are a way to reduce complexity of register modification lines.
+#define GET_BIT(val, field) (val & field ## _Msk) >> field ## _Pos
+#define REG_GET_BIT(reg, field) (USB->reg & USB_ ## reg ## _ ## field ## _Msk)
+#define REG_SET_BIT(reg, field) USB->reg |= USB_ ## reg ## _ ## field ## _Msk
+#define REG_CLR_BIT(reg, field) USB->reg &= ~USB_ ## reg ## _ ## field ## _Msk
+#define REG_SET_VAL(reg, field, val) USB->reg = (USB->reg & ~USB_ ## reg ## _ ## field ## _Msk) | (val << USB_ ## reg ## _ ## field ## _Pos)
+
+static EPx_REGS * const ep_regs[EP_MAX] = {
+  EP_REGS(USB_EPC0_REG),
+  EP_REGS(USB_EPC1_REG),
+  EP_REGS(USB_EPC3_REG),
+  EP_REGS(USB_EPC5_REG),
+};
+
+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;
+  // 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;
+  // DATA0/1 toggle bit 1 DATA1 is expected or transmitted
+  uint8_t data1 : 1;
+  // Endpoint is stalled
+  uint8_t stall : 1;
+  // ISO endpoint
+  uint8_t iso : 1;
+} xfer_ctl_t;
+
+static struct
+{
+  bool vbus_present;
+  bool init_called;
+  uint8_t nfsr;
+  xfer_ctl_t xfer_status[EP_MAX][2];
+  // Endpoints that use DMA, one for each direction
+  uint8_t dma_ep[2];
+} _dcd =
+{
+  .vbus_present = false,
+  .init_called = false,
+};
+
+// Converts xfer pointer to epnum (0,1,2,3) regardless of xfer direction
+#define XFER_EPNUM(xfer)      ((xfer - &_dcd.xfer_status[0][0]) >> 1)
+// Converts xfer pinter to EPx_REGS pointer (returns same pointer for IN and OUT with same endpoint number)
+#define XFER_REGS(xfer)       ep_regs[XFER_EPNUM(xfer)]
+// Converts epnum (0,1,2,3) to EPx_REGS pointer
+#define EPNUM_REGS(epnum)     ep_regs[epnum]
+
+// Two endpoint 0 descriptor definition for unified dcd_edpt_open()
+static const tusb_desc_endpoint_t 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 const tusb_desc_endpoint_t 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 set_nfsr(uint8_t val)
+{
+  _dcd.nfsr = val;
+  // Write only lower 2 bits to register, higher bits are used
+  // to count down till OPERATIONAL state can be entered when
+  // remote wakeup activated.
+  USB->USB_NFSR_REG = val & 3;
+}
+
+static void fill_tx_fifo(xfer_ctl_t * xfer)
+{
+  int left_to_send;
+  uint8_t const *src;
+  uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
+  EPx_REGS *regs = EPNUM_REGS(epnum);
+
+  src = &xfer->buffer[xfer->transferred];
+  left_to_send = xfer->total_len - xfer->transferred;
+  if (left_to_send > xfer->max_packet_size - xfer->last_packet_size)
+  {
+    left_to_send = xfer->max_packet_size - xfer->last_packet_size;
+  }
+
+  // Loop checks TCOUNT all the time since this value is saturated to 31
+  // and can't be read just once before.
+  while ((regs->txs & USB_USB_TXS1_REG_USB_TCOUNT_Msk) > 0 && left_to_send > 0)
+  {
+    regs->txd = *src++;
+    xfer->last_packet_size++;
+    left_to_send--;
+  }
+  if (epnum != 0)
+  {
+    if (left_to_send > 0)
+    {
+      // Max packet size is set to value greater then FIFO. Enable fifo level warning
+      // to handle larger packets.
+      regs->txc |= (3 << USB_USB_TXC1_REG_USB_TFWL_Pos);
+      USB->USB_FWMSK_REG |= 1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_TXWARN31_Pos);
+    }
+    else
+    {
+      regs->txc &= ~USB_USB_TXC1_REG_USB_TFWL_Msk;
+      USB->USB_FWMSK_REG &= ~(1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_TXWARN31_Pos));
+      // Whole packet already in fifo, no need to refill it later.  Mark last.
+      regs->txc |= USB_USB_TXC1_REG_USB_LAST_Msk;
+    }
+  }
+}
+
+static bool try_allocate_dma(uint8_t epnum, uint8_t dir)
+{
+  // TODO: Disable interrupts while checking
+  if (_dcd.dma_ep[dir] == 0)
+  {
+    _dcd.dma_ep[dir] = epnum;
+    if (dir == TUSB_DIR_OUT)
+      USB->USB_DMA_CTRL_REG = (USB->USB_DMA_CTRL_REG & ~USB_USB_DMA_CTRL_REG_USB_DMA_RX_Msk) |
+        ((epnum - 1) << USB_USB_DMA_CTRL_REG_USB_DMA_RX_Pos);
+    else
+      USB->USB_DMA_CTRL_REG = (USB->USB_DMA_CTRL_REG & ~USB_USB_DMA_CTRL_REG_USB_DMA_TX_Msk) |
+        ((epnum - 1) << USB_USB_DMA_CTRL_REG_USB_DMA_TX_Pos);
+    USB->USB_DMA_CTRL_REG |= USB_USB_DMA_CTRL_REG_USB_DMA_EN_Msk;
+  }
+  return _dcd.dma_ep[dir] == epnum;
+}
+
+static void start_rx_dma(volatile void *src, void *dst, uint16_t size)
+{
+  // Setup SRC and DST registers
+  RX_DMA_REGS->DMAx_A_START_REG = (uint32_t)src;
+  RX_DMA_REGS->DMAx_B_START_REG = (uint32_t)dst;
+  // Don't need DMA interrupt, read end is determined by RX_LAST or RX_ERR events.
+  RX_DMA_REGS->DMAx_INT_REG = size - 1;
+  RX_DMA_REGS->DMAx_LEN_REG = size - 1;
+  RX_DMA_REGS->DMAx_CTRL_REG = RX_DMA_START;
+}
+
+static void start_rx_packet(xfer_ctl_t *xfer)
+{
+  uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
+  uint16_t remaining = xfer->total_len - xfer->transferred;
+  uint16_t size = tu_min16(remaining, xfer->max_packet_size);
+  EPx_REGS *regs = XFER_REGS(xfer);
+
+  xfer->last_packet_size = 0;
+  if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE)
+  {
+    if (try_allocate_dma(epnum, TUSB_DIR_OUT))
+    {
+      start_rx_dma(&regs->rxd, xfer->buffer + xfer->transferred, size);
+    }
+    else
+    {
+      // Other endpoint is using DMA in that direction, fall back to interrupts.
+      // For endpoint size greater than FIFO size enable FIFO level warning interrupt
+      // when FIFO has less than 17 bytes free.
+      regs->rxc |= USB_USB_RXC1_REG_USB_RFWL_Msk;
+      USB->USB_FWMSK_REG |= 1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_RXWARN31_Pos);
+    }
+  }
+  else if (epnum != 0)
+  {
+    // If max_packet_size would fit in FIFO no need for FIFO level warning interrupt.
+    regs->rxc &= ~USB_USB_RXC1_REG_USB_RFWL_Msk;
+    USB->USB_FWMSK_REG &= ~(1 << (epnum - 1 + USB_USB_FWMSK_REG_USB_M_RXWARN31_Pos));
+  }
+  regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
+}
+
+static void start_tx_dma(void *src, volatile void *dst, uint16_t size)
+{
+  // Setup SRC and DST registers
+  TX_DMA_REGS->DMAx_A_START_REG = (uint32_t)src;
+  TX_DMA_REGS->DMAx_B_START_REG = (uint32_t)dst;
+  // Interrupt not needed
+  TX_DMA_REGS->DMAx_INT_REG = size;
+  TX_DMA_REGS->DMAx_LEN_REG = size - 1;
+  TX_DMA_REGS->DMAx_CTRL_REG = TX_DMA_START;
+}
+
+static void start_tx_packet(xfer_ctl_t *xfer)
+{
+  uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
+  uint16_t remaining = xfer->total_len - xfer->transferred;
+  uint16_t size = tu_min16(remaining, xfer->max_packet_size);
+  EPx_REGS *regs = EPNUM_REGS(epnum);
+
+  xfer->last_packet_size = 0;
+
+  regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
+  regs->txc = USB_USB_TXC1_REG_USB_IGN_ISOMSK_Msk;
+  if (xfer->data1) regs->txc |= USB_USB_TXC1_REG_USB_TOGGLE_TX_Msk;
+
+  if (xfer->max_packet_size > FIFO_SIZE && remaining > FIFO_SIZE && try_allocate_dma(epnum, TUSB_DIR_IN))
+  {
+    // Whole packet will be put in FIFO by DMA. Set LAST bit before start.
+    start_tx_dma(xfer->buffer + xfer->transferred, &regs->txd, size);
+    regs->txc |= USB_USB_TXC1_REG_USB_LAST_Msk;
+  }
+  else
+  {
+    fill_tx_fifo(xfer);
+  }
+  regs->txc |= USB_USB_TXC1_REG_USB_TX_EN_Msk;
+}
+
+static uint16_t read_rx_fifo(xfer_ctl_t *xfer, uint16_t bytes_in_fifo)
+{
+  EPx_REGS *regs = XFER_REGS(xfer);
+  uint16_t remaining = xfer->total_len - xfer->transferred - xfer->last_packet_size;
+  uint16_t receive_this_time = bytes_in_fifo;
+
+  if (remaining < bytes_in_fifo) receive_this_time = remaining;
+
+  uint8_t *buf = xfer->buffer + xfer->transferred + xfer->last_packet_size;
+
+  for (int i = 0; i < receive_this_time; ++i) buf[i] = regs->rxd;
+
+  xfer->last_packet_size += receive_this_time;
+
+  return bytes_in_fifo - receive_this_time;
+}
+
+static void handle_ep0_rx(void)
+{
+  int fifo_bytes;
+  uint32_t rxs0 = USB->USB_RXS0_REG;
+
+  xfer_ctl_t *xfer = XFER_CTL_BASE(0, TUSB_DIR_OUT);
+
+  fifo_bytes = GET_BIT(rxs0, USB_USB_RXS0_REG_USB_RCOUNT);
+  if (rxs0 & USB_USB_RXS0_REG_USB_SETUP_Msk)
+  {
+    xfer_ctl_t *xfer_in = XFER_CTL_BASE(0, TUSB_DIR_IN);
+    // Setup packet is in
+    for (int i = 0; i < fifo_bytes; ++i) _setup_packet[i] = USB->USB_RXD0_REG;
+
+    xfer->stall = 0;
+    xfer->data1 = 1;
+    xfer_in->stall = 0;
+    xfer_in->data1 = 1;
+    REG_SET_BIT(USB_TXC0_REG, USB_TOGGLE_TX0);
+    REG_CLR_BIT(USB_EPC0_REG, USB_STALL);
+    dcd_event_setup_received(0, _setup_packet,true);
+  }
+  else
+  {
+    if (GET_BIT(rxs0, USB_USB_RXS0_REG_USB_TOGGLE_RX0) != xfer->data1)
+    {
+      // Toggle bit does not match discard packet
+      REG_SET_BIT(USB_RXC0_REG, USB_FLUSH);
+      xfer->last_packet_size = 0;
+    }
+    else
+    {
+      read_rx_fifo(xfer, fifo_bytes);
+      if (rxs0 & USB_USB_RXS0_REG_USB_RX_LAST_Msk)
+      {
+        xfer->transferred += xfer->last_packet_size;
+        xfer->data1 ^= 1;
+
+        if (xfer->total_len == xfer->transferred || xfer->last_packet_size < xfer->max_packet_size)
+        {
+          dcd_event_xfer_complete(0, 0, xfer->transferred, XFER_RESULT_SUCCESS, true);
+        }
+        else
+        {
+          // Re-enable reception
+          REG_SET_BIT(USB_RXC0_REG, USB_RX_EN);
+        }
+        xfer->last_packet_size = 0;
+      }
+    }
+  }
+}
+
+static void handle_ep0_tx(void)
+{
+  uint32_t txs0;
+  xfer_ctl_t *xfer = XFER_CTL_BASE(0, TUSB_DIR_IN);
+  EPx_REGS *regs = XFER_REGS(xfer);
+
+  txs0 = regs->USB_TXS0_REG;
+
+  if (GET_BIT(txs0, USB_USB_TXS0_REG_USB_TX_DONE))
+  {
+    // ACK received
+    if (GET_BIT(txs0, USB_USB_TXS0_REG_USB_ACK_STAT))
+    {
+      xfer->transferred += xfer->last_packet_size;
+      xfer->last_packet_size = 0;
+      xfer->data1 ^= 1;
+      REG_SET_VAL(USB_TXC0_REG, USB_TOGGLE_TX0, xfer->data1);
+      if (xfer->transferred == xfer->total_len)
+      {
+        dcd_event_xfer_complete(0, 0 | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
+        return;
+      }
+    }
+    else
+    {
+      // Start from the beginning
+      xfer->last_packet_size = 0;
+    }
+    fill_tx_fifo(xfer);
+  }
+}
+
+static void handle_epx_rx_ev(uint8_t ep)
+{
+  uint32_t rxs;
+  int fifo_bytes;
+  xfer_ctl_t *xfer = XFER_CTL_BASE(ep, TUSB_DIR_OUT);
+
+  EPx_REGS *regs = EPNUM_REGS(ep);
+
+  do
+  {
+    rxs = regs->rxs;
+
+    if (GET_BIT(rxs, USB_USB_RXS1_REG_USB_RX_ERR))
+    {
+      regs->rxc |= USB_USB_RXC1_REG_USB_FLUSH_Msk;
+      xfer->last_packet_size = 0;
+      if (_dcd.dma_ep[TUSB_DIR_OUT] == ep)
+      {
+        // Stop DMA
+        RX_DMA_REGS->DMAx_CTRL_REG &= ~DMA_DMA0_CTRL_REG_DMA_ON_Msk;
+        // Restart DMA since packet was dropped, all parameters should still work.
+        RX_DMA_REGS->DMAx_CTRL_REG |= DMA_DMA0_CTRL_REG_DMA_ON_Msk;
+      }
+      break;
+    }
+    else
+    {
+      if (_dcd.dma_ep[TUSB_DIR_OUT] == ep)
+      {
+        // Disable DMA and update last_packet_size with what DMA reported.
+        RX_DMA_REGS->DMAx_CTRL_REG &= ~DMA_DMA0_CTRL_REG_DMA_ON_Msk;
+        xfer->last_packet_size = RX_DMA_REGS->DMAx_IDX_REG;
+        // When DMA did not finished (packet was smaller then MPS), DMAx_IDX_REG holds exact number of bytes transmitted.
+        // When DMA finished value in DMAx_IDX_REG is one less then actual number of transmitted bytes.
+        if (xfer->last_packet_size == RX_DMA_REGS->DMAx_LEN_REG) xfer->last_packet_size++;
+        // Release DMA to use by other endpoints.
+        _dcd.dma_ep[TUSB_DIR_OUT] = 0;
+      }
+      fifo_bytes = GET_BIT(rxs, USB_USB_RXS1_REG_USB_RXCOUNT);
+      // FIFO maybe empty if DMA read it before or it's final iteration and function already read all that was to read.
+      if (fifo_bytes > 0)
+      {
+        fifo_bytes = read_rx_fifo(xfer, fifo_bytes);
+      }
+      if (GET_BIT(rxs, USB_USB_RXS1_REG_USB_RX_LAST))
+      {
+        if (!xfer->iso && GET_BIT(rxs, USB_USB_RXS1_REG_USB_TOGGLE_RX) != xfer->data1)
+        {
+          // Toggle bit does not match discard packet
+          regs->rxc |= USB_USB_RXC1_REG_USB_FLUSH_Msk;
+        }
+        else
+        {
+          xfer->data1 ^= 1;
+          xfer->transferred += xfer->last_packet_size;
+          if (xfer->total_len == xfer->transferred || xfer->last_packet_size < xfer->max_packet_size || xfer->iso)
+          {
+            if (fifo_bytes)
+            {
+              // There are extra bytes in the FIFO just flush them
+              regs->rxc |= USB_USB_RXC1_REG_USB_FLUSH_Msk;
+              fifo_bytes = 0;
+            }
+
+            dcd_event_xfer_complete(0, xfer->ep_addr, xfer->transferred, XFER_RESULT_SUCCESS, true);
+          }
+          else
+          {
+            // Re-enable reception
+            start_rx_packet(xfer);
+          }
+        }
+        xfer->last_packet_size = 0;
+      }
+    }
+  } while (fifo_bytes > TU_DA1469X_FIFO_READ_THRESHOLD);
+}
+
+static void handle_rx_ev(void)
+{
+  if (USB->USB_RXEV_REG & 1)
+    handle_epx_rx_ev(1);
+  if (USB->USB_RXEV_REG & 2)
+    handle_epx_rx_ev(2);
+  if (USB->USB_RXEV_REG & 4)
+    handle_epx_rx_ev(3);
+}
+
+static void handle_epx_tx_ev(xfer_ctl_t *xfer)
+{
+  uint8_t const epnum = tu_edpt_number(xfer->ep_addr);
+  uint32_t txs;
+  EPx_REGS *regs = EPNUM_REGS(epnum);
+
+  txs = regs->txs;
+
+  if (GET_BIT(txs, USB_USB_TXS1_REG_USB_TX_DONE))
+  {
+    if (_dcd.dma_ep[TUSB_DIR_IN] == epnum)
+    {
+      // Disable DMA and update last_packet_size with what DMA reported.
+      TX_DMA_REGS->DMAx_CTRL_REG &= ~DMA_DMA1_CTRL_REG_DMA_ON_Msk;
+      xfer->last_packet_size = TX_DMA_REGS->DMAx_IDX_REG + 1;
+      // Release DMA to used by other endpoints.
+      _dcd.dma_ep[TUSB_DIR_IN] = 0;
+    }
+    if (GET_BIT(txs, USB_USB_TXS1_REG_USB_ACK_STAT))
+    {
+      // ACK received, update transfer state and DATA0/1 bit
+      xfer->transferred += xfer->last_packet_size;
+      xfer->last_packet_size = 0;
+      xfer->data1 ^= 1;
+
+      if (xfer->transferred == xfer->total_len)
+      {
+        dcd_event_xfer_complete(0, xfer->ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true);
+        return;
+      }
+    }
+    else if (regs->epc_in & USB_USB_EPC1_REG_USB_STALL_Msk)
+    {
+      // TX_DONE also indicates that STALL packet was just sent, there is
+      // no point to put anything into transmit FIFO. It could result in
+      // empty packet being scheduled.
+      return;
+    }
+  }
+  if (txs & USB_USB_TXS1_REG_USB_TX_URUN_Msk)
+  {
+    TU_LOG1("EP %d FIFO underrun\n", epnum);
+  }
+  // Start next or repeated packet.
+  start_tx_packet(xfer);
+}
+
+static void handle_tx_ev(void)
+{
+  if (USB->USB_TXEV_REG & 1)
+    handle_epx_tx_ev(XFER_CTL_BASE(1, TUSB_DIR_IN));
+  if (USB->USB_TXEV_REG & 2)
+    handle_epx_tx_ev(XFER_CTL_BASE(2, TUSB_DIR_IN));
+  if (USB->USB_TXEV_REG & 4)
+    handle_epx_tx_ev(XFER_CTL_BASE(3, TUSB_DIR_IN));
+}
+
+static uint32_t check_reset_end(uint32_t alt_ev)
+{
+  if (_dcd.nfsr == NFSR_NODE_RESET)
+  {
+    if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESET))
+    {
+      // Could be still in reset, but since USB_M_RESET is disabled it can
+      // be also old reset state that was not cleared yet.
+      // If (after reading USB_ALTEV_REG register again) bit is cleared
+      // reset state just ended.
+      // Keep non-reset bits combined from two previous ALTEV read and
+      // one from the next line.
+      alt_ev = (alt_ev & ~USB_USB_ALTEV_REG_USB_RESET_Msk) | USB->USB_ALTEV_REG;
+    }
+    if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESET) == 0)
+    {
+      USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
+                            USB_USB_ALTEV_REG_USB_SD3_Msk;
+      set_nfsr(NFSR_NODE_OPERATIONAL);
+      dcd_edpt_open(0, &ep0OUT_desc);
+      dcd_edpt_open(0, &ep0IN_desc);
+    }
+  }
+  return alt_ev;
+}
+
+static void handle_bus_reset(void)
+{
+  uint32_t alt_ev;
+
+  USB->USB_NFSR_REG = 0;
+  USB->USB_FAR_REG = 0x80;
+  USB->USB_ALTMSK_REG = 0;
+  USB->USB_NFSR_REG = NFSR_NODE_RESET;
+  USB->USB_TXMSK_REG = 0;
+  USB->USB_RXMSK_REG = 0;
+  set_nfsr(NFSR_NODE_RESET);
+
+  dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+  USB->USB_DMA_CTRL_REG = 0;
+
+  USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
+                       USB_USB_MAMSK_REG_USB_M_FRAME_Msk |
+                       USB_USB_MAMSK_REG_USB_M_WARN_Msk |
+                       USB_USB_MAMSK_REG_USB_M_ALT_Msk;
+  USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESUME_Msk;
+  alt_ev = USB->USB_ALTEV_REG;
+  check_reset_end(alt_ev);
+}
+
+static void handle_alt_ev(void)
+{
+  uint32_t alt_ev = USB->USB_ALTEV_REG;
+
+  alt_ev = check_reset_end(alt_ev);
+  if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESET) && _dcd.nfsr != NFSR_NODE_RESET)
+  {
+    handle_bus_reset();
+  }
+  else if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESUME))
+  {
+    if (USB->USB_NFSR_REG == NFSR_NODE_SUSPEND)
+    {
+      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;
+      dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+    }
+  }
+  else if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_SD3))
+  {
+    set_nfsr(NFSR_NODE_SUSPEND);
+    USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
+                          USB_USB_ALTMSK_REG_USB_M_RESUME_Msk;
+    dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+  }
+}
+
+static void handle_epx_tx_warn_ev(uint8_t ep)
+{
+  fill_tx_fifo(XFER_CTL_BASE(ep, TUSB_DIR_IN));
+}
+
+static void handle_fifo_warning(void)
+{
+  uint32_t fifo_warning = USB->USB_FWEV_REG;
+
+  if (fifo_warning & 0x01)
+    handle_epx_tx_warn_ev(1);
+  if (fifo_warning & 0x02)
+    handle_epx_tx_warn_ev(2);
+  if (fifo_warning & 0x04)
+    handle_epx_tx_warn_ev(3);
+  if (fifo_warning & 0x10)
+    handle_epx_rx_ev(1);
+  if (fifo_warning & 0x20)
+    handle_epx_rx_ev(2);
+  if (fifo_warning & 0x40)
+    handle_epx_rx_ev(3);
+}
+
+static void handle_ep0_nak(void)
+{
+  uint32_t ep0_nak = USB->USB_EP0_NAK_REG;
+
+  if (REG_GET_BIT(USB_EPC0_REG, USB_STALL))
+  {
+    if (GET_BIT(ep0_nak, USB_USB_EP0_NAK_REG_USB_EP0_INNAK))
+    {
+      // EP0 is stalled and NAK was sent, it means that RX is enabled
+      // Disable RX for now.
+      REG_CLR_BIT(USB_RXC0_REG, USB_RX_EN);
+      REG_SET_BIT(USB_TXC0_REG, USB_TX_EN);
+    }
+    if (GET_BIT(ep0_nak, USB_USB_EP0_NAK_REG_USB_EP0_OUTNAK))
+    {
+      REG_SET_BIT(USB_RXC0_REG, USB_RX_EN);
+    }
+  }
+  else
+  {
+    REG_CLR_BIT(USB_MAMSK_REG, USB_M_EP0_NAK);
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  _dcd.init_called = true;
+  if (_dcd.vbus_present)
+  {
+    dcd_connect(rhport);
+  }
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void)rhport;
+
+  NVIC_EnableIRQ(USB_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void)rhport;
+
+  NVIC_DisableIRQ(USB_IRQn);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  (void)rhport;
+
+  // Set default address for one ZLP
+  USB->USB_EPC0_REG = USB_USB_EPC0_REG_USB_DEF_Msk;
+  USB->USB_FAR_REG = (dev_addr & USB_USB_FAR_REG_USB_AD_Msk) | USB_USB_FAR_REG_USB_AD_EN_Msk;
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void)rhport;
+  if (_dcd.nfsr == NFSR_NODE_SUSPEND)
+  {
+    // Enter fake state that will use FRAME interrupt to wait before going operational.
+    set_nfsr(NFSR_NODE_WAKING);
+    USB->USB_MAMSK_REG |= USB_USB_MAMSK_REG_USB_M_FRAME_Msk;
+  }
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void)rhport;
+
+  if (GET_BIT(USB->USB_MCTRL_REG, USB_USB_MCTRL_REG_USB_NAT) == 0)
+  {
+    USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk;
+    USB->USB_NFSR_REG = 0;
+    USB->USB_FAR_REG = 0x80;
+    USB->USB_TXMSK_REG = 0;
+    USB->USB_RXMSK_REG = 0;
+
+    USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
+                         USB_USB_MAMSK_REG_USB_M_ALT_Msk |
+                         USB_USB_MAMSK_REG_USB_M_WARN_Msk;
+    USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
+                          USB_USB_ALTEV_REG_USB_SD3_Msk;
+
+    USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk | USB_USB_MCTRL_REG_USB_NAT_Msk;
+
+    // Select chosen DMA to be triggered by USB.
+    DMA->DMA_REQ_MUX_REG = (DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) | DA146XX_DMA_USB_MUX;
+  }
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void)rhport;
+
+  REG_CLR_BIT(USB_MCTRL_REG, USB_NAT);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
+{
+  return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0;
+}
+
+void tusb_vbus_changed(bool present)
+{
+  if (present && !_dcd.vbus_present)
+  {
+    _dcd.vbus_present = true;
+    // If power event happened before USB started, delay dcd_connect
+    // until dcd_init is called.
+    if (_dcd.init_called)
+    {
+      dcd_connect(0);
+    }
+  }
+  else if (!present && _dcd.vbus_present)
+  {
+    _dcd.vbus_present = false;
+    USB->USB_MCTRL_REG = 0;
+    dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr());
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* 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);
+  EPx_REGS *regs = EPNUM_REGS(epnum);
+  uint8_t iso_mask = 0;
+
+  TU_ASSERT(epnum < EP_MAX);
+
+  xfer->max_packet_size = tu_edpt_packet_size(desc_edpt);
+  xfer->ep_addr = desc_edpt->bEndpointAddress;
+  xfer->data1 = 0;
+  xfer->iso = 0;
+
+  if (epnum != 0 && desc_edpt->bmAttributes.xfer == 1)
+  {
+    iso_mask = USB_USB_EPC1_REG_USB_ISO_Msk;
+    xfer->iso = 1;
+  }
+
+  if (epnum == 0)
+  {
+    USB->USB_MAMSK_REG |= USB_USB_MAMSK_REG_USB_M_EP0_RX_Msk |
+                          USB_USB_MAMSK_REG_USB_M_EP0_TX_Msk;
+  }
+  else
+  {
+    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);
+      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);
+      REG_SET_BIT(USB_MAMSK_REG, USB_M_TX_EV);
+    }
+  }
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+
+  for (int epnum = 1; epnum < EP_MAX; ++epnum)
+  {
+    dcd_edpt_close(0, epnum | TUSB_DIR_OUT);
+    dcd_edpt_close(0, epnum | TUSB_DIR_IN);
+  }
+}
+
+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);
+  EPx_REGS *regs = EPNUM_REGS(epnum);
+  xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+
+  (void)rhport;
+
+  TU_ASSERT(epnum < EP_MAX,);
+
+  if (epnum == 0)
+  {
+    USB->USB_MAMSK_REG &= ~(USB_USB_MAMSK_REG_USB_M_EP0_RX_Msk |
+                            USB_USB_MAMSK_REG_USB_M_EP0_TX_Msk);
+  }
+  else
+  {
+    if (dir == TUSB_DIR_OUT)
+    {
+      regs->rxc = USB_USB_RXC1_REG_USB_FLUSH_Msk;
+      regs->epc_out = 0;
+      USB->USB_RXMSK_REG &= ~(0x101 << (epnum - 1));
+      // Release DMA if needed
+      if (_dcd.dma_ep[TUSB_DIR_OUT] == epnum)
+      {
+        RX_DMA_REGS->DMAx_CTRL_REG &= ~DMA_DMA0_CTRL_REG_DMA_ON_Msk;
+        _dcd.dma_ep[TUSB_DIR_OUT] = 0;
+      }
+    }
+    else
+    {
+      regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
+      regs->epc_in = 0;
+      USB->USB_TXMSK_REG &= ~(0x101 << (epnum - 1));
+      // Release DMA if needed
+      if (_dcd.dma_ep[TUSB_DIR_IN] == epnum)
+      {
+        TX_DMA_REGS->DMAx_CTRL_REG &= ~DMA_DMA1_CTRL_REG_DMA_ON_Msk;
+        _dcd.dma_ep[TUSB_DIR_IN] = 0;
+      }
+    }
+  }
+  tu_memclr(xfer, sizeof(*xfer));
+}
+
+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 (dir == TUSB_DIR_OUT)
+  {
+    start_rx_packet(xfer);
+  }
+  else // IN
+  {
+    start_tx_packet(xfer);
+  }
+
+  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;
+
+  xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+  EPx_REGS *regs = EPNUM_REGS(epnum);
+  xfer->stall = 1;
+
+  if (epnum == 0)
+  {
+    // EP0 has just one registers to control stall for IN and OUT
+    REG_SET_BIT(USB_EPC0_REG, USB_STALL);
+    if (dir == TUSB_DIR_OUT)
+    {
+      regs->USB_RXC0_REG = USB_USB_RXC0_REG_USB_RX_EN_Msk;
+    }
+    else
+    {
+      if (regs->USB_RXC0_REG & USB_USB_RXC0_REG_USB_RX_EN_Msk)
+      {
+        // If RX is also enabled TX will not be stalled since RX has
+        // higher priority. Enable NAK interrupt to handle stall.
+        REG_SET_BIT(USB_MAMSK_REG, USB_M_EP0_NAK);
+      }
+      else
+      {
+        regs->USB_TXC0_REG |= USB_USB_TXC0_REG_USB_TX_EN_Msk;
+      }
+    }
+  }
+  else
+  {
+    if (dir == TUSB_DIR_OUT)
+    {
+      regs->epc_out |= USB_USB_EPC1_REG_USB_STALL_Msk;
+      regs->rxc |= USB_USB_RXC1_REG_USB_RX_EN_Msk;
+    }
+    else
+    {
+      regs->epc_in |= USB_USB_EPC1_REG_USB_STALL_Msk;
+      regs->txc |= USB_USB_TXC1_REG_USB_TX_EN_Msk | USB_USB_TXC1_REG_USB_LAST_Msk;
+    }
+  }
+}
+
+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;
+
+  xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+  EPx_REGS *regs = EPNUM_REGS(epnum);
+
+  // Clear stall is called in response to Clear Feature ENDPOINT_HALT, reset toggle
+  xfer->data1 = 0;
+  xfer->stall = 0;
+
+  if (dir == TUSB_DIR_OUT)
+  {
+    regs->epc_out &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
+  }
+  else
+  {
+    regs->epc_in &= ~USB_USB_EPC1_REG_USB_STALL_Msk;
+  }
+  if (epnum == 0)
+  {
+    REG_CLR_BIT(USB_MAMSK_REG, USB_M_EP0_NAK);
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* Interrupt Handler
+ *------------------------------------------------------------------*/
+
+void dcd_int_handler(uint8_t rhport)
+{
+  uint32_t int_status = USB->USB_MAEV_REG & USB->USB_MAMSK_REG;
+
+  (void)rhport;
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_WARN))
+  {
+    handle_fifo_warning();
+  }
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_CH_EV))
+  {
+    // TODO: for now just clear interrupt
+    (void)USB->USB_CHARGER_STAT_REG;
+  }
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_EP0_NAK))
+  {
+    handle_ep0_nak();
+  }
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_EP0_RX))
+  {
+    handle_ep0_rx();
+  }
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_EP0_TX))
+  {
+    handle_ep0_tx();
+  }
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_RX_EV))
+  {
+    handle_rx_ev();
+  }
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_NAK))
+  {
+    (void)USB->USB_NAKEV_REG;
+  }
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_FRAME))
+  {
+    if (_dcd.nfsr == NFSR_NODE_RESET)
+    {
+      // During reset FRAME interrupt is enabled to periodically
+      // check when reset state ends.
+      // FRAME interrupt is generated every 1ms without host sending
+      // actual SOF.
+      check_reset_end(USB_USB_ALTEV_REG_USB_RESET_Msk);
+    }
+    else if (_dcd.nfsr == NFSR_NODE_WAKING)
+    {
+      // No need to call set_nfsr, just set state
+      _dcd.nfsr = NFSR_NODE_WAKING2;
+    }
+    else if (_dcd.nfsr == NFSR_NODE_WAKING2)
+    {
+      // No need to call set_nfsr, just set state
+      _dcd.nfsr = NFSR_NODE_RESUME;
+    }
+    else if (_dcd.nfsr == NFSR_NODE_RESUME)
+    {
+      set_nfsr(NFSR_NODE_OPERATIONAL);
+    }
+    else
+    {
+#if USE_SOF
+      dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+#else
+      // FRAME interrupt was used to re-enable reset detection or remote
+      // wakeup no need to keep it enabled when USE_SOF is off.
+      USB->USB_MAMSK_REG &= ~USB_USB_MAMSK_REG_USB_M_FRAME_Msk;
+#endif
+    }
+  }
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_TX_EV))
+  {
+    handle_tx_ev();
+  }
+
+  if (GET_BIT(int_status, USB_USB_MAEV_REG_USB_ALT))
+  {
+    handle_alt_ev();
+  }
+}
+
+#endif
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
new file mode 100644
index 0000000..e92f8a9
--- /dev/null
+++ b/src/portable/ehci/ehci.c
@@ -0,0 +1,893 @@
+/* 
+ * 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 "host/hcd_attr.h"
+
+#if TUSB_OPT_HOST_ENABLED && defined(HCD_ATTR_EHCI_TRANSDIMENSION)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "osal/osal.h"
+
+#include "host/hcd.h"
+#include "ehci_api.h"
+#include "ehci.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+// Debug level of EHCI
+#define EHCI_DBG     2
+
+// Framelist size as small as possible to save SRAM
+#ifdef HCD_ATTR_EHCI_TRANSDIMENSION
+  // NXP Transdimension: 8 elements
+  #define FRAMELIST_SIZE_BIT_VALUE      7u
+  #define FRAMELIST_SIZE_USBCMD_VALUE   (((FRAMELIST_SIZE_BIT_VALUE &  3) << EHCI_USBCMD_POS_FRAMELIST_SIZE) | \
+                                         ((FRAMELIST_SIZE_BIT_VALUE >> 2) << EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB))
+#else
+  // STD EHCI: 256 elements
+  #define FRAMELIST_SIZE_BIT_VALUE      2u
+  #define FRAMELIST_SIZE_USBCMD_VALUE   ((FRAMELIST_SIZE_BIT_VALUE &  3) << EHCI_USBCMD_POS_FRAMELIST_SIZE)
+#endif
+
+#define FRAMELIST_SIZE                  (1024 >> FRAMELIST_SIZE_BIT_VALUE)
+
+typedef struct
+{
+  ehci_link_t period_framelist[FRAMELIST_SIZE];
+
+  // TODO only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
+  // [0] : 1ms, [1] : 2ms, [2] : 4ms, [3] : 8 ms
+  // TODO better implementation without dummy head to save SRAM
+  ehci_qhd_t period_head_arr[4];
+
+  // Note control qhd of dev0 is used as head of async list
+  struct {
+    ehci_qhd_t qhd;
+    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_registers_t* regs;
+
+  volatile uint32_t uframe_number;
+}ehci_data_t;
+
+// Periodic frame list must be 4K alignment
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
+
+//--------------------------------------------------------------------+
+// PROTOTYPE
+//--------------------------------------------------------------------+
+static inline ehci_link_t* get_period_head(uint8_t rhport, uint32_t interval_ms)
+{
+  (void) rhport;
+  return (ehci_link_t*) &ehci_data.period_head_arr[ tu_log2( tu_min32(FRAMELIST_SIZE, interval_ms) ) ];
+}
+
+static inline ehci_qhd_t* qhd_control(uint8_t dev_addr)
+{
+  return &ehci_data.control[dev_addr].qhd;
+}
+
+static inline ehci_qhd_t* qhd_async_head(uint8_t rhport)
+{
+  (void) rhport;
+  // control qhd of dev0 is used as async head
+  return qhd_control(0);
+}
+
+static inline ehci_qtd_t* qtd_control(uint8_t dev_addr)
+{
+  return &ehci_data.control[dev_addr].qtd;
+}
+
+
+static inline ehci_qhd_t* qhd_next (ehci_qhd_t const * p_qhd);
+static inline ehci_qhd_t* qhd_find_free (void);
+static inline ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
+
+// determine if a queue head has bus-related error
+static inline bool qhd_has_xact_error (ehci_qhd_t * p_qhd)
+{
+  return (p_qhd->qtd_overlay.buffer_err || p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err);
+  //p_qhd->qtd_overlay.non_hs_period_missed_uframe || p_qhd->qtd_overlay.pingstate_err TODO split transaction error
+}
+
+static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
+
+static inline ehci_qtd_t* qtd_find_free (void);
+static inline ehci_qtd_t* qtd_next (ehci_qtd_t const * p_qtd);
+static inline void qtd_insert_to_qhd (ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new);
+static inline void qtd_remove_1st_from_qhd (ehci_qhd_t *p_qhd);
+static void qtd_init (ehci_qtd_t* p_qtd, void const* buffer, uint16_t total_bytes);
+
+static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
+static inline ehci_link_t* list_next (ehci_link_t *p_link_pointer);
+
+//--------------------------------------------------------------------+
+// HCD API
+//--------------------------------------------------------------------+
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+  (void) rhport;
+  return (ehci_data.uframe_number + ehci_data.regs->frame_index) >> 3;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  ehci_registers_t* regs = ehci_data.regs;
+
+//  regs->portsc_bm.port_enabled = 0; // disable port before reset
+//  regs->portsc_bm.port_reset = 1;
+
+  uint32_t portsc = regs->portsc;
+
+  portsc &= ~(EHCI_PORTSC_MASK_PORT_EANBLED);
+  portsc |= EHCI_PORTSC_MASK_PORT_RESET;
+
+  regs->portsc = portsc;
+}
+
+#if 0
+void hcd_port_reset_end(uint8_t rhport)
+{
+  (void) rhport;
+
+  ehci_registers_t* regs = ehci_data.regs;
+  regs->portsc_bm.port_reset = 0;
+}
+#endif
+
+bool hcd_port_connect_status(uint8_t rhport)
+{
+  (void) rhport;
+  return ehci_data.regs->portsc_bm.current_connect_status;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+  (void) rhport;
+  return (tusb_speed_t) ehci_data.regs->portsc_bm.nxp_port_speed; // NXP specific port speed
+}
+
+static void list_remove_qhd_by_addr(ehci_link_t* list_head, uint8_t dev_addr)
+{
+  for(ehci_link_t* prev = list_head;
+      !prev->terminate && (tu_align32(prev->address) != (uint32_t) list_head);
+      prev = list_next(prev) )
+  {
+    // TODO check type for ISO iTD and siTD
+    ehci_qhd_t* qhd = (ehci_qhd_t*) list_next(prev);
+    if ( qhd->dev_addr == dev_addr )
+    {
+      // TODO deactive all TD, wait for QHD to inactive before removal
+      prev->address = qhd->next.address;
+
+      // EHCI 4.8.2 link the removed qhd to async head (which always reachable by Host Controller)
+      qhd->next.address = ((uint32_t) list_head) | (EHCI_QTYPE_QHD << 1);
+
+      if ( qhd->int_smask )
+      {
+        // period list queue element is guarantee to be free in the next frame (1 ms)
+        qhd->used = 0;
+      }else
+      {
+        // async list use async advance handshake
+        // mark as removing, will completely re-usable when async advance isr occurs
+        qhd->removing = 1;
+      }
+    }
+  }
+}
+
+// Close all opened endpoint belong to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+  // skip dev0
+  if (dev_addr == 0) return;
+
+  // Remove from async list
+  list_remove_qhd_by_addr( (ehci_link_t*) qhd_async_head(rhport), dev_addr );
+
+  // Remove from all interval period list
+  for(uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++)
+  {
+    list_remove_qhd_by_addr( (ehci_link_t*) &ehci_data.period_head_arr[i], dev_addr);
+  }
+
+  // Async doorbell (EHCI 4.8.2 for operational details)
+  ehci_data.regs->command_bm.async_adv_doorbell = 1;
+}
+
+bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
+{
+  (void) capability_reg; // not used yet
+
+  tu_memclr(&ehci_data, sizeof(ehci_data_t));
+
+  ehci_data.regs = (ehci_registers_t* ) operatial_reg;
+
+  ehci_registers_t* regs = ehci_data.regs;
+
+  //------------- CTRLDSSEGMENT Register (skip) -------------//
+  //------------- USB INT Register -------------//
+  regs->inten  = 0;                 // 1. disable all the interrupt
+  regs->status = EHCI_INT_MASK_ALL; // 2. clear all status
+
+  regs->inten  = EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE | EHCI_INT_MASK_ASYNC_ADVANCE |
+                 EHCI_INT_MASK_NXP_PERIODIC | EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
+
+  //------------- Asynchronous List -------------//
+  ehci_qhd_t * const async_head = qhd_async_head(rhport);
+  tu_memclr(async_head, sizeof(ehci_qhd_t));
+
+  async_head->next.address                    = (uint32_t) async_head; // circular list, next is itself
+  async_head->next.type                       = EHCI_QTYPE_QHD;
+  async_head->head_list_flag                  = 1;
+  async_head->qtd_overlay.halted              = 1; // inactive most of time
+  async_head->qtd_overlay.next.terminate      = 1; // TODO removed if verified
+
+  regs->async_list_addr = (uint32_t) async_head;
+
+  //------------- Periodic List -------------//
+  // Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only
+  for ( uint32_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++ )
+  {
+    ehci_data.period_head_arr[i].int_smask          = 1; // queue head in period list must have smask non-zero
+    ehci_data.period_head_arr[i].qtd_overlay.halted = 1; // dummy node, always inactive
+  }
+
+  ehci_link_t * const framelist  = ehci_data.period_framelist;
+  ehci_link_t * const period_1ms = get_period_head(rhport, 1u);
+
+  // all links --> period_head_arr[0] (1ms)
+  // 0, 2, 4, 6 etc --> period_head_arr[1] (2ms)
+  // 1, 5 --> period_head_arr[2] (4ms)
+  // 3 --> period_head_arr[3] (8ms)
+
+  // TODO EHCI_FRAMELIST_SIZE with other size than 8
+  for(uint32_t i=0; i<FRAMELIST_SIZE; i++)
+  {
+    framelist[i].address = (uint32_t) period_1ms;
+    framelist[i].type    = EHCI_QTYPE_QHD;
+  }
+
+  for(uint32_t i=0; i<FRAMELIST_SIZE; i+=2)
+  {
+    list_insert(framelist + i, get_period_head(rhport, 2u), EHCI_QTYPE_QHD);
+  }
+
+  for(uint32_t i=1; i<FRAMELIST_SIZE; i+=4)
+  {
+    list_insert(framelist + i, get_period_head(rhport, 4u), EHCI_QTYPE_QHD);
+  }
+
+  list_insert(framelist+3, get_period_head(rhport, 8u), EHCI_QTYPE_QHD);
+
+  period_1ms->terminate    = 1;
+
+  regs->periodic_list_base = (uint32_t) framelist;
+
+  //------------- TT Control (NXP only) -------------//
+  regs->nxp_tt_control = 0;
+
+  //------------- USB CMD Register -------------//
+  regs->command |= TU_BIT(EHCI_USBCMD_POS_RUN_STOP) | TU_BIT(EHCI_USBCMD_POS_ASYNC_ENABLE) |
+                   TU_BIT(EHCI_USBCMD_POS_PERIOD_ENABLE) |  // TODO enable period list only there is int/iso endpoint
+                   FRAMELIST_SIZE_USBCMD_VALUE;
+
+  //------------- ConfigFlag Register (skip) -------------//
+  regs->portsc_bm.port_power = 1; // enable port power
+
+  return true;
+}
+
+#if 0
+static void ehci_stop(uint8_t rhport)
+{
+  (void) rhport;
+
+  ehci_registers_t* regs = ehci_data.regs;
+
+  regs->command_bm.run_stop = 0;
+
+  // USB Spec: controller has to stop within 16 uframe = 2 frames
+  while( regs->status_bm.hc_halted == 0 ) {}
+}
+#endif
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+  (void) rhport;
+
+  // TODO not support ISO yet
+  TU_ASSERT (ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
+
+  //------------- Prepare Queue Head -------------//
+  ehci_qhd_t * p_qhd;
+
+  if ( ep_desc->bEndpointAddress == 0 )
+  {
+    p_qhd = qhd_control(dev_addr);
+  }else
+  {
+    p_qhd = qhd_find_free();
+  }
+  TU_ASSERT(p_qhd);
+
+  qhd_init(p_qhd, dev_addr, ep_desc);
+
+  // control of dev0 is always present as async head
+  if ( dev_addr == 0 ) return true;
+
+  // Insert to list
+  ehci_link_t * list_head = NULL;
+
+  switch (ep_desc->bmAttributes.xfer)
+  {
+    case TUSB_XFER_CONTROL:
+    case TUSB_XFER_BULK:
+      list_head = (ehci_link_t*) qhd_async_head(rhport);
+    break;
+
+    case TUSB_XFER_INTERRUPT:
+      list_head = get_period_head(rhport, p_qhd->interval_ms);
+    break;
+
+    case TUSB_XFER_ISOCHRONOUS:
+      // TODO iso is not supported
+    break;
+
+    default: break;
+  }
+
+  TU_ASSERT(list_head);
+
+  // TODO might need to disable async/period list
+  list_insert(list_head, (ehci_link_t*) p_qhd, EHCI_QTYPE_QHD);
+
+  return true;
+}
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+  (void) rhport;
+
+  ehci_qhd_t* qhd = &ehci_data.control[dev_addr].qhd;
+  ehci_qtd_t* td  = &ehci_data.control[dev_addr].qtd;
+
+  qtd_init(td, setup_packet, 8);
+  td->pid          = EHCI_PID_SETUP;
+  td->int_on_complete = 1;
+  td->next.terminate  = 1;
+
+  // sw region
+  qhd->p_qtd_list_head = td;
+  qhd->p_qtd_list_tail = td;
+
+  // attach TD
+  qhd->qtd_overlay.next.address = (uint32_t) td;
+
+  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;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  if ( epnum == 0 )
+  {
+    ehci_qhd_t* qhd = qhd_control(dev_addr);
+    ehci_qtd_t* qtd = qtd_control(dev_addr);
+
+    qtd_init(qtd, buffer, buflen);
+
+    // first first data toggle is always 1 (data & setup stage)
+    qtd->data_toggle = 1;
+    qtd->pid = dir ? EHCI_PID_IN : EHCI_PID_OUT;
+    qtd->int_on_complete = 1;
+    qtd->next.terminate  = 1;
+
+    // sw region
+    qhd->p_qtd_list_head = qtd;
+    qhd->p_qtd_list_tail = qtd;
+
+    // attach TD
+    qhd->qtd_overlay.next.address = (uint32_t) qtd;
+  }else
+  {
+    ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
+    ehci_qtd_t *p_qtd = qtd_find_free();
+    TU_ASSERT(p_qtd);
+
+    qtd_init(p_qtd, buffer, buflen);
+    p_qtd->pid = p_qhd->pid;
+
+    // Insert TD to QH
+    qtd_insert_to_qhd(p_qhd, p_qtd);
+
+    p_qhd->p_qtd_list_tail->int_on_complete = 1;
+
+    // attach head QTD to QHD start transferring
+    p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head;
+  }
+
+  return true;
+}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+  ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
+  p_qhd->qtd_overlay.halted = 0;
+  // TODO reset data toggle ?
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// EHCI Interrupt Handler
+//--------------------------------------------------------------------+
+
+// async_advance is handshake between usb stack & ehci controller.
+// This isr mean it is safe to modify previously removed queue head from async list.
+// In tinyusb, queue head is only removed when device is unplugged.
+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++)
+  {
+    if ( qhd_pool[i].removing )
+    {
+      qhd_pool[i].removing = 0;
+      qhd_pool[i].used     = 0;
+    }
+  }
+}
+
+static void port_connect_status_change_isr(uint8_t rhport)
+{
+  // NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
+  if (ehci_data.regs->portsc_bm.current_connect_status)
+  {
+    hcd_port_reset(rhport);
+    hcd_event_device_attach(rhport, true);
+  }else // device unplugged
+  {
+    hcd_event_device_remove(rhport, true);
+  }
+}
+
+static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd)
+{
+  // free all TDs from the head td to the first active TD
+  while(p_qhd->p_qtd_list_head != NULL && !p_qhd->p_qtd_list_head->active)
+  {
+    ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) p_qhd->p_qtd_list_head;
+    bool const is_ioc = (qtd->int_on_complete != 0);
+    uint8_t const ep_addr = tu_edpt_addr(p_qhd->ep_number, qtd->pid == EHCI_PID_IN ? 1 : 0);
+
+    p_qhd->total_xferred_bytes += qtd->expected_bytes - qtd->total_bytes;
+
+    // TD need to be freed and removed from qhd, before invoking callback
+    qtd->used = 0; // free QTD
+    qtd_remove_1st_from_qhd(p_qhd);
+
+    if (is_ioc)
+    {
+      hcd_event_xfer_complete(p_qhd->dev_addr, ep_addr, p_qhd->total_xferred_bytes, XFER_RESULT_SUCCESS, true);
+      p_qhd->total_xferred_bytes = 0;
+    }
+  }
+}
+
+static void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
+{
+  ehci_qhd_t *p_qhd = async_head;
+  do
+  {
+    if ( !p_qhd->qtd_overlay.halted ) // halted or error is processed in error isr
+    {
+      qhd_xfer_complete_isr(p_qhd);
+    }
+    p_qhd = qhd_next(p_qhd);
+  }while(p_qhd != async_head); // async list traversal, stop if loop around
+}
+
+static void period_list_xfer_complete_isr(uint8_t hostid, uint32_t interval_ms)
+{
+  uint16_t max_loop = 0;
+  uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1u);
+  ehci_link_t next_item = * get_period_head(hostid, 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)
+  {
+    switch ( next_item.type )
+    {
+      case EHCI_QTYPE_QHD:
+      {
+        ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) tu_align32(next_item.address);
+        if ( !p_qhd_int->qtd_overlay.halted )
+        {
+          qhd_xfer_complete_isr(p_qhd_int);
+        }
+      }
+      break;
+
+      case EHCI_QTYPE_ITD: // TODO support hs/fs ISO
+      case EHCI_QTYPE_SITD:
+      case EHCI_QTYPE_FSTN:
+				
+      default: break;
+    }
+
+    next_item = *list_next(&next_item);
+    max_loop++;
+  }
+}
+
+static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd)
+{
+  if ( (p_qhd->dev_addr != 0 && p_qhd->qtd_overlay.halted) || // addr0 cannot be protocol STALL
+        qhd_has_xact_error(p_qhd) )
+  {
+    // current qhd has error in transaction
+    xfer_result_t error_event;
+
+    // no error bits are set, endpoint is halted due to STALL
+    error_event = qhd_has_xact_error(p_qhd) ? XFER_RESULT_FAILED : XFER_RESULT_STALLED;
+
+    p_qhd->total_xferred_bytes += p_qhd->p_qtd_list_head->expected_bytes - p_qhd->p_qtd_list_head->total_bytes;
+
+//    if ( XFER_RESULT_FAILED == error_event )    TU_BREAKPOINT(); // TODO skip unplugged device
+
+    p_qhd->p_qtd_list_head->used = 0; // free QTD
+    qtd_remove_1st_from_qhd(p_qhd);
+
+    if ( 0 == p_qhd->ep_number )
+    {
+      // control cannot be halted --> clear all qtd list
+      p_qhd->p_qtd_list_head = NULL;
+      p_qhd->p_qtd_list_tail = NULL;
+
+      p_qhd->qtd_overlay.next.terminate      = 1;
+      p_qhd->qtd_overlay.alternate.terminate = 1;
+      p_qhd->qtd_overlay.halted              = 0;
+
+      ehci_qtd_t *p_setup = qtd_control(p_qhd->dev_addr);
+      p_setup->used = 0;
+    }
+
+    // call USBH callback
+    hcd_event_xfer_complete(p_qhd->dev_addr, tu_edpt_addr(p_qhd->ep_number, p_qhd->pid == EHCI_PID_IN ? 1 : 0), p_qhd->total_xferred_bytes, error_event, true);
+
+    p_qhd->total_xferred_bytes = 0;
+  }
+}
+
+static void xfer_error_isr(uint8_t hostid)
+{
+  //------------- async list -------------//
+  ehci_qhd_t * const async_head = qhd_async_head(hostid);
+  ehci_qhd_t *p_qhd = async_head;
+  do
+  {
+    qhd_xfer_error_isr( p_qhd );
+    p_qhd = qhd_next(p_qhd);
+  }while(p_qhd != async_head); // async list traversal, stop if loop around
+
+  //------------- TODO refractor period list -------------//
+  uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1u);
+  for (uint32_t interval_ms=1; interval_ms <= FRAMELIST_SIZE; interval_ms *= 2)
+  {
+    ehci_link_t next_item = * get_period_head(hostid, interval_ms);
+
+    // TODO abstract max loop guard for period
+    while( !next_item.terminate &&
+           !(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) )
+    {
+      switch ( next_item.type )
+      {
+        case EHCI_QTYPE_QHD:
+        {
+          ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) tu_align32(next_item.address);
+          qhd_xfer_error_isr(p_qhd_int);
+        }
+        break;
+
+				// TODO support hs/fs ISO
+        case EHCI_QTYPE_ITD:
+        case EHCI_QTYPE_SITD:
+        case EHCI_QTYPE_FSTN:
+        default: break;
+      }
+
+      next_item = *list_next(&next_item);
+    }
+  }
+}
+
+//------------- Host Controller Driver's Interrupt Handler -------------//
+void hcd_int_handler(uint8_t rhport)
+{
+  ehci_registers_t* regs = ehci_data.regs;
+
+  uint32_t int_status = regs->status;
+  int_status &= regs->inten;
+  
+  regs->status |= int_status; // Acknowledge handled interrupt
+
+  if (int_status == 0) return;
+
+  if (int_status & EHCI_INT_MASK_FRAMELIST_ROLLOVER)
+  {
+    ehci_data.uframe_number += (FRAMELIST_SIZE << 3);
+  }
+
+  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);
+
+    if (regs->portsc_bm.connect_status_change)
+    {
+      port_connect_status_change_isr(rhport);
+    }
+
+    regs->portsc |= port_status; // Acknowledge change bits in portsc
+  }
+
+  if (int_status & EHCI_INT_MASK_ERROR)
+  {
+    xfer_error_isr(rhport);
+  }
+
+  //------------- some QTD/SITD/ITD with IOC set is completed -------------//
+  if (int_status & EHCI_INT_MASK_NXP_ASYNC)
+  {
+    async_list_xfer_complete_isr( qhd_async_head(rhport) );
+  }
+
+  if (int_status & EHCI_INT_MASK_NXP_PERIODIC)
+  {
+    for (uint32_t i=1; i <= FRAMELIST_SIZE; i *= 2)
+    {
+      period_list_xfer_complete_isr( rhport, i );
+    }
+  }
+
+  //------------- There is some removed async previously -------------//
+  if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) // need to place after EHCI_INT_MASK_NXP_ASYNC
+  {
+    async_advance_isr(rhport);
+  }
+}
+
+//--------------------------------------------------------------------+
+// HELPER
+//--------------------------------------------------------------------+
+
+
+//------------- queue head helper -------------//
+static inline ehci_qhd_t* qhd_find_free (void)
+{
+  for (uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+  {
+    if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
+  }
+
+  return NULL;
+}
+
+static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd)
+{
+  return (ehci_qhd_t*) tu_align32(p_qhd->next.address);
+}
+
+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++)
+  {
+    if ( (qhd_pool[i].dev_addr == dev_addr) &&
+          ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) )
+    {
+      return &qhd_pool[i];
+    }
+  }
+
+  return NULL;
+}
+
+//------------- TD helper -------------//
+static inline ehci_qtd_t* qtd_find_free(void)
+{
+  for (uint32_t i=0; i<HCD_MAX_XFER; i++)
+  {
+    if ( !ehci_data.qtd_pool[i].used ) return &ehci_data.qtd_pool[i];
+  }
+
+  return NULL;
+}
+
+static inline ehci_qtd_t* qtd_next(ehci_qtd_t const * p_qtd )
+{
+  return (ehci_qtd_t*) tu_align32(p_qtd->next.address);
+}
+
+static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd)
+{
+  if (p_qhd->p_qtd_list_head == p_qhd->p_qtd_list_tail) // last TD --> make it NULL
+  {
+    p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = NULL;
+  }else
+  {
+    p_qhd->p_qtd_list_head = qtd_next( p_qhd->p_qtd_list_head );
+  }
+}
+
+static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new)
+{
+  if (p_qhd->p_qtd_list_head == NULL) // empty list
+  {
+    p_qhd->p_qtd_list_head               = p_qhd->p_qtd_list_tail = p_qtd_new;
+  }else
+  {
+    p_qhd->p_qtd_list_tail->next.address = (uint32_t) p_qtd_new;
+    p_qhd->p_qtd_list_tail               = p_qtd_new;
+  }
+}
+
+static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+  // address 0 is used as async head, which always on the list --> cannot be cleared (ehci halted otherwise)
+  if (dev_addr != 0)
+  {
+    tu_memclr(p_qhd, sizeof(ehci_qhd_t));
+  }
+
+  hcd_devtree_info_t devtree_info;
+  hcd_devtree_get_info(dev_addr, &devtree_info);
+
+  uint8_t const xfer_type = ep_desc->bmAttributes.xfer;
+  uint8_t const interval = ep_desc->bInterval;
+
+  p_qhd->dev_addr           = dev_addr;
+  p_qhd->fl_inactive_next_xact = 0;
+  p_qhd->ep_number          = tu_edpt_number(ep_desc->bEndpointAddress);
+  p_qhd->ep_speed           = devtree_info.speed;
+  p_qhd->data_toggle_control= (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0;
+  p_qhd->head_list_flag     = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static asyn list head
+  p_qhd->max_packet_size    = tu_edpt_packet_size(ep_desc);
+  p_qhd->fl_ctrl_ep_flag    = ((xfer_type == TUSB_XFER_CONTROL) && (p_qhd->ep_speed != TUSB_SPEED_HIGH))  ? 1 : 0;
+  p_qhd->nak_reload         = 0;
+
+  // Bulk/Control -> smask = cmask = 0
+  // TODO Isochronous
+  if (TUSB_XFER_INTERRUPT == xfer_type)
+  {
+    if (TUSB_SPEED_HIGH == p_qhd->ep_speed)
+    {
+      TU_ASSERT( interval <= 16, );
+      if ( interval < 4) // sub milisecond interval
+      {
+        p_qhd->interval_ms = 0;
+        p_qhd->int_smask   = (interval == 1) ? TU_BIN8(11111111) :
+                             (interval == 2) ? TU_BIN8(10101010) : TU_BIN8(01000100);
+      }else
+      {
+        p_qhd->interval_ms = (uint8_t) tu_min16( 1 << (interval-4), 255 );
+        p_qhd->int_smask = TU_BIT(interval % 8);
+      }
+    }else
+    {
+      TU_ASSERT( 0 != interval, );
+      // Full/Low: 4.12.2.1 (EHCI) case 1 schedule start split at 1 us & complete split at 2,3,4 uframes
+      p_qhd->int_smask    = 0x01;
+      p_qhd->fl_int_cmask = TU_BIN8(11100);
+      p_qhd->interval_ms  = interval;
+    }
+  }else
+  {
+    p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
+  }
+
+  p_qhd->fl_hub_addr     = devtree_info.hub_addr;
+  p_qhd->fl_hub_port     = devtree_info.hub_port;
+  p_qhd->mult            = 1; // TODO not use high bandwidth/park mode yet
+
+  //------------- HCD Management Data -------------//
+  p_qhd->used            = 1;
+  p_qhd->removing        = 0;
+  p_qhd->p_qtd_list_head = NULL;
+  p_qhd->p_qtd_list_tail = NULL;
+  p_qhd->pid = tu_edpt_dir(ep_desc->bEndpointAddress) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint
+
+  //------------- active, but no TD list -------------//
+  p_qhd->qtd_overlay.halted              = 0;
+  p_qhd->qtd_overlay.next.terminate      = 1;
+  p_qhd->qtd_overlay.alternate.terminate = 1;
+  if (TUSB_XFER_BULK == xfer_type && p_qhd->ep_speed == TUSB_SPEED_HIGH && p_qhd->pid == EHCI_PID_OUT)
+  {
+    p_qhd->qtd_overlay.ping_err = 1; // do PING for Highspeed Bulk OUT, EHCI section 4.11
+  }
+}
+
+static void qtd_init(ehci_qtd_t* p_qtd, void const* buffer, uint16_t total_bytes)
+{
+  tu_memclr(p_qtd, sizeof(ehci_qtd_t));
+
+  p_qtd->used                = 1;
+
+  p_qtd->next.terminate      = 1; // init to null
+  p_qtd->alternate.terminate = 1; // not used, always set to terminated
+  p_qtd->active              = 1;
+  p_qtd->err_count           = 3; // TODO 3 consecutive errors tolerance
+  p_qtd->data_toggle         = 0;
+  p_qtd->total_bytes         = total_bytes;
+  p_qtd->expected_bytes      = total_bytes;
+
+  p_qtd->buffer[0] = (uint32_t) buffer;
+  for(uint8_t i=1; i<5; i++)
+  {
+    p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096;
+  }
+}
+
+//------------- List Managing Helper -------------//
+static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
+{
+  new->address = current->address;
+  current->address = ((uint32_t) new) | (new_type << 1);
+}
+
+static inline ehci_link_t* list_next(ehci_link_t *p_link_pointer)
+{
+  return (ehci_link_t*) tu_align32(p_link_pointer->address);
+}
+
+#endif
diff --git a/src/portable/ehci/ehci.h b/src/portable/ehci/ehci.h
new file mode 100644
index 0000000..c2bee67
--- /dev/null
+++ b/src/portable/ehci/ehci.h
@@ -0,0 +1,420 @@
+/*
+ * 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.
+ */
+
+#ifndef _TUSB_EHCI_H_
+#define _TUSB_EHCI_H_
+
+
+/* Abbreviation
+ * HC: Host Controller
+ * HCD: Host Controller Driver
+ * QHD: Queue Head for non-ISO transfer
+ * QTD: Queue Transfer Descriptor for non-ISO transfer
+ * ITD: Iso Transfer Descriptor for highspeed
+ * SITD: Split ISO Transfer Descriptor for full-speed
+ * SMASK: Start Split mask for Slipt Transaction
+ * CMASK: Complete Split mask for Slipt Transaction
+*/
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// EHCI CONFIGURATION & CONSTANTS
+//--------------------------------------------------------------------+
+
+// TODO merge OHCI with EHCI
+enum {
+  EHCI_MAX_ITD  = 4,
+  EHCI_MAX_SITD = 16
+};
+
+//--------------------------------------------------------------------+
+// EHCI Data Structure
+//--------------------------------------------------------------------+
+enum
+{
+  EHCI_QTYPE_ITD = 0 ,
+  EHCI_QTYPE_QHD     ,
+  EHCI_QTYPE_SITD    ,
+  EHCI_QTYPE_FSTN
+};
+
+/// EHCI PID
+enum
+{
+  EHCI_PID_OUT = 0 ,
+  EHCI_PID_IN      ,
+  EHCI_PID_SETUP
+};
+
+/// Link pointer
+typedef union {
+	uint32_t address;
+	struct  {
+		uint32_t terminate : 1;
+		uint32_t type      : 2;
+	};
+}ehci_link_t;
+
+/// Queue Element Transfer Descriptor
+/// Qtd is used to declare overlay in ehci_qhd_t -> cannot be declared with TU_ATTR_ALIGNED(32)
+typedef struct
+{
+	// Word 0: Next QTD Pointer
+	ehci_link_t next;
+
+	// Word 1: Alternate Next QTD Pointer (not used)
+	union{
+	  ehci_link_t alternate;
+	  struct {
+	    uint32_t                : 5;
+	    uint32_t used           : 1;
+	    uint32_t                : 10;
+	    uint32_t expected_bytes : 16;
+	  };
+	};
+
+	// 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 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
+	volatile uint32_t halted               : 1  ; ///< Serious error or STALL received
+	volatile uint32_t active               : 1  ; ///< Start transfer, clear by HC when complete
+
+	uint32_t pid                           : 2  ; ///< 0: OUT, 1: IN, 2 Setup
+	volatile uint32_t err_count            : 2  ; ///< Error Counter of consecutive errors
+	volatile uint32_t current_page         : 3  ; ///< Index into the qTD buffer pointer list
+	uint32_t int_on_complete               : 1  ; ///< Interrupt on complete
+	volatile uint32_t total_bytes          : 15 ; ///< Transfer bytes, decreased during transaction
+	volatile uint32_t data_toggle          : 1  ; ///< Data Toogle bit
+
+
+	/// 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];
+} ehci_qtd_t;
+
+TU_VERIFY_STATIC( sizeof(ehci_qtd_t) == 32, "size is not correct" );
+
+/// Queue Head
+typedef struct TU_ATTR_ALIGNED(32)
+{
+  // Word 0: Next QHD
+	ehci_link_t next;
+
+	// Word 1: Endpoint Characteristics
+	uint32_t dev_addr              : 7  ; ///< device address
+	uint32_t fl_inactive_next_xact : 1  ; ///< Only valid for Periodic with Full/Slow speed
+	uint32_t ep_number             : 4  ; ///< EP number
+	uint32_t ep_speed              : 2  ; ///< 0: Full, 1: Low, 2: High
+	uint32_t data_toggle_control   : 1  ; ///< 0: use DT in qHD, 1: use DT in qTD
+	uint32_t head_list_flag        : 1  ; ///< Head of the queue
+	uint32_t max_packet_size       : 11 ; ///< Max packet size
+	uint32_t fl_ctrl_ep_flag       : 1  ; ///< 1 if is Full/Low speed control endpoint
+	uint32_t nak_reload            : 4  ; ///< Used by HC
+
+	// Word 2: Endpoint Capabilities
+	uint32_t int_smask             : 8  ; ///< Interrupt Schedule Mask
+	uint32_t fl_int_cmask          : 8  ; ///< Split Completion Mask for Full/Slow speed
+	uint32_t fl_hub_addr           : 7  ; ///< Hub Address for Full/Slow speed
+	uint32_t fl_hub_port           : 7  ; ///< Hub Port for Full/Slow speed
+	uint32_t mult                  : 2  ; ///< Transaction per micro frame
+
+	// Word 3: Current qTD Pointer
+	volatile uint32_t qtd_addr;
+
+	// Word 4-11: Transfer Overlay
+	volatile ehci_qtd_t qtd_overlay;
+
+	//--------------------------------------------------------------------+
+  /// Due to the fact QHD is 32 bytes aligned but occupies only 48 bytes
+	/// thus there are 16 bytes padding free that we can make use of.
+  //--------------------------------------------------------------------+
+	uint8_t used;
+	uint8_t removing; // removed from asyn list, waiting for async advance
+	uint8_t pid;
+	uint8_t interval_ms; // polling interval in frames (or milisecond)
+
+	uint16_t total_xferred_bytes; // number of bytes xferred until a qtd with ioc bit set
+	uint8_t reserved2[2];
+
+	ehci_qtd_t * volatile p_qtd_list_head;	// head of the scheduled TD list
+	ehci_qtd_t * volatile p_qtd_list_tail;	// tail of the scheduled TD list
+} ehci_qhd_t;
+
+TU_VERIFY_STATIC( sizeof(ehci_qhd_t) == 64, "size is not correct" );
+
+/// Highspeed Isochronous Transfer Descriptor (section 3.3)
+typedef struct TU_ATTR_ALIGNED(32) {
+	// Word 0: Next Link Pointer
+	ehci_link_t next;
+
+	// Word 1-8: iTD Transaction Status and Control List
+	struct  {
+	  // iTD Control
+		volatile uint32_t offset          : 12 ; ///< This field is a value that is an offset, expressed in bytes, from the beginning of a buffer.
+		volatile uint32_t page_select     : 3  ; ///< These bits are set by software to indicate which of the buffer page pointers the offset field in this slot should be concatenated to produce the starting memory address for this transaction. The valid range of values for this field is 0 to 6
+             uint32_t int_on_complete : 1  ; ///< If this bit is set to a one, it specifies that when this transaction completes, the Host Controller should issue an interrupt at the next interrupt threshold
+		volatile uint32_t length          : 12 ; ///< For an OUT, this field is the number of data bytes the host controller will send during the transaction. The host controller is not required to update this field to reflect the actual number of bytes transferred during the transfer
+																						 ///< For an IN, the initial value of the field is the number of bytes the host expects the endpoint to deliver. During the status update, the host controller writes back the number of bytes successfully received. The value in this register is the actual byte count
+		// iTD Status
+		volatile uint32_t error           : 1  ; ///< Set to a one by the Host Controller during status update in the case where the host did not receive a valid response from the device (Timeout, CRC, Bad PID, etc.). This bit may only be set for isochronous IN transactions.
+		volatile uint32_t babble_err      : 1  ; ///< Set to a 1 by the Host Controller during status update when a babble is detected during the transaction
+		volatile uint32_t buffer_err      : 1  ; ///< Set to a 1 by the Host Controller during status update to indicate that the Host Controller is unable to keep up with the reception of incoming data (overrun) or is unable to supply data fast enough during transmission (underrun).
+		volatile uint32_t active          : 1  ; ///< Set to 1 by software to enable the execution of an isochronous transaction by the Host Controller
+	} xact[8];
+
+	// Word 9-15  Buffer Page Pointer List (Plus)
+	uint32_t BufferPointer[7];
+
+//	// FIXME: Store meta data into buffer pointer reserved for saving memory
+//	/*---------- HCD Area ----------*/
+//	uint32_t used;
+//	uint32_t IhdIdx;
+//	uint32_t reserved[6];
+} ehci_itd_t;
+
+TU_VERIFY_STATIC( sizeof(ehci_itd_t) == 64, "size is not correct" );
+
+/// Split (Full-Speed) Isochronous Transfer Descriptor
+typedef struct TU_ATTR_ALIGNED(32)
+{
+  // Word 0: Next Link Pointer
+	ehci_link_t next;
+
+	// Word 1: siTD Endpoint Characteristics
+	uint32_t dev_addr    : 7; ///< This field selects the specific device serving as the data source or sink.
+	uint32_t             : 1; ///< reserved
+	uint32_t ep_number   : 4; ///< This 4-bit field selects the particular endpoint number on the device serving as the data source or sink.
+	uint32_t             : 4; ///< This field is reserved and should be set to zero.
+	uint32_t hub_addr    : 7; ///< This field holds the device address of the transaction translators’ hub.
+	uint32_t             : 1; ///< reserved
+	uint32_t port_number : 7; ///< This field is the port number of the recipient transaction translator.
+	uint32_t direction   : 1; ///<  0 = OUT; 1 = IN. This field encodes whether the full-speed transaction should be an IN or OUT.
+
+	// Word 2: Micro-frame Schedule Control
+	uint8_t int_smask   ; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute complete-split transactions
+	uint8_t fl_int_cmask; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute start-split transactions.
+	uint16_t reserved ; ///< reserved
+
+	// Word 3: siTD Transfer Status and Control
+	// Status [7:0] TODO indentical to qTD Token'status --> refractor later
+	volatile uint32_t                 : 1  ; // reserved
+	volatile uint32_t split_state     : 1  ;
+	volatile uint32_t missed_uframe   : 1  ;
+	volatile uint32_t xact_err        : 1  ;
+	volatile uint32_t babble_err      : 1  ;
+	volatile uint32_t buffer_err      : 1  ;
+	volatile uint32_t error           : 1  ;
+	volatile uint32_t active          : 1  ;
+	// Micro-frame Schedule Control
+	volatile uint32_t cmask_progress  : 8  ; ///< This field is used by the host controller to record which split-completes have been executed. See Section 4.12.3.3.2 for behavioral requirements.
+	volatile uint32_t total_bytes     : 10 ; ///< This field is initialized by software to the total number of bytes expected in this transfer. Maximum value is 1023
+	volatile uint32_t                 : 4  ; ///< reserved
+	volatile uint32_t page_select     : 1  ; ///< Used to indicate which data page pointer should be concatenated with the CurrentOffsetfield to construct a data buffer pointer
+					 uint32_t int_on_complete : 1  ; ///< Do not interrupt when transaction is complete. 1 = Do interrupt when transaction is complete
+					 uint32_t                 : 0  ; // padding to the end of current storage unit
+
+	/// Word 4-5: Buffer Pointer List
+	uint32_t buffer[2];		// buffer[1] TP: Transaction Position - T-Count: Transaction Count
+
+// 	union{
+// 		uint32_t BufferPointer1;
+// 		struct  {
+// 			volatile uint32_t TCount : 3;
+// 			volatile uint32_t TPosition : 2;
+// 		};
+// 	};
+
+	/*---------- Word 6 ----------*/
+	ehci_link_t back;
+
+	/// SITD is 32-byte aligned but occupies only 28 --> 4 bytes for storing extra data
+	uint8_t used;
+	uint8_t ihd_idx;
+	uint8_t reserved2[2];
+} ehci_sitd_t;
+
+TU_VERIFY_STATIC( sizeof(ehci_sitd_t) == 32, "size is not correct" );
+
+//--------------------------------------------------------------------+
+// EHCI Operational Register
+//--------------------------------------------------------------------+
+enum ehci_interrupt_mask_{
+  EHCI_INT_MASK_USB                   = TU_BIT(0),
+  EHCI_INT_MASK_ERROR                 = TU_BIT(1),
+  EHCI_INT_MASK_PORT_CHANGE           = TU_BIT(2),
+
+  EHCI_INT_MASK_FRAMELIST_ROLLOVER    = TU_BIT(3),
+  EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR = TU_BIT(4),
+  EHCI_INT_MASK_ASYNC_ADVANCE         = TU_BIT(5),
+  EHCI_INT_MASK_NXP_SOF               = TU_BIT(7),
+
+  EHCI_INT_MASK_NXP_ASYNC             = TU_BIT(18),
+  EHCI_INT_MASK_NXP_PERIODIC          = TU_BIT(19),
+
+  EHCI_INT_MASK_ALL                   =
+      EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
+      EHCI_INT_MASK_FRAMELIST_ROLLOVER | EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR |
+      EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF |
+      EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC
+};
+
+enum ehci_usbcmd_pos_ {
+  EHCI_USBCMD_POS_RUN_STOP               = 0,
+  EHCI_USBCMD_POS_FRAMELIST_SIZE         = 2,
+  EHCI_USBCMD_POS_PERIOD_ENABLE          = 4,
+  EHCI_USBCMD_POS_ASYNC_ENABLE           = 5,
+  EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB = 15,
+  EHCI_USBCMD_POS_INTERRUPT_THRESHOLD    = 16
+};
+
+enum ehci_portsc_change_mask_{
+  EHCI_PORTSC_MASK_CURRENT_CONNECT_STATUS = TU_BIT(0),
+  EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE  = TU_BIT(1),
+  EHCI_PORTSC_MASK_PORT_EANBLED           = TU_BIT(2),
+  EHCI_PORTSC_MASK_PORT_ENABLE_CHAGNE     = TU_BIT(3),
+  EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE    = TU_BIT(5),
+  EHCI_PORTSC_MASK_PORT_RESET             = TU_BIT(8),
+
+  EHCI_PORTSC_MASK_ALL =
+      EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE |
+      EHCI_PORTSC_MASK_PORT_ENABLE_CHAGNE |
+      EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE
+};
+
+typedef volatile struct
+{
+  union {
+    uint32_t command;
+
+    struct {
+      uint32_t run_stop               : 1 ; ///< 1=Run. 0=Stop
+      uint32_t reset                  : 1 ; ///< SW write 1 to reset HC, clear by HC when complete
+      uint32_t framelist_size         : 2 ; ///< Frame List size 0: 1024, 1: 512, 2: 256
+      uint32_t periodic_enable        : 1 ; ///< This bit controls whether the host controller skips processing the Periodic Schedule. Values mean: 0b Do not process the Periodic Schedule 1b Use the PERIODICLISTBASE register to access the Periodic Schedule.
+      uint32_t async_enable           : 1 ; ///< This bit controls whether the host controller skips processing the Asynchronous Schedule. Values mean: 0b Do not process the Asynchronous Schedule 1b Use the ASYNCLISTADDR register to access the Asynchronous Schedule.
+      uint32_t async_adv_doorbell     : 1 ; ///< Tell HC to interrupt next time it advances async list. Clear by HC
+      uint32_t light_reset            : 1 ; ///< Reset HC without affecting ports state
+      uint32_t async_park_count       : 2 ; ///< not used by tinyusb
+      uint32_t                        : 1 ;
+      uint32_t async_park_enable      : 1 ; ///< Enable park mode, not used by tinyusb
+      uint32_t                        : 3 ;
+      uint32_t nxp_framelist_size_msb : 1 ; ///< NXP customized : Bit 2 of the Frame List Size bits \n 011b: 128 elements \n 100b: 64 elements \n 101b: 32 elements \n 110b: 16 elements \n 111b: 8 elements
+      uint32_t int_threshold          : 8 ; ///< Default 08h. Interrupt rate in unit of micro frame
+    }command_bm;
+  };
+
+  union {
+    uint32_t status;
+
+    struct {
+      uint32_t usb                   : 1  ; ///< qTD with IOC is retired
+      uint32_t usb_error             : 1  ; ///< qTD retired due to error
+      uint32_t port_change_detect    : 1  ; ///< Set when PortOwner or ForcePortResume change from 0 -> 1
+      uint32_t framelist_rollover    : 1  ; ///< R/WC The Host Controller sets this bit to a one when the Frame List Index(see Section 2.3.4) rolls over from its maximum value to zero. The exact value at which the rollover occurs depends on the frame list size. For example, if the frame list size (as programmed in the Frame List Sizefield of the USBCMD register) is 1024, the Frame Index Registerrolls over every time FRINDEX[13] toggles. Similarly, if the size is 512, the Host Controller sets this bit to a one every time FRINDEX[12] toggles.
+      uint32_t pci_host_system_error : 1  ; ///< R/WC (not used by NXP) The Host Controller sets this bit to 1 when a serious error occurs during a host system access involving the Host Controller module. In a PCI system, conditions that set this bit to 1 include PCI Parity error, PCI Master Abort, and PCI Target Abort. When this error occurs, the Host Controller clears the Run/Stop bit in the Command register to prevent further execution of the scheduled TDs.
+      uint32_t async_adv             : 1  ; ///< Async Advance interrupt
+      uint32_t                       : 1  ;
+      uint32_t nxp_int_sof           : 1  ; ///< NXP customized:  this bit will be set every 125us and can be used by host controller driver as a time base.
+      uint32_t                       : 4  ;
+      uint32_t hc_halted             : 1  ; ///< Opposite value to run_stop bit.
+      uint32_t reclamation           : 1  ; ///< Used to detect empty async shecudle
+      uint32_t periodic_status       : 1  ; ///< Periodic schedule status
+      uint32_t async_status          : 1  ; ///< Async schedule status
+      uint32_t                       : 2  ;
+      uint32_t nxp_int_async         : 1  ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set andthe TD was from the asynchronous schedule. This bit is also set by the Host when a short packet is detected andthe packet is on the asynchronous schedule.
+      uint32_t nxp_int_period        : 1  ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set andthe TD was from the periodic schedule.
+      uint32_t                       : 12 ;
+    }status_bm;
+  };
+
+  union{
+    uint32_t inten;
+
+    struct {
+      uint32_t usb                   : 1  ;
+      uint32_t usb_error             : 1  ;
+      uint32_t port_change_detect    : 1  ;
+      uint32_t framelist_rollover    : 1  ;
+      uint32_t pci_host_system_error : 1  ;
+      uint32_t async_adv             : 1  ;
+      uint32_t                       : 1  ;
+      uint32_t nxp_int_sof           : 1  ;
+      uint32_t                       : 10 ;
+      uint32_t nxp_int_async         : 1  ;
+      uint32_t nxp_int_period        : 1  ;
+      uint32_t                       : 12 ;
+    }inten_bm;
+  };
+
+  uint32_t frame_index        ; ///< Micro frame counter
+  uint32_t ctrl_ds_seg        ; ///< Control Data Structure Segment
+  uint32_t periodic_list_base ; ///< Beginning address of perodic frame list
+  uint32_t async_list_addr    ; ///< Address of next async QHD to be executed
+  uint32_t nxp_tt_control     ; ///< nxp embedded transaction translator (reserved by EHCI specs)
+  uint32_t reserved[8]        ;
+  uint32_t config_flag        ; ///< not used by NXP
+
+  union {
+    uint32_t portsc             ; ///< port status and control
+    struct {
+      uint32_t current_connect_status      : 1; ///< 0: No device, 1: Device is present on port
+      uint32_t connect_status_change       : 1; ///< Change in Current Connect Status
+      uint32_t port_enabled                : 1; ///< Ports can only be enabled by HC as a part of the reset and enable. SW can write 0 to disable
+      uint32_t port_enable_change          : 1; ///< Port Enabled has changed
+      uint32_t over_current_active         : 1; ///< Port has an over-current condition
+      uint32_t over_current_change         : 1; ///< Change to Over-current Active
+      uint32_t force_port_resume           : 1; ///< Resume detected/driven on port. This functionality defined for manipulating this bit depends on the value of the Suspend bit.
+      uint32_t suspend                     : 1; ///< Port in suspend state
+      uint32_t port_reset                  : 1; ///< 1=Port is in Reset. 0=Port is not in Reset
+      uint32_t nxp_highspeed_status        : 1; ///< NXP customized: 0=connected to the port is not in High-speed mode, 1=connected to the port is in High-speed mode
+      uint32_t line_status                 : 2; ///< D+/D- state: 00: SE0, 10: J-state, 01: K-state
+      uint32_t port_power                  : 1; ///< 0= power off, 1= power on
+      uint32_t port_owner                  : 1; ///< not used by NXP
+      uint32_t port_indicator_control      : 2; ///< 00b: off, 01b: Amber, 10b: green, 11b: undefined
+      uint32_t port_test_control           : 4; ///< Port test mode, not used by tinyusb
+      uint32_t wake_on_connect_enable      : 1; ///< Enables device connects as wake-up events
+      uint32_t wake_on_disconnect_enable   : 1; ///< Enables device disconnects as wake-up events
+      uint32_t wake_on_over_current_enable : 1; ///< Enables over-current conditions as wake-up events
+      uint32_t nxp_phy_clock_disable       : 1; ///< NXP customized: the PHY can be put into Low Power Suspend – Clock Disable when the downstream device has been put into suspend mode or when no downstream device is connected. Low power suspend is completely under the control of software. 0: enable PHY clock, 1: disable PHY clock
+      uint32_t nxp_port_force_fullspeed    : 1; ///< NXP customized: Writing this bit to a 1 will force the port to only connect at Full Speed. It disables the chirp sequence that allowsthe port to identify itself as High Speed. This is useful for testing FS configurations with a HS host, hub or device.
+      uint32_t TU_RESERVED                 : 1;
+      uint32_t nxp_port_speed              : 2; ///< NXP customized: This register field indicates the speed atwhich the port is operating. For HS mode operation in the host controllerand HS/FS operation in the device controller the port routing steers data to the Protocol engine. For FS and LS mode operation in the host controller, the port routing steers data to the Protocol Engine w/ Embedded Transaction Translator. 0x0: Fullspeed, 0x1: Lowspeed, 0x2: Highspeed
+      uint32_t TU_RESERVED                 : 4;
+    }portsc_bm;
+  };
+}ehci_registers_t;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_EHCI_H_ */
diff --git a/src/portable/ehci/ehci_api.h b/src/portable/ehci/ehci_api.h
new file mode 100644
index 0000000..12e0a73
--- /dev/null
+++ b/src/portable/ehci/ehci_api.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 _TUSB_EHCI_API_H_
+#define _TUSB_EHCI_API_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// API Implemented by EHCI
+//--------------------------------------------------------------------+
+
+// Initialize EHCI driver
+bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
new file mode 100644
index 0000000..a9c3113
--- /dev/null
+++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -0,0 +1,854 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * Additions Copyright (c) 2020, Espressif Systems (Shanghai) Co. 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.
+ */
+
+#include "tusb_option.h"
+
+#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) ||  (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && TUSB_OPT_DEVICE_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"
+#include "soc/periph_defs.h" // for interrupt source
+
+#include "device/dcd.h"
+
+// Max number of bi-directional endpoints including EP0
+// Note: ESP32S2 specs say there are only up to 5 IN active endpoints include EP0
+// We should probably prohibit enabling Endpoint IN > 4 (not done yet)
+#define EP_MAX            USB_OUT_EP_NUM
+
+// FIFO size in bytes
+#define EP_FIFO_SIZE      1024
+
+// Max number of IN EP FIFOs
+#define EP_FIFO_NUM 5
+
+typedef struct {
+    uint8_t *buffer;
+    // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
+    uint16_t total_len;
+    uint16_t queued_len;
+    uint16_t max_size;
+    bool short_packet;
+} xfer_ctl_t;
+
+static const char *TAG = "TUSB:DCD";
+static intr_handle_t usb_ih;
+
+
+static uint32_t _setup_packet[2];
+
+#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
+static xfer_ctl_t xfer_status[EP_MAX][2];
+
+// Keep count of how many FIFOs are in use
+static uint8_t _allocated_fifos = 1; //FIFO0 is always in use
+
+// Will either return an unused FIFO number, or 0 if all are used.
+static uint8_t get_free_fifo(void)
+{
+  if (_allocated_fifos < EP_FIFO_NUM) return _allocated_fifos++;
+  return 0;
+}
+
+// Setup the control endpoint 0.
+static void bus_reset(void)
+{
+  for (int ep_num = 0; ep_num < USB_OUT_EP_NUM; ep_num++) {
+    USB0.out_ep_reg[ep_num].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK
+  }
+
+  // clear device address
+  USB0.dcfg &= ~USB_DEVADDR_M;
+
+  USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
+  USB0.doepmsk  = USB_SETUPMSK_M | USB_XFERCOMPLMSK;
+  USB0.diepmsk  = USB_TIMEOUTMSK_M | USB_DI_XFERCOMPLMSK_M /*| USB_INTKNTXFEMPMSK_M*/;
+
+  // "USB Data FIFOs" section in reference manual
+  // Peripheral FIFO architecture
+  //
+  // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+  // | IN FIFO MAX |
+  // ---------------
+  // |    ...      |
+  // --------------- y + x + 16 + GRXFSIZ
+  // | IN FIFO 2   |
+  // --------------- x + 16 + GRXFSIZ
+  // | IN FIFO 1   |
+  // --------------- 16 + GRXFSIZ
+  // | IN FIFO 0   |
+  // --------------- 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
+  //   * 10 locations in hardware for setup packets + setup control words (up to 3 setup packets).
+  //   * 2 locations for OUT endpoint control words.
+  //   * 16 for largest packet size of 64 bytes. ( TODO Highspeed is 512 bytes)
+  //   * 1 location for global NAK (not required/used here).
+  //   * It is recommended to allocate 2 times the largest packet size, therefore
+  //   Recommended value = 10 + 1 + 2 x (16+2) = 47 --> Let's make it 52
+  USB0.grstctl |= 0x10 << USB_TXFNUM_S; // fifo 0x10,
+  USB0.grstctl |= USB_TXFFLSH_M;        // Flush fifo
+  USB0.grxfsiz = 52;
+
+  // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
+  USB0.gnptxfsiz = (16 << USB_NPTXFDEP_S) | (USB0.grxfsiz & 0x0000ffffUL);
+
+  // Ready to receive SETUP packet
+  USB0.out_ep_reg[0].doeptsiz |= USB_SUPCNT0_M;
+
+  USB0.gintmsk |= USB_IEPINTMSK_M | USB_OEPINTMSK_M;
+}
+
+static void enum_done_processing(void)
+{
+  ESP_EARLY_LOGV(TAG, "dcd_int_handler - Speed enumeration done! Sending DCD_EVENT_BUS_RESET then");
+  // On current silicon on the Full Speed core, speed is fixed to Full Speed.
+  // However, keep for debugging and in case Low Speed is ever supported.
+  uint32_t enum_spd = (USB0.dsts >> USB_ENUMSPD_S) & (USB_ENUMSPD_V);
+
+  // Maximum packet size for EP 0 is set for both directions by writing DIEPCTL
+  if (enum_spd == 0x03) { // Full-Speed (PHY on 48 MHz)
+    USB0.in_ep_reg[0].diepctl &= ~USB_D_MPS0_V;    // 64 bytes
+    USB0.in_ep_reg[0].diepctl &= ~USB_D_STALL0_M; // clear Stall
+    xfer_status[0][TUSB_DIR_OUT].max_size = 64;
+    xfer_status[0][TUSB_DIR_IN].max_size = 64;
+  } else {
+    USB0.in_ep_reg[0].diepctl |= USB_D_MPS0_V;     // 8 bytes
+    USB0.in_ep_reg[0].diepctl &= ~USB_D_STALL0_M; // clear Stall
+    xfer_status[0][TUSB_DIR_OUT].max_size = 8;
+    xfer_status[0][TUSB_DIR_IN].max_size = 8;
+  }
+}
+
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+  ESP_LOGV(TAG, "DCD init - Start");
+
+  // A. Disconnect
+  ESP_LOGV(TAG, "DCD init - Soft DISCONNECT and Setting up");
+  USB0.dctl |= USB_SFTDISCON_M; // Soft disconnect
+
+  // B. Programming DCFG
+  /* If USB host misbehaves during status portion of control xfer
+    (non zero-length packet), send STALL back and discard. Full speed. */
+  USB0.dcfg |= USB_NZSTSOUTHSHK_M | // NonZero .... STALL
+      (3 << 0);            // dev speed: fullspeed 1.1 on 48 mhz  // TODO no value in usb_reg.h (IDF-1476)
+
+  USB0.gahbcfg |= USB_NPTXFEMPLVL_M | USB_GLBLLNTRMSK_M; // Global interruptions ON
+  USB0.gusbcfg |= USB_FORCEDEVMODE_M;                    // force devmode
+  USB0.gotgctl &= ~(USB_BVALIDOVVAL_M | USB_BVALIDOVEN_M | USB_VBVALIDOVVAL_M); //no overrides
+
+  // C. Setting SNAKs, then connect
+  for (int n = 0; n < USB_OUT_EP_NUM; n++) {
+    USB0.out_ep_reg[n].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK
+  }
+
+  // D. Interruption masking
+  USB0.gintmsk = 0;   //mask all
+  USB0.gotgint = ~0U; //clear OTG ints
+  USB0.gintsts = ~0U; //clear pending ints
+  USB0.gintmsk = USB_OTGINTMSK_M   |
+                 USB_MODEMISMSK_M  |
+                 USB_RXFLVIMSK_M   |
+                 USB_ERLYSUSPMSK_M |
+                 USB_USBSUSPMSK_M  |
+                 USB_USBRSTMSK_M   |
+                 USB_ENUMDONEMSK_M |
+                 USB_RESETDETMSK_M |
+                 USB_DISCONNINTMSK_M; // host most only
+
+  dcd_connect(rhport);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  (void)rhport;
+  ESP_LOGV(TAG, "DCD init - Set address : %u", dev_addr);
+  USB0.dcfg |= ((dev_addr & USB_DEVADDR_V) << USB_DEVADDR_S);
+  // Response with status after changing device address
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void)rhport;
+
+  // set remote wakeup
+  USB0.dctl |= USB_RMTWKUPSIG_M;
+
+  // enable SOF to detect bus resume
+  USB0.gintsts = USB_SOF_M;
+  USB0.gintmsk |= USB_SOFMSK_M;
+
+  // Per specs: remote wakeup signal bit must be clear within 1-15ms
+  vTaskDelay(pdMS_TO_TICKS(1));
+
+  USB0.dctl &= ~USB_RMTWKUPSIG_M;
+}
+
+// connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  USB0.dctl &= ~USB_SFTDISCON_M;
+}
+
+// disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  USB0.dctl |= USB_SFTDISCON_M;
+}
+
+/*------------------------------------------------------------------*/
+/* DCD Endpoint port
+ *------------------------------------------------------------------*/
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
+{
+  ESP_LOGV(TAG, "DCD endpoint opened");
+  (void)rhport;
+
+  usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
+  usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
+
+  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);
+
+  if (dir == TUSB_DIR_OUT) {
+    out_ep[epnum].doepctl |= USB_USBACTEP1_M |
+                             desc_edpt->bmAttributes.xfer << USB_EPTYPE1_S |
+                             (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_DO_SETD0PID1_M : 0) |
+                             xfer->max_size << USB_MPS1_S;
+    USB0.daintmsk |= (1 << (16 + epnum));
+  } else {
+    // "USB Data FIFOs" section in reference manual
+    // Peripheral FIFO architecture
+    //
+    // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+    // | IN FIFO MAX |
+    // ---------------
+    // |    ...      |
+    // --------------- y + x + 16 + GRXFSIZ
+    // | IN FIFO 2   |
+    // --------------- x + 16 + GRXFSIZ
+    // | IN FIFO 1   |
+    // --------------- 16 + GRXFSIZ
+    // | IN FIFO 0   |
+    // --------------- GRXFSIZ
+    // | OUT FIFO    |
+    // | ( Shared )  |
+    // --------------- 0
+    //
+    // Since OUT FIFO = GRXFSIZ, FIFO 0 = 16, for simplicity, we equally allocated for the rest of endpoints
+    // - Size  : (FIFO_SIZE/4 - GRXFSIZ - 16) / (EP_MAX-1)
+    // - Offset: GRXFSIZ + 16 + Size*(epnum-1)
+    // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
+
+    uint8_t fifo_num = get_free_fifo();
+    TU_ASSERT(fifo_num != 0);
+
+    in_ep[epnum].diepctl &= ~(USB_D_TXFNUM1_M | USB_D_EPTYPE1_M | USB_DI_SETD0PID1 | USB_D_MPS1_M);
+    in_ep[epnum].diepctl |= USB_D_USBACTEP1_M |
+                            fifo_num << USB_D_TXFNUM1_S |
+                            desc_edpt->bmAttributes.xfer << USB_D_EPTYPE1_S |
+                            (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? (1 << USB_DI_SETD0PID1_S) : 0) |
+                            xfer->max_size << 0;
+
+    USB0.daintmsk |= (1 << (0 + epnum));
+
+    // Both TXFD and TXSA are in unit of 32-bit words.
+    // IN FIFO 0 was configured during enumeration, hence the "+ 16".
+    uint16_t const allocated_size = (USB0.grxfsiz & 0x0000ffff) + 16;
+    uint16_t const fifo_size = (EP_FIFO_SIZE/4 - allocated_size) / (EP_FIFO_NUM-1);
+    uint32_t const fifo_offset = allocated_size + fifo_size*(fifo_num-1);
+
+    // DIEPTXF starts at FIFO #1.
+    USB0.dieptxf[epnum - 1] = (fifo_size << USB_NPTXFDEP_S) | fifo_offset;
+  }
+  return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+  (void) rhport;
+
+  usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
+  usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
+
+  // Disable non-control interrupt
+  USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
+
+  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;
+  }
+
+  _allocated_fifos = 1;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+  (void)rhport;
+
+  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; // TODO support dcd_edpt_xfer_fifo API
+  xfer->total_len    = total_bytes;
+  xfer->queued_len   = 0;
+  xfer->short_packet = false;
+
+  uint16_t num_packets = (total_bytes / xfer->max_size);
+  uint8_t short_packet_size = total_bytes % xfer->max_size;
+
+  // Zero-size packet is special case.
+  if (short_packet_size > 0 || (total_bytes == 0)) {
+    num_packets++;
+  }
+
+  ESP_LOGV(TAG, "Transfer <-> EP%i, %s, pkgs: %i, bytes: %i",
+           epnum, ((dir == TUSB_DIR_IN) ? "USB0.HOST (in)" : "HOST->DEV (out)"),
+           num_packets, 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.
+    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
+
+    // Enable fifo empty interrupt only if there are something to put in the fifo.
+    if(total_bytes != 0) {
+      USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
+    }
+  } else {
+    // 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;
+  }
+  return true;
+}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+  (void)rhport;
+}
+#endif
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void)rhport;
+
+  usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
+  usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
+
+  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_D_EPENA1_M)) {
+      in_ep[epnum].diepctl |= (USB_DI_SNAK1_M | USB_D_STALL1_M);
+    } else {
+      // Stop transmitting packets and NAK IN xfers.
+      in_ep[epnum].diepctl |= USB_DI_SNAK1_M;
+      while ((in_ep[epnum].diepint & USB_DI_SNAK1_M) == 0) ;
+
+      // Disable the endpoint. Note that both SNAK and STALL are set here.
+      in_ep[epnum].diepctl |= (USB_DI_SNAK1_M | USB_D_STALL1_M | USB_D_EPDIS1_M);
+      while ((in_ep[epnum].diepint & USB_D_EPDISBLD0_M) == 0) ;
+      in_ep[epnum].diepint = USB_D_EPDISBLD0_M;
+    }
+
+    // Flush the FIFO, and wait until we have confirmed it cleared.
+    uint8_t const fifo_num = ((in_ep[epnum].diepctl >> USB_D_TXFNUM1_S) & USB_D_TXFNUM1_V);
+    USB0.grstctl |= (fifo_num << USB_TXFNUM_S);
+    USB0.grstctl |= USB_TXFFLSH_M;
+    while ((USB0.grstctl & USB_TXFFLSH_M) != 0) ;
+  } else {
+    // Only disable currently enabled non-control endpoint
+    if ((epnum == 0) || !(out_ep[epnum].doepctl & USB_EPENA0_M)) {
+      out_ep[epnum].doepctl |= USB_STALL0_M;
+    } 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.
+      USB0.dctl |= USB_SGOUTNAK_M;
+      while ((USB0.gintsts & USB_GOUTNAKEFF_M) == 0) ;
+
+      // Ditto here- disable the endpoint. Note that only STALL and not SNAK
+      // is set here.
+      out_ep[epnum].doepctl |= (USB_STALL0_M | USB_EPDIS0_M);
+      while ((out_ep[epnum].doepint & USB_EPDISBLD0_M) == 0) ;
+      out_ep[epnum].doepint = USB_EPDISBLD0_M;
+
+      // Allow other OUT endpoints to keep receiving.
+      USB0.dctl |= USB_CGOUTNAK_M;
+    }
+  }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void)rhport;
+
+  usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
+  usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir = tu_edpt_dir(ep_addr);
+
+  if (dir == TUSB_DIR_IN) {
+    in_ep[epnum].diepctl &= ~USB_D_STALL1_M;
+
+    uint8_t eptype = (in_ep[epnum].diepctl & USB_D_EPTYPE1_M) >> USB_D_EPTYPE1_S;
+    // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt
+    // and bulk endpoints.
+    if (eptype == 2 || eptype == 3) {
+      in_ep[epnum].diepctl |= USB_DI_SETD0PID1_M;
+    }
+  } else {
+    out_ep[epnum].doepctl &= ~USB_STALL1_M;
+
+    uint8_t eptype = (out_ep[epnum].doepctl & USB_EPTYPE1_M) >> USB_EPTYPE1_S;
+    // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt
+    // and bulk endpoints.
+    if (eptype == 2 || eptype == 3) {
+      out_ep[epnum].doepctl |= USB_DO_SETD0PID1_M;
+    }
+  }
+}
+
+/*------------------------------------------------------------------*/
+
+static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ uint16_t xfer_size)
+{
+  ESP_EARLY_LOGV(TAG, "USB - receive_packet");
+  volatile uint32_t *rx_fifo = USB0.fifo[0];
+
+  // See above TODO
+  // uint16_t remaining = (out_ep->DOEPTSIZ & UsbDOEPTSIZ_XFRSIZ_Msk) >> UsbDOEPTSIZ_XFRSIZ_Pos;
+  // xfer->queued_len = xfer->total_len - remaining;
+
+  uint16_t remaining = xfer->total_len - xfer->queued_len;
+  uint16_t to_recv_size;
+
+  if (remaining <= xfer->max_size) {
+    // Avoid buffer overflow.
+    to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
+  } else {
+    // Room for full packet, choose recv_size based on what the microcontroller
+    // claims.
+    to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
+  }
+
+  // Common buffer read
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+  if (xfer->ff)
+  {
+    // Ring buffer
+    tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) rx_fifo, to_recv_size);
+  }
+  else
+#endif
+  {
+    uint8_t to_recv_rem = to_recv_size % 4;
+    uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem;
+
+    // Do not assume xfer buffer is aligned.
+    uint8_t *base = (xfer->buffer + xfer->queued_len);
+
+    // This for loop always runs at least once- skip if less than 4 bytes
+    // to collect.
+    if (to_recv_size >= 4) {
+      for (uint16_t i = 0; i < to_recv_size_aligned; i += 4) {
+        uint32_t tmp = (*rx_fifo);
+        base[i] = tmp & 0x000000FF;
+        base[i + 1] = (tmp & 0x0000FF00) >> 8;
+        base[i + 2] = (tmp & 0x00FF0000) >> 16;
+        base[i + 3] = (tmp & 0xFF000000) >> 24;
+      }
+    }
+
+    // Do not read invalid bytes from RX FIFO.
+    if (to_recv_rem != 0) {
+      uint32_t tmp = (*rx_fifo);
+      uint8_t *last_32b_bound = base + to_recv_size_aligned;
+
+      last_32b_bound[0] = tmp & 0x000000FF;
+      if (to_recv_rem > 1) {
+        last_32b_bound[1] = (tmp & 0x0000FF00) >> 8;
+      }
+      if (to_recv_rem > 2) {
+        last_32b_bound[2] = (tmp & 0x00FF0000) >> 16;
+      }
+    }
+  }
+
+  xfer->queued_len += xfer_size;
+
+  // Per USB spec, a short OUT packet (including length 0) is always
+  // indicative of the end of a transfer (at least for ctl, bulk, int).
+  xfer->short_packet = (xfer_size < xfer->max_size);
+}
+
+static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, uint8_t fifo_num)
+{
+  ESP_EARLY_LOGV(TAG, "USB - transmit_packet");
+  volatile uint32_t *tx_fifo = USB0.fifo[fifo_num];
+
+  uint16_t remaining = (in_ep->dieptsiz & 0x7FFFFU) >> USB_D_XFERSIZE0_S;
+  xfer->queued_len = xfer->total_len - remaining;
+
+  uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining;
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+  if (xfer->ff)
+  {
+    tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) tx_fifo, to_xfer_size);
+  }
+  else
+#endif
+  {
+    uint8_t to_xfer_rem = to_xfer_size % 4;
+    uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem;
+
+    // Buffer might not be aligned to 32b, so we need to force alignment
+    // by copying to a temp var.
+    uint8_t *base = (xfer->buffer + xfer->queued_len);
+
+    // This for loop always runs at least once- skip if less than 4 bytes
+    // to send off.
+    if (to_xfer_size >= 4) {
+      for (uint16_t i = 0; i < to_xfer_size_aligned; i += 4) {
+        uint32_t tmp = base[i] | (base[i + 1] << 8) |
+            (base[i + 2] << 16) | (base[i + 3] << 24);
+        (*tx_fifo) = tmp;
+      }
+    }
+
+    // Do not read beyond end of buffer if not divisible by 4.
+    if (to_xfer_rem != 0) {
+      uint32_t tmp = 0;
+      uint8_t *last_32b_bound = base + to_xfer_size_aligned;
+
+      tmp |= last_32b_bound[0];
+      if (to_xfer_rem > 1) {
+        tmp |= (last_32b_bound[1] << 8);
+      }
+      if (to_xfer_rem > 2) {
+        tmp |= (last_32b_bound[2] << 16);
+      }
+
+      (*tx_fifo) = tmp;
+    }
+  }
+}
+
+static void read_rx_fifo(void)
+{
+  // Pop control word off FIFO (completed xfers will have 2 control words,
+  // we only pop one ctl word each interrupt).
+  uint32_t const ctl_word = USB0.grxstsp;
+  uint8_t  const pktsts   = (ctl_word & USB_PKTSTS_M) >> USB_PKTSTS_S;
+  uint8_t  const epnum    = (ctl_word & USB_CHNUM_M ) >> USB_CHNUM_S;
+  uint16_t const bcnt     = (ctl_word & USB_BCNT_M  ) >> USB_BCNT_S;
+
+  switch (pktsts) {
+    case 0x01: // Global OUT NAK (Interrupt)
+      ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Global OUT NAK");
+      break;
+
+    case 0x02: { // Out packet recvd
+      ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Out packet");
+      xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
+      receive_packet(xfer, bcnt);
+    }
+    break;
+
+    case 0x03: // Out packet done (Interrupt)
+      ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Out packet done");
+      break;
+
+    case 0x04: // Step 2: Setup transaction completed (Interrupt)
+      // After this event, OEPINT interrupt will occur with SETUP bit set
+      ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX : Setup packet done");
+      USB0.out_ep_reg[epnum].doeptsiz |= USB_SUPCNT0_M;
+      break;
+
+    case 0x06: { // Step1: Setup data packet received
+      volatile uint32_t *rx_fifo = USB0.fifo[0];
+
+      // We can receive up to three setup packets in succession, but
+      // only the last one is valid. Therefore we just overwrite it
+      _setup_packet[0] = (*rx_fifo);
+      _setup_packet[1] = (*rx_fifo);
+
+      ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX : Setup packet : 0x%08x 0x%08x", _setup_packet[0], _setup_packet[1]);
+    }
+    break;
+
+    default: // Invalid, do something here, like breakpoint?
+      TU_BREAKPOINT();
+      break;
+  }
+}
+
+static void handle_epout_ints(void)
+{
+  // GINTSTS will be cleared with DAINT == 0
+  // DAINT for a given EP clears when DOEPINTx is cleared.
+  // DOEPINT will be cleared when DAINT's out bits are cleared.
+  for (int n = 0; n < USB_OUT_EP_NUM; n++) {
+    xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
+
+    if (USB0.daint & (1 << (16 + n))) {
+      // SETUP packet Setup Phase done.
+      if ((USB0.out_ep_reg[n].doepint & USB_SETUP0_M)) {
+        USB0.out_ep_reg[n].doepint = USB_STUPPKTRCVD0_M | USB_SETUP0_M; // clear
+        dcd_event_setup_received(0, (uint8_t *)&_setup_packet[0], true);
+      }
+
+      // OUT XFER complete (single packet).q
+      if (USB0.out_ep_reg[n].doepint & USB_XFERCOMPL0_M) {
+
+        ESP_EARLY_LOGV(TAG, "TUSB IRQ - EP OUT - XFER complete (single packet)");
+        USB0.out_ep_reg[n].doepint = USB_XFERCOMPL0_M;
+
+        // Transfer complete if short packet or total len is transferred
+        if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
+          xfer->short_packet = false;
+          dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+        } else {
+          // Schedule another packet to be received.
+          USB0.out_ep_reg[n].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
+          USB0.out_ep_reg[n].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
+        }
+      }
+    }
+  }
+}
+
+static void handle_epin_ints(void)
+{
+  // GINTSTS will be cleared with DAINT == 0
+  // DAINT for a given EP clears when DIEPINTx is cleared.
+  // IEPINT will be cleared when DAINT's out bits are cleared.
+  for (uint32_t n = 0; n < USB_IN_EP_NUM; n++) {
+    xfer_ctl_t *xfer = &xfer_status[n][TUSB_DIR_IN];
+
+    if (USB0.daint & (1 << (0 + n))) {
+      ESP_EARLY_LOGV(TAG, "TUSB IRQ - EP IN %u", n);
+      // IN XFER complete (entire xfer).
+      if (USB0.in_ep_reg[n].diepint & USB_D_XFERCOMPL0_M) {
+        ESP_EARLY_LOGV(TAG, "TUSB IRQ - IN XFER complete!");
+        USB0.in_ep_reg[n].diepint = USB_D_XFERCOMPL0_M;
+        dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
+      }
+
+      // XFER FIFO empty
+      if (USB0.in_ep_reg[n].diepint & USB_D_TXFEMP0_M) {
+        ESP_EARLY_LOGV(TAG, "TUSB IRQ - IN XFER FIFO empty!");
+        USB0.in_ep_reg[n].diepint = USB_D_TXFEMP0_M;
+        transmit_packet(xfer, &USB0.in_ep_reg[n], n);
+
+        // Turn off TXFE if all bytes are written.
+        if (xfer->queued_len == xfer->total_len)
+        {
+          USB0.dtknqr4_fifoemptymsk &= ~(1 << n);
+        }
+      }
+
+      // XFER Timeout
+      if (USB0.in_ep_reg[n].diepint & USB_D_TIMEOUT0_M) {
+        // Clear interrupt or enpoint will hang.
+        USB0.in_ep_reg[n].diepint = USB_D_TIMEOUT0_M;
+        // Maybe retry?
+      }
+    }
+  }
+}
+
+
+static void _dcd_int_handler(void* arg)
+{
+  (void) arg;
+  uint8_t const rhport = 0;
+
+  const uint32_t int_msk = USB0.gintmsk;
+  const uint32_t int_status = USB0.gintsts & int_msk;
+
+  if (int_status & USB_USBRST_M) {
+    // start of reset
+    ESP_EARLY_LOGV(TAG, "dcd_int_handler - reset");
+    USB0.gintsts = USB_USBRST_M;
+    // FIFOs will be reassigned when the endpoints are reopen
+    _allocated_fifos = 1;
+    bus_reset();
+  }
+
+  if (int_status & USB_RESETDET_M) {
+    ESP_EARLY_LOGV(TAG, "dcd_int_handler - reset while suspend");
+    USB0.gintsts = USB_RESETDET_M;
+    bus_reset();
+  }
+
+  if (int_status & USB_ENUMDONE_M) {
+    // ENUMDNE detects speed of the link. For full-speed, we
+    // always expect the same value. This interrupt is considered
+    // the end of reset.
+    USB0.gintsts = USB_ENUMDONE_M;
+    enum_done_processing();
+    dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+  }
+
+  if(int_status & USB_USBSUSP_M)
+  {
+    USB0.gintsts = USB_USBSUSP_M;
+    dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+  }
+
+  if(int_status & USB_WKUPINT_M)
+  {
+    USB0.gintsts = USB_WKUPINT_M;
+    dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+  }
+
+  if (int_status & USB_OTGINT_M)
+  {
+    // OTG INT bit is read-only
+    ESP_EARLY_LOGV(TAG, "dcd_int_handler - disconnected");
+
+    uint32_t const otg_int = USB0.gotgint;
+
+    if (otg_int & USB_SESENDDET_M)
+    {
+      dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+    }
+
+    USB0.gotgint = otg_int;
+  }
+
+  if (int_status & USB_SOF_M) {
+    USB0.gintsts = USB_SOF_M;
+
+    // Disable SOF interrupt since currently only used for remote wakeup detection
+    USB0.gintmsk &= ~USB_SOFMSK_M;
+
+    dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+  }
+
+
+  if (int_status & USB_RXFLVI_M) {
+    // RXFLVL bit is read-only
+    ESP_EARLY_LOGV(TAG, "dcd_int_handler - rx!");
+
+    // Mask out RXFLVL while reading data from FIFO
+    USB0.gintmsk &= ~USB_RXFLVIMSK_M;
+    read_rx_fifo();
+    USB0.gintmsk |= USB_RXFLVIMSK_M;
+  }
+
+  // OUT endpoint interrupt handling.
+  if (int_status & USB_OEPINT_M) {
+    // OEPINT is read-only
+    ESP_EARLY_LOGV(TAG, "dcd_int_handler - OUT endpoint!");
+    handle_epout_ints();
+  }
+
+  // IN endpoint interrupt handling.
+  if (int_status & USB_IEPINT_M) {
+    // IEPINT bit read-only
+    ESP_EARLY_LOGV(TAG, "dcd_int_handler - IN endpoint!");
+    handle_epin_ints();
+  }
+
+  // Without handling
+  USB0.gintsts |= USB_CURMOD_INT_M  |
+                  USB_MODEMIS_M     |
+                  USB_OTGINT_M      |
+                  USB_NPTXFEMP_M    |
+                  USB_GINNAKEFF_M   |
+                  USB_GOUTNAKEFF    |
+                  USB_ERLYSUSP_M    |
+                  USB_USBSUSP_M     |
+                  USB_ISOOUTDROP_M  |
+                  USB_EOPF_M        |
+                  USB_EPMIS_M       |
+                  USB_INCOMPISOIN_M |
+                  USB_INCOMPIP_M    |
+                  USB_FETSUSP_M     |
+                  USB_PTXFEMP_M;
+}
+
+void dcd_int_enable (uint8_t rhport)
+{
+  (void) rhport;
+  esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, (intr_handler_t) _dcd_int_handler, NULL, &usb_ih);
+}
+
+void dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  esp_intr_free(usb_ih);
+}
+
+#endif // #if OPT_MCU_ESP32S2 || OPT_MCU_ESP32S3
+
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
new file mode 100644
index 0000000..f6e05e1
--- /dev/null
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -0,0 +1,900 @@
+/* 
+ * 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 TUSB_OPT_DEVICE_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 "device/dcd.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
+  #define FIFO1_WORD FIFO1
+
+#else
+  #error "Unsupported MCUs"
+#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 {
+  uint16_t TXMAXP;
+  uint8_t  TXCSRL;
+  uint8_t  TXCSRH;
+  uint16_t RXMAXP;
+  uint8_t  RXCSRL;
+  uint8_t  RXCSRH;
+  uint16_t RXCOUNT;
+  uint16_t RESERVED[3];
+} 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
+{
+  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;
+
+/*------------------------------------------------------------------
+ * INTERNAL OBJECT & 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
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+  free_block_t free_blocks[2 * (DCD_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 < DCD_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;
+      print_block_list(free_blocks, num_blocks);
+    }
+    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;
+      print_block_list(free_blocks, num_blocks);
+    }
+  }
+  print_block_list(free_blocks, num_blocks);
+
+  /* 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 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 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);
+}
+
+static void process_setup_packet(uint8_t rhport)
+{
+  uint32_t *p = (void*)&_dcd.setup_packet;
+  p[0]        = USB0->FIFO0_WORD;
+  p[1]        = USB0->FIFO0_WORD;
+
+  _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) USB0->CSRL0 = USB_CSRL0_RXRDYC;
+}
+
+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;
+  }
+
+  volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
+  const unsigned mps = regs->TXMAXP;
+  const unsigned len = TU_MIN(mps, rem);
+  void          *buf = pipe->buf;
+  // TU_LOG1("   %p mps %d len %d rem %d\n", buf, mps, len, rem);
+  if (len) {
+    if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
+      pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_IN);
+    } else {
+      pipe_write_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len);
+      pipe->buf       = buf + len;
+    }
+    pipe->remaining = rem - len;
+  }
+  regs->TXCSRL = USB_TXCSRL1_TXRDY;
+  // 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];
+  volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
+  // TU_LOG1(" RXCSRL%d = %x\n", epnum_minus1 + 1, regs->RXCSRL);
+
+  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) {
+    if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
+      pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_OUT);
+    } else {
+      pipe_read_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len);
+      pipe->buf       = buf + len;
+    }
+    pipe->remaining = rem - len;
+  }
+  if ((len < mps) || (rem == len)) {
+    pipe->buf = NULL;
+    return NULL != buf;
+  }
+  regs->RXCSRL = 0; /* Clear RXRDY bit */
+  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;
+
+  if (dir_in) {
+    handle_xfer_in(ep_addr);
+  } else {
+    volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
+    if (regs->RXCSRL & USB_RXCSRL1_RXRDY) regs->RXCSRL = 0;
+  }
+  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);
+
+  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 USB0->CSRL0 = %x\n", USB0->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, &USB0->FIFO0_WORD, 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. */
+        USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
+      } else {
+        USB0->CSRL0 = USB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */
+      }
+      // TU_LOG1(" IN USB0->CSRL0 = %x\n", USB0->CSRL0);
+    } else {
+      // TU_LOG1(" OUT USB0->CSRL0 = %x\n", USB0->CSRL0);
+      _dcd.pipe0.buf       = buffer;
+      _dcd.pipe0.length    = len;
+      _dcd.pipe0.remaining = len;
+      USB0->CSRL0 = USB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */
+    }
+  } else if (dir_in) {
+    // TU_LOG1(" STATUS IN USB0->CSRL0 = %x\n", USB0->CSRL0);
+    _dcd.pipe0.buf = NULL;
+    _dcd.pipe0.length    = 0;
+    _dcd.pipe0.remaining = 0;
+    /* Clear RX FIFO and reverse the transaction direction */
+    USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND;
+  }
+  return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+  uint_fast8_t csrl = USB0->CSRL0;
+
+  // TU_LOG1(" EP0 USB0->CSRL0 = %x\n", csrl);
+
+  if (csrl & USB_CSRL0_STALLED) {
+    /* Returned STALL packet to HOST. */
+    USB0->CSRL0 = 0; /* Clear STALL */
+    return;
+  }
+
+  unsigned req = _dcd.setup_packet.bmRequestType;
+  if (csrl & USB_CSRL0_SETEND) {
+    TU_LOG1("   ABORT by the next packets\n");
+    USB0->CSRL0 = USB_CSRL0_SETENDC;
+    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) == USB0->COUNT0,);
+      process_setup_packet(rhport);
+      return;
+    }
+    if (_dcd.pipe0.buf) {
+      /* DATA OUT */
+      const unsigned vld = USB0->COUNT0;
+      const unsigned rem = _dcd.pipe0.remaining;
+      const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
+      pipe_read_packet(_dcd.pipe0.buf, &USB0->FIFO0_WORD, 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. */
+      USB0->FADDR = (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_minus1 = tu_edpt_number(ep_addr) - 1;
+
+  volatile hw_endpoint_t *regs = edpt_regs(epn_minus1);
+  if (dir_in) {
+    // TU_LOG1(" TXCSRL%d = %x\n", epn_minus1 + 1, regs->TXCSRL);
+    if (regs->TXCSRL & USB_TXCSRL1_STALLED) {
+      regs->TXCSRL &= ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_UNDRN);
+      return;
+    }
+    completed = handle_xfer_in(ep_addr);
+  } else {
+    // TU_LOG1(" RXCSRL%d = %x\n", epn_minus1 + 1, regs->RXCSRL);
+    if (regs->RXCSRL & USB_RXCSRL1_STALLED) {
+      regs->RXCSRL &= ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_OVER);
+      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;
+
+  USB0->TXIE = 1; /* Enable only EP0 */
+  USB0->RXIE = 0; 
+
+  /* Clear FIFO settings */
+  for (unsigned i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+    USB0->EPIDX     = i;
+    USB0->TXFIFOSZ  = 0;
+    USB0->TXFIFOADD = 0;
+    USB0->RXFIFOSZ  = 0;
+    USB0->RXFIFOADD = 0;
+  }
+  dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+/*------------------------------------------------------------------
+ * Device API
+ *------------------------------------------------------------------*/
+
+void dcd_init(uint8_t rhport)
+{
+  (void)rhport;
+  USB0->IE |= USB_IE_SUSPND;
+  NVIC_ClearPendingIRQ(USB0_IRQn);
+
+  dcd_connect(rhport);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void)rhport;
+  NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void)rhport;
+  NVIC_DisableIRQ(USB0_IRQn);
+}
+
+// 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. */
+  USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND;
+}
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void)rhport;
+  USB0->POWER |= USB_POWER_RESUME;
+
+  unsigned cnt = SystemCoreClock / 1000;
+  while (cnt--) __NOP();
+
+  USB0->POWER &= ~USB_POWER_RESUME;
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+  (void)rhport;
+  USB0->POWER |= USB_POWER_SOFTCONN;
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+  (void)rhport;
+  USB0->POWER &= ~USB_POWER_SOFTCONN;
+}
+
+//--------------------------------------------------------------------+
+// 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;
+
+  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 < DCD_ATTR_ENDPOINT_MAX);
+
+  pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
+  pipe->buf       = NULL;
+  pipe->length    = 0;
+  pipe->remaining = 0;
+
+  volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+  if (dir_in) {
+    regs->TXMAXP = mps;
+    regs->TXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_TXCSRH1_ISO : 0;
+    if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+      regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+    else
+      regs->TXCSRL = USB_TXCSRL1_CLRDT;
+    USB0->TXIE |= TU_BIT(epn);
+  } else {
+    regs->RXMAXP = mps;
+    regs->RXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_RXCSRH1_ISO : 0;
+    if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+      regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+    else
+      regs->RXCSRL = USB_RXCSRL1_CLRDT;
+    USB0->RXIE |= TU_BIT(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);
+
+  USB0->EPIDX = epn;
+  if (dir_in) {
+    USB0->TXFIFOADD = addr;
+    USB0->TXFIFOSZ  = size_in_log2_minus3;
+  } else {
+    USB0->RXFIFOADD = addr;
+    USB0->RXFIFOSZ  = size_in_log2_minus3;
+  }
+
+  return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+  (void) rhport;
+  volatile hw_endpoint_t *regs = (volatile hw_endpoint_t *)(uintptr_t)&USB0->TXMAXP1;
+  unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  USB0->TXIE = 1; /* Enable only EP0 */
+  USB0->RXIE = 0; 
+  for (unsigned i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+    regs->TXMAXP = 0;
+    regs->TXCSRH = 0;
+    if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+      regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+    else
+      regs->TXCSRL = USB_TXCSRL1_CLRDT;
+
+    regs->RXMAXP = 0;
+    regs->RXCSRH = 0;
+    if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+      regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+    else
+      regs->RXCSRL = USB_RXCSRL1_CLRDT;
+
+    USB0->EPIDX     = i;
+    USB0->TXFIFOSZ  = 0;
+    USB0->TXFIFOADD = 0;
+    USB0->RXFIFOSZ  = 0;
+    USB0->RXFIFOADD = 0;
+  }
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+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);
+
+  hw_endpoint_t volatile *regs = edpt_regs(epn - 1);
+  unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  if (dir_in) {
+    USB0->TXIE  &= ~TU_BIT(epn);
+    regs->TXMAXP = 0;
+    regs->TXCSRH = 0;
+    if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
+      regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
+    else
+      regs->TXCSRL = USB_TXCSRL1_CLRDT;
+
+    USB0->EPIDX     = epn;
+    USB0->TXFIFOSZ  = 0;
+    USB0->TXFIFOADD = 0;
+  } else {
+    USB0->RXIE  &= ~TU_BIT(epn);
+    regs->RXMAXP = 0;
+    regs->RXCSRH = 0;
+    if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
+      regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
+    else
+      regs->RXCSRL = USB_RXCSRL1_CLRDT;
+
+    USB0->EPIDX     = epn;
+    USB0->RXFIFOSZ  = 0;
+    USB0->RXFIFOADD = 0;
+  }
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+// 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);
+  unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  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);
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+  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);
+  unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  _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);
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+  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);
+  unsigned const ie  = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  if (0 == epn) {
+    if (!ep_addr) { /* Ignore EP80 */
+      _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+      _dcd.pipe0.buf = NULL;
+      USB0->CSRL0 = USB_CSRL0_STALL;
+    }
+  } else {
+    volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+    if (tu_edpt_dir(ep_addr)) { /* IN */
+      regs->TXCSRL = USB_TXCSRL1_STALL;
+    } else { /* OUT */
+      TU_ASSERT(!(regs->RXCSRL & USB_RXCSRL1_RXRDY),);
+      regs->RXCSRL = USB_RXCSRL1_STALL;
+    }
+  }
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+// 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);
+  hw_endpoint_t volatile *regs = edpt_regs(epn - 1);
+  unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  if (tu_edpt_dir(ep_addr)) { /* IN */
+    regs->TXCSRL = USB_TXCSRL1_CLRDT;
+  } else { /* OUT */
+    regs->RXCSRL = USB_RXCSRL1_CLRDT; 
+  }
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+/*-------------------------------------------------------------------
+ * ISR
+ *-------------------------------------------------------------------*/
+void dcd_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_DISCON) {
+  }
+  if (is & USB_IS_SOF) {
+    dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+  }
+  if (is & USB_IS_RESET) {
+    process_bus_reset(rhport);
+  }
+  if (is & USB_IS_RESUME) {
+    dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+  }
+  if (is & USB_IS_SUSPEND) {
+    dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+  }
+
+  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_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN));
+    txis &= ~TU_BIT(num);
+  }
+  rxis &= USB0->RXIE; /* Clear disabled interrupts */
+  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/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c
new file mode 100644
index 0000000..acccb76
--- /dev/null
+++ b/src/portable/mentor/musb/hcd_musb.c
@@ -0,0 +1,876 @@
+/* 
+ * 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 TUSB_OPT_HOST_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;
+}
+
+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/mentor/musb/musb_msp432e.h b/src/portable/mentor/musb/musb_msp432e.h
new file mode 100644
index 0000000..fce21de
--- /dev/null
+++ b/src/portable/mentor/musb/musb_msp432e.h
@@ -0,0 +1,40 @@
+/*
+ * 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_MUSB_MSP432E_H_
+#define _TUSB_MUSB_MSP432E_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "msp.h"
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/mentor/musb/musb_tm4c.h b/src/portable/mentor/musb/musb_tm4c.h
new file mode 100644
index 0000000..65a1751
--- /dev/null
+++ b/src/portable/mentor/musb/musb_tm4c.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 _TUSB_MUSB_TM4C_H_
+#define _TUSB_MUSB_TM4C_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_TM4C123
+  #include "TM4C123.h"
+//#elif CFG_TUSB_MCU == OPT_MCU_TM4C129
+#else
+  #error "Unsupported MCUs"
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h
new file mode 100644
index 0000000..8f83305
--- /dev/null
+++ b/src/portable/mentor/musb/musb_type.h
@@ -0,0 +1,2624 @@
+/******************************************************************************
+*
+* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+*  Redistributions of source code must retain the above copyright
+*  notice, this list of conditions and the following disclaimer.
+*
+*  Redistributions in binary form must reproduce the above copyright
+*  notice, this list of conditions and the following disclaimer in the
+*  documentation and/or other materials provided with the
+*  distribution.
+*
+*  Neither the name of Texas Instruments Incorporated nor the names of
+*  its contributors may be used to endorse or promote products derived
+*  from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*******************************************************************************/
+
+#ifndef _TUSB_MUSB_TYPE_H_
+#define _TUSB_MUSB_TYPE_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FADDR register.
+//
+//*****************************************************************************
+#define USB_FADDR_M             0x0000007F  // Function Address
+#define USB_FADDR_S             0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_POWER register.
+//
+//*****************************************************************************
+#define USB_POWER_ISOUP         0x00000080  // Isochronous Update
+#define USB_POWER_SOFTCONN      0x00000040  // Soft Connect/Disconnect
+#define USB_POWER_HSENAB        0x00000020  // High Speed Enable
+#define USB_POWER_HSMODE        0x00000010  // High Speed Enable
+#define USB_POWER_RESET         0x00000008  // RESET Signaling
+#define USB_POWER_RESUME        0x00000004  // RESUME Signaling
+#define USB_POWER_SUSPEND       0x00000002  // SUSPEND Mode
+#define USB_POWER_PWRDNPHY      0x00000001  // Power Down PHY
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXIS register.
+//
+//*****************************************************************************
+#define USB_TXIS_EP7            0x00000080  // TX Endpoint 7 Interrupt
+#define USB_TXIS_EP6            0x00000040  // TX Endpoint 6 Interrupt
+#define USB_TXIS_EP5            0x00000020  // TX Endpoint 5 Interrupt
+#define USB_TXIS_EP4            0x00000010  // TX Endpoint 4 Interrupt
+#define USB_TXIS_EP3            0x00000008  // TX Endpoint 3 Interrupt
+#define USB_TXIS_EP2            0x00000004  // TX Endpoint 2 Interrupt
+#define USB_TXIS_EP1            0x00000002  // TX Endpoint 1 Interrupt
+#define USB_TXIS_EP0            0x00000001  // TX and RX Endpoint 0 Interrupt
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXIS register.
+//
+//*****************************************************************************
+#define USB_RXIS_EP7            0x00000080  // RX Endpoint 7 Interrupt
+#define USB_RXIS_EP6            0x00000040  // RX Endpoint 6 Interrupt
+#define USB_RXIS_EP5            0x00000020  // RX Endpoint 5 Interrupt
+#define USB_RXIS_EP4            0x00000010  // RX Endpoint 4 Interrupt
+#define USB_RXIS_EP3            0x00000008  // RX Endpoint 3 Interrupt
+#define USB_RXIS_EP2            0x00000004  // RX Endpoint 2 Interrupt
+#define USB_RXIS_EP1            0x00000002  // RX Endpoint 1 Interrupt
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXIE register.
+//
+//*****************************************************************************
+#define USB_TXIE_EP7            0x00000080  // TX Endpoint 7 Interrupt Enable
+#define USB_TXIE_EP6            0x00000040  // TX Endpoint 6 Interrupt Enable
+#define USB_TXIE_EP5            0x00000020  // TX Endpoint 5 Interrupt Enable
+#define USB_TXIE_EP4            0x00000010  // TX Endpoint 4 Interrupt Enable
+#define USB_TXIE_EP3            0x00000008  // TX Endpoint 3 Interrupt Enable
+#define USB_TXIE_EP2            0x00000004  // TX Endpoint 2 Interrupt Enable
+#define USB_TXIE_EP1            0x00000002  // TX Endpoint 1 Interrupt Enable
+#define USB_TXIE_EP0            0x00000001  // TX and RX Endpoint 0 Interrupt
+                                            // Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXIE register.
+//
+//*****************************************************************************
+#define USB_RXIE_EP7            0x00000080  // RX Endpoint 7 Interrupt Enable
+#define USB_RXIE_EP6            0x00000040  // RX Endpoint 6 Interrupt Enable
+#define USB_RXIE_EP5            0x00000020  // RX Endpoint 5 Interrupt Enable
+#define USB_RXIE_EP4            0x00000010  // RX Endpoint 4 Interrupt Enable
+#define USB_RXIE_EP3            0x00000008  // RX Endpoint 3 Interrupt Enable
+#define USB_RXIE_EP2            0x00000004  // RX Endpoint 2 Interrupt Enable
+#define USB_RXIE_EP1            0x00000002  // RX Endpoint 1 Interrupt Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_IS register.
+//
+//*****************************************************************************
+#define USB_IS_VBUSERR          0x00000080  // VBUS Error (OTG only)
+#define USB_IS_SESREQ           0x00000040  // SESSION REQUEST (OTG only)
+#define USB_IS_DISCON           0x00000020  // Session Disconnect (OTG only)
+#define USB_IS_CONN             0x00000010  // Session Connect
+#define USB_IS_SOF              0x00000008  // Start of Frame
+#define USB_IS_BABBLE           0x00000004  // Babble Detected
+#define USB_IS_RESET            0x00000004  // RESET Signaling Detected
+#define USB_IS_RESUME           0x00000002  // RESUME Signaling Detected
+#define USB_IS_SUSPEND          0x00000001  // SUSPEND Signaling Detected
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_IE register.
+//
+//*****************************************************************************
+#define USB_IE_VBUSERR          0x00000080  // Enable VBUS Error Interrupt (OTG
+                                            // only)
+#define USB_IE_SESREQ           0x00000040  // Enable Session Request (OTG
+                                            // only)
+#define USB_IE_DISCON           0x00000020  // Enable Disconnect Interrupt
+#define USB_IE_CONN             0x00000010  // Enable Connect Interrupt
+#define USB_IE_SOF              0x00000008  // Enable Start-of-Frame Interrupt
+#define USB_IE_BABBLE           0x00000004  // Enable Babble Interrupt
+#define USB_IE_RESET            0x00000004  // Enable RESET Interrupt
+#define USB_IE_RESUME           0x00000002  // Enable RESUME Interrupt
+#define USB_IE_SUSPND           0x00000001  // Enable SUSPEND Interrupt
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FRAME register.
+//
+//*****************************************************************************
+#define USB_FRAME_M             0x000007FF  // Frame Number
+#define USB_FRAME_S             0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPIDX register.
+//
+//*****************************************************************************
+#define USB_EPIDX_EPIDX_M       0x0000000F  // Endpoint Index
+#define USB_EPIDX_EPIDX_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TEST register.
+//
+//*****************************************************************************
+#define USB_TEST_FORCEH         0x00000080  // Force Host Mode
+#define USB_TEST_FIFOACC        0x00000040  // FIFO Access
+#define USB_TEST_FORCEFS        0x00000020  // Force Full-Speed Mode
+#define USB_TEST_FORCEHS        0x00000010  // Force High-Speed Mode
+#define USB_TEST_TESTPKT        0x00000008  // Test Packet Mode Enable
+#define USB_TEST_TESTK          0x00000004  // Test_K Mode Enable
+#define USB_TEST_TESTJ          0x00000002  // Test_J Mode Enable
+#define USB_TEST_TESTSE0NAK     0x00000001  // Test_SE0_NAK Test Mode Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO0 register.
+//
+//*****************************************************************************
+#define USB_FIFO0_EPDATA_M      0xFFFFFFFF  // Endpoint Data
+#define USB_FIFO0_EPDATA_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO1 register.
+//
+//*****************************************************************************
+#define USB_FIFO1_EPDATA_M      0xFFFFFFFF  // Endpoint Data
+#define USB_FIFO1_EPDATA_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO2 register.
+//
+//*****************************************************************************
+#define USB_FIFO2_EPDATA_M      0xFFFFFFFF  // Endpoint Data
+#define USB_FIFO2_EPDATA_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO3 register.
+//
+//*****************************************************************************
+#define USB_FIFO3_EPDATA_M      0xFFFFFFFF  // Endpoint Data
+#define USB_FIFO3_EPDATA_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO4 register.
+//
+//*****************************************************************************
+#define USB_FIFO4_EPDATA_M      0xFFFFFFFF  // Endpoint Data
+#define USB_FIFO4_EPDATA_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO5 register.
+//
+//*****************************************************************************
+#define USB_FIFO5_EPDATA_M      0xFFFFFFFF  // Endpoint Data
+#define USB_FIFO5_EPDATA_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO6 register.
+//
+//*****************************************************************************
+#define USB_FIFO6_EPDATA_M      0xFFFFFFFF  // Endpoint Data
+#define USB_FIFO6_EPDATA_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FIFO7 register.
+//
+//*****************************************************************************
+#define USB_FIFO7_EPDATA_M      0xFFFFFFFF  // Endpoint Data
+#define USB_FIFO7_EPDATA_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DEVCTL register.
+//
+//*****************************************************************************
+#define USB_DEVCTL_DEV          0x00000080  // Device Mode (OTG only)
+#define USB_DEVCTL_FSDEV        0x00000040  // Full-Speed Device Detected
+#define USB_DEVCTL_LSDEV        0x00000020  // Low-Speed Device Detected
+#define USB_DEVCTL_VBUS_M       0x00000018  // VBUS Level (OTG only)
+#define USB_DEVCTL_VBUS_NONE    0x00000000  // Below SessionEnd
+#define USB_DEVCTL_VBUS_SEND    0x00000008  // Above SessionEnd, below AValid
+#define USB_DEVCTL_VBUS_AVALID  0x00000010  // Above AValid, below VBUSValid
+#define USB_DEVCTL_VBUS_VALID   0x00000018  // Above VBUSValid
+#define USB_DEVCTL_HOST         0x00000004  // Host Mode
+#define USB_DEVCTL_HOSTREQ      0x00000002  // Host Request (OTG only)
+#define USB_DEVCTL_SESSION      0x00000001  // Session Start/End (OTG only)
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CCONF register.
+//
+//*****************************************************************************
+#define USB_CCONF_TXEDMA        0x00000002  // TX Early DMA Enable
+#define USB_CCONF_RXEDMA        0x00000001  // TX Early DMA Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFIFOSZ register.
+//
+//*****************************************************************************
+#define USB_TXFIFOSZ_DPB        0x00000010  // Double Packet Buffer Support
+#define USB_TXFIFOSZ_SIZE_M     0x0000000F  // Max Packet Size
+#define USB_TXFIFOSZ_SIZE_8     0x00000000  // 8
+#define USB_TXFIFOSZ_SIZE_16    0x00000001  // 16
+#define USB_TXFIFOSZ_SIZE_32    0x00000002  // 32
+#define USB_TXFIFOSZ_SIZE_64    0x00000003  // 64
+#define USB_TXFIFOSZ_SIZE_128   0x00000004  // 128
+#define USB_TXFIFOSZ_SIZE_256   0x00000005  // 256
+#define USB_TXFIFOSZ_SIZE_512   0x00000006  // 512
+#define USB_TXFIFOSZ_SIZE_1024  0x00000007  // 1024
+#define USB_TXFIFOSZ_SIZE_2048  0x00000008  // 2048
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFIFOSZ register.
+//
+//*****************************************************************************
+#define USB_RXFIFOSZ_DPB        0x00000010  // Double Packet Buffer Support
+#define USB_RXFIFOSZ_SIZE_M     0x0000000F  // Max Packet Size
+#define USB_RXFIFOSZ_SIZE_8     0x00000000  // 8
+#define USB_RXFIFOSZ_SIZE_16    0x00000001  // 16
+#define USB_RXFIFOSZ_SIZE_32    0x00000002  // 32
+#define USB_RXFIFOSZ_SIZE_64    0x00000003  // 64
+#define USB_RXFIFOSZ_SIZE_128   0x00000004  // 128
+#define USB_RXFIFOSZ_SIZE_256   0x00000005  // 256
+#define USB_RXFIFOSZ_SIZE_512   0x00000006  // 512
+#define USB_RXFIFOSZ_SIZE_1024  0x00000007  // 1024
+#define USB_RXFIFOSZ_SIZE_2048  0x00000008  // 2048
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFIFOADD
+// register.
+//
+//*****************************************************************************
+#define USB_TXFIFOADD_ADDR_M    0x000001FF  // Transmit/Receive Start Address
+#define USB_TXFIFOADD_ADDR_S    0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFIFOADD
+// register.
+//
+//*****************************************************************************
+#define USB_RXFIFOADD_ADDR_M    0x000001FF  // Transmit/Receive Start Address
+#define USB_RXFIFOADD_ADDR_S    0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_ULPIVBUSCTL
+// register.
+//
+//*****************************************************************************
+#define USB_ULPIVBUSCTL_USEEXTVBUSIND                                         \
+                                0x00000002  // Use External VBUS Indicator
+#define USB_ULPIVBUSCTL_USEEXTVBUS                                            \
+                                0x00000001  // Use External VBUS
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_ULPIREGDATA
+// register.
+//
+//*****************************************************************************
+#define USB_ULPIREGDATA_REGDATA_M                                             \
+                                0x000000FF  // Register Data
+#define USB_ULPIREGDATA_REGDATA_S                                             \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_ULPIREGADDR
+// register.
+//
+//*****************************************************************************
+#define USB_ULPIREGADDR_ADDR_M  0x000000FF  // Register Address
+#define USB_ULPIREGADDR_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_ULPIREGCTL
+// register.
+//
+//*****************************************************************************
+#define USB_ULPIREGCTL_RDWR     0x00000004  // Read/Write Control
+#define USB_ULPIREGCTL_REGCMPLT 0x00000002  // Register Access Complete
+#define USB_ULPIREGCTL_REGACC   0x00000001  // Initiate Register Access
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPINFO register.
+//
+//*****************************************************************************
+#define USB_EPINFO_RXEP_M       0x000000F0  // RX Endpoints
+#define USB_EPINFO_TXEP_M       0x0000000F  // TX Endpoints
+#define USB_EPINFO_RXEP_S       4
+#define USB_EPINFO_TXEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RAMINFO register.
+//
+//*****************************************************************************
+#define USB_RAMINFO_DMACHAN_M   0x000000F0  // DMA Channels
+#define USB_RAMINFO_RAMBITS_M   0x0000000F  // RAM Address Bus Width
+#define USB_RAMINFO_DMACHAN_S   4
+#define USB_RAMINFO_RAMBITS_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CONTIM register.
+//
+//*****************************************************************************
+#define USB_CONTIM_WTCON_M      0x000000F0  // Connect Wait
+#define USB_CONTIM_WTID_M       0x0000000F  // Wait ID
+#define USB_CONTIM_WTCON_S      4
+#define USB_CONTIM_WTID_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VPLEN register.
+//
+//*****************************************************************************
+#define USB_VPLEN_VPLEN_M       0x000000FF  // VBUS Pulse Length
+#define USB_VPLEN_VPLEN_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_HSEOF register.
+//
+//*****************************************************************************
+#define USB_HSEOF_HSEOFG_M      0x000000FF  // HIgh-Speed End-of-Frame Gap
+#define USB_HSEOF_HSEOFG_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_FSEOF register.
+//
+//*****************************************************************************
+#define USB_FSEOF_FSEOFG_M      0x000000FF  // Full-Speed End-of-Frame Gap
+#define USB_FSEOF_FSEOFG_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LSEOF register.
+//
+//*****************************************************************************
+#define USB_LSEOF_LSEOFG_M      0x000000FF  // Low-Speed End-of-Frame Gap
+#define USB_LSEOF_LSEOFG_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR0
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR0_ADDR_M  0x0000007F  // Device Address
+#define USB_TXFUNCADDR0_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR0
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR0_ADDR_M   0x0000007F  // Hub Address
+#define USB_TXHUBADDR0_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT0
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT0_PORT_M   0x0000007F  // Hub Port
+#define USB_TXHUBPORT0_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR1
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR1_ADDR_M  0x0000007F  // Device Address
+#define USB_TXFUNCADDR1_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR1
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR1_ADDR_M   0x0000007F  // Hub Address
+#define USB_TXHUBADDR1_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT1
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT1_PORT_M   0x0000007F  // Hub Port
+#define USB_TXHUBPORT1_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR1
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR1_ADDR_M  0x0000007F  // Device Address
+#define USB_RXFUNCADDR1_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR1
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR1_ADDR_M   0x0000007F  // Hub Address
+#define USB_RXHUBADDR1_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT1
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT1_PORT_M   0x0000007F  // Hub Port
+#define USB_RXHUBPORT1_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR2
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR2_ADDR_M  0x0000007F  // Device Address
+#define USB_TXFUNCADDR2_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR2
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR2_ADDR_M   0x0000007F  // Hub Address
+#define USB_TXHUBADDR2_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT2
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT2_PORT_M   0x0000007F  // Hub Port
+#define USB_TXHUBPORT2_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR2
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR2_ADDR_M  0x0000007F  // Device Address
+#define USB_RXFUNCADDR2_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR2
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR2_ADDR_M   0x0000007F  // Hub Address
+#define USB_RXHUBADDR2_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT2
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT2_PORT_M   0x0000007F  // Hub Port
+#define USB_RXHUBPORT2_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR3
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR3_ADDR_M  0x0000007F  // Device Address
+#define USB_TXFUNCADDR3_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR3
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR3_ADDR_M   0x0000007F  // Hub Address
+#define USB_TXHUBADDR3_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT3
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT3_PORT_M   0x0000007F  // Hub Port
+#define USB_TXHUBPORT3_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR3
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR3_ADDR_M  0x0000007F  // Device Address
+#define USB_RXFUNCADDR3_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR3
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR3_ADDR_M   0x0000007F  // Hub Address
+#define USB_RXHUBADDR3_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT3
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT3_PORT_M   0x0000007F  // Hub Port
+#define USB_RXHUBPORT3_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR4
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR4_ADDR_M  0x0000007F  // Device Address
+#define USB_TXFUNCADDR4_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR4
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR4_ADDR_M   0x0000007F  // Hub Address
+#define USB_TXHUBADDR4_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT4
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT4_PORT_M   0x0000007F  // Hub Port
+#define USB_TXHUBPORT4_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR4
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR4_ADDR_M  0x0000007F  // Device Address
+#define USB_RXFUNCADDR4_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR4
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR4_ADDR_M   0x0000007F  // Hub Address
+#define USB_RXHUBADDR4_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT4
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT4_PORT_M   0x0000007F  // Hub Port
+#define USB_RXHUBPORT4_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR5
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR5_ADDR_M  0x0000007F  // Device Address
+#define USB_TXFUNCADDR5_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR5
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR5_ADDR_M   0x0000007F  // Hub Address
+#define USB_TXHUBADDR5_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT5
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT5_PORT_M   0x0000007F  // Hub Port
+#define USB_TXHUBPORT5_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR5
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR5_ADDR_M  0x0000007F  // Device Address
+#define USB_RXFUNCADDR5_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR5
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR5_ADDR_M   0x0000007F  // Hub Address
+#define USB_RXHUBADDR5_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT5
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT5_PORT_M   0x0000007F  // Hub Port
+#define USB_RXHUBPORT5_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR6
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR6_ADDR_M  0x0000007F  // Device Address
+#define USB_TXFUNCADDR6_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR6
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR6_ADDR_M   0x0000007F  // Hub Address
+#define USB_TXHUBADDR6_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT6
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT6_PORT_M   0x0000007F  // Hub Port
+#define USB_TXHUBPORT6_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR6
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR6_ADDR_M  0x0000007F  // Device Address
+#define USB_RXFUNCADDR6_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR6
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR6_ADDR_M   0x0000007F  // Hub Address
+#define USB_RXHUBADDR6_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT6
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT6_PORT_M   0x0000007F  // Hub Port
+#define USB_RXHUBPORT6_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXFUNCADDR7
+// register.
+//
+//*****************************************************************************
+#define USB_TXFUNCADDR7_ADDR_M  0x0000007F  // Device Address
+#define USB_TXFUNCADDR7_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBADDR7
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBADDR7_ADDR_M   0x0000007F  // Hub Address
+#define USB_TXHUBADDR7_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXHUBPORT7
+// register.
+//
+//*****************************************************************************
+#define USB_TXHUBPORT7_PORT_M   0x0000007F  // Hub Port
+#define USB_TXHUBPORT7_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXFUNCADDR7
+// register.
+//
+//*****************************************************************************
+#define USB_RXFUNCADDR7_ADDR_M  0x0000007F  // Device Address
+#define USB_RXFUNCADDR7_ADDR_S  0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBADDR7
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBADDR7_ADDR_M   0x0000007F  // Hub Address
+#define USB_RXHUBADDR7_ADDR_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXHUBPORT7
+// register.
+//
+//*****************************************************************************
+#define USB_RXHUBPORT7_PORT_M   0x0000007F  // Hub Port
+#define USB_RXHUBPORT7_PORT_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CSRL0 register.
+//
+//*****************************************************************************
+#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
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CSRH0 register.
+//
+//*****************************************************************************
+#define USB_CSRH0_DISPING       0x00000008  // PING Disable
+#define USB_CSRH0_DTWE          0x00000004  // Data Toggle Write Enable
+#define USB_CSRH0_DT            0x00000002  // Data Toggle
+#define USB_CSRH0_FLUSH         0x00000001  // Flush FIFO
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_COUNT0 register.
+//
+//*****************************************************************************
+#define USB_COUNT0_COUNT_M      0x0000007F  // FIFO Count
+#define USB_COUNT0_COUNT_S      0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TYPE0 register.
+//
+//*****************************************************************************
+#define USB_TYPE0_SPEED_M       0x000000C0  // Operating Speed
+#define USB_TYPE0_SPEED_HIGH    0x00000040  // High
+#define USB_TYPE0_SPEED_FULL    0x00000080  // Full
+#define USB_TYPE0_SPEED_LOW     0x000000C0  // Low
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_NAKLMT register.
+//
+//*****************************************************************************
+#define USB_NAKLMT_NAKLMT_M     0x0000001F  // EP0 NAK Limit
+#define USB_NAKLMT_NAKLMT_S     0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP1 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP1_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_TXMAXP1_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL1 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL1_NAKTO       0x00000080  // NAK Timeout
+#define USB_TXCSRL1_CLRDT       0x00000040  // Clear Data Toggle
+#define USB_TXCSRL1_STALLED     0x00000020  // Endpoint Stalled
+#define USB_TXCSRL1_STALL       0x00000010  // Send STALL
+#define USB_TXCSRL1_SETUP       0x00000010  // Setup Packet
+#define USB_TXCSRL1_FLUSH       0x00000008  // Flush FIFO
+#define USB_TXCSRL1_ERROR       0x00000004  // Error
+#define USB_TXCSRL1_UNDRN       0x00000004  // Underrun
+#define USB_TXCSRL1_FIFONE      0x00000002  // FIFO Not Empty
+#define USB_TXCSRL1_TXRDY       0x00000001  // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH1 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH1_AUTOSET     0x00000080  // Auto Set
+#define USB_TXCSRH1_ISO         0x00000040  // Isochronous Transfers
+#define USB_TXCSRH1_MODE        0x00000020  // Mode
+#define USB_TXCSRH1_DMAEN       0x00000010  // DMA Request Enable
+#define USB_TXCSRH1_FDT         0x00000008  // Force Data Toggle
+#define USB_TXCSRH1_DMAMOD      0x00000004  // DMA Request Mode
+#define USB_TXCSRH1_DTWE        0x00000002  // Data Toggle Write Enable
+#define USB_TXCSRH1_DT          0x00000001  // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP1 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP1_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_RXMAXP1_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL1 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL1_CLRDT       0x00000080  // Clear Data Toggle
+#define USB_RXCSRL1_STALLED     0x00000040  // Endpoint Stalled
+#define USB_RXCSRL1_STALL       0x00000020  // Send STALL
+#define USB_RXCSRL1_REQPKT      0x00000020  // Request Packet
+#define USB_RXCSRL1_FLUSH       0x00000010  // Flush FIFO
+#define USB_RXCSRL1_DATAERR     0x00000008  // Data Error
+#define USB_RXCSRL1_NAKTO       0x00000008  // NAK Timeout
+#define USB_RXCSRL1_OVER        0x00000004  // Overrun
+#define USB_RXCSRL1_ERROR       0x00000004  // Error
+#define USB_RXCSRL1_FULL        0x00000002  // FIFO Full
+#define USB_RXCSRL1_RXRDY       0x00000001  // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH1 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH1_AUTOCL      0x00000080  // Auto Clear
+#define USB_RXCSRH1_AUTORQ      0x00000040  // Auto Request
+#define USB_RXCSRH1_ISO         0x00000040  // Isochronous Transfers
+#define USB_RXCSRH1_DMAEN       0x00000020  // DMA Request Enable
+#define USB_RXCSRH1_DISNYET     0x00000010  // Disable NYET
+#define USB_RXCSRH1_PIDERR      0x00000010  // PID Error
+#define USB_RXCSRH1_DMAMOD      0x00000008  // DMA Request Mode
+#define USB_RXCSRH1_DTWE        0x00000004  // Data Toggle Write Enable
+#define USB_RXCSRH1_DT          0x00000002  // Data Toggle
+#define USB_RXCSRH1_INCOMPRX    0x00000001  // Incomplete RX Transmission
+                                            // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT1 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT1_COUNT_M    0x00001FFF  // Receive Packet Count
+#define USB_RXCOUNT1_COUNT_S    0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE1 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE1_SPEED_M     0x000000C0  // Operating Speed
+#define USB_TXTYPE1_SPEED_DFLT  0x00000000  // Default
+#define USB_TXTYPE1_SPEED_HIGH  0x00000040  // High
+#define USB_TXTYPE1_SPEED_FULL  0x00000080  // Full
+#define USB_TXTYPE1_SPEED_LOW   0x000000C0  // Low
+#define USB_TXTYPE1_PROTO_M     0x00000030  // Protocol
+#define USB_TXTYPE1_PROTO_CTRL  0x00000000  // Control
+#define USB_TXTYPE1_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_TXTYPE1_PROTO_BULK  0x00000020  // Bulk
+#define USB_TXTYPE1_PROTO_INT   0x00000030  // Interrupt
+#define USB_TXTYPE1_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_TXTYPE1_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL1
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL1_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_TXINTERVAL1_TXPOLL_M                                              \
+                                0x000000FF  // TX Polling
+#define USB_TXINTERVAL1_TXPOLL_S                                              \
+                                0
+#define USB_TXINTERVAL1_NAKLMT_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE1 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE1_SPEED_M     0x000000C0  // Operating Speed
+#define USB_RXTYPE1_SPEED_DFLT  0x00000000  // Default
+#define USB_RXTYPE1_SPEED_HIGH  0x00000040  // High
+#define USB_RXTYPE1_SPEED_FULL  0x00000080  // Full
+#define USB_RXTYPE1_SPEED_LOW   0x000000C0  // Low
+#define USB_RXTYPE1_PROTO_M     0x00000030  // Protocol
+#define USB_RXTYPE1_PROTO_CTRL  0x00000000  // Control
+#define USB_RXTYPE1_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_RXTYPE1_PROTO_BULK  0x00000020  // Bulk
+#define USB_RXTYPE1_PROTO_INT   0x00000030  // Interrupt
+#define USB_RXTYPE1_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_RXTYPE1_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL1
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL1_TXPOLL_M                                              \
+                                0x000000FF  // RX Polling
+#define USB_RXINTERVAL1_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_RXINTERVAL1_TXPOLL_S                                              \
+                                0
+#define USB_RXINTERVAL1_NAKLMT_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP2 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP2_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_TXMAXP2_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL2 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL2_NAKTO       0x00000080  // NAK Timeout
+#define USB_TXCSRL2_CLRDT       0x00000040  // Clear Data Toggle
+#define USB_TXCSRL2_STALLED     0x00000020  // Endpoint Stalled
+#define USB_TXCSRL2_SETUP       0x00000010  // Setup Packet
+#define USB_TXCSRL2_STALL       0x00000010  // Send STALL
+#define USB_TXCSRL2_FLUSH       0x00000008  // Flush FIFO
+#define USB_TXCSRL2_ERROR       0x00000004  // Error
+#define USB_TXCSRL2_UNDRN       0x00000004  // Underrun
+#define USB_TXCSRL2_FIFONE      0x00000002  // FIFO Not Empty
+#define USB_TXCSRL2_TXRDY       0x00000001  // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH2 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH2_AUTOSET     0x00000080  // Auto Set
+#define USB_TXCSRH2_ISO         0x00000040  // Isochronous Transfers
+#define USB_TXCSRH2_MODE        0x00000020  // Mode
+#define USB_TXCSRH2_DMAEN       0x00000010  // DMA Request Enable
+#define USB_TXCSRH2_FDT         0x00000008  // Force Data Toggle
+#define USB_TXCSRH2_DMAMOD      0x00000004  // DMA Request Mode
+#define USB_TXCSRH2_DTWE        0x00000002  // Data Toggle Write Enable
+#define USB_TXCSRH2_DT          0x00000001  // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP2 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP2_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_RXMAXP2_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL2 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL2_CLRDT       0x00000080  // Clear Data Toggle
+#define USB_RXCSRL2_STALLED     0x00000040  // Endpoint Stalled
+#define USB_RXCSRL2_REQPKT      0x00000020  // Request Packet
+#define USB_RXCSRL2_STALL       0x00000020  // Send STALL
+#define USB_RXCSRL2_FLUSH       0x00000010  // Flush FIFO
+#define USB_RXCSRL2_DATAERR     0x00000008  // Data Error
+#define USB_RXCSRL2_NAKTO       0x00000008  // NAK Timeout
+#define USB_RXCSRL2_ERROR       0x00000004  // Error
+#define USB_RXCSRL2_OVER        0x00000004  // Overrun
+#define USB_RXCSRL2_FULL        0x00000002  // FIFO Full
+#define USB_RXCSRL2_RXRDY       0x00000001  // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH2 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH2_AUTOCL      0x00000080  // Auto Clear
+#define USB_RXCSRH2_AUTORQ      0x00000040  // Auto Request
+#define USB_RXCSRH2_ISO         0x00000040  // Isochronous Transfers
+#define USB_RXCSRH2_DMAEN       0x00000020  // DMA Request Enable
+#define USB_RXCSRH2_DISNYET     0x00000010  // Disable NYET
+#define USB_RXCSRH2_PIDERR      0x00000010  // PID Error
+#define USB_RXCSRH2_DMAMOD      0x00000008  // DMA Request Mode
+#define USB_RXCSRH2_DTWE        0x00000004  // Data Toggle Write Enable
+#define USB_RXCSRH2_DT          0x00000002  // Data Toggle
+#define USB_RXCSRH2_INCOMPRX    0x00000001  // Incomplete RX Transmission
+                                            // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT2 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT2_COUNT_M    0x00001FFF  // Receive Packet Count
+#define USB_RXCOUNT2_COUNT_S    0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE2 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE2_SPEED_M     0x000000C0  // Operating Speed
+#define USB_TXTYPE2_SPEED_DFLT  0x00000000  // Default
+#define USB_TXTYPE2_SPEED_HIGH  0x00000040  // High
+#define USB_TXTYPE2_SPEED_FULL  0x00000080  // Full
+#define USB_TXTYPE2_SPEED_LOW   0x000000C0  // Low
+#define USB_TXTYPE2_PROTO_M     0x00000030  // Protocol
+#define USB_TXTYPE2_PROTO_CTRL  0x00000000  // Control
+#define USB_TXTYPE2_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_TXTYPE2_PROTO_BULK  0x00000020  // Bulk
+#define USB_TXTYPE2_PROTO_INT   0x00000030  // Interrupt
+#define USB_TXTYPE2_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_TXTYPE2_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL2
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL2_TXPOLL_M                                              \
+                                0x000000FF  // TX Polling
+#define USB_TXINTERVAL2_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_TXINTERVAL2_NAKLMT_S                                              \
+                                0
+#define USB_TXINTERVAL2_TXPOLL_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE2 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE2_SPEED_M     0x000000C0  // Operating Speed
+#define USB_RXTYPE2_SPEED_DFLT  0x00000000  // Default
+#define USB_RXTYPE2_SPEED_HIGH  0x00000040  // High
+#define USB_RXTYPE2_SPEED_FULL  0x00000080  // Full
+#define USB_RXTYPE2_SPEED_LOW   0x000000C0  // Low
+#define USB_RXTYPE2_PROTO_M     0x00000030  // Protocol
+#define USB_RXTYPE2_PROTO_CTRL  0x00000000  // Control
+#define USB_RXTYPE2_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_RXTYPE2_PROTO_BULK  0x00000020  // Bulk
+#define USB_RXTYPE2_PROTO_INT   0x00000030  // Interrupt
+#define USB_RXTYPE2_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_RXTYPE2_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL2
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL2_TXPOLL_M                                              \
+                                0x000000FF  // RX Polling
+#define USB_RXINTERVAL2_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_RXINTERVAL2_TXPOLL_S                                              \
+                                0
+#define USB_RXINTERVAL2_NAKLMT_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP3 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP3_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_TXMAXP3_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL3 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL3_NAKTO       0x00000080  // NAK Timeout
+#define USB_TXCSRL3_CLRDT       0x00000040  // Clear Data Toggle
+#define USB_TXCSRL3_STALLED     0x00000020  // Endpoint Stalled
+#define USB_TXCSRL3_SETUP       0x00000010  // Setup Packet
+#define USB_TXCSRL3_STALL       0x00000010  // Send STALL
+#define USB_TXCSRL3_FLUSH       0x00000008  // Flush FIFO
+#define USB_TXCSRL3_ERROR       0x00000004  // Error
+#define USB_TXCSRL3_UNDRN       0x00000004  // Underrun
+#define USB_TXCSRL3_FIFONE      0x00000002  // FIFO Not Empty
+#define USB_TXCSRL3_TXRDY       0x00000001  // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH3 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH3_AUTOSET     0x00000080  // Auto Set
+#define USB_TXCSRH3_ISO         0x00000040  // Isochronous Transfers
+#define USB_TXCSRH3_MODE        0x00000020  // Mode
+#define USB_TXCSRH3_DMAEN       0x00000010  // DMA Request Enable
+#define USB_TXCSRH3_FDT         0x00000008  // Force Data Toggle
+#define USB_TXCSRH3_DMAMOD      0x00000004  // DMA Request Mode
+#define USB_TXCSRH3_DTWE        0x00000002  // Data Toggle Write Enable
+#define USB_TXCSRH3_DT          0x00000001  // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP3 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP3_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_RXMAXP3_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL3 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL3_CLRDT       0x00000080  // Clear Data Toggle
+#define USB_RXCSRL3_STALLED     0x00000040  // Endpoint Stalled
+#define USB_RXCSRL3_STALL       0x00000020  // Send STALL
+#define USB_RXCSRL3_REQPKT      0x00000020  // Request Packet
+#define USB_RXCSRL3_FLUSH       0x00000010  // Flush FIFO
+#define USB_RXCSRL3_DATAERR     0x00000008  // Data Error
+#define USB_RXCSRL3_NAKTO       0x00000008  // NAK Timeout
+#define USB_RXCSRL3_ERROR       0x00000004  // Error
+#define USB_RXCSRL3_OVER        0x00000004  // Overrun
+#define USB_RXCSRL3_FULL        0x00000002  // FIFO Full
+#define USB_RXCSRL3_RXRDY       0x00000001  // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH3 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH3_AUTOCL      0x00000080  // Auto Clear
+#define USB_RXCSRH3_AUTORQ      0x00000040  // Auto Request
+#define USB_RXCSRH3_ISO         0x00000040  // Isochronous Transfers
+#define USB_RXCSRH3_DMAEN       0x00000020  // DMA Request Enable
+#define USB_RXCSRH3_DISNYET     0x00000010  // Disable NYET
+#define USB_RXCSRH3_PIDERR      0x00000010  // PID Error
+#define USB_RXCSRH3_DMAMOD      0x00000008  // DMA Request Mode
+#define USB_RXCSRH3_DTWE        0x00000004  // Data Toggle Write Enable
+#define USB_RXCSRH3_DT          0x00000002  // Data Toggle
+#define USB_RXCSRH3_INCOMPRX    0x00000001  // Incomplete RX Transmission
+                                            // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT3 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT3_COUNT_M    0x00001FFF  // Receive Packet Count
+#define USB_RXCOUNT3_COUNT_S    0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE3 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE3_SPEED_M     0x000000C0  // Operating Speed
+#define USB_TXTYPE3_SPEED_DFLT  0x00000000  // Default
+#define USB_TXTYPE3_SPEED_HIGH  0x00000040  // High
+#define USB_TXTYPE3_SPEED_FULL  0x00000080  // Full
+#define USB_TXTYPE3_SPEED_LOW   0x000000C0  // Low
+#define USB_TXTYPE3_PROTO_M     0x00000030  // Protocol
+#define USB_TXTYPE3_PROTO_CTRL  0x00000000  // Control
+#define USB_TXTYPE3_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_TXTYPE3_PROTO_BULK  0x00000020  // Bulk
+#define USB_TXTYPE3_PROTO_INT   0x00000030  // Interrupt
+#define USB_TXTYPE3_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_TXTYPE3_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL3
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL3_TXPOLL_M                                              \
+                                0x000000FF  // TX Polling
+#define USB_TXINTERVAL3_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_TXINTERVAL3_TXPOLL_S                                              \
+                                0
+#define USB_TXINTERVAL3_NAKLMT_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE3 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE3_SPEED_M     0x000000C0  // Operating Speed
+#define USB_RXTYPE3_SPEED_DFLT  0x00000000  // Default
+#define USB_RXTYPE3_SPEED_HIGH  0x00000040  // High
+#define USB_RXTYPE3_SPEED_FULL  0x00000080  // Full
+#define USB_RXTYPE3_SPEED_LOW   0x000000C0  // Low
+#define USB_RXTYPE3_PROTO_M     0x00000030  // Protocol
+#define USB_RXTYPE3_PROTO_CTRL  0x00000000  // Control
+#define USB_RXTYPE3_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_RXTYPE3_PROTO_BULK  0x00000020  // Bulk
+#define USB_RXTYPE3_PROTO_INT   0x00000030  // Interrupt
+#define USB_RXTYPE3_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_RXTYPE3_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL3
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL3_TXPOLL_M                                              \
+                                0x000000FF  // RX Polling
+#define USB_RXINTERVAL3_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_RXINTERVAL3_TXPOLL_S                                              \
+                                0
+#define USB_RXINTERVAL3_NAKLMT_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP4 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP4_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_TXMAXP4_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL4 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL4_NAKTO       0x00000080  // NAK Timeout
+#define USB_TXCSRL4_CLRDT       0x00000040  // Clear Data Toggle
+#define USB_TXCSRL4_STALLED     0x00000020  // Endpoint Stalled
+#define USB_TXCSRL4_SETUP       0x00000010  // Setup Packet
+#define USB_TXCSRL4_STALL       0x00000010  // Send STALL
+#define USB_TXCSRL4_FLUSH       0x00000008  // Flush FIFO
+#define USB_TXCSRL4_ERROR       0x00000004  // Error
+#define USB_TXCSRL4_UNDRN       0x00000004  // Underrun
+#define USB_TXCSRL4_FIFONE      0x00000002  // FIFO Not Empty
+#define USB_TXCSRL4_TXRDY       0x00000001  // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH4 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH4_AUTOSET     0x00000080  // Auto Set
+#define USB_TXCSRH4_ISO         0x00000040  // Isochronous Transfers
+#define USB_TXCSRH4_MODE        0x00000020  // Mode
+#define USB_TXCSRH4_DMAEN       0x00000010  // DMA Request Enable
+#define USB_TXCSRH4_FDT         0x00000008  // Force Data Toggle
+#define USB_TXCSRH4_DMAMOD      0x00000004  // DMA Request Mode
+#define USB_TXCSRH4_DTWE        0x00000002  // Data Toggle Write Enable
+#define USB_TXCSRH4_DT          0x00000001  // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP4 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP4_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_RXMAXP4_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL4 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL4_CLRDT       0x00000080  // Clear Data Toggle
+#define USB_RXCSRL4_STALLED     0x00000040  // Endpoint Stalled
+#define USB_RXCSRL4_STALL       0x00000020  // Send STALL
+#define USB_RXCSRL4_REQPKT      0x00000020  // Request Packet
+#define USB_RXCSRL4_FLUSH       0x00000010  // Flush FIFO
+#define USB_RXCSRL4_NAKTO       0x00000008  // NAK Timeout
+#define USB_RXCSRL4_DATAERR     0x00000008  // Data Error
+#define USB_RXCSRL4_OVER        0x00000004  // Overrun
+#define USB_RXCSRL4_ERROR       0x00000004  // Error
+#define USB_RXCSRL4_FULL        0x00000002  // FIFO Full
+#define USB_RXCSRL4_RXRDY       0x00000001  // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH4 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH4_AUTOCL      0x00000080  // Auto Clear
+#define USB_RXCSRH4_AUTORQ      0x00000040  // Auto Request
+#define USB_RXCSRH4_ISO         0x00000040  // Isochronous Transfers
+#define USB_RXCSRH4_DMAEN       0x00000020  // DMA Request Enable
+#define USB_RXCSRH4_DISNYET     0x00000010  // Disable NYET
+#define USB_RXCSRH4_PIDERR      0x00000010  // PID Error
+#define USB_RXCSRH4_DMAMOD      0x00000008  // DMA Request Mode
+#define USB_RXCSRH4_DTWE        0x00000004  // Data Toggle Write Enable
+#define USB_RXCSRH4_DT          0x00000002  // Data Toggle
+#define USB_RXCSRH4_INCOMPRX    0x00000001  // Incomplete RX Transmission
+                                            // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT4 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT4_COUNT_M    0x00001FFF  // Receive Packet Count
+#define USB_RXCOUNT4_COUNT_S    0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE4 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE4_SPEED_M     0x000000C0  // Operating Speed
+#define USB_TXTYPE4_SPEED_DFLT  0x00000000  // Default
+#define USB_TXTYPE4_SPEED_HIGH  0x00000040  // High
+#define USB_TXTYPE4_SPEED_FULL  0x00000080  // Full
+#define USB_TXTYPE4_SPEED_LOW   0x000000C0  // Low
+#define USB_TXTYPE4_PROTO_M     0x00000030  // Protocol
+#define USB_TXTYPE4_PROTO_CTRL  0x00000000  // Control
+#define USB_TXTYPE4_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_TXTYPE4_PROTO_BULK  0x00000020  // Bulk
+#define USB_TXTYPE4_PROTO_INT   0x00000030  // Interrupt
+#define USB_TXTYPE4_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_TXTYPE4_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL4
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL4_TXPOLL_M                                              \
+                                0x000000FF  // TX Polling
+#define USB_TXINTERVAL4_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_TXINTERVAL4_NAKLMT_S                                              \
+                                0
+#define USB_TXINTERVAL4_TXPOLL_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE4 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE4_SPEED_M     0x000000C0  // Operating Speed
+#define USB_RXTYPE4_SPEED_DFLT  0x00000000  // Default
+#define USB_RXTYPE4_SPEED_HIGH  0x00000040  // High
+#define USB_RXTYPE4_SPEED_FULL  0x00000080  // Full
+#define USB_RXTYPE4_SPEED_LOW   0x000000C0  // Low
+#define USB_RXTYPE4_PROTO_M     0x00000030  // Protocol
+#define USB_RXTYPE4_PROTO_CTRL  0x00000000  // Control
+#define USB_RXTYPE4_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_RXTYPE4_PROTO_BULK  0x00000020  // Bulk
+#define USB_RXTYPE4_PROTO_INT   0x00000030  // Interrupt
+#define USB_RXTYPE4_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_RXTYPE4_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL4
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL4_TXPOLL_M                                              \
+                                0x000000FF  // RX Polling
+#define USB_RXINTERVAL4_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_RXINTERVAL4_NAKLMT_S                                              \
+                                0
+#define USB_RXINTERVAL4_TXPOLL_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP5 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP5_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_TXMAXP5_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL5 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL5_NAKTO       0x00000080  // NAK Timeout
+#define USB_TXCSRL5_CLRDT       0x00000040  // Clear Data Toggle
+#define USB_TXCSRL5_STALLED     0x00000020  // Endpoint Stalled
+#define USB_TXCSRL5_SETUP       0x00000010  // Setup Packet
+#define USB_TXCSRL5_STALL       0x00000010  // Send STALL
+#define USB_TXCSRL5_FLUSH       0x00000008  // Flush FIFO
+#define USB_TXCSRL5_ERROR       0x00000004  // Error
+#define USB_TXCSRL5_UNDRN       0x00000004  // Underrun
+#define USB_TXCSRL5_FIFONE      0x00000002  // FIFO Not Empty
+#define USB_TXCSRL5_TXRDY       0x00000001  // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH5 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH5_AUTOSET     0x00000080  // Auto Set
+#define USB_TXCSRH5_ISO         0x00000040  // Isochronous Transfers
+#define USB_TXCSRH5_MODE        0x00000020  // Mode
+#define USB_TXCSRH5_DMAEN       0x00000010  // DMA Request Enable
+#define USB_TXCSRH5_FDT         0x00000008  // Force Data Toggle
+#define USB_TXCSRH5_DMAMOD      0x00000004  // DMA Request Mode
+#define USB_TXCSRH5_DTWE        0x00000002  // Data Toggle Write Enable
+#define USB_TXCSRH5_DT          0x00000001  // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP5 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP5_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_RXMAXP5_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL5 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL5_CLRDT       0x00000080  // Clear Data Toggle
+#define USB_RXCSRL5_STALLED     0x00000040  // Endpoint Stalled
+#define USB_RXCSRL5_STALL       0x00000020  // Send STALL
+#define USB_RXCSRL5_REQPKT      0x00000020  // Request Packet
+#define USB_RXCSRL5_FLUSH       0x00000010  // Flush FIFO
+#define USB_RXCSRL5_NAKTO       0x00000008  // NAK Timeout
+#define USB_RXCSRL5_DATAERR     0x00000008  // Data Error
+#define USB_RXCSRL5_ERROR       0x00000004  // Error
+#define USB_RXCSRL5_OVER        0x00000004  // Overrun
+#define USB_RXCSRL5_FULL        0x00000002  // FIFO Full
+#define USB_RXCSRL5_RXRDY       0x00000001  // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH5 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH5_AUTOCL      0x00000080  // Auto Clear
+#define USB_RXCSRH5_AUTORQ      0x00000040  // Auto Request
+#define USB_RXCSRH5_ISO         0x00000040  // Isochronous Transfers
+#define USB_RXCSRH5_DMAEN       0x00000020  // DMA Request Enable
+#define USB_RXCSRH5_DISNYET     0x00000010  // Disable NYET
+#define USB_RXCSRH5_PIDERR      0x00000010  // PID Error
+#define USB_RXCSRH5_DMAMOD      0x00000008  // DMA Request Mode
+#define USB_RXCSRH5_DTWE        0x00000004  // Data Toggle Write Enable
+#define USB_RXCSRH5_DT          0x00000002  // Data Toggle
+#define USB_RXCSRH5_INCOMPRX    0x00000001  // Incomplete RX Transmission
+                                            // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT5 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT5_COUNT_M    0x00001FFF  // Receive Packet Count
+#define USB_RXCOUNT5_COUNT_S    0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE5 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE5_SPEED_M     0x000000C0  // Operating Speed
+#define USB_TXTYPE5_SPEED_DFLT  0x00000000  // Default
+#define USB_TXTYPE5_SPEED_HIGH  0x00000040  // High
+#define USB_TXTYPE5_SPEED_FULL  0x00000080  // Full
+#define USB_TXTYPE5_SPEED_LOW   0x000000C0  // Low
+#define USB_TXTYPE5_PROTO_M     0x00000030  // Protocol
+#define USB_TXTYPE5_PROTO_CTRL  0x00000000  // Control
+#define USB_TXTYPE5_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_TXTYPE5_PROTO_BULK  0x00000020  // Bulk
+#define USB_TXTYPE5_PROTO_INT   0x00000030  // Interrupt
+#define USB_TXTYPE5_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_TXTYPE5_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL5
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL5_TXPOLL_M                                              \
+                                0x000000FF  // TX Polling
+#define USB_TXINTERVAL5_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_TXINTERVAL5_NAKLMT_S                                              \
+                                0
+#define USB_TXINTERVAL5_TXPOLL_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE5 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE5_SPEED_M     0x000000C0  // Operating Speed
+#define USB_RXTYPE5_SPEED_DFLT  0x00000000  // Default
+#define USB_RXTYPE5_SPEED_HIGH  0x00000040  // High
+#define USB_RXTYPE5_SPEED_FULL  0x00000080  // Full
+#define USB_RXTYPE5_SPEED_LOW   0x000000C0  // Low
+#define USB_RXTYPE5_PROTO_M     0x00000030  // Protocol
+#define USB_RXTYPE5_PROTO_CTRL  0x00000000  // Control
+#define USB_RXTYPE5_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_RXTYPE5_PROTO_BULK  0x00000020  // Bulk
+#define USB_RXTYPE5_PROTO_INT   0x00000030  // Interrupt
+#define USB_RXTYPE5_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_RXTYPE5_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL5
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL5_TXPOLL_M                                              \
+                                0x000000FF  // RX Polling
+#define USB_RXINTERVAL5_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_RXINTERVAL5_TXPOLL_S                                              \
+                                0
+#define USB_RXINTERVAL5_NAKLMT_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP6 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP6_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_TXMAXP6_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL6 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL6_NAKTO       0x00000080  // NAK Timeout
+#define USB_TXCSRL6_CLRDT       0x00000040  // Clear Data Toggle
+#define USB_TXCSRL6_STALLED     0x00000020  // Endpoint Stalled
+#define USB_TXCSRL6_STALL       0x00000010  // Send STALL
+#define USB_TXCSRL6_SETUP       0x00000010  // Setup Packet
+#define USB_TXCSRL6_FLUSH       0x00000008  // Flush FIFO
+#define USB_TXCSRL6_ERROR       0x00000004  // Error
+#define USB_TXCSRL6_UNDRN       0x00000004  // Underrun
+#define USB_TXCSRL6_FIFONE      0x00000002  // FIFO Not Empty
+#define USB_TXCSRL6_TXRDY       0x00000001  // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH6 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH6_AUTOSET     0x00000080  // Auto Set
+#define USB_TXCSRH6_ISO         0x00000040  // Isochronous Transfers
+#define USB_TXCSRH6_MODE        0x00000020  // Mode
+#define USB_TXCSRH6_DMAEN       0x00000010  // DMA Request Enable
+#define USB_TXCSRH6_FDT         0x00000008  // Force Data Toggle
+#define USB_TXCSRH6_DMAMOD      0x00000004  // DMA Request Mode
+#define USB_TXCSRH6_DTWE        0x00000002  // Data Toggle Write Enable
+#define USB_TXCSRH6_DT          0x00000001  // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP6 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP6_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_RXMAXP6_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL6 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL6_CLRDT       0x00000080  // Clear Data Toggle
+#define USB_RXCSRL6_STALLED     0x00000040  // Endpoint Stalled
+#define USB_RXCSRL6_REQPKT      0x00000020  // Request Packet
+#define USB_RXCSRL6_STALL       0x00000020  // Send STALL
+#define USB_RXCSRL6_FLUSH       0x00000010  // Flush FIFO
+#define USB_RXCSRL6_NAKTO       0x00000008  // NAK Timeout
+#define USB_RXCSRL6_DATAERR     0x00000008  // Data Error
+#define USB_RXCSRL6_ERROR       0x00000004  // Error
+#define USB_RXCSRL6_OVER        0x00000004  // Overrun
+#define USB_RXCSRL6_FULL        0x00000002  // FIFO Full
+#define USB_RXCSRL6_RXRDY       0x00000001  // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH6 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH6_AUTOCL      0x00000080  // Auto Clear
+#define USB_RXCSRH6_AUTORQ      0x00000040  // Auto Request
+#define USB_RXCSRH6_ISO         0x00000040  // Isochronous Transfers
+#define USB_RXCSRH6_DMAEN       0x00000020  // DMA Request Enable
+#define USB_RXCSRH6_DISNYET     0x00000010  // Disable NYET
+#define USB_RXCSRH6_PIDERR      0x00000010  // PID Error
+#define USB_RXCSRH6_DMAMOD      0x00000008  // DMA Request Mode
+#define USB_RXCSRH6_DTWE        0x00000004  // Data Toggle Write Enable
+#define USB_RXCSRH6_DT          0x00000002  // Data Toggle
+#define USB_RXCSRH6_INCOMPRX    0x00000001  // Incomplete RX Transmission
+                                            // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT6 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT6_COUNT_M    0x00001FFF  // Receive Packet Count
+#define USB_RXCOUNT6_COUNT_S    0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE6 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE6_SPEED_M     0x000000C0  // Operating Speed
+#define USB_TXTYPE6_SPEED_DFLT  0x00000000  // Default
+#define USB_TXTYPE6_SPEED_HIGH  0x00000040  // High
+#define USB_TXTYPE6_SPEED_FULL  0x00000080  // Full
+#define USB_TXTYPE6_SPEED_LOW   0x000000C0  // Low
+#define USB_TXTYPE6_PROTO_M     0x00000030  // Protocol
+#define USB_TXTYPE6_PROTO_CTRL  0x00000000  // Control
+#define USB_TXTYPE6_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_TXTYPE6_PROTO_BULK  0x00000020  // Bulk
+#define USB_TXTYPE6_PROTO_INT   0x00000030  // Interrupt
+#define USB_TXTYPE6_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_TXTYPE6_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL6
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL6_TXPOLL_M                                              \
+                                0x000000FF  // TX Polling
+#define USB_TXINTERVAL6_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_TXINTERVAL6_TXPOLL_S                                              \
+                                0
+#define USB_TXINTERVAL6_NAKLMT_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE6 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE6_SPEED_M     0x000000C0  // Operating Speed
+#define USB_RXTYPE6_SPEED_DFLT  0x00000000  // Default
+#define USB_RXTYPE6_SPEED_HIGH  0x00000040  // High
+#define USB_RXTYPE6_SPEED_FULL  0x00000080  // Full
+#define USB_RXTYPE6_SPEED_LOW   0x000000C0  // Low
+#define USB_RXTYPE6_PROTO_M     0x00000030  // Protocol
+#define USB_RXTYPE6_PROTO_CTRL  0x00000000  // Control
+#define USB_RXTYPE6_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_RXTYPE6_PROTO_BULK  0x00000020  // Bulk
+#define USB_RXTYPE6_PROTO_INT   0x00000030  // Interrupt
+#define USB_RXTYPE6_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_RXTYPE6_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL6
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL6_TXPOLL_M                                              \
+                                0x000000FF  // RX Polling
+#define USB_RXINTERVAL6_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_RXINTERVAL6_NAKLMT_S                                              \
+                                0
+#define USB_RXINTERVAL6_TXPOLL_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXMAXP7 register.
+//
+//*****************************************************************************
+#define USB_TXMAXP7_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_TXMAXP7_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRL7 register.
+//
+//*****************************************************************************
+#define USB_TXCSRL7_NAKTO       0x00000080  // NAK Timeout
+#define USB_TXCSRL7_CLRDT       0x00000040  // Clear Data Toggle
+#define USB_TXCSRL7_STALLED     0x00000020  // Endpoint Stalled
+#define USB_TXCSRL7_STALL       0x00000010  // Send STALL
+#define USB_TXCSRL7_SETUP       0x00000010  // Setup Packet
+#define USB_TXCSRL7_FLUSH       0x00000008  // Flush FIFO
+#define USB_TXCSRL7_ERROR       0x00000004  // Error
+#define USB_TXCSRL7_UNDRN       0x00000004  // Underrun
+#define USB_TXCSRL7_FIFONE      0x00000002  // FIFO Not Empty
+#define USB_TXCSRL7_TXRDY       0x00000001  // Transmit Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXCSRH7 register.
+//
+//*****************************************************************************
+#define USB_TXCSRH7_AUTOSET     0x00000080  // Auto Set
+#define USB_TXCSRH7_ISO         0x00000040  // Isochronous Transfers
+#define USB_TXCSRH7_MODE        0x00000020  // Mode
+#define USB_TXCSRH7_DMAEN       0x00000010  // DMA Request Enable
+#define USB_TXCSRH7_FDT         0x00000008  // Force Data Toggle
+#define USB_TXCSRH7_DMAMOD      0x00000004  // DMA Request Mode
+#define USB_TXCSRH7_DTWE        0x00000002  // Data Toggle Write Enable
+#define USB_TXCSRH7_DT          0x00000001  // Data Toggle
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXMAXP7 register.
+//
+//*****************************************************************************
+#define USB_RXMAXP7_MAXLOAD_M   0x000007FF  // Maximum Payload
+#define USB_RXMAXP7_MAXLOAD_S   0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRL7 register.
+//
+//*****************************************************************************
+#define USB_RXCSRL7_CLRDT       0x00000080  // Clear Data Toggle
+#define USB_RXCSRL7_STALLED     0x00000040  // Endpoint Stalled
+#define USB_RXCSRL7_REQPKT      0x00000020  // Request Packet
+#define USB_RXCSRL7_STALL       0x00000020  // Send STALL
+#define USB_RXCSRL7_FLUSH       0x00000010  // Flush FIFO
+#define USB_RXCSRL7_DATAERR     0x00000008  // Data Error
+#define USB_RXCSRL7_NAKTO       0x00000008  // NAK Timeout
+#define USB_RXCSRL7_ERROR       0x00000004  // Error
+#define USB_RXCSRL7_OVER        0x00000004  // Overrun
+#define USB_RXCSRL7_FULL        0x00000002  // FIFO Full
+#define USB_RXCSRL7_RXRDY       0x00000001  // Receive Packet Ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCSRH7 register.
+//
+//*****************************************************************************
+#define USB_RXCSRH7_AUTOCL      0x00000080  // Auto Clear
+#define USB_RXCSRH7_ISO         0x00000040  // Isochronous Transfers
+#define USB_RXCSRH7_AUTORQ      0x00000040  // Auto Request
+#define USB_RXCSRH7_DMAEN       0x00000020  // DMA Request Enable
+#define USB_RXCSRH7_PIDERR      0x00000010  // PID Error
+#define USB_RXCSRH7_DISNYET     0x00000010  // Disable NYET
+#define USB_RXCSRH7_DMAMOD      0x00000008  // DMA Request Mode
+#define USB_RXCSRH7_DTWE        0x00000004  // Data Toggle Write Enable
+#define USB_RXCSRH7_DT          0x00000002  // Data Toggle
+#define USB_RXCSRH7_INCOMPRX    0x00000001  // Incomplete RX Transmission
+                                            // Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXCOUNT7 register.
+//
+//*****************************************************************************
+#define USB_RXCOUNT7_COUNT_M    0x00001FFF  // Receive Packet Count
+#define USB_RXCOUNT7_COUNT_S    0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXTYPE7 register.
+//
+//*****************************************************************************
+#define USB_TXTYPE7_SPEED_M     0x000000C0  // Operating Speed
+#define USB_TXTYPE7_SPEED_DFLT  0x00000000  // Default
+#define USB_TXTYPE7_SPEED_HIGH  0x00000040  // High
+#define USB_TXTYPE7_SPEED_FULL  0x00000080  // Full
+#define USB_TXTYPE7_SPEED_LOW   0x000000C0  // Low
+#define USB_TXTYPE7_PROTO_M     0x00000030  // Protocol
+#define USB_TXTYPE7_PROTO_CTRL  0x00000000  // Control
+#define USB_TXTYPE7_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_TXTYPE7_PROTO_BULK  0x00000020  // Bulk
+#define USB_TXTYPE7_PROTO_INT   0x00000030  // Interrupt
+#define USB_TXTYPE7_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_TXTYPE7_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXINTERVAL7
+// register.
+//
+//*****************************************************************************
+#define USB_TXINTERVAL7_TXPOLL_M                                              \
+                                0x000000FF  // TX Polling
+#define USB_TXINTERVAL7_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_TXINTERVAL7_NAKLMT_S                                              \
+                                0
+#define USB_TXINTERVAL7_TXPOLL_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXTYPE7 register.
+//
+//*****************************************************************************
+#define USB_RXTYPE7_SPEED_M     0x000000C0  // Operating Speed
+#define USB_RXTYPE7_SPEED_DFLT  0x00000000  // Default
+#define USB_RXTYPE7_SPEED_HIGH  0x00000040  // High
+#define USB_RXTYPE7_SPEED_FULL  0x00000080  // Full
+#define USB_RXTYPE7_SPEED_LOW   0x000000C0  // Low
+#define USB_RXTYPE7_PROTO_M     0x00000030  // Protocol
+#define USB_RXTYPE7_PROTO_CTRL  0x00000000  // Control
+#define USB_RXTYPE7_PROTO_ISOC  0x00000010  // Isochronous
+#define USB_RXTYPE7_PROTO_BULK  0x00000020  // Bulk
+#define USB_RXTYPE7_PROTO_INT   0x00000030  // Interrupt
+#define USB_RXTYPE7_TEP_M       0x0000000F  // Target Endpoint Number
+#define USB_RXTYPE7_TEP_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXINTERVAL7
+// register.
+//
+//*****************************************************************************
+#define USB_RXINTERVAL7_TXPOLL_M                                              \
+                                0x000000FF  // RX Polling
+#define USB_RXINTERVAL7_NAKLMT_M                                              \
+                                0x000000FF  // NAK Limit
+#define USB_RXINTERVAL7_NAKLMT_S                                              \
+                                0
+#define USB_RXINTERVAL7_TXPOLL_S                                              \
+                                0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAINTR register.
+//
+//*****************************************************************************
+#define USB_DMAINTR_CH7         0x00000080  // Channel 7 DMA Interrupt
+#define USB_DMAINTR_CH6         0x00000040  // Channel 6 DMA Interrupt
+#define USB_DMAINTR_CH5         0x00000020  // Channel 5 DMA Interrupt
+#define USB_DMAINTR_CH4         0x00000010  // Channel 4 DMA Interrupt
+#define USB_DMAINTR_CH3         0x00000008  // Channel 3 DMA Interrupt
+#define USB_DMAINTR_CH2         0x00000004  // Channel 2 DMA Interrupt
+#define USB_DMAINTR_CH1         0x00000002  // Channel 1 DMA Interrupt
+#define USB_DMAINTR_CH0         0x00000001  // Channel 0 DMA Interrupt
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL0 register.
+//
+//*****************************************************************************
+#define USB_DMACTL0_BRSTM_M     0x00000600  // Burst Mode
+#define USB_DMACTL0_BRSTM_ANY   0x00000000  // Bursts of unspecified length
+#define USB_DMACTL0_BRSTM_INC4  0x00000200  // INCR4 or unspecified length
+#define USB_DMACTL0_BRSTM_INC8  0x00000400  // INCR8, INCR4 or unspecified
+                                            // length
+#define USB_DMACTL0_BRSTM_INC16 0x00000600  // INCR16, INCR8, INCR4 or
+                                            // unspecified length
+#define USB_DMACTL0_ERR         0x00000100  // Bus Error Bit
+#define USB_DMACTL0_EP_M        0x000000F0  // Endpoint number
+#define USB_DMACTL0_IE          0x00000008  // DMA Interrupt Enable
+#define USB_DMACTL0_MODE        0x00000004  // DMA Transfer Mode
+#define USB_DMACTL0_DIR         0x00000002  // DMA Direction
+#define USB_DMACTL0_ENABLE      0x00000001  // DMA Transfer Enable
+#define USB_DMACTL0_EP_S        4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR0 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR0_ADDR_M     0xFFFFFFFC  // DMA Address
+#define USB_DMAADDR0_ADDR_S     2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT0
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT0_COUNT_M   0xFFFFFFFC  // DMA Count
+#define USB_DMACOUNT0_COUNT_S   2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL1 register.
+//
+//*****************************************************************************
+#define USB_DMACTL1_BRSTM_M     0x00000600  // Burst Mode
+#define USB_DMACTL1_BRSTM_ANY   0x00000000  // Bursts of unspecified length
+#define USB_DMACTL1_BRSTM_INC4  0x00000200  // INCR4 or unspecified length
+#define USB_DMACTL1_BRSTM_INC8  0x00000400  // INCR8, INCR4 or unspecified
+                                            // length
+#define USB_DMACTL1_BRSTM_INC16 0x00000600  // INCR16, INCR8, INCR4 or
+                                            // unspecified length
+#define USB_DMACTL1_ERR         0x00000100  // Bus Error Bit
+#define USB_DMACTL1_EP_M        0x000000F0  // Endpoint number
+#define USB_DMACTL1_IE          0x00000008  // DMA Interrupt Enable
+#define USB_DMACTL1_MODE        0x00000004  // DMA Transfer Mode
+#define USB_DMACTL1_DIR         0x00000002  // DMA Direction
+#define USB_DMACTL1_ENABLE      0x00000001  // DMA Transfer Enable
+#define USB_DMACTL1_EP_S        4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR1 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR1_ADDR_M     0xFFFFFFFC  // DMA Address
+#define USB_DMAADDR1_ADDR_S     2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT1
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT1_COUNT_M   0xFFFFFFFC  // DMA Count
+#define USB_DMACOUNT1_COUNT_S   2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL2 register.
+//
+//*****************************************************************************
+#define USB_DMACTL2_BRSTM_M     0x00000600  // Burst Mode
+#define USB_DMACTL2_BRSTM_ANY   0x00000000  // Bursts of unspecified length
+#define USB_DMACTL2_BRSTM_INC4  0x00000200  // INCR4 or unspecified length
+#define USB_DMACTL2_BRSTM_INC8  0x00000400  // INCR8, INCR4 or unspecified
+                                            // length
+#define USB_DMACTL2_BRSTM_INC16 0x00000600  // INCR16, INCR8, INCR4 or
+                                            // unspecified length
+#define USB_DMACTL2_ERR         0x00000100  // Bus Error Bit
+#define USB_DMACTL2_EP_M        0x000000F0  // Endpoint number
+#define USB_DMACTL2_IE          0x00000008  // DMA Interrupt Enable
+#define USB_DMACTL2_MODE        0x00000004  // DMA Transfer Mode
+#define USB_DMACTL2_DIR         0x00000002  // DMA Direction
+#define USB_DMACTL2_ENABLE      0x00000001  // DMA Transfer Enable
+#define USB_DMACTL2_EP_S        4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR2 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR2_ADDR_M     0xFFFFFFFC  // DMA Address
+#define USB_DMAADDR2_ADDR_S     2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT2
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT2_COUNT_M   0xFFFFFFFC  // DMA Count
+#define USB_DMACOUNT2_COUNT_S   2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL3 register.
+//
+//*****************************************************************************
+#define USB_DMACTL3_BRSTM_M     0x00000600  // Burst Mode
+#define USB_DMACTL3_BRSTM_ANY   0x00000000  // Bursts of unspecified length
+#define USB_DMACTL3_BRSTM_INC4  0x00000200  // INCR4 or unspecified length
+#define USB_DMACTL3_BRSTM_INC8  0x00000400  // INCR8, INCR4 or unspecified
+                                            // length
+#define USB_DMACTL3_BRSTM_INC16 0x00000600  // INCR16, INCR8, INCR4 or
+                                            // unspecified length
+#define USB_DMACTL3_ERR         0x00000100  // Bus Error Bit
+#define USB_DMACTL3_EP_M        0x000000F0  // Endpoint number
+#define USB_DMACTL3_IE          0x00000008  // DMA Interrupt Enable
+#define USB_DMACTL3_MODE        0x00000004  // DMA Transfer Mode
+#define USB_DMACTL3_DIR         0x00000002  // DMA Direction
+#define USB_DMACTL3_ENABLE      0x00000001  // DMA Transfer Enable
+#define USB_DMACTL3_EP_S        4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR3 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR3_ADDR_M     0xFFFFFFFC  // DMA Address
+#define USB_DMAADDR3_ADDR_S     2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT3
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT3_COUNT_M   0xFFFFFFFC  // DMA Count
+#define USB_DMACOUNT3_COUNT_S   2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL4 register.
+//
+//*****************************************************************************
+#define USB_DMACTL4_BRSTM_M     0x00000600  // Burst Mode
+#define USB_DMACTL4_BRSTM_ANY   0x00000000  // Bursts of unspecified length
+#define USB_DMACTL4_BRSTM_INC4  0x00000200  // INCR4 or unspecified length
+#define USB_DMACTL4_BRSTM_INC8  0x00000400  // INCR8, INCR4 or unspecified
+                                            // length
+#define USB_DMACTL4_BRSTM_INC16 0x00000600  // INCR16, INCR8, INCR4 or
+                                            // unspecified length
+#define USB_DMACTL4_ERR         0x00000100  // Bus Error Bit
+#define USB_DMACTL4_EP_M        0x000000F0  // Endpoint number
+#define USB_DMACTL4_IE          0x00000008  // DMA Interrupt Enable
+#define USB_DMACTL4_MODE        0x00000004  // DMA Transfer Mode
+#define USB_DMACTL4_DIR         0x00000002  // DMA Direction
+#define USB_DMACTL4_ENABLE      0x00000001  // DMA Transfer Enable
+#define USB_DMACTL4_EP_S        4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR4 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR4_ADDR_M     0xFFFFFFFC  // DMA Address
+#define USB_DMAADDR4_ADDR_S     2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT4
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT4_COUNT_M   0xFFFFFFFC  // DMA Count
+#define USB_DMACOUNT4_COUNT_S   2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL5 register.
+//
+//*****************************************************************************
+#define USB_DMACTL5_BRSTM_M     0x00000600  // Burst Mode
+#define USB_DMACTL5_BRSTM_ANY   0x00000000  // Bursts of unspecified length
+#define USB_DMACTL5_BRSTM_INC4  0x00000200  // INCR4 or unspecified length
+#define USB_DMACTL5_BRSTM_INC8  0x00000400  // INCR8, INCR4 or unspecified
+                                            // length
+#define USB_DMACTL5_BRSTM_INC16 0x00000600  // INCR16, INCR8, INCR4 or
+                                            // unspecified length
+#define USB_DMACTL5_ERR         0x00000100  // Bus Error Bit
+#define USB_DMACTL5_EP_M        0x000000F0  // Endpoint number
+#define USB_DMACTL5_IE          0x00000008  // DMA Interrupt Enable
+#define USB_DMACTL5_MODE        0x00000004  // DMA Transfer Mode
+#define USB_DMACTL5_DIR         0x00000002  // DMA Direction
+#define USB_DMACTL5_ENABLE      0x00000001  // DMA Transfer Enable
+#define USB_DMACTL5_EP_S        4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR5 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR5_ADDR_M     0xFFFFFFFC  // DMA Address
+#define USB_DMAADDR5_ADDR_S     2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT5
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT5_COUNT_M   0xFFFFFFFC  // DMA Count
+#define USB_DMACOUNT5_COUNT_S   2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL6 register.
+//
+//*****************************************************************************
+#define USB_DMACTL6_BRSTM_M     0x00000600  // Burst Mode
+#define USB_DMACTL6_BRSTM_ANY   0x00000000  // Bursts of unspecified length
+#define USB_DMACTL6_BRSTM_INC4  0x00000200  // INCR4 or unspecified length
+#define USB_DMACTL6_BRSTM_INC8  0x00000400  // INCR8, INCR4 or unspecified
+                                            // length
+#define USB_DMACTL6_BRSTM_INC16 0x00000600  // INCR16, INCR8, INCR4 or
+                                            // unspecified length
+#define USB_DMACTL6_ERR         0x00000100  // Bus Error Bit
+#define USB_DMACTL6_EP_M        0x000000F0  // Endpoint number
+#define USB_DMACTL6_IE          0x00000008  // DMA Interrupt Enable
+#define USB_DMACTL6_MODE        0x00000004  // DMA Transfer Mode
+#define USB_DMACTL6_DIR         0x00000002  // DMA Direction
+#define USB_DMACTL6_ENABLE      0x00000001  // DMA Transfer Enable
+#define USB_DMACTL6_EP_S        4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR6 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR6_ADDR_M     0xFFFFFFFC  // DMA Address
+#define USB_DMAADDR6_ADDR_S     2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT6
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT6_COUNT_M   0xFFFFFFFC  // DMA Count
+#define USB_DMACOUNT6_COUNT_S   2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACTL7 register.
+//
+//*****************************************************************************
+#define USB_DMACTL7_BRSTM_M     0x00000600  // Burst Mode
+#define USB_DMACTL7_BRSTM_ANY   0x00000000  // Bursts of unspecified length
+#define USB_DMACTL7_BRSTM_INC4  0x00000200  // INCR4 or unspecified length
+#define USB_DMACTL7_BRSTM_INC8  0x00000400  // INCR8, INCR4 or unspecified
+                                            // length
+#define USB_DMACTL7_BRSTM_INC16 0x00000600  // INCR16, INCR8, INCR4 or
+                                            // unspecified length
+#define USB_DMACTL7_ERR         0x00000100  // Bus Error Bit
+#define USB_DMACTL7_EP_M        0x000000F0  // Endpoint number
+#define USB_DMACTL7_IE          0x00000008  // DMA Interrupt Enable
+#define USB_DMACTL7_MODE        0x00000004  // DMA Transfer Mode
+#define USB_DMACTL7_DIR         0x00000002  // DMA Direction
+#define USB_DMACTL7_ENABLE      0x00000001  // DMA Transfer Enable
+#define USB_DMACTL7_EP_S        4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMAADDR7 register.
+//
+//*****************************************************************************
+#define USB_DMAADDR7_ADDR_M     0xFFFFFFFC  // DMA Address
+#define USB_DMAADDR7_ADDR_S     2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DMACOUNT7
+// register.
+//
+//*****************************************************************************
+#define USB_DMACOUNT7_COUNT_M   0xFFFFFFFC  // DMA Count
+#define USB_DMACOUNT7_COUNT_S   2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT1
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT1_M       0x0000FFFF  // Block Transfer Packet Count
+#define USB_RQPKTCOUNT1_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT2
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT2_M       0x0000FFFF  // Block Transfer Packet Count
+#define USB_RQPKTCOUNT2_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT3
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT3_M       0x0000FFFF  // Block Transfer Packet Count
+#define USB_RQPKTCOUNT3_S       0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT4
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT4_COUNT_M 0x0000FFFF  // Block Transfer Packet Count
+#define USB_RQPKTCOUNT4_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT5
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT5_COUNT_M 0x0000FFFF  // Block Transfer Packet Count
+#define USB_RQPKTCOUNT5_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT6
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT6_COUNT_M 0x0000FFFF  // Block Transfer Packet Count
+#define USB_RQPKTCOUNT6_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RQPKTCOUNT7
+// register.
+//
+//*****************************************************************************
+#define USB_RQPKTCOUNT7_COUNT_M 0x0000FFFF  // Block Transfer Packet Count
+#define USB_RQPKTCOUNT7_COUNT_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_RXDPKTBUFDIS
+// register.
+//
+//*****************************************************************************
+#define USB_RXDPKTBUFDIS_EP7    0x00000080  // EP7 RX Double-Packet Buffer
+                                            // Disable
+#define USB_RXDPKTBUFDIS_EP6    0x00000040  // EP6 RX Double-Packet Buffer
+                                            // Disable
+#define USB_RXDPKTBUFDIS_EP5    0x00000020  // EP5 RX Double-Packet Buffer
+                                            // Disable
+#define USB_RXDPKTBUFDIS_EP4    0x00000010  // EP4 RX Double-Packet Buffer
+                                            // Disable
+#define USB_RXDPKTBUFDIS_EP3    0x00000008  // EP3 RX Double-Packet Buffer
+                                            // Disable
+#define USB_RXDPKTBUFDIS_EP2    0x00000004  // EP2 RX Double-Packet Buffer
+                                            // Disable
+#define USB_RXDPKTBUFDIS_EP1    0x00000002  // EP1 RX Double-Packet Buffer
+                                            // Disable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_TXDPKTBUFDIS
+// register.
+//
+//*****************************************************************************
+#define USB_TXDPKTBUFDIS_EP7    0x00000080  // EP7 TX Double-Packet Buffer
+                                            // Disable
+#define USB_TXDPKTBUFDIS_EP6    0x00000040  // EP6 TX Double-Packet Buffer
+                                            // Disable
+#define USB_TXDPKTBUFDIS_EP5    0x00000020  // EP5 TX Double-Packet Buffer
+                                            // Disable
+#define USB_TXDPKTBUFDIS_EP4    0x00000010  // EP4 TX Double-Packet Buffer
+                                            // Disable
+#define USB_TXDPKTBUFDIS_EP3    0x00000008  // EP3 TX Double-Packet Buffer
+                                            // Disable
+#define USB_TXDPKTBUFDIS_EP2    0x00000004  // EP2 TX Double-Packet Buffer
+                                            // Disable
+#define USB_TXDPKTBUFDIS_EP1    0x00000002  // EP1 TX Double-Packet Buffer
+                                            // Disable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CTO register.
+//
+//*****************************************************************************
+#define USB_CTO_CCTV_M          0x0000FFFF  // Configurable Chirp Timeout Value
+#define USB_CTO_CCTV_S          0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_HHSRTN register.
+//
+//*****************************************************************************
+#define USB_HHSRTN_HHSRTN_M     0x0000FFFF  // HIgh Speed to UTM Operating
+                                            // Delay
+#define USB_HHSRTN_HHSRTN_S     0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_HSBT register.
+//
+//*****************************************************************************
+#define USB_HSBT_HSBT_M         0x0000000F  // High Speed Timeout Adder
+#define USB_HSBT_HSBT_S         0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMATTR register.
+//
+//*****************************************************************************
+#define USB_LPMATTR_ENDPT_M     0x0000F000  // Endpoint
+#define USB_LPMATTR_RMTWAK      0x00000100  // Remote Wake
+#define USB_LPMATTR_HIRD_M      0x000000F0  // Host Initiated Resume Duration
+#define USB_LPMATTR_LS_M        0x0000000F  // Link State
+#define USB_LPMATTR_LS_L1       0x00000001  // Sleep State (L1)
+#define USB_LPMATTR_ENDPT_S     12
+#define USB_LPMATTR_HIRD_S      4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMCNTRL register.
+//
+//*****************************************************************************
+#define USB_LPMCNTRL_NAK        0x00000010  // LPM NAK
+#define USB_LPMCNTRL_EN_M       0x0000000C  // LPM Enable
+#define USB_LPMCNTRL_EN_NONE    0x00000000  // LPM and Extended transactions
+                                            // are not supported. In this case,
+                                            // the USB does not respond to LPM
+                                            // transactions and LPM
+                                            // transactions cause a timeout
+#define USB_LPMCNTRL_EN_EXT     0x00000004  // LPM is not supported but
+                                            // extended transactions are
+                                            // supported. In this case, the USB
+                                            // does respond to an LPM
+                                            // transaction with a STALL
+#define USB_LPMCNTRL_EN_LPMEXT  0x0000000C  // The USB supports LPM extended
+                                            // transactions. In this case, the
+                                            // USB responds with a NYET or an
+                                            // ACK as determined by the value
+                                            // of TXLPM and other conditions
+#define USB_LPMCNTRL_RES        0x00000002  // LPM Resume
+#define USB_LPMCNTRL_TXLPM      0x00000001  // Transmit LPM Transaction Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMIM register.
+//
+//*****************************************************************************
+#define USB_LPMIM_ERR           0x00000020  // LPM Error Interrupt Mask
+#define USB_LPMIM_RES           0x00000010  // LPM Resume Interrupt Mask
+#define USB_LPMIM_NC            0x00000008  // LPM NC Interrupt Mask
+#define USB_LPMIM_ACK           0x00000004  // LPM ACK Interrupt Mask
+#define USB_LPMIM_NY            0x00000002  // LPM NY Interrupt Mask
+#define USB_LPMIM_STALL         0x00000001  // LPM STALL Interrupt Mask
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMRIS register.
+//
+//*****************************************************************************
+#define USB_LPMRIS_ERR          0x00000020  // LPM Interrupt Status
+#define USB_LPMRIS_RES          0x00000010  // LPM Resume Interrupt Status
+#define USB_LPMRIS_NC           0x00000008  // LPM NC Interrupt Status
+#define USB_LPMRIS_ACK          0x00000004  // LPM ACK Interrupt Status
+#define USB_LPMRIS_NY           0x00000002  // LPM NY Interrupt Status
+#define USB_LPMRIS_LPMST        0x00000001  // LPM STALL Interrupt Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_LPMFADDR register.
+//
+//*****************************************************************************
+#define USB_LPMFADDR_ADDR_M     0x0000007F  // LPM Function Address
+#define USB_LPMFADDR_ADDR_S     0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPC register.
+//
+//*****************************************************************************
+#define USB_EPC_PFLTACT_M       0x00000300  // Power Fault Action
+#define USB_EPC_PFLTACT_UNCHG   0x00000000  // Unchanged
+#define USB_EPC_PFLTACT_TRIS    0x00000100  // Tristate
+#define USB_EPC_PFLTACT_LOW     0x00000200  // Low
+#define USB_EPC_PFLTACT_HIGH    0x00000300  // High
+#define USB_EPC_PFLTAEN         0x00000040  // Power Fault Action Enable
+#define USB_EPC_PFLTSEN_HIGH    0x00000020  // Power Fault Sense
+#define USB_EPC_PFLTEN          0x00000010  // Power Fault Input Enable
+#define USB_EPC_EPENDE          0x00000004  // EPEN Drive Enable
+#define USB_EPC_EPEN_M          0x00000003  // External Power Supply Enable
+                                            // Configuration
+#define USB_EPC_EPEN_LOW        0x00000000  // Power Enable Active Low
+#define USB_EPC_EPEN_HIGH       0x00000001  // Power Enable Active High
+#define USB_EPC_EPEN_VBLOW      0x00000002  // Power Enable High if VBUS Low
+                                            // (OTG only)
+#define USB_EPC_EPEN_VBHIGH     0x00000003  // Power Enable High if VBUS High
+                                            // (OTG only)
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPCRIS register.
+//
+//*****************************************************************************
+#define USB_EPCRIS_PF           0x00000001  // USB Power Fault Interrupt Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPCIM register.
+//
+//*****************************************************************************
+#define USB_EPCIM_PF            0x00000001  // USB Power Fault Interrupt Mask
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_EPCISC register.
+//
+//*****************************************************************************
+#define USB_EPCISC_PF           0x00000001  // USB Power Fault Interrupt Status
+                                            // and Clear
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DRRIS register.
+//
+//*****************************************************************************
+#define USB_DRRIS_RESUME        0x00000001  // RESUME Interrupt Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DRIM register.
+//
+//*****************************************************************************
+#define USB_DRIM_RESUME         0x00000001  // RESUME Interrupt Mask
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_DRISC register.
+//
+//*****************************************************************************
+#define USB_DRISC_RESUME        0x00000001  // RESUME Interrupt Status and
+                                            // Clear
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_GPCS register.
+//
+//*****************************************************************************
+#define USB_GPCS_DEVMOD_M       0x00000007  // Device Mode
+#define USB_GPCS_DEVMOD_OTG     0x00000000  // Use USB0VBUS and USB0ID pin
+#define USB_GPCS_DEVMOD_HOST    0x00000002  // Force USB0VBUS and USB0ID low
+#define USB_GPCS_DEVMOD_DEV     0x00000003  // Force USB0VBUS and USB0ID high
+#define USB_GPCS_DEVMOD_HOSTVBUS                                              \
+                                0x00000004  // Use USB0VBUS and force USB0ID
+                                            // low
+#define USB_GPCS_DEVMOD_DEVVBUS 0x00000005  // Use USB0VBUS and force USB0ID
+                                            // high
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VDC register.
+//
+//*****************************************************************************
+#define USB_VDC_VBDEN           0x00000001  // VBUS Droop Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VDCRIS register.
+//
+//*****************************************************************************
+#define USB_VDCRIS_VD           0x00000001  // VBUS Droop Raw Interrupt Status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VDCIM register.
+//
+//*****************************************************************************
+#define USB_VDCIM_VD            0x00000001  // VBUS Droop Interrupt Mask
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_VDCISC register.
+//
+//*****************************************************************************
+#define USB_VDCISC_VD           0x00000001  // VBUS Droop Interrupt Status and
+                                            // Clear
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_PP register.
+//
+//*****************************************************************************
+#define USB_PP_ECNT_M           0x0000FF00  // Endpoint Count
+#define USB_PP_USB_M            0x000000C0  // USB Capability
+#define USB_PP_USB_DEVICE       0x00000040  // DEVICE
+#define USB_PP_USB_HOSTDEVICE   0x00000080  // HOST
+#define USB_PP_USB_OTG          0x000000C0  // OTG
+#define USB_PP_ULPI             0x00000020  // ULPI Present
+#define USB_PP_PHY              0x00000010  // PHY Present
+#define USB_PP_TYPE_M           0x0000000F  // Controller Type
+#define USB_PP_TYPE_0           0x00000000  // The first-generation USB
+                                            // controller
+#define USB_PP_TYPE_1           0x00000001  // The second-generation USB
+                                            // controller revision
+#define USB_PP_ECNT_S           8
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_PC register.
+//
+//*****************************************************************************
+#define USB_PC_ULPIEN           0x00010000  // ULPI Enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the USB_O_CC register.
+//
+//*****************************************************************************
+#define USB_CC_CLKEN            0x00000200  // USB Clock Enable
+#define USB_CC_CSD              0x00000100  // Clock Source/Direction
+#define USB_CC_CLKDIV_M         0x0000000F  // PLL Clock Divisor
+#define USB_CC_CLKDIV_S         0
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c
new file mode 100644
index 0000000..46aabc5
--- /dev/null
+++ b/src/portable/microchip/samd/dcd_samd.c
@@ -0,0 +1,419 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * 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_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)
+
+#include "sam.h"
+#include "device/dcd.h"
+
+/*------------------------------------------------------------------*/
+/* MACRO TYPEDEF CONSTANT ENUM
+ *------------------------------------------------------------------*/
+static TU_ATTR_ALIGNED(4) UsbDeviceDescBank sram_registers[8][2];
+
+// Setup packet is only 8 bytes in length. However under certain scenario,
+// USB DMA controller may decide to overwrite/overflow the buffer  with
+// 2 extra bytes of CRC. From datasheet's "Management of SETUP Transactions" section
+//    If the number of received data bytes is the maximum data payload specified by
+//    PCKSIZE.SIZE minus one, only the first CRC data is written to the data buffer.
+//    If the number of received data is equal or less than the data payload specified
+//    by PCKSIZE.SIZE minus two, both CRC data bytes are written to the data buffer.
+// Therefore we will need to increase it to 10 bytes here.
+static TU_ATTR_ALIGNED(4) uint8_t _setup_packet[8+2];
+
+// ready for receiving SETUP packet
+static inline void prepare_setup(void)
+{
+  // Only make sure the EP0 OUT buffer is ready
+  sram_registers[0][0].ADDR.reg = (uint32_t) _setup_packet;
+  sram_registers[0][0].PCKSIZE.bit.MULTI_PACKET_SIZE = sizeof(tusb_control_request_t);
+  sram_registers[0][0].PCKSIZE.bit.BYTE_COUNT = 0;
+}
+
+// Setup the control endpoint 0.
+static void bus_reset(void)
+{
+  // Max size of packets is 64 bytes.
+  UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT];
+  bank_out->PCKSIZE.bit.SIZE = 0x3;
+  UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN];
+  bank_in->PCKSIZE.bit.SIZE = 0x3;
+
+  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0];
+  ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1);
+  ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP;
+
+  // Prepare for setup packet
+  prepare_setup();
+}
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+void dcd_init (uint8_t rhport)
+{
+  (void) rhport;
+
+  // Reset to get in a clean state.
+  USB->DEVICE.CTRLA.bit.SWRST = true;
+  while (USB->DEVICE.SYNCBUSY.bit.SWRST == 0) {}
+  while (USB->DEVICE.SYNCBUSY.bit.SWRST == 1) {}
+
+  USB->DEVICE.PADCAL.bit.TRANSP = (*((uint32_t*) USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
+  USB->DEVICE.PADCAL.bit.TRANSN = (*((uint32_t*) USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
+  USB->DEVICE.PADCAL.bit.TRIM   = (*((uint32_t*) USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
+
+  USB->DEVICE.QOSCTRL.bit.CQOS = 3; // High Quality
+  USB->DEVICE.QOSCTRL.bit.DQOS = 3; // High Quality
+
+  // Configure registers
+  USB->DEVICE.DESCADD.reg = (uint32_t) &sram_registers;
+  USB->DEVICE.CTRLB.reg = USB_DEVICE_CTRLB_SPDCONF_FS;
+  USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY;
+  while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {}
+
+  USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending
+  USB->DEVICE.INTENSET.reg = /* USB_DEVICE_INTENSET_SOF | */ USB_DEVICE_INTENSET_EORST;
+}
+
+#if CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USB_0_IRQn);
+  NVIC_EnableIRQ(USB_1_IRQn);
+  NVIC_EnableIRQ(USB_2_IRQn);
+  NVIC_EnableIRQ(USB_3_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB_3_IRQn);
+  NVIC_DisableIRQ(USB_2_IRQn);
+  NVIC_DisableIRQ(USB_1_IRQn);
+  NVIC_DisableIRQ(USB_0_IRQn);
+}
+
+#elif CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
+      CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USB_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB_IRQn);
+}
+
+#else
+
+#error "No implementation available for dcd_int_enable / dcd_int_disable"
+
+#endif
+
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+  (void) dev_addr;
+
+  // Response with zlp status
+  dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+
+  // DCD can only set address after status for this request is complete
+  // do it at dcd_edpt0_status_complete()
+
+  // Enable SUSPEND interrupt since the bus signal D+/D- are stable now.
+  USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending
+  USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND;
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+  USB->DEVICE.CTRLB.bit.UPRSM = 1;
+}
+
+// disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  USB->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_DETACH;
+}
+
+// connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+   USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH;
+}
+
+/*------------------------------------------------------------------*/
+/* DCD Endpoint port
+ *------------------------------------------------------------------*/
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+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 &&
+      request->bRequest == TUSB_REQ_SET_ADDRESS )
+  {
+    uint8_t const dev_addr = (uint8_t) request->wValue;
+    USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
+  }
+
+  // Just finished status stage, prepare for next setup packet
+  // Note: we may already prepare setup when queueing the control status.
+  // but it has no harm to do it again here
+  prepare_setup();
+}
+
+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);
+
+  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)) {
+      break;
+    }
+    size_value++;
+  }
+
+  // unsupported endpoint size
+  if ( size_value == 7 && tu_edpt_packet_size(desc_edpt) != 1023 ) return false;
+
+  bank->PCKSIZE.bit.SIZE = size_value;
+
+  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
+
+  if ( dir == TUSB_DIR_OUT )
+  {
+    ep->EPCFG.bit.EPTYPE0 = desc_edpt->bmAttributes.xfer + 1;
+    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0 | USB_DEVICE_EPSTATUSCLR_DTGLOUT; // clear stall & dtoggle
+    ep->EPINTENSET.bit.TRCPT0 = true;
+  }else
+  {
+    ep->EPCFG.bit.EPTYPE1 = desc_edpt->bmAttributes.xfer + 1;
+    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1 | USB_DEVICE_EPSTATUSCLR_DTGLIN; // clear stall & dtoggle
+    ep->EPINTENSET.bit.TRCPT1 = true;
+  }
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
+  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
+
+  bank->ADDR.reg = (uint32_t) buffer;
+
+  // A SETUP token can occur immediately after an ZLP Status.
+  // So make sure we have a valid buffer for setup packet.
+  //   Status = ZLP EP0 with direction opposite to one in the dir bit of current setup
+  if ( (epnum == 0) && (buffer == NULL) && (total_bytes == 0) && (dir != tu_edpt_dir(_setup_packet[0])) ) {
+    prepare_setup();
+  }
+
+  if ( dir == TUSB_DIR_OUT )
+  {
+    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;
+  } 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;
+  }
+
+  return true;
+}
+
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
+
+  if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
+    ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1;
+  } else {
+    ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0;
+  }
+}
+
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
+
+  if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
+    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1 | USB_DEVICE_EPSTATUSCLR_DTGLIN;
+  } else {
+    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0 | USB_DEVICE_EPSTATUSCLR_DTGLOUT;
+  }
+}
+
+//--------------------------------------------------------------------+
+// Interrupt Handler
+//--------------------------------------------------------------------+
+void maybe_transfer_complete(void) {
+  uint32_t epints = USB->DEVICE.EPINTSMRY.reg;
+
+  for (uint8_t epnum = 0; epnum < USB_EPT_NUM; epnum++) {
+    if ((epints & (1 << epnum)) == 0) {
+      continue;
+    }
+
+    UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
+    uint32_t epintflag = ep->EPINTFLAG.reg;
+
+    // Handle IN completions
+    if ((epintflag & USB_DEVICE_EPINTFLAG_TRCPT1) != 0) {
+      UsbDeviceDescBank* bank = &sram_registers[epnum][TUSB_DIR_IN];
+      uint16_t const total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
+
+      dcd_event_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, total_transfer_size, XFER_RESULT_SUCCESS, true);
+
+      ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT1;
+    }
+
+    // Handle OUT completions
+    if ((epintflag & USB_DEVICE_EPINTFLAG_TRCPT0) != 0) {
+      UsbDeviceDescBank* bank = &sram_registers[epnum][TUSB_DIR_OUT];
+      uint16_t const total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
+
+      dcd_event_xfer_complete(0, epnum, total_transfer_size, XFER_RESULT_SUCCESS, true);
+
+      ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT0;
+    }
+  }
+}
+
+
+void dcd_int_handler (uint8_t rhport)
+{
+  (void) rhport;
+
+  uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg;
+
+  // Start of Frame
+  if ( int_status & USB_DEVICE_INTFLAG_SOF )
+  {
+    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;
+    dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+  }
+
+  // SAMD doesn't distinguish between Suspend and Disconnect state.
+  // Both condition will cause SUSPEND interrupt triggered.
+  // To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only
+  // enabled when we received SET_ADDRESS request and cleared on Bus Reset
+  if ( int_status & USB_DEVICE_INTFLAG_SUSPEND )
+  {
+    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SUSPEND;
+
+    // Enable wakeup interrupt
+    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending
+    USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP;
+
+    dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+  }
+
+  // Wakeup interrupt is only enabled when we got suspended.
+  // Wakeup interrupt will disable itself
+  if ( int_status & USB_DEVICE_INTFLAG_WAKEUP )
+  {
+    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP;
+
+    // disable wakeup interrupt itself
+    USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP;
+    dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+  }
+
+  // Enable of Reset
+  if ( int_status & USB_DEVICE_INTFLAG_EORST )
+  {
+    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST;
+
+    // Disable both suspend and wakeup interrupt
+    USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND;
+
+    bus_reset();
+    dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+  }
+
+  // Handle SETUP packet
+  if (USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP)
+  {
+    // This copies the data elsewhere so we can reuse the buffer.
+    dcd_event_setup_received(0, _setup_packet, true);
+
+    // Although Setup packet only set RXSTP bit,
+    // TRCPT0 bit could already be set by previous ZLP OUT Status (not handled until now).
+    // Since control status complete event is optional, we can just clear TRCPT0 and skip the status event
+    USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP | USB_DEVICE_EPINTFLAG_TRCPT0;
+  }
+
+  // Handle complete transfer
+  maybe_transfer_complete();
+}
+
+#endif
diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c
new file mode 100644
index 0000000..2e98541
--- /dev/null
+++ b/src/portable/microchip/samg/dcd_samg.c
@@ -0,0 +1,492 @@
+/* 
+ * 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_TUSB_MCU == OPT_MCU_SAMG
+
+#include "sam.h"
+#include "device/dcd.h"
+
+// TODO should support (SAM3S || SAM4S || SAM4E || SAMG55)
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+#define EP_COUNT    6
+
+// Transfer descriptor
+typedef struct
+{
+  uint8_t* buffer;
+  // tu_fifo_t* ff; // TODO support dcd_edpt_xfer_fifo API
+  uint16_t total_len;
+  volatile uint16_t actual_len;
+  uint16_t  epsize;
+} xfer_desc_t;
+
+// Endpoint 0-5, each can only be either OUT or In
+xfer_desc_t _dcd_xfer[EP_COUNT];
+
+void xfer_epsize_set(xfer_desc_t* xfer, uint16_t epsize)
+{
+  xfer->epsize = epsize;
+}
+
+void xfer_begin(xfer_desc_t* xfer, uint8_t * buffer, uint16_t total_bytes)
+{
+  xfer->buffer     = buffer;
+  // xfer->ff         = NULL; // TODO support dcd_edpt_xfer_fifo API
+  xfer->total_len  = total_bytes;
+  xfer->actual_len = 0;
+}
+
+void xfer_end(xfer_desc_t* xfer)
+{
+  xfer->buffer     = NULL;
+  // xfer->ff         = NULL; // TODO support dcd_edpt_xfer_fifo API
+  xfer->total_len  = 0;
+  xfer->actual_len = 0;
+}
+
+uint16_t xfer_packet_len(xfer_desc_t* xfer)
+{
+  // also cover zero-length packet
+  return tu_min16(xfer->total_len - xfer->actual_len, xfer->epsize);
+}
+
+void xfer_packet_done(xfer_desc_t* xfer)
+{
+  uint16_t const xact_len = xfer_packet_len(xfer);
+
+  xfer->buffer += xact_len;
+  xfer->actual_len += xact_len;
+}
+
+//------------- Transaction helpers -------------//
+
+// Write data to EP FIFO, return number of written bytes
+static void xact_ep_write(uint8_t epnum, uint8_t* buffer, uint16_t xact_len)
+{
+  for(uint16_t i=0; i<xact_len; i++)
+  {
+    UDP->UDP_FDR[epnum] = (uint32_t) buffer[i];
+  }
+}
+
+// Read data from EP FIFO
+static void xact_ep_read(uint8_t epnum, uint8_t* buffer, uint16_t xact_len)
+{
+  for(uint16_t i=0; i<xact_len; i++)
+  {
+    buffer[i] = (uint8_t) UDP->UDP_FDR[epnum];
+  }
+}
+
+
+//! Bitmap for all status bits in CSR that are not affected by a value 1.
+#define CSR_NO_EFFECT_1_ALL (UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 | UDP_CSR_STALLSENT | UDP_CSR_RXSETUP | UDP_CSR_TXCOMP)
+
+// Per Specs: CSR need synchronization each write
+static inline void csr_write(uint8_t epnum, uint32_t value)
+{
+  uint32_t const csr = value;
+  UDP->UDP_CSR[epnum] = csr;
+
+  volatile uint32_t nop_count;
+  for (nop_count = 0; nop_count < 20; nop_count ++) __NOP();
+}
+
+// Per Specs: CSR need synchronization each write
+static inline void csr_set(uint8_t epnum, uint32_t mask)
+{
+  csr_write(epnum, UDP->UDP_CSR[epnum] | CSR_NO_EFFECT_1_ALL | mask);
+}
+
+// Per Specs: CSR need synchronization each write
+static inline void csr_clear(uint8_t epnum, uint32_t mask)
+{
+  csr_write(epnum, (UDP->UDP_CSR[epnum] | CSR_NO_EFFECT_1_ALL) & ~mask);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+// Set up endpoint 0, clear all other endpoints
+static void bus_reset(void)
+{
+  tu_memclr(_dcd_xfer, sizeof(_dcd_xfer));
+
+  xfer_epsize_set(&_dcd_xfer[0], CFG_TUD_ENDPOINT0_SIZE);
+
+  // Enable EP0 control
+  csr_write(0, UDP_CSR_EPEDS_Msk);
+
+  // Enable interrupt : EP0, Suspend, Resume, Wakeup
+  UDP->UDP_IER = UDP_IER_EP0INT_Msk | UDP_IER_RXSUSP_Msk | UDP_IER_RXRSM_Msk | UDP_IER_WAKEUP_Msk;
+
+  // Enable transceiver
+  UDP->UDP_TXVC &= ~UDP_TXVC_TXVDIS_Msk;
+}
+
+// Initialize controller to device mode
+void dcd_init (uint8_t rhport)
+{
+  tu_memclr(_dcd_xfer, sizeof(_dcd_xfer));
+  dcd_connect(rhport);
+}
+
+// Enable device interrupt
+void dcd_int_enable (uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(UDP_IRQn);
+}
+
+// Disable device interrupt
+void dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(UDP_IRQn);
+}
+
+// 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;
+
+  // Response with zlp status
+  dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+
+  // DCD can only set address after status for this request is complete.
+  // do it at dcd_edpt0_status_complete()
+}
+
+// Wake up host
+void dcd_remote_wakeup (uint8_t rhport)
+{
+  (void) rhport;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+
+  // Enable pull-up, disable transceiver
+  UDP->UDP_TXVC = UDP_TXVC_PUON | UDP_TXVC_TXVDIS_Msk;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+
+  // disable both pullup and transceiver
+  UDP->UDP_TXVC = UDP_TXVC_TXVDIS_Msk;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+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)
+    {
+      uint8_t const dev_addr = (uint8_t) request->wValue;
+
+      // Enable addressed state
+      UDP->UDP_GLB_STAT |= UDP_GLB_STAT_FADDEN_Msk;
+
+      // Set new address & Function enable bit
+      UDP->UDP_FADDR = UDP_FADDR_FEN_Msk | UDP_FADDR_FADD(dev_addr);
+    }
+    else if (request->bRequest == TUSB_REQ_SET_CONFIGURATION)
+    {
+      // Configured State
+      UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG_Msk;
+    }
+  }
+}
+
+// Configure endpoint's registers according to descriptor
+// SAMG doesn't support a same endpoint number with IN and OUT
+//    e.g EP1 OUT & EP1 IN cannot exist together
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(ep_desc->bEndpointAddress);
+  uint8_t const dir   = tu_edpt_dir(ep_desc->bEndpointAddress);
+
+  // TODO Isochronous is not supported yet
+  TU_VERIFY(ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
+  TU_VERIFY(epnum < EP_COUNT);
+
+  // Must not already enabled
+  TU_ASSERT((UDP->UDP_CSR[epnum] & UDP_CSR_EPEDS_Msk) == 0);
+
+  xfer_epsize_set(&_dcd_xfer[epnum], tu_edpt_packet_size(ep_desc));
+
+  // Configure type and enable EP
+  csr_write(epnum, UDP_CSR_EPEDS_Msk | UDP_CSR_EPTYPE(ep_desc->bmAttributes.xfer + 4*dir));
+
+  // Enable EP Interrupt for IN
+  if (dir == TUSB_DIR_IN) UDP->UDP_IER |= (1 << epnum);
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+// 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 const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  xfer_desc_t* xfer = &_dcd_xfer[epnum];
+  xfer_begin(xfer, buffer, total_bytes);
+
+  if (dir == TUSB_DIR_OUT)
+  {
+    // Enable interrupt when starting OUT transfer
+    if (epnum != 0) UDP->UDP_IER |= (1 << epnum);
+  }
+  else
+  {
+    xact_ep_write(epnum, xfer->buffer, xfer_packet_len(xfer));
+
+    // TX ready for transfer
+    csr_set(epnum, UDP_CSR_TXPKTRDY_Msk);
+  }
+
+  return true;
+}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+  (void) rhport;
+  return true;
+}
+#endif
+
+// Stall endpoint
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  // For EP0 USBD will stall both EP0 Out and In with 0x00 and 0x80
+  // only handle one by skipping 0x80
+  if ( ep_addr == tu_edpt_addr(0, TUSB_DIR_IN_MASK) ) return;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+
+  // Set force stall bit
+  csr_set(epnum, UDP_CSR_FORCESTALL_Msk);
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+
+  // clear stall
+  csr_clear(epnum, UDP_CSR_FORCESTALL_Msk);
+
+  // must also reset EP to clear data toggle
+  UDP->UDP_RST_EP |= (1 << epnum);
+  UDP->UDP_RST_EP &= ~(1 << epnum);
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+  uint32_t const intr_mask   = UDP->UDP_IMR;
+  uint32_t const intr_status = UDP->UDP_ISR & intr_mask;
+
+  // clear interrupt
+  UDP->UDP_ICR = intr_status;
+
+  // Bus reset
+  if (intr_status & UDP_ISR_ENDBUSRES_Msk)
+  {
+    bus_reset();
+    dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+  }
+
+  // SOF
+//  if (intr_status & UDP_ISR_SOFINT_Msk) dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+
+  // Suspend
+  if (intr_status & UDP_ISR_RXSUSP_Msk) dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+
+  // Resume
+  if (intr_status & UDP_ISR_RXRSM_Msk)  dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+
+  // Wakeup
+  if (intr_status & UDP_ISR_WAKEUP_Msk)  dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+
+  //------------- Endpoints -------------//
+
+  if ( intr_status & TU_BIT(0) )
+  {
+    // setup packet
+    if ( UDP->UDP_CSR[0] & UDP_CSR_RXSETUP )
+    {
+      // get setup from FIFO
+      uint8_t setup[8];
+      for(uint8_t i=0; i<sizeof(setup); i++)
+      {
+        setup[i] = (uint8_t) UDP->UDP_FDR[0];
+      }
+
+      // notify usbd
+      dcd_event_setup_received(rhport, setup, true);
+
+      // Set EP direction bit according to DATA stage
+      // MUST only be set before RXSETUP is clear per specs
+      if ( tu_edpt_dir(setup[0]) )
+      {
+        csr_set(0, UDP_CSR_DIR_Msk);
+      }
+      else
+      {
+        csr_clear(0, UDP_CSR_DIR_Msk);
+      }
+
+      // Clear Setup, stall and other on-going transfer bits
+      csr_clear(0, UDP_CSR_RXSETUP_Msk | UDP_CSR_TXPKTRDY_Msk | UDP_CSR_TXCOMP_Msk | UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 | UDP_CSR_STALLSENT_Msk | UDP_CSR_FORCESTALL_Msk);
+    }
+  }
+
+  for(uint8_t epnum = 0; epnum < EP_COUNT; epnum++)
+  {
+    if ( intr_status & TU_BIT(epnum) )
+    {
+      xfer_desc_t* xfer = &_dcd_xfer[epnum];
+
+      //------------- Endpoint IN -------------//
+      if (UDP->UDP_CSR[epnum] & UDP_CSR_TXCOMP_Msk)
+      {
+        xfer_packet_done(xfer);
+
+        uint16_t const xact_len = xfer_packet_len(xfer);
+
+        if (xact_len)
+        {
+          // write to EP fifo
+#if 0 // TODO support dcd_edpt_xfer_fifo
+          if (xfer->ff)
+          {
+            tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len);
+          }
+          else
+#endif
+          {
+            xact_ep_write(epnum, xfer->buffer, xact_len);
+          }
+
+          // TX ready for transfer
+          csr_set(epnum, UDP_CSR_TXPKTRDY_Msk);
+        }else
+        {
+          // xfer is complete
+          dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
+
+          // Required since control OUT can happen right after before stack handle this event
+          xfer_end(xfer);
+        }
+
+        // Clear TX Complete bit
+        csr_clear(epnum, UDP_CSR_TXCOMP_Msk);
+      }
+
+      //------------- Endpoint OUT -------------//
+      // Ping-Pong is a MUST for Bulk/Iso
+      // NOTE: When both Bank0 and Bank1 are both set, there is no way to know which one comes first
+      uint32_t const banks_complete = UDP->UDP_CSR[epnum] & (UDP_CSR_RX_DATA_BK0_Msk | UDP_CSR_RX_DATA_BK1_Msk);
+      if (banks_complete)
+      {
+        uint16_t const xact_len = (uint16_t) ((UDP->UDP_CSR[epnum] & UDP_CSR_RXBYTECNT_Msk) >> UDP_CSR_RXBYTECNT_Pos);
+
+        // Read from EP fifo
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+        if (xfer->ff)
+        {
+          tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len);
+        }
+        else
+#endif
+        {
+          xact_ep_read(epnum, xfer->buffer, xact_len);
+        }
+
+        xfer_packet_done(xfer);
+
+        if ( 0 == xfer_packet_len(xfer) )
+        {
+          // Disable OUT EP interrupt when transfer is complete
+          if (epnum != 0) UDP->UDP_IDR |= (1 << epnum);
+
+          dcd_event_xfer_complete(rhport, epnum, xfer->actual_len, XFER_RESULT_SUCCESS, true);
+          xfer_end(xfer);
+        }
+
+        // Clear DATA Bank0/1 bit
+        csr_clear(epnum, banks_complete);
+      }
+
+      // Stall sent to host
+      if (UDP->UDP_CSR[epnum] & UDP_CSR_STALLSENT_Msk)
+      {
+        csr_clear(epnum, UDP_CSR_STALLSENT_Msk);
+      }
+    }
+  }
+}
+
+#endif
diff --git a/src/portable/microchip/samx7x/common_usb_regs.h b/src/portable/microchip/samx7x/common_usb_regs.h
new file mode 100644
index 0000000..d232f0b
--- /dev/null
+++ b/src/portable/microchip/samx7x/common_usb_regs.h
@@ -0,0 +1,2108 @@
+ /*
+* The MIT License (MIT)
+*
+* Copyright (c) 2019 Microchip Technology Inc.
+* Copyright (c) 2018, hathach (tinyusb.org)
+* Copyright (c) 2021, HiFiPhile
+*
+* 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 _COMMON_USB_REGS_H_
+#define _COMMON_USB_REGS_H_
+
+#if CFG_TUSB_MCU == OPT_MCU_SAMX7X
+
+/* -------- DEVDMANXTDSC : (USBHS Offset: 0x00) (R/W 32) Device DMA Channel Next Descriptor Address Register -------- */
+
+#define DEVDMANXTDSC_OFFSET           (0x00)                                        /**<  (DEVDMANXTDSC) Device DMA Channel Next Descriptor Address Register  Offset */
+
+#define DEVDMANXTDSC_NXT_DSC_ADD_Pos  0                                              /**< (DEVDMANXTDSC) Next Descriptor Address Position */
+#define DEVDMANXTDSC_NXT_DSC_ADD      (_U_(0xFFFFFFFF) << DEVDMANXTDSC_NXT_DSC_ADD_Pos)  /**< (DEVDMANXTDSC) Next Descriptor Address Mask */
+#define DEVDMANXTDSC_Msk              _U_(0xFFFFFFFF)                                /**< (DEVDMANXTDSC) Register Mask  */
+
+
+/* -------- DEVDMAADDRESS : (USBHS Offset: 0x04) (R/W 32) Device DMA Channel Address Register -------- */
+
+#define DEVDMAADDRESS_OFFSET          (0x04)                                        /**<  (DEVDMAADDRESS) Device DMA Channel Address Register  Offset */
+
+#define DEVDMAADDRESS_BUFF_ADD_Pos    0                                              /**< (DEVDMAADDRESS) Buffer Address Position */
+#define DEVDMAADDRESS_BUFF_ADD        (_U_(0xFFFFFFFF) << DEVDMAADDRESS_BUFF_ADD_Pos)  /**< (DEVDMAADDRESS) Buffer Address Mask */
+#define DEVDMAADDRESS_Msk             _U_(0xFFFFFFFF)                                /**< (DEVDMAADDRESS) Register Mask  */
+
+
+/* -------- DEVDMACONTROL : (USBHS Offset: 0x08) (R/W 32) Device DMA Channel Control Register -------- */
+
+#define DEVDMACONTROL_OFFSET          (0x08)                                        /**<  (DEVDMACONTROL) Device DMA Channel Control Register  Offset */
+
+#define DEVDMACONTROL_CHANN_ENB_Pos   0                                              /**< (DEVDMACONTROL) Channel Enable Command Position */
+#define DEVDMACONTROL_CHANN_ENB       (_U_(0x1) << DEVDMACONTROL_CHANN_ENB_Pos)  /**< (DEVDMACONTROL) Channel Enable Command Mask */
+#define DEVDMACONTROL_LDNXT_DSC_Pos   1                                              /**< (DEVDMACONTROL) Load Next Channel Transfer Descriptor Enable Command Position */
+#define DEVDMACONTROL_LDNXT_DSC       (_U_(0x1) << DEVDMACONTROL_LDNXT_DSC_Pos)  /**< (DEVDMACONTROL) Load Next Channel Transfer Descriptor Enable Command Mask */
+#define DEVDMACONTROL_END_TR_EN_Pos   2                                              /**< (DEVDMACONTROL) End of Transfer Enable Control (OUT transfers only) Position */
+#define DEVDMACONTROL_END_TR_EN       (_U_(0x1) << DEVDMACONTROL_END_TR_EN_Pos)  /**< (DEVDMACONTROL) End of Transfer Enable Control (OUT transfers only) Mask */
+#define DEVDMACONTROL_END_B_EN_Pos    3                                              /**< (DEVDMACONTROL) End of Buffer Enable Control Position */
+#define DEVDMACONTROL_END_B_EN        (_U_(0x1) << DEVDMACONTROL_END_B_EN_Pos)  /**< (DEVDMACONTROL) End of Buffer Enable Control Mask */
+#define DEVDMACONTROL_END_TR_IT_Pos   4                                              /**< (DEVDMACONTROL) End of Transfer Interrupt Enable Position */
+#define DEVDMACONTROL_END_TR_IT       (_U_(0x1) << DEVDMACONTROL_END_TR_IT_Pos)  /**< (DEVDMACONTROL) End of Transfer Interrupt Enable Mask */
+#define DEVDMACONTROL_END_BUFFIT_Pos  5                                              /**< (DEVDMACONTROL) End of Buffer Interrupt Enable Position */
+#define DEVDMACONTROL_END_BUFFIT      (_U_(0x1) << DEVDMACONTROL_END_BUFFIT_Pos)  /**< (DEVDMACONTROL) End of Buffer Interrupt Enable Mask */
+#define DEVDMACONTROL_DESC_LD_IT_Pos  6                                              /**< (DEVDMACONTROL) Descriptor Loaded Interrupt Enable Position */
+#define DEVDMACONTROL_DESC_LD_IT      (_U_(0x1) << DEVDMACONTROL_DESC_LD_IT_Pos)  /**< (DEVDMACONTROL) Descriptor Loaded Interrupt Enable Mask */
+#define DEVDMACONTROL_BURST_LCK_Pos   7                                              /**< (DEVDMACONTROL) Burst Lock Enable Position */
+#define DEVDMACONTROL_BURST_LCK       (_U_(0x1) << DEVDMACONTROL_BURST_LCK_Pos)  /**< (DEVDMACONTROL) Burst Lock Enable Mask */
+#define DEVDMACONTROL_BUFF_LENGTH_Pos 16                                             /**< (DEVDMACONTROL) Buffer Byte Length (Write-only) Position */
+#define DEVDMACONTROL_BUFF_LENGTH     (_U_(0xFFFF) << DEVDMACONTROL_BUFF_LENGTH_Pos)  /**< (DEVDMACONTROL) Buffer Byte Length (Write-only) Mask */
+#define DEVDMACONTROL_Msk             _U_(0xFFFF00FF)                                /**< (DEVDMACONTROL) Register Mask  */
+
+
+/* -------- DEVDMASTATUS : (USBHS Offset: 0x0c) (R/W 32) Device DMA Channel Status Register -------- */
+
+#define DEVDMASTATUS_OFFSET           (0x0C)                                        /**<  (DEVDMASTATUS) Device DMA Channel Status Register  Offset */
+
+#define DEVDMASTATUS_CHANN_ENB_Pos    0                                              /**< (DEVDMASTATUS) Channel Enable Status Position */
+#define DEVDMASTATUS_CHANN_ENB        (_U_(0x1) << DEVDMASTATUS_CHANN_ENB_Pos)  /**< (DEVDMASTATUS) Channel Enable Status Mask */
+#define DEVDMASTATUS_CHANN_ACT_Pos    1                                              /**< (DEVDMASTATUS) Channel Active Status Position */
+#define DEVDMASTATUS_CHANN_ACT        (_U_(0x1) << DEVDMASTATUS_CHANN_ACT_Pos)  /**< (DEVDMASTATUS) Channel Active Status Mask */
+#define DEVDMASTATUS_END_TR_ST_Pos    4                                              /**< (DEVDMASTATUS) End of Channel Transfer Status Position */
+#define DEVDMASTATUS_END_TR_ST        (_U_(0x1) << DEVDMASTATUS_END_TR_ST_Pos)  /**< (DEVDMASTATUS) End of Channel Transfer Status Mask */
+#define DEVDMASTATUS_END_BF_ST_Pos    5                                              /**< (DEVDMASTATUS) End of Channel Buffer Status Position */
+#define DEVDMASTATUS_END_BF_ST        (_U_(0x1) << DEVDMASTATUS_END_BF_ST_Pos)  /**< (DEVDMASTATUS) End of Channel Buffer Status Mask */
+#define DEVDMASTATUS_DESC_LDST_Pos    6                                              /**< (DEVDMASTATUS) Descriptor Loaded Status Position */
+#define DEVDMASTATUS_DESC_LDST        (_U_(0x1) << DEVDMASTATUS_DESC_LDST_Pos)  /**< (DEVDMASTATUS) Descriptor Loaded Status Mask */
+#define DEVDMASTATUS_BUFF_COUNT_Pos   16                                             /**< (DEVDMASTATUS) Buffer Byte Count Position */
+#define DEVDMASTATUS_BUFF_COUNT       (_U_(0xFFFF) << DEVDMASTATUS_BUFF_COUNT_Pos)  /**< (DEVDMASTATUS) Buffer Byte Count Mask */
+#define DEVDMASTATUS_Msk              _U_(0xFFFF0073)                                /**< (DEVDMASTATUS) Register Mask  */
+
+
+/* -------- HSTDMANXTDSC : (USBHS Offset: 0x00) (R/W 32) Host DMA Channel Next Descriptor Address Register -------- */
+
+#define HSTDMANXTDSC_OFFSET           (0x00)                                        /**<  (HSTDMANXTDSC) Host DMA Channel Next Descriptor Address Register  Offset */
+
+#define HSTDMANXTDSC_NXT_DSC_ADD_Pos  0                                              /**< (HSTDMANXTDSC) Next Descriptor Address Position */
+#define HSTDMANXTDSC_NXT_DSC_ADD      (_U_(0xFFFFFFFF) << HSTDMANXTDSC_NXT_DSC_ADD_Pos)  /**< (HSTDMANXTDSC) Next Descriptor Address Mask */
+#define HSTDMANXTDSC_Msk              _U_(0xFFFFFFFF)                                /**< (HSTDMANXTDSC) Register Mask  */
+
+
+/* -------- HSTDMAADDRESS : (USBHS Offset: 0x04) (R/W 32) Host DMA Channel Address Register -------- */
+
+#define HSTDMAADDRESS_OFFSET          (0x04)                                        /**<  (HSTDMAADDRESS) Host DMA Channel Address Register  Offset */
+
+#define HSTDMAADDRESS_BUFF_ADD_Pos    0                                              /**< (HSTDMAADDRESS) Buffer Address Position */
+#define HSTDMAADDRESS_BUFF_ADD        (_U_(0xFFFFFFFF) << HSTDMAADDRESS_BUFF_ADD_Pos)  /**< (HSTDMAADDRESS) Buffer Address Mask */
+#define HSTDMAADDRESS_Msk             _U_(0xFFFFFFFF)                                /**< (HSTDMAADDRESS) Register Mask  */
+
+
+/* -------- HSTDMACONTROL : (USBHS Offset: 0x08) (R/W 32) Host DMA Channel Control Register -------- */
+
+#define HSTDMACONTROL_OFFSET          (0x08)                                        /**<  (HSTDMACONTROL) Host DMA Channel Control Register  Offset */
+
+#define HSTDMACONTROL_CHANN_ENB_Pos   0                                              /**< (HSTDMACONTROL) Channel Enable Command Position */
+#define HSTDMACONTROL_CHANN_ENB       (_U_(0x1) << HSTDMACONTROL_CHANN_ENB_Pos)  /**< (HSTDMACONTROL) Channel Enable Command Mask */
+#define HSTDMACONTROL_LDNXT_DSC_Pos   1                                              /**< (HSTDMACONTROL) Load Next Channel Transfer Descriptor Enable Command Position */
+#define HSTDMACONTROL_LDNXT_DSC       (_U_(0x1) << HSTDMACONTROL_LDNXT_DSC_Pos)  /**< (HSTDMACONTROL) Load Next Channel Transfer Descriptor Enable Command Mask */
+#define HSTDMACONTROL_END_TR_EN_Pos   2                                              /**< (HSTDMACONTROL) End of Transfer Enable Control (OUT transfers only) Position */
+#define HSTDMACONTROL_END_TR_EN       (_U_(0x1) << HSTDMACONTROL_END_TR_EN_Pos)  /**< (HSTDMACONTROL) End of Transfer Enable Control (OUT transfers only) Mask */
+#define HSTDMACONTROL_END_B_EN_Pos    3                                              /**< (HSTDMACONTROL) End of Buffer Enable Control Position */
+#define HSTDMACONTROL_END_B_EN        (_U_(0x1) << HSTDMACONTROL_END_B_EN_Pos)  /**< (HSTDMACONTROL) End of Buffer Enable Control Mask */
+#define HSTDMACONTROL_END_TR_IT_Pos   4                                              /**< (HSTDMACONTROL) End of Transfer Interrupt Enable Position */
+#define HSTDMACONTROL_END_TR_IT       (_U_(0x1) << HSTDMACONTROL_END_TR_IT_Pos)  /**< (HSTDMACONTROL) End of Transfer Interrupt Enable Mask */
+#define HSTDMACONTROL_END_BUFFIT_Pos  5                                              /**< (HSTDMACONTROL) End of Buffer Interrupt Enable Position */
+#define HSTDMACONTROL_END_BUFFIT      (_U_(0x1) << HSTDMACONTROL_END_BUFFIT_Pos)  /**< (HSTDMACONTROL) End of Buffer Interrupt Enable Mask */
+#define HSTDMACONTROL_DESC_LD_IT_Pos  6                                              /**< (HSTDMACONTROL) Descriptor Loaded Interrupt Enable Position */
+#define HSTDMACONTROL_DESC_LD_IT      (_U_(0x1) << HSTDMACONTROL_DESC_LD_IT_Pos)  /**< (HSTDMACONTROL) Descriptor Loaded Interrupt Enable Mask */
+#define HSTDMACONTROL_BURST_LCK_Pos   7                                              /**< (HSTDMACONTROL) Burst Lock Enable Position */
+#define HSTDMACONTROL_BURST_LCK       (_U_(0x1) << HSTDMACONTROL_BURST_LCK_Pos)  /**< (HSTDMACONTROL) Burst Lock Enable Mask */
+#define HSTDMACONTROL_BUFF_LENGTH_Pos 16                                             /**< (HSTDMACONTROL) Buffer Byte Length (Write-only) Position */
+#define HSTDMACONTROL_BUFF_LENGTH     (_U_(0xFFFF) << HSTDMACONTROL_BUFF_LENGTH_Pos)  /**< (HSTDMACONTROL) Buffer Byte Length (Write-only) Mask */
+#define HSTDMACONTROL_Msk             _U_(0xFFFF00FF)                                /**< (HSTDMACONTROL) Register Mask  */
+
+
+/* -------- HSTDMASTATUS : (USBHS Offset: 0x0c) (R/W 32) Host DMA Channel Status Register -------- */
+
+#define HSTDMASTATUS_OFFSET           (0x0C)                                        /**<  (HSTDMASTATUS) Host DMA Channel Status Register  Offset */
+
+#define HSTDMASTATUS_CHANN_ENB_Pos    0                                              /**< (HSTDMASTATUS) Channel Enable Status Position */
+#define HSTDMASTATUS_CHANN_ENB        (_U_(0x1) << HSTDMASTATUS_CHANN_ENB_Pos)  /**< (HSTDMASTATUS) Channel Enable Status Mask */
+#define HSTDMASTATUS_CHANN_ACT_Pos    1                                              /**< (HSTDMASTATUS) Channel Active Status Position */
+#define HSTDMASTATUS_CHANN_ACT        (_U_(0x1) << HSTDMASTATUS_CHANN_ACT_Pos)  /**< (HSTDMASTATUS) Channel Active Status Mask */
+#define HSTDMASTATUS_END_TR_ST_Pos    4                                              /**< (HSTDMASTATUS) End of Channel Transfer Status Position */
+#define HSTDMASTATUS_END_TR_ST        (_U_(0x1) << HSTDMASTATUS_END_TR_ST_Pos)  /**< (HSTDMASTATUS) End of Channel Transfer Status Mask */
+#define HSTDMASTATUS_END_BF_ST_Pos    5                                              /**< (HSTDMASTATUS) End of Channel Buffer Status Position */
+#define HSTDMASTATUS_END_BF_ST        (_U_(0x1) << HSTDMASTATUS_END_BF_ST_Pos)  /**< (HSTDMASTATUS) End of Channel Buffer Status Mask */
+#define HSTDMASTATUS_DESC_LDST_Pos    6                                              /**< (HSTDMASTATUS) Descriptor Loaded Status Position */
+#define HSTDMASTATUS_DESC_LDST        (_U_(0x1) << HSTDMASTATUS_DESC_LDST_Pos)  /**< (HSTDMASTATUS) Descriptor Loaded Status Mask */
+#define HSTDMASTATUS_BUFF_COUNT_Pos   16                                             /**< (HSTDMASTATUS) Buffer Byte Count Position */
+#define HSTDMASTATUS_BUFF_COUNT       (_U_(0xFFFF) << HSTDMASTATUS_BUFF_COUNT_Pos)  /**< (HSTDMASTATUS) Buffer Byte Count Mask */
+#define HSTDMASTATUS_Msk              _U_(0xFFFF0073)                                /**< (HSTDMASTATUS) Register Mask  */
+
+
+/* -------- DEVCTRL : (USBHS Offset: 0x00) (R/W 32) Device General Control Register -------- */
+
+#define DEVCTRL_OFFSET                (0x00)                                        /**<  (DEVCTRL) Device General Control Register  Offset */
+
+#define DEVCTRL_UADD_Pos              0                                              /**< (DEVCTRL) USB Address Position */
+#define DEVCTRL_UADD                  (_U_(0x7F) << DEVCTRL_UADD_Pos)          /**< (DEVCTRL) USB Address Mask */
+#define DEVCTRL_ADDEN_Pos             7                                              /**< (DEVCTRL) Address Enable Position */
+#define DEVCTRL_ADDEN                 (_U_(0x1) << DEVCTRL_ADDEN_Pos)          /**< (DEVCTRL) Address Enable Mask */
+#define DEVCTRL_DETACH_Pos            8                                              /**< (DEVCTRL) Detach Position */
+#define DEVCTRL_DETACH                (_U_(0x1) << DEVCTRL_DETACH_Pos)         /**< (DEVCTRL) Detach Mask */
+#define DEVCTRL_RMWKUP_Pos            9                                              /**< (DEVCTRL) Remote Wake-Up Position */
+#define DEVCTRL_RMWKUP                (_U_(0x1) << DEVCTRL_RMWKUP_Pos)         /**< (DEVCTRL) Remote Wake-Up Mask */
+#define DEVCTRL_SPDCONF_Pos           10                                             /**< (DEVCTRL) Mode Configuration Position */
+#define DEVCTRL_SPDCONF               (_U_(0x3) << DEVCTRL_SPDCONF_Pos)        /**< (DEVCTRL) Mode Configuration Mask */
+#define   DEVCTRL_SPDCONF_NORMAL_Val  _U_(0x0)                                       /**< (DEVCTRL) The peripheral starts in Full-speed mode and performs a high-speed reset to switch to High-speed mode if the host is high-speed-capable.  */
+#define   DEVCTRL_SPDCONF_LOW_POWER_Val _U_(0x1)                                       /**< (DEVCTRL) For a better consumption, if high speed is not needed.  */
+#define   DEVCTRL_SPDCONF_HIGH_SPEED_Val _U_(0x2)                                       /**< (DEVCTRL) Forced high speed.  */
+#define   DEVCTRL_SPDCONF_FORCED_FS_Val _U_(0x3)                                       /**< (DEVCTRL) The peripheral remains in Full-speed mode whatever the host speed capability.  */
+#define DEVCTRL_SPDCONF_NORMAL        (DEVCTRL_SPDCONF_NORMAL_Val << DEVCTRL_SPDCONF_Pos)  /**< (DEVCTRL) The peripheral starts in Full-speed mode and performs a high-speed reset to switch to High-speed mode if the host is high-speed-capable. Position  */
+#define DEVCTRL_SPDCONF_LOW_POWER     (DEVCTRL_SPDCONF_LOW_POWER_Val << DEVCTRL_SPDCONF_Pos)  /**< (DEVCTRL) For a better consumption, if high speed is not needed. Position  */
+#define DEVCTRL_SPDCONF_HIGH_SPEED    (DEVCTRL_SPDCONF_HIGH_SPEED_Val << DEVCTRL_SPDCONF_Pos)  /**< (DEVCTRL) Forced high speed. Position  */
+#define DEVCTRL_SPDCONF_FORCED_FS     (DEVCTRL_SPDCONF_FORCED_FS_Val << DEVCTRL_SPDCONF_Pos)  /**< (DEVCTRL) The peripheral remains in Full-speed mode whatever the host speed capability. Position  */
+#define DEVCTRL_LS_Pos                12                                             /**< (DEVCTRL) Low-Speed Mode Force Position */
+#define DEVCTRL_LS                    (_U_(0x1) << DEVCTRL_LS_Pos)             /**< (DEVCTRL) Low-Speed Mode Force Mask */
+#define DEVCTRL_TSTJ_Pos              13                                             /**< (DEVCTRL) Test mode J Position */
+#define DEVCTRL_TSTJ                  (_U_(0x1) << DEVCTRL_TSTJ_Pos)           /**< (DEVCTRL) Test mode J Mask */
+#define DEVCTRL_TSTK_Pos              14                                             /**< (DEVCTRL) Test mode K Position */
+#define DEVCTRL_TSTK                  (_U_(0x1) << DEVCTRL_TSTK_Pos)           /**< (DEVCTRL) Test mode K Mask */
+#define DEVCTRL_TSTPCKT_Pos           15                                             /**< (DEVCTRL) Test packet mode Position */
+#define DEVCTRL_TSTPCKT               (_U_(0x1) << DEVCTRL_TSTPCKT_Pos)        /**< (DEVCTRL) Test packet mode Mask */
+#define DEVCTRL_OPMODE2_Pos           16                                             /**< (DEVCTRL) Specific Operational mode Position */
+#define DEVCTRL_OPMODE2               (_U_(0x1) << DEVCTRL_OPMODE2_Pos)        /**< (DEVCTRL) Specific Operational mode Mask */
+#define DEVCTRL_Msk                   _U_(0x1FFFF)                                   /**< (DEVCTRL) Register Mask  */
+
+#define DEVCTRL_OPMODE_Pos            16                                             /**< (DEVCTRL Position) Specific Operational mode */
+#define DEVCTRL_OPMODE                (_U_(0x1) << DEVCTRL_OPMODE_Pos)         /**< (DEVCTRL Mask) OPMODE */
+
+/* -------- DEVISR : (USBHS Offset: 0x04) (R/ 32) Device Global Interrupt Status Register -------- */
+
+#define DEVISR_OFFSET                 (0x04)                                        /**<  (DEVISR) Device Global Interrupt Status Register  Offset */
+
+#define DEVISR_SUSP_Pos               0                                              /**< (DEVISR) Suspend Interrupt Position */
+#define DEVISR_SUSP                   (_U_(0x1) << DEVISR_SUSP_Pos)            /**< (DEVISR) Suspend Interrupt Mask */
+#define DEVISR_MSOF_Pos               1                                              /**< (DEVISR) Micro Start of Frame Interrupt Position */
+#define DEVISR_MSOF                   (_U_(0x1) << DEVISR_MSOF_Pos)            /**< (DEVISR) Micro Start of Frame Interrupt Mask */
+#define DEVISR_SOF_Pos                2                                              /**< (DEVISR) Start of Frame Interrupt Position */
+#define DEVISR_SOF                    (_U_(0x1) << DEVISR_SOF_Pos)             /**< (DEVISR) Start of Frame Interrupt Mask */
+#define DEVISR_EORST_Pos              3                                              /**< (DEVISR) End of Reset Interrupt Position */
+#define DEVISR_EORST                  (_U_(0x1) << DEVISR_EORST_Pos)           /**< (DEVISR) End of Reset Interrupt Mask */
+#define DEVISR_WAKEUP_Pos             4                                              /**< (DEVISR) Wake-Up Interrupt Position */
+#define DEVISR_WAKEUP                 (_U_(0x1) << DEVISR_WAKEUP_Pos)          /**< (DEVISR) Wake-Up Interrupt Mask */
+#define DEVISR_EORSM_Pos              5                                              /**< (DEVISR) End of Resume Interrupt Position */
+#define DEVISR_EORSM                  (_U_(0x1) << DEVISR_EORSM_Pos)           /**< (DEVISR) End of Resume Interrupt Mask */
+#define DEVISR_UPRSM_Pos              6                                              /**< (DEVISR) Upstream Resume Interrupt Position */
+#define DEVISR_UPRSM                  (_U_(0x1) << DEVISR_UPRSM_Pos)           /**< (DEVISR) Upstream Resume Interrupt Mask */
+#define DEVISR_PEP_0_Pos              12                                             /**< (DEVISR) Endpoint 0 Interrupt Position */
+#define DEVISR_PEP_0                  (_U_(0x1) << DEVISR_PEP_0_Pos)           /**< (DEVISR) Endpoint 0 Interrupt Mask */
+#define DEVISR_PEP_1_Pos              13                                             /**< (DEVISR) Endpoint 1 Interrupt Position */
+#define DEVISR_PEP_1                  (_U_(0x1) << DEVISR_PEP_1_Pos)           /**< (DEVISR) Endpoint 1 Interrupt Mask */
+#define DEVISR_PEP_2_Pos              14                                             /**< (DEVISR) Endpoint 2 Interrupt Position */
+#define DEVISR_PEP_2                  (_U_(0x1) << DEVISR_PEP_2_Pos)           /**< (DEVISR) Endpoint 2 Interrupt Mask */
+#define DEVISR_PEP_3_Pos              15                                             /**< (DEVISR) Endpoint 3 Interrupt Position */
+#define DEVISR_PEP_3                  (_U_(0x1) << DEVISR_PEP_3_Pos)           /**< (DEVISR) Endpoint 3 Interrupt Mask */
+#define DEVISR_PEP_4_Pos              16                                             /**< (DEVISR) Endpoint 4 Interrupt Position */
+#define DEVISR_PEP_4                  (_U_(0x1) << DEVISR_PEP_4_Pos)           /**< (DEVISR) Endpoint 4 Interrupt Mask */
+#define DEVISR_PEP_5_Pos              17                                             /**< (DEVISR) Endpoint 5 Interrupt Position */
+#define DEVISR_PEP_5                  (_U_(0x1) << DEVISR_PEP_5_Pos)           /**< (DEVISR) Endpoint 5 Interrupt Mask */
+#define DEVISR_PEP_6_Pos              18                                             /**< (DEVISR) Endpoint 6 Interrupt Position */
+#define DEVISR_PEP_6                  (_U_(0x1) << DEVISR_PEP_6_Pos)           /**< (DEVISR) Endpoint 6 Interrupt Mask */
+#define DEVISR_PEP_7_Pos              19                                             /**< (DEVISR) Endpoint 7 Interrupt Position */
+#define DEVISR_PEP_7                  (_U_(0x1) << DEVISR_PEP_7_Pos)           /**< (DEVISR) Endpoint 7 Interrupt Mask */
+#define DEVISR_PEP_8_Pos              20                                             /**< (DEVISR) Endpoint 8 Interrupt Position */
+#define DEVISR_PEP_8                  (_U_(0x1) << DEVISR_PEP_8_Pos)           /**< (DEVISR) Endpoint 8 Interrupt Mask */
+#define DEVISR_PEP_9_Pos              21                                             /**< (DEVISR) Endpoint 9 Interrupt Position */
+#define DEVISR_PEP_9                  (_U_(0x1) << DEVISR_PEP_9_Pos)           /**< (DEVISR) Endpoint 9 Interrupt Mask */
+#define DEVISR_DMA_1_Pos              25                                             /**< (DEVISR) DMA Channel 1 Interrupt Position */
+#define DEVISR_DMA_1                  (_U_(0x1) << DEVISR_DMA_1_Pos)           /**< (DEVISR) DMA Channel 1 Interrupt Mask */
+#define DEVISR_DMA_2_Pos              26                                             /**< (DEVISR) DMA Channel 2 Interrupt Position */
+#define DEVISR_DMA_2                  (_U_(0x1) << DEVISR_DMA_2_Pos)           /**< (DEVISR) DMA Channel 2 Interrupt Mask */
+#define DEVISR_DMA_3_Pos              27                                             /**< (DEVISR) DMA Channel 3 Interrupt Position */
+#define DEVISR_DMA_3                  (_U_(0x1) << DEVISR_DMA_3_Pos)           /**< (DEVISR) DMA Channel 3 Interrupt Mask */
+#define DEVISR_DMA_4_Pos              28                                             /**< (DEVISR) DMA Channel 4 Interrupt Position */
+#define DEVISR_DMA_4                  (_U_(0x1) << DEVISR_DMA_4_Pos)           /**< (DEVISR) DMA Channel 4 Interrupt Mask */
+#define DEVISR_DMA_5_Pos              29                                             /**< (DEVISR) DMA Channel 5 Interrupt Position */
+#define DEVISR_DMA_5                  (_U_(0x1) << DEVISR_DMA_5_Pos)           /**< (DEVISR) DMA Channel 5 Interrupt Mask */
+#define DEVISR_DMA_6_Pos              30                                             /**< (DEVISR) DMA Channel 6 Interrupt Position */
+#define DEVISR_DMA_6                  (_U_(0x1) << DEVISR_DMA_6_Pos)           /**< (DEVISR) DMA Channel 6 Interrupt Mask */
+#define DEVISR_DMA_7_Pos              31                                             /**< (DEVISR) DMA Channel 7 Interrupt Position */
+#define DEVISR_DMA_7                  (_U_(0x1) << DEVISR_DMA_7_Pos)           /**< (DEVISR) DMA Channel 7 Interrupt Mask */
+#define DEVISR_Msk                    _U_(0xFE3FF07F)                                /**< (DEVISR) Register Mask  */
+
+#define DEVISR_PEP__Pos               12                                             /**< (DEVISR Position) Endpoint x Interrupt */
+#define DEVISR_PEP_                   (_U_(0x3FF) << DEVISR_PEP__Pos)          /**< (DEVISR Mask) PEP_ */
+#define DEVISR_DMA__Pos               25                                             /**< (DEVISR Position) DMA Channel 7 Interrupt */
+#define DEVISR_DMA_                   (_U_(0x7F) << DEVISR_DMA__Pos)           /**< (DEVISR Mask) DMA_ */
+
+/* -------- DEVICR : (USBHS Offset: 0x08) (/W 32) Device Global Interrupt Clear Register -------- */
+
+#define DEVICR_OFFSET                 (0x08)                                        /**<  (DEVICR) Device Global Interrupt Clear Register  Offset */
+
+#define DEVICR_SUSPC_Pos              0                                              /**< (DEVICR) Suspend Interrupt Clear Position */
+#define DEVICR_SUSPC                  (_U_(0x1) << DEVICR_SUSPC_Pos)           /**< (DEVICR) Suspend Interrupt Clear Mask */
+#define DEVICR_MSOFC_Pos              1                                              /**< (DEVICR) Micro Start of Frame Interrupt Clear Position */
+#define DEVICR_MSOFC                  (_U_(0x1) << DEVICR_MSOFC_Pos)           /**< (DEVICR) Micro Start of Frame Interrupt Clear Mask */
+#define DEVICR_SOFC_Pos               2                                              /**< (DEVICR) Start of Frame Interrupt Clear Position */
+#define DEVICR_SOFC                   (_U_(0x1) << DEVICR_SOFC_Pos)            /**< (DEVICR) Start of Frame Interrupt Clear Mask */
+#define DEVICR_EORSTC_Pos             3                                              /**< (DEVICR) End of Reset Interrupt Clear Position */
+#define DEVICR_EORSTC                 (_U_(0x1) << DEVICR_EORSTC_Pos)          /**< (DEVICR) End of Reset Interrupt Clear Mask */
+#define DEVICR_WAKEUPC_Pos            4                                              /**< (DEVICR) Wake-Up Interrupt Clear Position */
+#define DEVICR_WAKEUPC                (_U_(0x1) << DEVICR_WAKEUPC_Pos)         /**< (DEVICR) Wake-Up Interrupt Clear Mask */
+#define DEVICR_EORSMC_Pos             5                                              /**< (DEVICR) End of Resume Interrupt Clear Position */
+#define DEVICR_EORSMC                 (_U_(0x1) << DEVICR_EORSMC_Pos)          /**< (DEVICR) End of Resume Interrupt Clear Mask */
+#define DEVICR_UPRSMC_Pos             6                                              /**< (DEVICR) Upstream Resume Interrupt Clear Position */
+#define DEVICR_UPRSMC                 (_U_(0x1) << DEVICR_UPRSMC_Pos)          /**< (DEVICR) Upstream Resume Interrupt Clear Mask */
+#define DEVICR_Msk                    _U_(0x7F)                                      /**< (DEVICR) Register Mask  */
+
+
+/* -------- DEVIFR : (USBHS Offset: 0x0c) (/W 32) Device Global Interrupt Set Register -------- */
+
+#define DEVIFR_OFFSET                 (0x0C)                                        /**<  (DEVIFR) Device Global Interrupt Set Register  Offset */
+
+#define DEVIFR_SUSPS_Pos              0                                              /**< (DEVIFR) Suspend Interrupt Set Position */
+#define DEVIFR_SUSPS                  (_U_(0x1) << DEVIFR_SUSPS_Pos)           /**< (DEVIFR) Suspend Interrupt Set Mask */
+#define DEVIFR_MSOFS_Pos              1                                              /**< (DEVIFR) Micro Start of Frame Interrupt Set Position */
+#define DEVIFR_MSOFS                  (_U_(0x1) << DEVIFR_MSOFS_Pos)           /**< (DEVIFR) Micro Start of Frame Interrupt Set Mask */
+#define DEVIFR_SOFS_Pos               2                                              /**< (DEVIFR) Start of Frame Interrupt Set Position */
+#define DEVIFR_SOFS                   (_U_(0x1) << DEVIFR_SOFS_Pos)            /**< (DEVIFR) Start of Frame Interrupt Set Mask */
+#define DEVIFR_EORSTS_Pos             3                                              /**< (DEVIFR) End of Reset Interrupt Set Position */
+#define DEVIFR_EORSTS                 (_U_(0x1) << DEVIFR_EORSTS_Pos)          /**< (DEVIFR) End of Reset Interrupt Set Mask */
+#define DEVIFR_WAKEUPS_Pos            4                                              /**< (DEVIFR) Wake-Up Interrupt Set Position */
+#define DEVIFR_WAKEUPS                (_U_(0x1) << DEVIFR_WAKEUPS_Pos)         /**< (DEVIFR) Wake-Up Interrupt Set Mask */
+#define DEVIFR_EORSMS_Pos             5                                              /**< (DEVIFR) End of Resume Interrupt Set Position */
+#define DEVIFR_EORSMS                 (_U_(0x1) << DEVIFR_EORSMS_Pos)          /**< (DEVIFR) End of Resume Interrupt Set Mask */
+#define DEVIFR_UPRSMS_Pos             6                                              /**< (DEVIFR) Upstream Resume Interrupt Set Position */
+#define DEVIFR_UPRSMS                 (_U_(0x1) << DEVIFR_UPRSMS_Pos)          /**< (DEVIFR) Upstream Resume Interrupt Set Mask */
+#define DEVIFR_DMA_1_Pos              25                                             /**< (DEVIFR) DMA Channel 1 Interrupt Set Position */
+#define DEVIFR_DMA_1                  (_U_(0x1) << DEVIFR_DMA_1_Pos)           /**< (DEVIFR) DMA Channel 1 Interrupt Set Mask */
+#define DEVIFR_DMA_2_Pos              26                                             /**< (DEVIFR) DMA Channel 2 Interrupt Set Position */
+#define DEVIFR_DMA_2                  (_U_(0x1) << DEVIFR_DMA_2_Pos)           /**< (DEVIFR) DMA Channel 2 Interrupt Set Mask */
+#define DEVIFR_DMA_3_Pos              27                                             /**< (DEVIFR) DMA Channel 3 Interrupt Set Position */
+#define DEVIFR_DMA_3                  (_U_(0x1) << DEVIFR_DMA_3_Pos)           /**< (DEVIFR) DMA Channel 3 Interrupt Set Mask */
+#define DEVIFR_DMA_4_Pos              28                                             /**< (DEVIFR) DMA Channel 4 Interrupt Set Position */
+#define DEVIFR_DMA_4                  (_U_(0x1) << DEVIFR_DMA_4_Pos)           /**< (DEVIFR) DMA Channel 4 Interrupt Set Mask */
+#define DEVIFR_DMA_5_Pos              29                                             /**< (DEVIFR) DMA Channel 5 Interrupt Set Position */
+#define DEVIFR_DMA_5                  (_U_(0x1) << DEVIFR_DMA_5_Pos)           /**< (DEVIFR) DMA Channel 5 Interrupt Set Mask */
+#define DEVIFR_DMA_6_Pos              30                                             /**< (DEVIFR) DMA Channel 6 Interrupt Set Position */
+#define DEVIFR_DMA_6                  (_U_(0x1) << DEVIFR_DMA_6_Pos)           /**< (DEVIFR) DMA Channel 6 Interrupt Set Mask */
+#define DEVIFR_DMA_7_Pos              31                                             /**< (DEVIFR) DMA Channel 7 Interrupt Set Position */
+#define DEVIFR_DMA_7                  (_U_(0x1) << DEVIFR_DMA_7_Pos)           /**< (DEVIFR) DMA Channel 7 Interrupt Set Mask */
+#define DEVIFR_Msk                    _U_(0xFE00007F)                                /**< (DEVIFR) Register Mask  */
+
+#define DEVIFR_DMA__Pos               25                                             /**< (DEVIFR Position) DMA Channel 7 Interrupt Set */
+#define DEVIFR_DMA_                   (_U_(0x7F) << DEVIFR_DMA__Pos)           /**< (DEVIFR Mask) DMA_ */
+
+/* -------- DEVIMR : (USBHS Offset: 0x10) (R/ 32) Device Global Interrupt Mask Register -------- */
+
+#define DEVIMR_OFFSET                 (0x10)                                        /**<  (DEVIMR) Device Global Interrupt Mask Register  Offset */
+
+#define DEVIMR_SUSPE_Pos              0                                              /**< (DEVIMR) Suspend Interrupt Mask Position */
+#define DEVIMR_SUSPE                  (_U_(0x1) << DEVIMR_SUSPE_Pos)           /**< (DEVIMR) Suspend Interrupt Mask Mask */
+#define DEVIMR_MSOFE_Pos              1                                              /**< (DEVIMR) Micro Start of Frame Interrupt Mask Position */
+#define DEVIMR_MSOFE                  (_U_(0x1) << DEVIMR_MSOFE_Pos)           /**< (DEVIMR) Micro Start of Frame Interrupt Mask Mask */
+#define DEVIMR_SOFE_Pos               2                                              /**< (DEVIMR) Start of Frame Interrupt Mask Position */
+#define DEVIMR_SOFE                   (_U_(0x1) << DEVIMR_SOFE_Pos)            /**< (DEVIMR) Start of Frame Interrupt Mask Mask */
+#define DEVIMR_EORSTE_Pos             3                                              /**< (DEVIMR) End of Reset Interrupt Mask Position */
+#define DEVIMR_EORSTE                 (_U_(0x1) << DEVIMR_EORSTE_Pos)          /**< (DEVIMR) End of Reset Interrupt Mask Mask */
+#define DEVIMR_WAKEUPE_Pos            4                                              /**< (DEVIMR) Wake-Up Interrupt Mask Position */
+#define DEVIMR_WAKEUPE                (_U_(0x1) << DEVIMR_WAKEUPE_Pos)         /**< (DEVIMR) Wake-Up Interrupt Mask Mask */
+#define DEVIMR_EORSME_Pos             5                                              /**< (DEVIMR) End of Resume Interrupt Mask Position */
+#define DEVIMR_EORSME                 (_U_(0x1) << DEVIMR_EORSME_Pos)          /**< (DEVIMR) End of Resume Interrupt Mask Mask */
+#define DEVIMR_UPRSME_Pos             6                                              /**< (DEVIMR) Upstream Resume Interrupt Mask Position */
+#define DEVIMR_UPRSME                 (_U_(0x1) << DEVIMR_UPRSME_Pos)          /**< (DEVIMR) Upstream Resume Interrupt Mask Mask */
+#define DEVIMR_PEP_0_Pos              12                                             /**< (DEVIMR) Endpoint 0 Interrupt Mask Position */
+#define DEVIMR_PEP_0                  (_U_(0x1) << DEVIMR_PEP_0_Pos)           /**< (DEVIMR) Endpoint 0 Interrupt Mask Mask */
+#define DEVIMR_PEP_1_Pos              13                                             /**< (DEVIMR) Endpoint 1 Interrupt Mask Position */
+#define DEVIMR_PEP_1                  (_U_(0x1) << DEVIMR_PEP_1_Pos)           /**< (DEVIMR) Endpoint 1 Interrupt Mask Mask */
+#define DEVIMR_PEP_2_Pos              14                                             /**< (DEVIMR) Endpoint 2 Interrupt Mask Position */
+#define DEVIMR_PEP_2                  (_U_(0x1) << DEVIMR_PEP_2_Pos)           /**< (DEVIMR) Endpoint 2 Interrupt Mask Mask */
+#define DEVIMR_PEP_3_Pos              15                                             /**< (DEVIMR) Endpoint 3 Interrupt Mask Position */
+#define DEVIMR_PEP_3                  (_U_(0x1) << DEVIMR_PEP_3_Pos)           /**< (DEVIMR) Endpoint 3 Interrupt Mask Mask */
+#define DEVIMR_PEP_4_Pos              16                                             /**< (DEVIMR) Endpoint 4 Interrupt Mask Position */
+#define DEVIMR_PEP_4                  (_U_(0x1) << DEVIMR_PEP_4_Pos)           /**< (DEVIMR) Endpoint 4 Interrupt Mask Mask */
+#define DEVIMR_PEP_5_Pos              17                                             /**< (DEVIMR) Endpoint 5 Interrupt Mask Position */
+#define DEVIMR_PEP_5                  (_U_(0x1) << DEVIMR_PEP_5_Pos)           /**< (DEVIMR) Endpoint 5 Interrupt Mask Mask */
+#define DEVIMR_PEP_6_Pos              18                                             /**< (DEVIMR) Endpoint 6 Interrupt Mask Position */
+#define DEVIMR_PEP_6                  (_U_(0x1) << DEVIMR_PEP_6_Pos)           /**< (DEVIMR) Endpoint 6 Interrupt Mask Mask */
+#define DEVIMR_PEP_7_Pos              19                                             /**< (DEVIMR) Endpoint 7 Interrupt Mask Position */
+#define DEVIMR_PEP_7                  (_U_(0x1) << DEVIMR_PEP_7_Pos)           /**< (DEVIMR) Endpoint 7 Interrupt Mask Mask */
+#define DEVIMR_PEP_8_Pos              20                                             /**< (DEVIMR) Endpoint 8 Interrupt Mask Position */
+#define DEVIMR_PEP_8                  (_U_(0x1) << DEVIMR_PEP_8_Pos)           /**< (DEVIMR) Endpoint 8 Interrupt Mask Mask */
+#define DEVIMR_PEP_9_Pos              21                                             /**< (DEVIMR) Endpoint 9 Interrupt Mask Position */
+#define DEVIMR_PEP_9                  (_U_(0x1) << DEVIMR_PEP_9_Pos)           /**< (DEVIMR) Endpoint 9 Interrupt Mask Mask */
+#define DEVIMR_DMA_1_Pos              25                                             /**< (DEVIMR) DMA Channel 1 Interrupt Mask Position */
+#define DEVIMR_DMA_1                  (_U_(0x1) << DEVIMR_DMA_1_Pos)           /**< (DEVIMR) DMA Channel 1 Interrupt Mask Mask */
+#define DEVIMR_DMA_2_Pos              26                                             /**< (DEVIMR) DMA Channel 2 Interrupt Mask Position */
+#define DEVIMR_DMA_2                  (_U_(0x1) << DEVIMR_DMA_2_Pos)           /**< (DEVIMR) DMA Channel 2 Interrupt Mask Mask */
+#define DEVIMR_DMA_3_Pos              27                                             /**< (DEVIMR) DMA Channel 3 Interrupt Mask Position */
+#define DEVIMR_DMA_3                  (_U_(0x1) << DEVIMR_DMA_3_Pos)           /**< (DEVIMR) DMA Channel 3 Interrupt Mask Mask */
+#define DEVIMR_DMA_4_Pos              28                                             /**< (DEVIMR) DMA Channel 4 Interrupt Mask Position */
+#define DEVIMR_DMA_4                  (_U_(0x1) << DEVIMR_DMA_4_Pos)           /**< (DEVIMR) DMA Channel 4 Interrupt Mask Mask */
+#define DEVIMR_DMA_5_Pos              29                                             /**< (DEVIMR) DMA Channel 5 Interrupt Mask Position */
+#define DEVIMR_DMA_5                  (_U_(0x1) << DEVIMR_DMA_5_Pos)           /**< (DEVIMR) DMA Channel 5 Interrupt Mask Mask */
+#define DEVIMR_DMA_6_Pos              30                                             /**< (DEVIMR) DMA Channel 6 Interrupt Mask Position */
+#define DEVIMR_DMA_6                  (_U_(0x1) << DEVIMR_DMA_6_Pos)           /**< (DEVIMR) DMA Channel 6 Interrupt Mask Mask */
+#define DEVIMR_DMA_7_Pos              31                                             /**< (DEVIMR) DMA Channel 7 Interrupt Mask Position */
+#define DEVIMR_DMA_7                  (_U_(0x1) << DEVIMR_DMA_7_Pos)           /**< (DEVIMR) DMA Channel 7 Interrupt Mask Mask */
+#define DEVIMR_Msk                    _U_(0xFE3FF07F)                                /**< (DEVIMR) Register Mask  */
+
+#define DEVIMR_PEP__Pos               12                                             /**< (DEVIMR Position) Endpoint x Interrupt Mask */
+#define DEVIMR_PEP_                   (_U_(0x3FF) << DEVIMR_PEP__Pos)          /**< (DEVIMR Mask) PEP_ */
+#define DEVIMR_DMA__Pos               25                                             /**< (DEVIMR Position) DMA Channel 7 Interrupt Mask */
+#define DEVIMR_DMA_                   (_U_(0x7F) << DEVIMR_DMA__Pos)           /**< (DEVIMR Mask) DMA_ */
+
+/* -------- DEVIDR : (USBHS Offset: 0x14) (/W 32) Device Global Interrupt Disable Register -------- */
+
+#define DEVIDR_OFFSET                 (0x14)                                        /**<  (DEVIDR) Device Global Interrupt Disable Register  Offset */
+
+#define DEVIDR_SUSPEC_Pos             0                                              /**< (DEVIDR) Suspend Interrupt Disable Position */
+#define DEVIDR_SUSPEC                 (_U_(0x1) << DEVIDR_SUSPEC_Pos)          /**< (DEVIDR) Suspend Interrupt Disable Mask */
+#define DEVIDR_MSOFEC_Pos             1                                              /**< (DEVIDR) Micro Start of Frame Interrupt Disable Position */
+#define DEVIDR_MSOFEC                 (_U_(0x1) << DEVIDR_MSOFEC_Pos)          /**< (DEVIDR) Micro Start of Frame Interrupt Disable Mask */
+#define DEVIDR_SOFEC_Pos              2                                              /**< (DEVIDR) Start of Frame Interrupt Disable Position */
+#define DEVIDR_SOFEC                  (_U_(0x1) << DEVIDR_SOFEC_Pos)           /**< (DEVIDR) Start of Frame Interrupt Disable Mask */
+#define DEVIDR_EORSTEC_Pos            3                                              /**< (DEVIDR) End of Reset Interrupt Disable Position */
+#define DEVIDR_EORSTEC                (_U_(0x1) << DEVIDR_EORSTEC_Pos)         /**< (DEVIDR) End of Reset Interrupt Disable Mask */
+#define DEVIDR_WAKEUPEC_Pos           4                                              /**< (DEVIDR) Wake-Up Interrupt Disable Position */
+#define DEVIDR_WAKEUPEC               (_U_(0x1) << DEVIDR_WAKEUPEC_Pos)        /**< (DEVIDR) Wake-Up Interrupt Disable Mask */
+#define DEVIDR_EORSMEC_Pos            5                                              /**< (DEVIDR) End of Resume Interrupt Disable Position */
+#define DEVIDR_EORSMEC                (_U_(0x1) << DEVIDR_EORSMEC_Pos)         /**< (DEVIDR) End of Resume Interrupt Disable Mask */
+#define DEVIDR_UPRSMEC_Pos            6                                              /**< (DEVIDR) Upstream Resume Interrupt Disable Position */
+#define DEVIDR_UPRSMEC                (_U_(0x1) << DEVIDR_UPRSMEC_Pos)         /**< (DEVIDR) Upstream Resume Interrupt Disable Mask */
+#define DEVIDR_PEP_0_Pos              12                                             /**< (DEVIDR) Endpoint 0 Interrupt Disable Position */
+#define DEVIDR_PEP_0                  (_U_(0x1) << DEVIDR_PEP_0_Pos)           /**< (DEVIDR) Endpoint 0 Interrupt Disable Mask */
+#define DEVIDR_PEP_1_Pos              13                                             /**< (DEVIDR) Endpoint 1 Interrupt Disable Position */
+#define DEVIDR_PEP_1                  (_U_(0x1) << DEVIDR_PEP_1_Pos)           /**< (DEVIDR) Endpoint 1 Interrupt Disable Mask */
+#define DEVIDR_PEP_2_Pos              14                                             /**< (DEVIDR) Endpoint 2 Interrupt Disable Position */
+#define DEVIDR_PEP_2                  (_U_(0x1) << DEVIDR_PEP_2_Pos)           /**< (DEVIDR) Endpoint 2 Interrupt Disable Mask */
+#define DEVIDR_PEP_3_Pos              15                                             /**< (DEVIDR) Endpoint 3 Interrupt Disable Position */
+#define DEVIDR_PEP_3                  (_U_(0x1) << DEVIDR_PEP_3_Pos)           /**< (DEVIDR) Endpoint 3 Interrupt Disable Mask */
+#define DEVIDR_PEP_4_Pos              16                                             /**< (DEVIDR) Endpoint 4 Interrupt Disable Position */
+#define DEVIDR_PEP_4                  (_U_(0x1) << DEVIDR_PEP_4_Pos)           /**< (DEVIDR) Endpoint 4 Interrupt Disable Mask */
+#define DEVIDR_PEP_5_Pos              17                                             /**< (DEVIDR) Endpoint 5 Interrupt Disable Position */
+#define DEVIDR_PEP_5                  (_U_(0x1) << DEVIDR_PEP_5_Pos)           /**< (DEVIDR) Endpoint 5 Interrupt Disable Mask */
+#define DEVIDR_PEP_6_Pos              18                                             /**< (DEVIDR) Endpoint 6 Interrupt Disable Position */
+#define DEVIDR_PEP_6                  (_U_(0x1) << DEVIDR_PEP_6_Pos)           /**< (DEVIDR) Endpoint 6 Interrupt Disable Mask */
+#define DEVIDR_PEP_7_Pos              19                                             /**< (DEVIDR) Endpoint 7 Interrupt Disable Position */
+#define DEVIDR_PEP_7                  (_U_(0x1) << DEVIDR_PEP_7_Pos)           /**< (DEVIDR) Endpoint 7 Interrupt Disable Mask */
+#define DEVIDR_PEP_8_Pos              20                                             /**< (DEVIDR) Endpoint 8 Interrupt Disable Position */
+#define DEVIDR_PEP_8                  (_U_(0x1) << DEVIDR_PEP_8_Pos)           /**< (DEVIDR) Endpoint 8 Interrupt Disable Mask */
+#define DEVIDR_PEP_9_Pos              21                                             /**< (DEVIDR) Endpoint 9 Interrupt Disable Position */
+#define DEVIDR_PEP_9                  (_U_(0x1) << DEVIDR_PEP_9_Pos)           /**< (DEVIDR) Endpoint 9 Interrupt Disable Mask */
+#define DEVIDR_DMA_1_Pos              25                                             /**< (DEVIDR) DMA Channel 1 Interrupt Disable Position */
+#define DEVIDR_DMA_1                  (_U_(0x1) << DEVIDR_DMA_1_Pos)           /**< (DEVIDR) DMA Channel 1 Interrupt Disable Mask */
+#define DEVIDR_DMA_2_Pos              26                                             /**< (DEVIDR) DMA Channel 2 Interrupt Disable Position */
+#define DEVIDR_DMA_2                  (_U_(0x1) << DEVIDR_DMA_2_Pos)           /**< (DEVIDR) DMA Channel 2 Interrupt Disable Mask */
+#define DEVIDR_DMA_3_Pos              27                                             /**< (DEVIDR) DMA Channel 3 Interrupt Disable Position */
+#define DEVIDR_DMA_3                  (_U_(0x1) << DEVIDR_DMA_3_Pos)           /**< (DEVIDR) DMA Channel 3 Interrupt Disable Mask */
+#define DEVIDR_DMA_4_Pos              28                                             /**< (DEVIDR) DMA Channel 4 Interrupt Disable Position */
+#define DEVIDR_DMA_4                  (_U_(0x1) << DEVIDR_DMA_4_Pos)           /**< (DEVIDR) DMA Channel 4 Interrupt Disable Mask */
+#define DEVIDR_DMA_5_Pos              29                                             /**< (DEVIDR) DMA Channel 5 Interrupt Disable Position */
+#define DEVIDR_DMA_5                  (_U_(0x1) << DEVIDR_DMA_5_Pos)           /**< (DEVIDR) DMA Channel 5 Interrupt Disable Mask */
+#define DEVIDR_DMA_6_Pos              30                                             /**< (DEVIDR) DMA Channel 6 Interrupt Disable Position */
+#define DEVIDR_DMA_6                  (_U_(0x1) << DEVIDR_DMA_6_Pos)           /**< (DEVIDR) DMA Channel 6 Interrupt Disable Mask */
+#define DEVIDR_DMA_7_Pos              31                                             /**< (DEVIDR) DMA Channel 7 Interrupt Disable Position */
+#define DEVIDR_DMA_7                  (_U_(0x1) << DEVIDR_DMA_7_Pos)           /**< (DEVIDR) DMA Channel 7 Interrupt Disable Mask */
+#define DEVIDR_Msk                    _U_(0xFE3FF07F)                                /**< (DEVIDR) Register Mask  */
+
+#define DEVIDR_PEP__Pos               12                                             /**< (DEVIDR Position) Endpoint x Interrupt Disable */
+#define DEVIDR_PEP_                   (_U_(0x3FF) << DEVIDR_PEP__Pos)          /**< (DEVIDR Mask) PEP_ */
+#define DEVIDR_DMA__Pos               25                                             /**< (DEVIDR Position) DMA Channel 7 Interrupt Disable */
+#define DEVIDR_DMA_                   (_U_(0x7F) << DEVIDR_DMA__Pos)           /**< (DEVIDR Mask) DMA_ */
+
+/* -------- DEVIER : (USBHS Offset: 0x18) (/W 32) Device Global Interrupt Enable Register -------- */
+
+#define DEVIER_OFFSET                 (0x18)                                        /**<  (DEVIER) Device Global Interrupt Enable Register  Offset */
+
+#define DEVIER_SUSPES_Pos             0                                              /**< (DEVIER) Suspend Interrupt Enable Position */
+#define DEVIER_SUSPES                 (_U_(0x1) << DEVIER_SUSPES_Pos)          /**< (DEVIER) Suspend Interrupt Enable Mask */
+#define DEVIER_MSOFES_Pos             1                                              /**< (DEVIER) Micro Start of Frame Interrupt Enable Position */
+#define DEVIER_MSOFES                 (_U_(0x1) << DEVIER_MSOFES_Pos)          /**< (DEVIER) Micro Start of Frame Interrupt Enable Mask */
+#define DEVIER_SOFES_Pos              2                                              /**< (DEVIER) Start of Frame Interrupt Enable Position */
+#define DEVIER_SOFES                  (_U_(0x1) << DEVIER_SOFES_Pos)           /**< (DEVIER) Start of Frame Interrupt Enable Mask */
+#define DEVIER_EORSTES_Pos            3                                              /**< (DEVIER) End of Reset Interrupt Enable Position */
+#define DEVIER_EORSTES                (_U_(0x1) << DEVIER_EORSTES_Pos)         /**< (DEVIER) End of Reset Interrupt Enable Mask */
+#define DEVIER_WAKEUPES_Pos           4                                              /**< (DEVIER) Wake-Up Interrupt Enable Position */
+#define DEVIER_WAKEUPES               (_U_(0x1) << DEVIER_WAKEUPES_Pos)        /**< (DEVIER) Wake-Up Interrupt Enable Mask */
+#define DEVIER_EORSMES_Pos            5                                              /**< (DEVIER) End of Resume Interrupt Enable Position */
+#define DEVIER_EORSMES                (_U_(0x1) << DEVIER_EORSMES_Pos)         /**< (DEVIER) End of Resume Interrupt Enable Mask */
+#define DEVIER_UPRSMES_Pos            6                                              /**< (DEVIER) Upstream Resume Interrupt Enable Position */
+#define DEVIER_UPRSMES                (_U_(0x1) << DEVIER_UPRSMES_Pos)         /**< (DEVIER) Upstream Resume Interrupt Enable Mask */
+#define DEVIER_PEP_0_Pos              12                                             /**< (DEVIER) Endpoint 0 Interrupt Enable Position */
+#define DEVIER_PEP_0                  (_U_(0x1) << DEVIER_PEP_0_Pos)           /**< (DEVIER) Endpoint 0 Interrupt Enable Mask */
+#define DEVIER_PEP_1_Pos              13                                             /**< (DEVIER) Endpoint 1 Interrupt Enable Position */
+#define DEVIER_PEP_1                  (_U_(0x1) << DEVIER_PEP_1_Pos)           /**< (DEVIER) Endpoint 1 Interrupt Enable Mask */
+#define DEVIER_PEP_2_Pos              14                                             /**< (DEVIER) Endpoint 2 Interrupt Enable Position */
+#define DEVIER_PEP_2                  (_U_(0x1) << DEVIER_PEP_2_Pos)           /**< (DEVIER) Endpoint 2 Interrupt Enable Mask */
+#define DEVIER_PEP_3_Pos              15                                             /**< (DEVIER) Endpoint 3 Interrupt Enable Position */
+#define DEVIER_PEP_3                  (_U_(0x1) << DEVIER_PEP_3_Pos)           /**< (DEVIER) Endpoint 3 Interrupt Enable Mask */
+#define DEVIER_PEP_4_Pos              16                                             /**< (DEVIER) Endpoint 4 Interrupt Enable Position */
+#define DEVIER_PEP_4                  (_U_(0x1) << DEVIER_PEP_4_Pos)           /**< (DEVIER) Endpoint 4 Interrupt Enable Mask */
+#define DEVIER_PEP_5_Pos              17                                             /**< (DEVIER) Endpoint 5 Interrupt Enable Position */
+#define DEVIER_PEP_5                  (_U_(0x1) << DEVIER_PEP_5_Pos)           /**< (DEVIER) Endpoint 5 Interrupt Enable Mask */
+#define DEVIER_PEP_6_Pos              18                                             /**< (DEVIER) Endpoint 6 Interrupt Enable Position */
+#define DEVIER_PEP_6                  (_U_(0x1) << DEVIER_PEP_6_Pos)           /**< (DEVIER) Endpoint 6 Interrupt Enable Mask */
+#define DEVIER_PEP_7_Pos              19                                             /**< (DEVIER) Endpoint 7 Interrupt Enable Position */
+#define DEVIER_PEP_7                  (_U_(0x1) << DEVIER_PEP_7_Pos)           /**< (DEVIER) Endpoint 7 Interrupt Enable Mask */
+#define DEVIER_PEP_8_Pos              20                                             /**< (DEVIER) Endpoint 8 Interrupt Enable Position */
+#define DEVIER_PEP_8                  (_U_(0x1) << DEVIER_PEP_8_Pos)           /**< (DEVIER) Endpoint 8 Interrupt Enable Mask */
+#define DEVIER_PEP_9_Pos              21                                             /**< (DEVIER) Endpoint 9 Interrupt Enable Position */
+#define DEVIER_PEP_9                  (_U_(0x1) << DEVIER_PEP_9_Pos)           /**< (DEVIER) Endpoint 9 Interrupt Enable Mask */
+#define DEVIER_DMA_1_Pos              25                                             /**< (DEVIER) DMA Channel 1 Interrupt Enable Position */
+#define DEVIER_DMA_1                  (_U_(0x1) << DEVIER_DMA_1_Pos)           /**< (DEVIER) DMA Channel 1 Interrupt Enable Mask */
+#define DEVIER_DMA_2_Pos              26                                             /**< (DEVIER) DMA Channel 2 Interrupt Enable Position */
+#define DEVIER_DMA_2                  (_U_(0x1) << DEVIER_DMA_2_Pos)           /**< (DEVIER) DMA Channel 2 Interrupt Enable Mask */
+#define DEVIER_DMA_3_Pos              27                                             /**< (DEVIER) DMA Channel 3 Interrupt Enable Position */
+#define DEVIER_DMA_3                  (_U_(0x1) << DEVIER_DMA_3_Pos)           /**< (DEVIER) DMA Channel 3 Interrupt Enable Mask */
+#define DEVIER_DMA_4_Pos              28                                             /**< (DEVIER) DMA Channel 4 Interrupt Enable Position */
+#define DEVIER_DMA_4                  (_U_(0x1) << DEVIER_DMA_4_Pos)           /**< (DEVIER) DMA Channel 4 Interrupt Enable Mask */
+#define DEVIER_DMA_5_Pos              29                                             /**< (DEVIER) DMA Channel 5 Interrupt Enable Position */
+#define DEVIER_DMA_5                  (_U_(0x1) << DEVIER_DMA_5_Pos)           /**< (DEVIER) DMA Channel 5 Interrupt Enable Mask */
+#define DEVIER_DMA_6_Pos              30                                             /**< (DEVIER) DMA Channel 6 Interrupt Enable Position */
+#define DEVIER_DMA_6                  (_U_(0x1) << DEVIER_DMA_6_Pos)           /**< (DEVIER) DMA Channel 6 Interrupt Enable Mask */
+#define DEVIER_DMA_7_Pos              31                                             /**< (DEVIER) DMA Channel 7 Interrupt Enable Position */
+#define DEVIER_DMA_7                  (_U_(0x1) << DEVIER_DMA_7_Pos)           /**< (DEVIER) DMA Channel 7 Interrupt Enable Mask */
+#define DEVIER_Msk                    _U_(0xFE3FF07F)                                /**< (DEVIER) Register Mask  */
+
+#define DEVIER_PEP__Pos               12                                             /**< (DEVIER Position) Endpoint x Interrupt Enable */
+#define DEVIER_PEP_                   (_U_(0x3FF) << DEVIER_PEP__Pos)          /**< (DEVIER Mask) PEP_ */
+#define DEVIER_DMA__Pos               25                                             /**< (DEVIER Position) DMA Channel 7 Interrupt Enable */
+#define DEVIER_DMA_                   (_U_(0x7F) << DEVIER_DMA__Pos)           /**< (DEVIER Mask) DMA_ */
+
+/* -------- DEVEPT : (USBHS Offset: 0x1c) (R/W 32) Device Endpoint Register -------- */
+
+#define DEVEPT_OFFSET                 (0x1C)                                        /**<  (DEVEPT) Device Endpoint Register  Offset */
+
+#define DEVEPT_EPEN0_Pos              0                                              /**< (DEVEPT) Endpoint 0 Enable Position */
+#define DEVEPT_EPEN0                  (_U_(0x1) << DEVEPT_EPEN0_Pos)           /**< (DEVEPT) Endpoint 0 Enable Mask */
+#define DEVEPT_EPEN1_Pos              1                                              /**< (DEVEPT) Endpoint 1 Enable Position */
+#define DEVEPT_EPEN1                  (_U_(0x1) << DEVEPT_EPEN1_Pos)           /**< (DEVEPT) Endpoint 1 Enable Mask */
+#define DEVEPT_EPEN2_Pos              2                                              /**< (DEVEPT) Endpoint 2 Enable Position */
+#define DEVEPT_EPEN2                  (_U_(0x1) << DEVEPT_EPEN2_Pos)           /**< (DEVEPT) Endpoint 2 Enable Mask */
+#define DEVEPT_EPEN3_Pos              3                                              /**< (DEVEPT) Endpoint 3 Enable Position */
+#define DEVEPT_EPEN3                  (_U_(0x1) << DEVEPT_EPEN3_Pos)           /**< (DEVEPT) Endpoint 3 Enable Mask */
+#define DEVEPT_EPEN4_Pos              4                                              /**< (DEVEPT) Endpoint 4 Enable Position */
+#define DEVEPT_EPEN4                  (_U_(0x1) << DEVEPT_EPEN4_Pos)           /**< (DEVEPT) Endpoint 4 Enable Mask */
+#define DEVEPT_EPEN5_Pos              5                                              /**< (DEVEPT) Endpoint 5 Enable Position */
+#define DEVEPT_EPEN5                  (_U_(0x1) << DEVEPT_EPEN5_Pos)           /**< (DEVEPT) Endpoint 5 Enable Mask */
+#define DEVEPT_EPEN6_Pos              6                                              /**< (DEVEPT) Endpoint 6 Enable Position */
+#define DEVEPT_EPEN6                  (_U_(0x1) << DEVEPT_EPEN6_Pos)           /**< (DEVEPT) Endpoint 6 Enable Mask */
+#define DEVEPT_EPEN7_Pos              7                                              /**< (DEVEPT) Endpoint 7 Enable Position */
+#define DEVEPT_EPEN7                  (_U_(0x1) << DEVEPT_EPEN7_Pos)           /**< (DEVEPT) Endpoint 7 Enable Mask */
+#define DEVEPT_EPEN8_Pos              8                                              /**< (DEVEPT) Endpoint 8 Enable Position */
+#define DEVEPT_EPEN8                  (_U_(0x1) << DEVEPT_EPEN8_Pos)           /**< (DEVEPT) Endpoint 8 Enable Mask */
+#define DEVEPT_EPEN9_Pos              9                                              /**< (DEVEPT) Endpoint 9 Enable Position */
+#define DEVEPT_EPEN9                  (_U_(0x1) << DEVEPT_EPEN9_Pos)           /**< (DEVEPT) Endpoint 9 Enable Mask */
+#define DEVEPT_EPRST0_Pos             16                                             /**< (DEVEPT) Endpoint 0 Reset Position */
+#define DEVEPT_EPRST0                 (_U_(0x1) << DEVEPT_EPRST0_Pos)          /**< (DEVEPT) Endpoint 0 Reset Mask */
+#define DEVEPT_EPRST1_Pos             17                                             /**< (DEVEPT) Endpoint 1 Reset Position */
+#define DEVEPT_EPRST1                 (_U_(0x1) << DEVEPT_EPRST1_Pos)          /**< (DEVEPT) Endpoint 1 Reset Mask */
+#define DEVEPT_EPRST2_Pos             18                                             /**< (DEVEPT) Endpoint 2 Reset Position */
+#define DEVEPT_EPRST2                 (_U_(0x1) << DEVEPT_EPRST2_Pos)          /**< (DEVEPT) Endpoint 2 Reset Mask */
+#define DEVEPT_EPRST3_Pos             19                                             /**< (DEVEPT) Endpoint 3 Reset Position */
+#define DEVEPT_EPRST3                 (_U_(0x1) << DEVEPT_EPRST3_Pos)          /**< (DEVEPT) Endpoint 3 Reset Mask */
+#define DEVEPT_EPRST4_Pos             20                                             /**< (DEVEPT) Endpoint 4 Reset Position */
+#define DEVEPT_EPRST4                 (_U_(0x1) << DEVEPT_EPRST4_Pos)          /**< (DEVEPT) Endpoint 4 Reset Mask */
+#define DEVEPT_EPRST5_Pos             21                                             /**< (DEVEPT) Endpoint 5 Reset Position */
+#define DEVEPT_EPRST5                 (_U_(0x1) << DEVEPT_EPRST5_Pos)          /**< (DEVEPT) Endpoint 5 Reset Mask */
+#define DEVEPT_EPRST6_Pos             22                                             /**< (DEVEPT) Endpoint 6 Reset Position */
+#define DEVEPT_EPRST6                 (_U_(0x1) << DEVEPT_EPRST6_Pos)          /**< (DEVEPT) Endpoint 6 Reset Mask */
+#define DEVEPT_EPRST7_Pos             23                                             /**< (DEVEPT) Endpoint 7 Reset Position */
+#define DEVEPT_EPRST7                 (_U_(0x1) << DEVEPT_EPRST7_Pos)          /**< (DEVEPT) Endpoint 7 Reset Mask */
+#define DEVEPT_EPRST8_Pos             24                                             /**< (DEVEPT) Endpoint 8 Reset Position */
+#define DEVEPT_EPRST8                 (_U_(0x1) << DEVEPT_EPRST8_Pos)          /**< (DEVEPT) Endpoint 8 Reset Mask */
+#define DEVEPT_EPRST9_Pos             25                                             /**< (DEVEPT) Endpoint 9 Reset Position */
+#define DEVEPT_EPRST9                 (_U_(0x1) << DEVEPT_EPRST9_Pos)          /**< (DEVEPT) Endpoint 9 Reset Mask */
+#define DEVEPT_Msk                    _U_(0x3FF03FF)                                 /**< (DEVEPT) Register Mask  */
+
+#define DEVEPT_EPEN_Pos               0                                              /**< (DEVEPT Position) Endpoint x Enable */
+#define DEVEPT_EPEN                   (_U_(0x3FF) << DEVEPT_EPEN_Pos)          /**< (DEVEPT Mask) EPEN */
+#define DEVEPT_EPRST_Pos              16                                             /**< (DEVEPT Position) Endpoint 9 Reset */
+#define DEVEPT_EPRST                  (_U_(0x3FF) << DEVEPT_EPRST_Pos)         /**< (DEVEPT Mask) EPRST */
+
+/* -------- DEVFNUM : (USBHS Offset: 0x20) (R/ 32) Device Frame Number Register -------- */
+
+#define DEVFNUM_OFFSET                (0x20)                                        /**<  (DEVFNUM) Device Frame Number Register  Offset */
+
+#define DEVFNUM_MFNUM_Pos             0                                              /**< (DEVFNUM) Micro Frame Number Position */
+#define DEVFNUM_MFNUM                 (_U_(0x7) << DEVFNUM_MFNUM_Pos)          /**< (DEVFNUM) Micro Frame Number Mask */
+#define DEVFNUM_FNUM_Pos              3                                              /**< (DEVFNUM) Frame Number Position */
+#define DEVFNUM_FNUM                  (_U_(0x7FF) << DEVFNUM_FNUM_Pos)         /**< (DEVFNUM) Frame Number Mask */
+#define DEVFNUM_FNCERR_Pos            15                                             /**< (DEVFNUM) Frame Number CRC Error Position */
+#define DEVFNUM_FNCERR                (_U_(0x1) << DEVFNUM_FNCERR_Pos)         /**< (DEVFNUM) Frame Number CRC Error Mask */
+#define DEVFNUM_Msk                   _U_(0xBFFF)                                    /**< (DEVFNUM) Register Mask  */
+
+
+/* -------- DEVEPTCFG : (USBHS Offset: 0x100) (R/W 32) Device Endpoint Configuration Register -------- */
+
+#define DEVEPTCFG_OFFSET              (0x100)                                       /**<  (DEVEPTCFG) Device Endpoint Configuration Register  Offset */
+
+#define DEVEPTCFG_ALLOC_Pos           1                                              /**< (DEVEPTCFG) Endpoint Memory Allocate Position */
+#define DEVEPTCFG_ALLOC               (_U_(0x1) << DEVEPTCFG_ALLOC_Pos)        /**< (DEVEPTCFG) Endpoint Memory Allocate Mask */
+#define DEVEPTCFG_EPBK_Pos            2                                              /**< (DEVEPTCFG) Endpoint Banks Position */
+#define DEVEPTCFG_EPBK                (_U_(0x3) << DEVEPTCFG_EPBK_Pos)         /**< (DEVEPTCFG) Endpoint Banks Mask */
+#define   DEVEPTCFG_EPBK_1_BANK_Val   _U_(0x0)                                       /**< (DEVEPTCFG) Single-bank endpoint  */
+#define   DEVEPTCFG_EPBK_2_BANK_Val   _U_(0x1)                                       /**< (DEVEPTCFG) Double-bank endpoint  */
+#define   DEVEPTCFG_EPBK_3_BANK_Val   _U_(0x2)                                       /**< (DEVEPTCFG) Triple-bank endpoint  */
+#define DEVEPTCFG_EPBK_1_BANK         (DEVEPTCFG_EPBK_1_BANK_Val << DEVEPTCFG_EPBK_Pos)  /**< (DEVEPTCFG) Single-bank endpoint Position  */
+#define DEVEPTCFG_EPBK_2_BANK         (DEVEPTCFG_EPBK_2_BANK_Val << DEVEPTCFG_EPBK_Pos)  /**< (DEVEPTCFG) Double-bank endpoint Position  */
+#define DEVEPTCFG_EPBK_3_BANK         (DEVEPTCFG_EPBK_3_BANK_Val << DEVEPTCFG_EPBK_Pos)  /**< (DEVEPTCFG) Triple-bank endpoint Position  */
+#define DEVEPTCFG_EPSIZE_Pos          4                                              /**< (DEVEPTCFG) Endpoint Size Position */
+#define DEVEPTCFG_EPSIZE              (_U_(0x7) << DEVEPTCFG_EPSIZE_Pos)       /**< (DEVEPTCFG) Endpoint Size Mask */
+#define   DEVEPTCFG_EPSIZE_8_BYTE_Val _U_(0x0)                                       /**< (DEVEPTCFG) 8 bytes  */
+#define   DEVEPTCFG_EPSIZE_16_BYTE_Val _U_(0x1)                                       /**< (DEVEPTCFG) 16 bytes  */
+#define   DEVEPTCFG_EPSIZE_32_BYTE_Val _U_(0x2)                                       /**< (DEVEPTCFG) 32 bytes  */
+#define   DEVEPTCFG_EPSIZE_64_BYTE_Val _U_(0x3)                                       /**< (DEVEPTCFG) 64 bytes  */
+#define   DEVEPTCFG_EPSIZE_128_BYTE_Val _U_(0x4)                                       /**< (DEVEPTCFG) 128 bytes  */
+#define   DEVEPTCFG_EPSIZE_256_BYTE_Val _U_(0x5)                                       /**< (DEVEPTCFG) 256 bytes  */
+#define   DEVEPTCFG_EPSIZE_512_BYTE_Val _U_(0x6)                                       /**< (DEVEPTCFG) 512 bytes  */
+#define   DEVEPTCFG_EPSIZE_1024_BYTE_Val _U_(0x7)                                       /**< (DEVEPTCFG) 1024 bytes  */
+#define DEVEPTCFG_EPSIZE_8_BYTE       (DEVEPTCFG_EPSIZE_8_BYTE_Val << DEVEPTCFG_EPSIZE_Pos)  /**< (DEVEPTCFG) 8 bytes Position  */
+#define DEVEPTCFG_EPSIZE_16_BYTE      (DEVEPTCFG_EPSIZE_16_BYTE_Val << DEVEPTCFG_EPSIZE_Pos)  /**< (DEVEPTCFG) 16 bytes Position  */
+#define DEVEPTCFG_EPSIZE_32_BYTE      (DEVEPTCFG_EPSIZE_32_BYTE_Val << DEVEPTCFG_EPSIZE_Pos)  /**< (DEVEPTCFG) 32 bytes Position  */
+#define DEVEPTCFG_EPSIZE_64_BYTE      (DEVEPTCFG_EPSIZE_64_BYTE_Val << DEVEPTCFG_EPSIZE_Pos)  /**< (DEVEPTCFG) 64 bytes Position  */
+#define DEVEPTCFG_EPSIZE_128_BYTE     (DEVEPTCFG_EPSIZE_128_BYTE_Val << DEVEPTCFG_EPSIZE_Pos)  /**< (DEVEPTCFG) 128 bytes Position  */
+#define DEVEPTCFG_EPSIZE_256_BYTE     (DEVEPTCFG_EPSIZE_256_BYTE_Val << DEVEPTCFG_EPSIZE_Pos)  /**< (DEVEPTCFG) 256 bytes Position  */
+#define DEVEPTCFG_EPSIZE_512_BYTE     (DEVEPTCFG_EPSIZE_512_BYTE_Val << DEVEPTCFG_EPSIZE_Pos)  /**< (DEVEPTCFG) 512 bytes Position  */
+#define DEVEPTCFG_EPSIZE_1024_BYTE    (DEVEPTCFG_EPSIZE_1024_BYTE_Val << DEVEPTCFG_EPSIZE_Pos)  /**< (DEVEPTCFG) 1024 bytes Position  */
+#define DEVEPTCFG_EPDIR_Pos           8                                              /**< (DEVEPTCFG) Endpoint Direction Position */
+#define DEVEPTCFG_EPDIR               (_U_(0x1) << DEVEPTCFG_EPDIR_Pos)        /**< (DEVEPTCFG) Endpoint Direction Mask */
+#define   DEVEPTCFG_EPDIR_OUT_Val     _U_(0x0)                                       /**< (DEVEPTCFG) The endpoint direction is OUT.  */
+#define   DEVEPTCFG_EPDIR_IN_Val      _U_(0x1)                                       /**< (DEVEPTCFG) The endpoint direction is IN (nor for control endpoints).  */
+#define DEVEPTCFG_EPDIR_OUT           (DEVEPTCFG_EPDIR_OUT_Val << DEVEPTCFG_EPDIR_Pos)  /**< (DEVEPTCFG) The endpoint direction is OUT. Position  */
+#define DEVEPTCFG_EPDIR_IN            (DEVEPTCFG_EPDIR_IN_Val << DEVEPTCFG_EPDIR_Pos)  /**< (DEVEPTCFG) The endpoint direction is IN (nor for control endpoints). Position  */
+#define DEVEPTCFG_AUTOSW_Pos          9                                              /**< (DEVEPTCFG) Automatic Switch Position */
+#define DEVEPTCFG_AUTOSW              (_U_(0x1) << DEVEPTCFG_AUTOSW_Pos)       /**< (DEVEPTCFG) Automatic Switch Mask */
+#define DEVEPTCFG_EPTYPE_Pos          11                                             /**< (DEVEPTCFG) Endpoint Type Position */
+#define DEVEPTCFG_EPTYPE              (_U_(0x3) << DEVEPTCFG_EPTYPE_Pos)       /**< (DEVEPTCFG) Endpoint Type Mask */
+#define   DEVEPTCFG_EPTYPE_CTRL_Val   _U_(0x0)                                       /**< (DEVEPTCFG) Control  */
+#define   DEVEPTCFG_EPTYPE_ISO_Val    _U_(0x1)                                       /**< (DEVEPTCFG) Isochronous  */
+#define   DEVEPTCFG_EPTYPE_BLK_Val    _U_(0x2)                                       /**< (DEVEPTCFG) Bulk  */
+#define   DEVEPTCFG_EPTYPE_INTRPT_Val _U_(0x3)                                       /**< (DEVEPTCFG) Interrupt  */
+#define DEVEPTCFG_EPTYPE_CTRL         (DEVEPTCFG_EPTYPE_CTRL_Val << DEVEPTCFG_EPTYPE_Pos)  /**< (DEVEPTCFG) Control Position  */
+#define DEVEPTCFG_EPTYPE_ISO          (DEVEPTCFG_EPTYPE_ISO_Val << DEVEPTCFG_EPTYPE_Pos)  /**< (DEVEPTCFG) Isochronous Position  */
+#define DEVEPTCFG_EPTYPE_BLK          (DEVEPTCFG_EPTYPE_BLK_Val << DEVEPTCFG_EPTYPE_Pos)  /**< (DEVEPTCFG) Bulk Position  */
+#define DEVEPTCFG_EPTYPE_INTRPT       (DEVEPTCFG_EPTYPE_INTRPT_Val << DEVEPTCFG_EPTYPE_Pos)  /**< (DEVEPTCFG) Interrupt Position  */
+#define DEVEPTCFG_NBTRANS_Pos         13                                             /**< (DEVEPTCFG) Number of transactions per microframe for isochronous endpoint Position */
+#define DEVEPTCFG_NBTRANS             (_U_(0x3) << DEVEPTCFG_NBTRANS_Pos)      /**< (DEVEPTCFG) Number of transactions per microframe for isochronous endpoint Mask */
+#define   DEVEPTCFG_NBTRANS_0_TRANS_Val _U_(0x0)                                       /**< (DEVEPTCFG) Reserved to endpoint that does not have the high-bandwidth isochronous capability.  */
+#define   DEVEPTCFG_NBTRANS_1_TRANS_Val _U_(0x1)                                       /**< (DEVEPTCFG) Default value: one transaction per microframe.  */
+#define   DEVEPTCFG_NBTRANS_2_TRANS_Val _U_(0x2)                                       /**< (DEVEPTCFG) Two transactions per microframe. This endpoint should be configured as double-bank.  */
+#define   DEVEPTCFG_NBTRANS_3_TRANS_Val _U_(0x3)                                       /**< (DEVEPTCFG) Three transactions per microframe. This endpoint should be configured as triple-bank.  */
+#define DEVEPTCFG_NBTRANS_0_TRANS     (DEVEPTCFG_NBTRANS_0_TRANS_Val << DEVEPTCFG_NBTRANS_Pos)  /**< (DEVEPTCFG) Reserved to endpoint that does not have the high-bandwidth isochronous capability. Position  */
+#define DEVEPTCFG_NBTRANS_1_TRANS     (DEVEPTCFG_NBTRANS_1_TRANS_Val << DEVEPTCFG_NBTRANS_Pos)  /**< (DEVEPTCFG) Default value: one transaction per microframe. Position  */
+#define DEVEPTCFG_NBTRANS_2_TRANS     (DEVEPTCFG_NBTRANS_2_TRANS_Val << DEVEPTCFG_NBTRANS_Pos)  /**< (DEVEPTCFG) Two transactions per microframe. This endpoint should be configured as double-bank. Position  */
+#define DEVEPTCFG_NBTRANS_3_TRANS     (DEVEPTCFG_NBTRANS_3_TRANS_Val << DEVEPTCFG_NBTRANS_Pos)  /**< (DEVEPTCFG) Three transactions per microframe. This endpoint should be configured as triple-bank. Position  */
+#define DEVEPTCFG_Msk                 _U_(0x7B7E)                                    /**< (DEVEPTCFG) Register Mask  */
+
+
+/* -------- DEVEPTISR : (USBHS Offset: 0x130) (R/ 32) Device Endpoint Interrupt Status Register -------- */
+
+#define DEVEPTISR_OFFSET              (0x130)                                       /**<  (DEVEPTISR) Device Endpoint Interrupt Status Register  Offset */
+
+#define DEVEPTISR_TXINI_Pos           0                                              /**< (DEVEPTISR) Transmitted IN Data Interrupt Position */
+#define DEVEPTISR_TXINI               (_U_(0x1) << DEVEPTISR_TXINI_Pos)        /**< (DEVEPTISR) Transmitted IN Data Interrupt Mask */
+#define DEVEPTISR_RXOUTI_Pos          1                                              /**< (DEVEPTISR) Received OUT Data Interrupt Position */
+#define DEVEPTISR_RXOUTI              (_U_(0x1) << DEVEPTISR_RXOUTI_Pos)       /**< (DEVEPTISR) Received OUT Data Interrupt Mask */
+#define DEVEPTISR_OVERFI_Pos          5                                              /**< (DEVEPTISR) Overflow Interrupt Position */
+#define DEVEPTISR_OVERFI              (_U_(0x1) << DEVEPTISR_OVERFI_Pos)       /**< (DEVEPTISR) Overflow Interrupt Mask */
+#define DEVEPTISR_SHORTPACKET_Pos     7                                              /**< (DEVEPTISR) Short Packet Interrupt Position */
+#define DEVEPTISR_SHORTPACKET         (_U_(0x1) << DEVEPTISR_SHORTPACKET_Pos)  /**< (DEVEPTISR) Short Packet Interrupt Mask */
+#define DEVEPTISR_DTSEQ_Pos           8                                              /**< (DEVEPTISR) Data Toggle Sequence Position */
+#define DEVEPTISR_DTSEQ               (_U_(0x3) << DEVEPTISR_DTSEQ_Pos)        /**< (DEVEPTISR) Data Toggle Sequence Mask */
+#define   DEVEPTISR_DTSEQ_DATA0_Val   _U_(0x0)                                       /**< (DEVEPTISR) Data0 toggle sequence  */
+#define   DEVEPTISR_DTSEQ_DATA1_Val   _U_(0x1)                                       /**< (DEVEPTISR) Data1 toggle sequence  */
+#define   DEVEPTISR_DTSEQ_DATA2_Val   _U_(0x2)                                       /**< (DEVEPTISR) Reserved for high-bandwidth isochronous endpoint  */
+#define   DEVEPTISR_DTSEQ_MDATA_Val   _U_(0x3)                                       /**< (DEVEPTISR) Reserved for high-bandwidth isochronous endpoint  */
+#define DEVEPTISR_DTSEQ_DATA0         (DEVEPTISR_DTSEQ_DATA0_Val << DEVEPTISR_DTSEQ_Pos)  /**< (DEVEPTISR) Data0 toggle sequence Position  */
+#define DEVEPTISR_DTSEQ_DATA1         (DEVEPTISR_DTSEQ_DATA1_Val << DEVEPTISR_DTSEQ_Pos)  /**< (DEVEPTISR) Data1 toggle sequence Position  */
+#define DEVEPTISR_DTSEQ_DATA2         (DEVEPTISR_DTSEQ_DATA2_Val << DEVEPTISR_DTSEQ_Pos)  /**< (DEVEPTISR) Reserved for high-bandwidth isochronous endpoint Position  */
+#define DEVEPTISR_DTSEQ_MDATA         (DEVEPTISR_DTSEQ_MDATA_Val << DEVEPTISR_DTSEQ_Pos)  /**< (DEVEPTISR) Reserved for high-bandwidth isochronous endpoint Position  */
+#define DEVEPTISR_NBUSYBK_Pos         12                                             /**< (DEVEPTISR) Number of Busy Banks Position */
+#define DEVEPTISR_NBUSYBK             (_U_(0x3) << DEVEPTISR_NBUSYBK_Pos)      /**< (DEVEPTISR) Number of Busy Banks Mask */
+#define   DEVEPTISR_NBUSYBK_0_BUSY_Val _U_(0x0)                                       /**< (DEVEPTISR) 0 busy bank (all banks free)  */
+#define   DEVEPTISR_NBUSYBK_1_BUSY_Val _U_(0x1)                                       /**< (DEVEPTISR) 1 busy bank  */
+#define   DEVEPTISR_NBUSYBK_2_BUSY_Val _U_(0x2)                                       /**< (DEVEPTISR) 2 busy banks  */
+#define   DEVEPTISR_NBUSYBK_3_BUSY_Val _U_(0x3)                                       /**< (DEVEPTISR) 3 busy banks  */
+#define DEVEPTISR_NBUSYBK_0_BUSY      (DEVEPTISR_NBUSYBK_0_BUSY_Val << DEVEPTISR_NBUSYBK_Pos)  /**< (DEVEPTISR) 0 busy bank (all banks free) Position  */
+#define DEVEPTISR_NBUSYBK_1_BUSY      (DEVEPTISR_NBUSYBK_1_BUSY_Val << DEVEPTISR_NBUSYBK_Pos)  /**< (DEVEPTISR) 1 busy bank Position  */
+#define DEVEPTISR_NBUSYBK_2_BUSY      (DEVEPTISR_NBUSYBK_2_BUSY_Val << DEVEPTISR_NBUSYBK_Pos)  /**< (DEVEPTISR) 2 busy banks Position  */
+#define DEVEPTISR_NBUSYBK_3_BUSY      (DEVEPTISR_NBUSYBK_3_BUSY_Val << DEVEPTISR_NBUSYBK_Pos)  /**< (DEVEPTISR) 3 busy banks Position  */
+#define DEVEPTISR_CURRBK_Pos          14                                             /**< (DEVEPTISR) Current Bank Position */
+#define DEVEPTISR_CURRBK              (_U_(0x3) << DEVEPTISR_CURRBK_Pos)       /**< (DEVEPTISR) Current Bank Mask */
+#define   DEVEPTISR_CURRBK_BANK0_Val  _U_(0x0)                                       /**< (DEVEPTISR) Current bank is bank0  */
+#define   DEVEPTISR_CURRBK_BANK1_Val  _U_(0x1)                                       /**< (DEVEPTISR) Current bank is bank1  */
+#define   DEVEPTISR_CURRBK_BANK2_Val  _U_(0x2)                                       /**< (DEVEPTISR) Current bank is bank2  */
+#define DEVEPTISR_CURRBK_BANK0        (DEVEPTISR_CURRBK_BANK0_Val << DEVEPTISR_CURRBK_Pos)  /**< (DEVEPTISR) Current bank is bank0 Position  */
+#define DEVEPTISR_CURRBK_BANK1        (DEVEPTISR_CURRBK_BANK1_Val << DEVEPTISR_CURRBK_Pos)  /**< (DEVEPTISR) Current bank is bank1 Position  */
+#define DEVEPTISR_CURRBK_BANK2        (DEVEPTISR_CURRBK_BANK2_Val << DEVEPTISR_CURRBK_Pos)  /**< (DEVEPTISR) Current bank is bank2 Position  */
+#define DEVEPTISR_RWALL_Pos           16                                             /**< (DEVEPTISR) Read/Write Allowed Position */
+#define DEVEPTISR_RWALL               (_U_(0x1) << DEVEPTISR_RWALL_Pos)        /**< (DEVEPTISR) Read/Write Allowed Mask */
+#define DEVEPTISR_CFGOK_Pos           18                                             /**< (DEVEPTISR) Configuration OK Status Position */
+#define DEVEPTISR_CFGOK               (_U_(0x1) << DEVEPTISR_CFGOK_Pos)        /**< (DEVEPTISR) Configuration OK Status Mask */
+#define DEVEPTISR_BYCT_Pos            20                                             /**< (DEVEPTISR) Byte Count Position */
+#define DEVEPTISR_BYCT                (_U_(0x7FF) << DEVEPTISR_BYCT_Pos)       /**< (DEVEPTISR) Byte Count Mask */
+#define DEVEPTISR_Msk                 _U_(0x7FF5F3A3)                                /**< (DEVEPTISR) Register Mask  */
+
+/* CTRL mode */
+#define DEVEPTISR_CTRL_RXSTPI_Pos     2                                              /**< (DEVEPTISR) Received SETUP Interrupt Position */
+#define DEVEPTISR_CTRL_RXSTPI         (_U_(0x1) << DEVEPTISR_CTRL_RXSTPI_Pos)  /**< (DEVEPTISR) Received SETUP Interrupt Mask */
+#define DEVEPTISR_CTRL_NAKOUTI_Pos    3                                              /**< (DEVEPTISR) NAKed OUT Interrupt Position */
+#define DEVEPTISR_CTRL_NAKOUTI        (_U_(0x1) << DEVEPTISR_CTRL_NAKOUTI_Pos)  /**< (DEVEPTISR) NAKed OUT Interrupt Mask */
+#define DEVEPTISR_CTRL_NAKINI_Pos     4                                              /**< (DEVEPTISR) NAKed IN Interrupt Position */
+#define DEVEPTISR_CTRL_NAKINI         (_U_(0x1) << DEVEPTISR_CTRL_NAKINI_Pos)  /**< (DEVEPTISR) NAKed IN Interrupt Mask */
+#define DEVEPTISR_CTRL_STALLEDI_Pos   6                                              /**< (DEVEPTISR) STALLed Interrupt Position */
+#define DEVEPTISR_CTRL_STALLEDI       (_U_(0x1) << DEVEPTISR_CTRL_STALLEDI_Pos)  /**< (DEVEPTISR) STALLed Interrupt Mask */
+#define DEVEPTISR_CTRL_CTRLDIR_Pos    17                                             /**< (DEVEPTISR) Control Direction Position */
+#define DEVEPTISR_CTRL_CTRLDIR        (_U_(0x1) << DEVEPTISR_CTRL_CTRLDIR_Pos)  /**< (DEVEPTISR) Control Direction Mask */
+#define DEVEPTISR_CTRL_Msk            _U_(0x2005C)                                   /**< (DEVEPTISR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define DEVEPTISR_ISO_UNDERFI_Pos     2                                              /**< (DEVEPTISR) Underflow Interrupt Position */
+#define DEVEPTISR_ISO_UNDERFI         (_U_(0x1) << DEVEPTISR_ISO_UNDERFI_Pos)  /**< (DEVEPTISR) Underflow Interrupt Mask */
+#define DEVEPTISR_ISO_HBISOINERRI_Pos 3                                              /**< (DEVEPTISR) High Bandwidth Isochronous IN Underflow Error Interrupt Position */
+#define DEVEPTISR_ISO_HBISOINERRI     (_U_(0x1) << DEVEPTISR_ISO_HBISOINERRI_Pos)  /**< (DEVEPTISR) High Bandwidth Isochronous IN Underflow Error Interrupt Mask */
+#define DEVEPTISR_ISO_HBISOFLUSHI_Pos 4                                              /**< (DEVEPTISR) High Bandwidth Isochronous IN Flush Interrupt Position */
+#define DEVEPTISR_ISO_HBISOFLUSHI     (_U_(0x1) << DEVEPTISR_ISO_HBISOFLUSHI_Pos)  /**< (DEVEPTISR) High Bandwidth Isochronous IN Flush Interrupt Mask */
+#define DEVEPTISR_ISO_CRCERRI_Pos     6                                              /**< (DEVEPTISR) CRC Error Interrupt Position */
+#define DEVEPTISR_ISO_CRCERRI         (_U_(0x1) << DEVEPTISR_ISO_CRCERRI_Pos)  /**< (DEVEPTISR) CRC Error Interrupt Mask */
+#define DEVEPTISR_ISO_ERRORTRANS_Pos  10                                             /**< (DEVEPTISR) High-bandwidth Isochronous OUT Endpoint Transaction Error Interrupt Position */
+#define DEVEPTISR_ISO_ERRORTRANS      (_U_(0x1) << DEVEPTISR_ISO_ERRORTRANS_Pos)  /**< (DEVEPTISR) High-bandwidth Isochronous OUT Endpoint Transaction Error Interrupt Mask */
+#define DEVEPTISR_ISO_Msk             _U_(0x45C)                                     /**< (DEVEPTISR_ISO) Register Mask  */
+
+/* BLK mode */
+#define DEVEPTISR_BLK_RXSTPI_Pos      2                                              /**< (DEVEPTISR) Received SETUP Interrupt Position */
+#define DEVEPTISR_BLK_RXSTPI          (_U_(0x1) << DEVEPTISR_BLK_RXSTPI_Pos)   /**< (DEVEPTISR) Received SETUP Interrupt Mask */
+#define DEVEPTISR_BLK_NAKOUTI_Pos     3                                              /**< (DEVEPTISR) NAKed OUT Interrupt Position */
+#define DEVEPTISR_BLK_NAKOUTI         (_U_(0x1) << DEVEPTISR_BLK_NAKOUTI_Pos)  /**< (DEVEPTISR) NAKed OUT Interrupt Mask */
+#define DEVEPTISR_BLK_NAKINI_Pos      4                                              /**< (DEVEPTISR) NAKed IN Interrupt Position */
+#define DEVEPTISR_BLK_NAKINI          (_U_(0x1) << DEVEPTISR_BLK_NAKINI_Pos)   /**< (DEVEPTISR) NAKed IN Interrupt Mask */
+#define DEVEPTISR_BLK_STALLEDI_Pos    6                                              /**< (DEVEPTISR) STALLed Interrupt Position */
+#define DEVEPTISR_BLK_STALLEDI        (_U_(0x1) << DEVEPTISR_BLK_STALLEDI_Pos)  /**< (DEVEPTISR) STALLed Interrupt Mask */
+#define DEVEPTISR_BLK_CTRLDIR_Pos     17                                             /**< (DEVEPTISR) Control Direction Position */
+#define DEVEPTISR_BLK_CTRLDIR         (_U_(0x1) << DEVEPTISR_BLK_CTRLDIR_Pos)  /**< (DEVEPTISR) Control Direction Mask */
+#define DEVEPTISR_BLK_Msk             _U_(0x2005C)                                   /**< (DEVEPTISR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define DEVEPTISR_INTRPT_RXSTPI_Pos   2                                              /**< (DEVEPTISR) Received SETUP Interrupt Position */
+#define DEVEPTISR_INTRPT_RXSTPI       (_U_(0x1) << DEVEPTISR_INTRPT_RXSTPI_Pos)  /**< (DEVEPTISR) Received SETUP Interrupt Mask */
+#define DEVEPTISR_INTRPT_NAKOUTI_Pos  3                                              /**< (DEVEPTISR) NAKed OUT Interrupt Position */
+#define DEVEPTISR_INTRPT_NAKOUTI      (_U_(0x1) << DEVEPTISR_INTRPT_NAKOUTI_Pos)  /**< (DEVEPTISR) NAKed OUT Interrupt Mask */
+#define DEVEPTISR_INTRPT_NAKINI_Pos   4                                              /**< (DEVEPTISR) NAKed IN Interrupt Position */
+#define DEVEPTISR_INTRPT_NAKINI       (_U_(0x1) << DEVEPTISR_INTRPT_NAKINI_Pos)  /**< (DEVEPTISR) NAKed IN Interrupt Mask */
+#define DEVEPTISR_INTRPT_STALLEDI_Pos 6                                              /**< (DEVEPTISR) STALLed Interrupt Position */
+#define DEVEPTISR_INTRPT_STALLEDI     (_U_(0x1) << DEVEPTISR_INTRPT_STALLEDI_Pos)  /**< (DEVEPTISR) STALLed Interrupt Mask */
+#define DEVEPTISR_INTRPT_CTRLDIR_Pos  17                                             /**< (DEVEPTISR) Control Direction Position */
+#define DEVEPTISR_INTRPT_CTRLDIR      (_U_(0x1) << DEVEPTISR_INTRPT_CTRLDIR_Pos)  /**< (DEVEPTISR) Control Direction Mask */
+#define DEVEPTISR_INTRPT_Msk          _U_(0x2005C)                                   /**< (DEVEPTISR_INTRPT) Register Mask  */
+
+
+/* -------- DEVEPTICR : (USBHS Offset: 0x160) (/W 32) Device Endpoint Interrupt Clear Register -------- */
+
+#define DEVEPTICR_OFFSET              (0x160)                                       /**<  (DEVEPTICR) Device Endpoint Interrupt Clear Register  Offset */
+
+#define DEVEPTICR_TXINIC_Pos          0                                              /**< (DEVEPTICR) Transmitted IN Data Interrupt Clear Position */
+#define DEVEPTICR_TXINIC              (_U_(0x1) << DEVEPTICR_TXINIC_Pos)       /**< (DEVEPTICR) Transmitted IN Data Interrupt Clear Mask */
+#define DEVEPTICR_RXOUTIC_Pos         1                                              /**< (DEVEPTICR) Received OUT Data Interrupt Clear Position */
+#define DEVEPTICR_RXOUTIC             (_U_(0x1) << DEVEPTICR_RXOUTIC_Pos)      /**< (DEVEPTICR) Received OUT Data Interrupt Clear Mask */
+#define DEVEPTICR_OVERFIC_Pos         5                                              /**< (DEVEPTICR) Overflow Interrupt Clear Position */
+#define DEVEPTICR_OVERFIC             (_U_(0x1) << DEVEPTICR_OVERFIC_Pos)      /**< (DEVEPTICR) Overflow Interrupt Clear Mask */
+#define DEVEPTICR_SHORTPACKETC_Pos    7                                              /**< (DEVEPTICR) Short Packet Interrupt Clear Position */
+#define DEVEPTICR_SHORTPACKETC        (_U_(0x1) << DEVEPTICR_SHORTPACKETC_Pos)  /**< (DEVEPTICR) Short Packet Interrupt Clear Mask */
+#define DEVEPTICR_Msk                 _U_(0xA3)                                      /**< (DEVEPTICR) Register Mask  */
+
+/* CTRL mode */
+#define DEVEPTICR_CTRL_RXSTPIC_Pos    2                                              /**< (DEVEPTICR) Received SETUP Interrupt Clear Position */
+#define DEVEPTICR_CTRL_RXSTPIC        (_U_(0x1) << DEVEPTICR_CTRL_RXSTPIC_Pos)  /**< (DEVEPTICR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTICR_CTRL_NAKOUTIC_Pos   3                                              /**< (DEVEPTICR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTICR_CTRL_NAKOUTIC       (_U_(0x1) << DEVEPTICR_CTRL_NAKOUTIC_Pos)  /**< (DEVEPTICR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTICR_CTRL_NAKINIC_Pos    4                                              /**< (DEVEPTICR) NAKed IN Interrupt Clear Position */
+#define DEVEPTICR_CTRL_NAKINIC        (_U_(0x1) << DEVEPTICR_CTRL_NAKINIC_Pos)  /**< (DEVEPTICR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTICR_CTRL_STALLEDIC_Pos  6                                              /**< (DEVEPTICR) STALLed Interrupt Clear Position */
+#define DEVEPTICR_CTRL_STALLEDIC      (_U_(0x1) << DEVEPTICR_CTRL_STALLEDIC_Pos)  /**< (DEVEPTICR) STALLed Interrupt Clear Mask */
+#define DEVEPTICR_CTRL_Msk            _U_(0x5C)                                      /**< (DEVEPTICR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define DEVEPTICR_ISO_UNDERFIC_Pos    2                                              /**< (DEVEPTICR) Underflow Interrupt Clear Position */
+#define DEVEPTICR_ISO_UNDERFIC        (_U_(0x1) << DEVEPTICR_ISO_UNDERFIC_Pos)  /**< (DEVEPTICR) Underflow Interrupt Clear Mask */
+#define DEVEPTICR_ISO_HBISOINERRIC_Pos 3                                              /**< (DEVEPTICR) High Bandwidth Isochronous IN Underflow Error Interrupt Clear Position */
+#define DEVEPTICR_ISO_HBISOINERRIC     (_U_(0x1) << DEVEPTICR_ISO_HBISOINERRIC_Pos)  /**< (DEVEPTICR) High Bandwidth Isochronous IN Underflow Error Interrupt Clear Mask */
+#define DEVEPTICR_ISO_HBISOFLUSHIC_Pos 4                                              /**< (DEVEPTICR) High Bandwidth Isochronous IN Flush Interrupt Clear Position */
+#define DEVEPTICR_ISO_HBISOFLUSHIC     (_U_(0x1) << DEVEPTICR_ISO_HBISOFLUSHIC_Pos)  /**< (DEVEPTICR) High Bandwidth Isochronous IN Flush Interrupt Clear Mask */
+#define DEVEPTICR_ISO_CRCERRIC_Pos    6                                              /**< (DEVEPTICR) CRC Error Interrupt Clear Position */
+#define DEVEPTICR_ISO_CRCERRIC        (_U_(0x1) << DEVEPTICR_ISO_CRCERRIC_Pos)  /**< (DEVEPTICR) CRC Error Interrupt Clear Mask */
+#define DEVEPTICR_ISO_Msk             _U_(0x5C)                                      /**< (DEVEPTICR_ISO) Register Mask  */
+
+/* BLK mode */
+#define DEVEPTICR_BLK_RXSTPIC_Pos     2                                              /**< (DEVEPTICR) Received SETUP Interrupt Clear Position */
+#define DEVEPTICR_BLK_RXSTPIC         (_U_(0x1) << DEVEPTICR_BLK_RXSTPIC_Pos)  /**< (DEVEPTICR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTICR_BLK_NAKOUTIC_Pos    3                                              /**< (DEVEPTICR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTICR_BLK_NAKOUTIC        (_U_(0x1) << DEVEPTICR_BLK_NAKOUTIC_Pos)  /**< (DEVEPTICR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTICR_BLK_NAKINIC_Pos     4                                              /**< (DEVEPTICR) NAKed IN Interrupt Clear Position */
+#define DEVEPTICR_BLK_NAKINIC         (_U_(0x1) << DEVEPTICR_BLK_NAKINIC_Pos)  /**< (DEVEPTICR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTICR_BLK_STALLEDIC_Pos   6                                              /**< (DEVEPTICR) STALLed Interrupt Clear Position */
+#define DEVEPTICR_BLK_STALLEDIC       (_U_(0x1) << DEVEPTICR_BLK_STALLEDIC_Pos)  /**< (DEVEPTICR) STALLed Interrupt Clear Mask */
+#define DEVEPTICR_BLK_Msk             _U_(0x5C)                                      /**< (DEVEPTICR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define DEVEPTICR_INTRPT_RXSTPIC_Pos  2                                              /**< (DEVEPTICR) Received SETUP Interrupt Clear Position */
+#define DEVEPTICR_INTRPT_RXSTPIC      (_U_(0x1) << DEVEPTICR_INTRPT_RXSTPIC_Pos)  /**< (DEVEPTICR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTICR_INTRPT_NAKOUTIC_Pos 3                                              /**< (DEVEPTICR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTICR_INTRPT_NAKOUTIC     (_U_(0x1) << DEVEPTICR_INTRPT_NAKOUTIC_Pos)  /**< (DEVEPTICR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTICR_INTRPT_NAKINIC_Pos  4                                              /**< (DEVEPTICR) NAKed IN Interrupt Clear Position */
+#define DEVEPTICR_INTRPT_NAKINIC      (_U_(0x1) << DEVEPTICR_INTRPT_NAKINIC_Pos)  /**< (DEVEPTICR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTICR_INTRPT_STALLEDIC_Pos 6                                              /**< (DEVEPTICR) STALLed Interrupt Clear Position */
+#define DEVEPTICR_INTRPT_STALLEDIC     (_U_(0x1) << DEVEPTICR_INTRPT_STALLEDIC_Pos)  /**< (DEVEPTICR) STALLed Interrupt Clear Mask */
+#define DEVEPTICR_INTRPT_Msk          _U_(0x5C)                                      /**< (DEVEPTICR_INTRPT) Register Mask  */
+
+
+/* -------- DEVEPTIFR : (USBHS Offset: 0x190) (/W 32) Device Endpoint Interrupt Set Register -------- */
+
+#define DEVEPTIFR_OFFSET              (0x190)                                       /**<  (DEVEPTIFR) Device Endpoint Interrupt Set Register  Offset */
+
+#define DEVEPTIFR_TXINIS_Pos          0                                              /**< (DEVEPTIFR) Transmitted IN Data Interrupt Set Position */
+#define DEVEPTIFR_TXINIS              (_U_(0x1) << DEVEPTIFR_TXINIS_Pos)       /**< (DEVEPTIFR) Transmitted IN Data Interrupt Set Mask */
+#define DEVEPTIFR_RXOUTIS_Pos         1                                              /**< (DEVEPTIFR) Received OUT Data Interrupt Set Position */
+#define DEVEPTIFR_RXOUTIS             (_U_(0x1) << DEVEPTIFR_RXOUTIS_Pos)      /**< (DEVEPTIFR) Received OUT Data Interrupt Set Mask */
+#define DEVEPTIFR_OVERFIS_Pos         5                                              /**< (DEVEPTIFR) Overflow Interrupt Set Position */
+#define DEVEPTIFR_OVERFIS             (_U_(0x1) << DEVEPTIFR_OVERFIS_Pos)      /**< (DEVEPTIFR) Overflow Interrupt Set Mask */
+#define DEVEPTIFR_SHORTPACKETS_Pos    7                                              /**< (DEVEPTIFR) Short Packet Interrupt Set Position */
+#define DEVEPTIFR_SHORTPACKETS        (_U_(0x1) << DEVEPTIFR_SHORTPACKETS_Pos)  /**< (DEVEPTIFR) Short Packet Interrupt Set Mask */
+#define DEVEPTIFR_NBUSYBKS_Pos        12                                             /**< (DEVEPTIFR) Number of Busy Banks Interrupt Set Position */
+#define DEVEPTIFR_NBUSYBKS            (_U_(0x1) << DEVEPTIFR_NBUSYBKS_Pos)     /**< (DEVEPTIFR) Number of Busy Banks Interrupt Set Mask */
+#define DEVEPTIFR_Msk                 _U_(0x10A3)                                    /**< (DEVEPTIFR) Register Mask  */
+
+/* CTRL mode */
+#define DEVEPTIFR_CTRL_RXSTPIS_Pos    2                                              /**< (DEVEPTIFR) Received SETUP Interrupt Set Position */
+#define DEVEPTIFR_CTRL_RXSTPIS        (_U_(0x1) << DEVEPTIFR_CTRL_RXSTPIS_Pos)  /**< (DEVEPTIFR) Received SETUP Interrupt Set Mask */
+#define DEVEPTIFR_CTRL_NAKOUTIS_Pos   3                                              /**< (DEVEPTIFR) NAKed OUT Interrupt Set Position */
+#define DEVEPTIFR_CTRL_NAKOUTIS       (_U_(0x1) << DEVEPTIFR_CTRL_NAKOUTIS_Pos)  /**< (DEVEPTIFR) NAKed OUT Interrupt Set Mask */
+#define DEVEPTIFR_CTRL_NAKINIS_Pos    4                                              /**< (DEVEPTIFR) NAKed IN Interrupt Set Position */
+#define DEVEPTIFR_CTRL_NAKINIS        (_U_(0x1) << DEVEPTIFR_CTRL_NAKINIS_Pos)  /**< (DEVEPTIFR) NAKed IN Interrupt Set Mask */
+#define DEVEPTIFR_CTRL_STALLEDIS_Pos  6                                              /**< (DEVEPTIFR) STALLed Interrupt Set Position */
+#define DEVEPTIFR_CTRL_STALLEDIS      (_U_(0x1) << DEVEPTIFR_CTRL_STALLEDIS_Pos)  /**< (DEVEPTIFR) STALLed Interrupt Set Mask */
+#define DEVEPTIFR_CTRL_Msk            _U_(0x5C)                                      /**< (DEVEPTIFR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define DEVEPTIFR_ISO_UNDERFIS_Pos    2                                              /**< (DEVEPTIFR) Underflow Interrupt Set Position */
+#define DEVEPTIFR_ISO_UNDERFIS        (_U_(0x1) << DEVEPTIFR_ISO_UNDERFIS_Pos)  /**< (DEVEPTIFR) Underflow Interrupt Set Mask */
+#define DEVEPTIFR_ISO_HBISOINERRIS_Pos 3                                              /**< (DEVEPTIFR) High Bandwidth Isochronous IN Underflow Error Interrupt Set Position */
+#define DEVEPTIFR_ISO_HBISOINERRIS     (_U_(0x1) << DEVEPTIFR_ISO_HBISOINERRIS_Pos)  /**< (DEVEPTIFR) High Bandwidth Isochronous IN Underflow Error Interrupt Set Mask */
+#define DEVEPTIFR_ISO_HBISOFLUSHIS_Pos 4                                              /**< (DEVEPTIFR) High Bandwidth Isochronous IN Flush Interrupt Set Position */
+#define DEVEPTIFR_ISO_HBISOFLUSHIS     (_U_(0x1) << DEVEPTIFR_ISO_HBISOFLUSHIS_Pos)  /**< (DEVEPTIFR) High Bandwidth Isochronous IN Flush Interrupt Set Mask */
+#define DEVEPTIFR_ISO_CRCERRIS_Pos    6                                              /**< (DEVEPTIFR) CRC Error Interrupt Set Position */
+#define DEVEPTIFR_ISO_CRCERRIS        (_U_(0x1) << DEVEPTIFR_ISO_CRCERRIS_Pos)  /**< (DEVEPTIFR) CRC Error Interrupt Set Mask */
+#define DEVEPTIFR_ISO_Msk             _U_(0x5C)                                      /**< (DEVEPTIFR_ISO) Register Mask  */
+
+/* BLK mode */
+#define DEVEPTIFR_BLK_RXSTPIS_Pos     2                                              /**< (DEVEPTIFR) Received SETUP Interrupt Set Position */
+#define DEVEPTIFR_BLK_RXSTPIS         (_U_(0x1) << DEVEPTIFR_BLK_RXSTPIS_Pos)  /**< (DEVEPTIFR) Received SETUP Interrupt Set Mask */
+#define DEVEPTIFR_BLK_NAKOUTIS_Pos    3                                              /**< (DEVEPTIFR) NAKed OUT Interrupt Set Position */
+#define DEVEPTIFR_BLK_NAKOUTIS        (_U_(0x1) << DEVEPTIFR_BLK_NAKOUTIS_Pos)  /**< (DEVEPTIFR) NAKed OUT Interrupt Set Mask */
+#define DEVEPTIFR_BLK_NAKINIS_Pos     4                                              /**< (DEVEPTIFR) NAKed IN Interrupt Set Position */
+#define DEVEPTIFR_BLK_NAKINIS         (_U_(0x1) << DEVEPTIFR_BLK_NAKINIS_Pos)  /**< (DEVEPTIFR) NAKed IN Interrupt Set Mask */
+#define DEVEPTIFR_BLK_STALLEDIS_Pos   6                                              /**< (DEVEPTIFR) STALLed Interrupt Set Position */
+#define DEVEPTIFR_BLK_STALLEDIS       (_U_(0x1) << DEVEPTIFR_BLK_STALLEDIS_Pos)  /**< (DEVEPTIFR) STALLed Interrupt Set Mask */
+#define DEVEPTIFR_BLK_Msk             _U_(0x5C)                                      /**< (DEVEPTIFR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define DEVEPTIFR_INTRPT_RXSTPIS_Pos  2                                              /**< (DEVEPTIFR) Received SETUP Interrupt Set Position */
+#define DEVEPTIFR_INTRPT_RXSTPIS      (_U_(0x1) << DEVEPTIFR_INTRPT_RXSTPIS_Pos)  /**< (DEVEPTIFR) Received SETUP Interrupt Set Mask */
+#define DEVEPTIFR_INTRPT_NAKOUTIS_Pos 3                                              /**< (DEVEPTIFR) NAKed OUT Interrupt Set Position */
+#define DEVEPTIFR_INTRPT_NAKOUTIS     (_U_(0x1) << DEVEPTIFR_INTRPT_NAKOUTIS_Pos)  /**< (DEVEPTIFR) NAKed OUT Interrupt Set Mask */
+#define DEVEPTIFR_INTRPT_NAKINIS_Pos  4                                              /**< (DEVEPTIFR) NAKed IN Interrupt Set Position */
+#define DEVEPTIFR_INTRPT_NAKINIS      (_U_(0x1) << DEVEPTIFR_INTRPT_NAKINIS_Pos)  /**< (DEVEPTIFR) NAKed IN Interrupt Set Mask */
+#define DEVEPTIFR_INTRPT_STALLEDIS_Pos 6                                              /**< (DEVEPTIFR) STALLed Interrupt Set Position */
+#define DEVEPTIFR_INTRPT_STALLEDIS     (_U_(0x1) << DEVEPTIFR_INTRPT_STALLEDIS_Pos)  /**< (DEVEPTIFR) STALLed Interrupt Set Mask */
+#define DEVEPTIFR_INTRPT_Msk          _U_(0x5C)                                      /**< (DEVEPTIFR_INTRPT) Register Mask  */
+
+
+/* -------- DEVEPTIMR : (USBHS Offset: 0x1c0) (R/ 32) Device Endpoint Interrupt Mask Register -------- */
+
+#define DEVEPTIMR_OFFSET              (0x1C0)                                       /**<  (DEVEPTIMR) Device Endpoint Interrupt Mask Register  Offset */
+
+#define DEVEPTIMR_TXINE_Pos           0                                              /**< (DEVEPTIMR) Transmitted IN Data Interrupt Position */
+#define DEVEPTIMR_TXINE               (_U_(0x1) << DEVEPTIMR_TXINE_Pos)        /**< (DEVEPTIMR) Transmitted IN Data Interrupt Mask */
+#define DEVEPTIMR_RXOUTE_Pos          1                                              /**< (DEVEPTIMR) Received OUT Data Interrupt Position */
+#define DEVEPTIMR_RXOUTE              (_U_(0x1) << DEVEPTIMR_RXOUTE_Pos)       /**< (DEVEPTIMR) Received OUT Data Interrupt Mask */
+#define DEVEPTIMR_OVERFE_Pos          5                                              /**< (DEVEPTIMR) Overflow Interrupt Position */
+#define DEVEPTIMR_OVERFE              (_U_(0x1) << DEVEPTIMR_OVERFE_Pos)       /**< (DEVEPTIMR) Overflow Interrupt Mask */
+#define DEVEPTIMR_SHORTPACKETE_Pos    7                                              /**< (DEVEPTIMR) Short Packet Interrupt Position */
+#define DEVEPTIMR_SHORTPACKETE        (_U_(0x1) << DEVEPTIMR_SHORTPACKETE_Pos)  /**< (DEVEPTIMR) Short Packet Interrupt Mask */
+#define DEVEPTIMR_NBUSYBKE_Pos        12                                             /**< (DEVEPTIMR) Number of Busy Banks Interrupt Position */
+#define DEVEPTIMR_NBUSYBKE            (_U_(0x1) << DEVEPTIMR_NBUSYBKE_Pos)     /**< (DEVEPTIMR) Number of Busy Banks Interrupt Mask */
+#define DEVEPTIMR_KILLBK_Pos          13                                             /**< (DEVEPTIMR) Kill IN Bank Position */
+#define DEVEPTIMR_KILLBK              (_U_(0x1) << DEVEPTIMR_KILLBK_Pos)       /**< (DEVEPTIMR) Kill IN Bank Mask */
+#define DEVEPTIMR_FIFOCON_Pos         14                                             /**< (DEVEPTIMR) FIFO Control Position */
+#define DEVEPTIMR_FIFOCON             (_U_(0x1) << DEVEPTIMR_FIFOCON_Pos)      /**< (DEVEPTIMR) FIFO Control Mask */
+#define DEVEPTIMR_EPDISHDMA_Pos       16                                             /**< (DEVEPTIMR) Endpoint Interrupts Disable HDMA Request Position */
+#define DEVEPTIMR_EPDISHDMA           (_U_(0x1) << DEVEPTIMR_EPDISHDMA_Pos)    /**< (DEVEPTIMR) Endpoint Interrupts Disable HDMA Request Mask */
+#define DEVEPTIMR_RSTDT_Pos           18                                             /**< (DEVEPTIMR) Reset Data Toggle Position */
+#define DEVEPTIMR_RSTDT               (_U_(0x1) << DEVEPTIMR_RSTDT_Pos)        /**< (DEVEPTIMR) Reset Data Toggle Mask */
+#define DEVEPTIMR_Msk                 _U_(0x570A3)                                   /**< (DEVEPTIMR) Register Mask  */
+
+/* CTRL mode */
+#define DEVEPTIMR_CTRL_RXSTPE_Pos     2                                              /**< (DEVEPTIMR) Received SETUP Interrupt Position */
+#define DEVEPTIMR_CTRL_RXSTPE         (_U_(0x1) << DEVEPTIMR_CTRL_RXSTPE_Pos)  /**< (DEVEPTIMR) Received SETUP Interrupt Mask */
+#define DEVEPTIMR_CTRL_NAKOUTE_Pos    3                                              /**< (DEVEPTIMR) NAKed OUT Interrupt Position */
+#define DEVEPTIMR_CTRL_NAKOUTE        (_U_(0x1) << DEVEPTIMR_CTRL_NAKOUTE_Pos)  /**< (DEVEPTIMR) NAKed OUT Interrupt Mask */
+#define DEVEPTIMR_CTRL_NAKINE_Pos     4                                              /**< (DEVEPTIMR) NAKed IN Interrupt Position */
+#define DEVEPTIMR_CTRL_NAKINE         (_U_(0x1) << DEVEPTIMR_CTRL_NAKINE_Pos)  /**< (DEVEPTIMR) NAKed IN Interrupt Mask */
+#define DEVEPTIMR_CTRL_STALLEDE_Pos   6                                              /**< (DEVEPTIMR) STALLed Interrupt Position */
+#define DEVEPTIMR_CTRL_STALLEDE       (_U_(0x1) << DEVEPTIMR_CTRL_STALLEDE_Pos)  /**< (DEVEPTIMR) STALLed Interrupt Mask */
+#define DEVEPTIMR_CTRL_NYETDIS_Pos    17                                             /**< (DEVEPTIMR) NYET Token Disable Position */
+#define DEVEPTIMR_CTRL_NYETDIS        (_U_(0x1) << DEVEPTIMR_CTRL_NYETDIS_Pos)  /**< (DEVEPTIMR) NYET Token Disable Mask */
+#define DEVEPTIMR_CTRL_STALLRQ_Pos    19                                             /**< (DEVEPTIMR) STALL Request Position */
+#define DEVEPTIMR_CTRL_STALLRQ        (_U_(0x1) << DEVEPTIMR_CTRL_STALLRQ_Pos)  /**< (DEVEPTIMR) STALL Request Mask */
+#define DEVEPTIMR_CTRL_Msk            _U_(0xA005C)                                   /**< (DEVEPTIMR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define DEVEPTIMR_ISO_UNDERFE_Pos     2                                              /**< (DEVEPTIMR) Underflow Interrupt Position */
+#define DEVEPTIMR_ISO_UNDERFE         (_U_(0x1) << DEVEPTIMR_ISO_UNDERFE_Pos)  /**< (DEVEPTIMR) Underflow Interrupt Mask */
+#define DEVEPTIMR_ISO_HBISOINERRE_Pos 3                                              /**< (DEVEPTIMR) High Bandwidth Isochronous IN Underflow Error Interrupt Position */
+#define DEVEPTIMR_ISO_HBISOINERRE     (_U_(0x1) << DEVEPTIMR_ISO_HBISOINERRE_Pos)  /**< (DEVEPTIMR) High Bandwidth Isochronous IN Underflow Error Interrupt Mask */
+#define DEVEPTIMR_ISO_HBISOFLUSHE_Pos 4                                              /**< (DEVEPTIMR) High Bandwidth Isochronous IN Flush Interrupt Position */
+#define DEVEPTIMR_ISO_HBISOFLUSHE     (_U_(0x1) << DEVEPTIMR_ISO_HBISOFLUSHE_Pos)  /**< (DEVEPTIMR) High Bandwidth Isochronous IN Flush Interrupt Mask */
+#define DEVEPTIMR_ISO_CRCERRE_Pos     6                                              /**< (DEVEPTIMR) CRC Error Interrupt Position */
+#define DEVEPTIMR_ISO_CRCERRE         (_U_(0x1) << DEVEPTIMR_ISO_CRCERRE_Pos)  /**< (DEVEPTIMR) CRC Error Interrupt Mask */
+#define DEVEPTIMR_ISO_MDATAE_Pos      8                                              /**< (DEVEPTIMR) MData Interrupt Position */
+#define DEVEPTIMR_ISO_MDATAE          (_U_(0x1) << DEVEPTIMR_ISO_MDATAE_Pos)   /**< (DEVEPTIMR) MData Interrupt Mask */
+#define DEVEPTIMR_ISO_DATAXE_Pos      9                                              /**< (DEVEPTIMR) DataX Interrupt Position */
+#define DEVEPTIMR_ISO_DATAXE          (_U_(0x1) << DEVEPTIMR_ISO_DATAXE_Pos)   /**< (DEVEPTIMR) DataX Interrupt Mask */
+#define DEVEPTIMR_ISO_ERRORTRANSE_Pos 10                                             /**< (DEVEPTIMR) Transaction Error Interrupt Position */
+#define DEVEPTIMR_ISO_ERRORTRANSE     (_U_(0x1) << DEVEPTIMR_ISO_ERRORTRANSE_Pos)  /**< (DEVEPTIMR) Transaction Error Interrupt Mask */
+#define DEVEPTIMR_ISO_Msk             _U_(0x75C)                                     /**< (DEVEPTIMR_ISO) Register Mask  */
+
+/* BLK mode */
+#define DEVEPTIMR_BLK_RXSTPE_Pos      2                                              /**< (DEVEPTIMR) Received SETUP Interrupt Position */
+#define DEVEPTIMR_BLK_RXSTPE          (_U_(0x1) << DEVEPTIMR_BLK_RXSTPE_Pos)   /**< (DEVEPTIMR) Received SETUP Interrupt Mask */
+#define DEVEPTIMR_BLK_NAKOUTE_Pos     3                                              /**< (DEVEPTIMR) NAKed OUT Interrupt Position */
+#define DEVEPTIMR_BLK_NAKOUTE         (_U_(0x1) << DEVEPTIMR_BLK_NAKOUTE_Pos)  /**< (DEVEPTIMR) NAKed OUT Interrupt Mask */
+#define DEVEPTIMR_BLK_NAKINE_Pos      4                                              /**< (DEVEPTIMR) NAKed IN Interrupt Position */
+#define DEVEPTIMR_BLK_NAKINE          (_U_(0x1) << DEVEPTIMR_BLK_NAKINE_Pos)   /**< (DEVEPTIMR) NAKed IN Interrupt Mask */
+#define DEVEPTIMR_BLK_STALLEDE_Pos    6                                              /**< (DEVEPTIMR) STALLed Interrupt Position */
+#define DEVEPTIMR_BLK_STALLEDE        (_U_(0x1) << DEVEPTIMR_BLK_STALLEDE_Pos)  /**< (DEVEPTIMR) STALLed Interrupt Mask */
+#define DEVEPTIMR_BLK_NYETDIS_Pos     17                                             /**< (DEVEPTIMR) NYET Token Disable Position */
+#define DEVEPTIMR_BLK_NYETDIS         (_U_(0x1) << DEVEPTIMR_BLK_NYETDIS_Pos)  /**< (DEVEPTIMR) NYET Token Disable Mask */
+#define DEVEPTIMR_BLK_STALLRQ_Pos     19                                             /**< (DEVEPTIMR) STALL Request Position */
+#define DEVEPTIMR_BLK_STALLRQ         (_U_(0x1) << DEVEPTIMR_BLK_STALLRQ_Pos)  /**< (DEVEPTIMR) STALL Request Mask */
+#define DEVEPTIMR_BLK_Msk             _U_(0xA005C)                                   /**< (DEVEPTIMR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define DEVEPTIMR_INTRPT_RXSTPE_Pos   2                                              /**< (DEVEPTIMR) Received SETUP Interrupt Position */
+#define DEVEPTIMR_INTRPT_RXSTPE       (_U_(0x1) << DEVEPTIMR_INTRPT_RXSTPE_Pos)  /**< (DEVEPTIMR) Received SETUP Interrupt Mask */
+#define DEVEPTIMR_INTRPT_NAKOUTE_Pos  3                                              /**< (DEVEPTIMR) NAKed OUT Interrupt Position */
+#define DEVEPTIMR_INTRPT_NAKOUTE      (_U_(0x1) << DEVEPTIMR_INTRPT_NAKOUTE_Pos)  /**< (DEVEPTIMR) NAKed OUT Interrupt Mask */
+#define DEVEPTIMR_INTRPT_NAKINE_Pos   4                                              /**< (DEVEPTIMR) NAKed IN Interrupt Position */
+#define DEVEPTIMR_INTRPT_NAKINE       (_U_(0x1) << DEVEPTIMR_INTRPT_NAKINE_Pos)  /**< (DEVEPTIMR) NAKed IN Interrupt Mask */
+#define DEVEPTIMR_INTRPT_STALLEDE_Pos 6                                              /**< (DEVEPTIMR) STALLed Interrupt Position */
+#define DEVEPTIMR_INTRPT_STALLEDE     (_U_(0x1) << DEVEPTIMR_INTRPT_STALLEDE_Pos)  /**< (DEVEPTIMR) STALLed Interrupt Mask */
+#define DEVEPTIMR_INTRPT_NYETDIS_Pos  17                                             /**< (DEVEPTIMR) NYET Token Disable Position */
+#define DEVEPTIMR_INTRPT_NYETDIS      (_U_(0x1) << DEVEPTIMR_INTRPT_NYETDIS_Pos)  /**< (DEVEPTIMR) NYET Token Disable Mask */
+#define DEVEPTIMR_INTRPT_STALLRQ_Pos  19                                             /**< (DEVEPTIMR) STALL Request Position */
+#define DEVEPTIMR_INTRPT_STALLRQ      (_U_(0x1) << DEVEPTIMR_INTRPT_STALLRQ_Pos)  /**< (DEVEPTIMR) STALL Request Mask */
+#define DEVEPTIMR_INTRPT_Msk          _U_(0xA005C)                                   /**< (DEVEPTIMR_INTRPT) Register Mask  */
+
+
+/* -------- DEVEPTIER : (USBHS Offset: 0x1f0) (/W 32) Device Endpoint Interrupt Enable Register -------- */
+
+#define DEVEPTIER_OFFSET              (0x1F0)                                       /**<  (DEVEPTIER) Device Endpoint Interrupt Enable Register  Offset */
+
+#define DEVEPTIER_TXINES_Pos          0                                              /**< (DEVEPTIER) Transmitted IN Data Interrupt Enable Position */
+#define DEVEPTIER_TXINES              (_U_(0x1) << DEVEPTIER_TXINES_Pos)       /**< (DEVEPTIER) Transmitted IN Data Interrupt Enable Mask */
+#define DEVEPTIER_RXOUTES_Pos         1                                              /**< (DEVEPTIER) Received OUT Data Interrupt Enable Position */
+#define DEVEPTIER_RXOUTES             (_U_(0x1) << DEVEPTIER_RXOUTES_Pos)      /**< (DEVEPTIER) Received OUT Data Interrupt Enable Mask */
+#define DEVEPTIER_OVERFES_Pos         5                                              /**< (DEVEPTIER) Overflow Interrupt Enable Position */
+#define DEVEPTIER_OVERFES             (_U_(0x1) << DEVEPTIER_OVERFES_Pos)      /**< (DEVEPTIER) Overflow Interrupt Enable Mask */
+#define DEVEPTIER_SHORTPACKETES_Pos   7                                              /**< (DEVEPTIER) Short Packet Interrupt Enable Position */
+#define DEVEPTIER_SHORTPACKETES       (_U_(0x1) << DEVEPTIER_SHORTPACKETES_Pos)  /**< (DEVEPTIER) Short Packet Interrupt Enable Mask */
+#define DEVEPTIER_NBUSYBKES_Pos       12                                             /**< (DEVEPTIER) Number of Busy Banks Interrupt Enable Position */
+#define DEVEPTIER_NBUSYBKES           (_U_(0x1) << DEVEPTIER_NBUSYBKES_Pos)    /**< (DEVEPTIER) Number of Busy Banks Interrupt Enable Mask */
+#define DEVEPTIER_KILLBKS_Pos         13                                             /**< (DEVEPTIER) Kill IN Bank Position */
+#define DEVEPTIER_KILLBKS             (_U_(0x1) << DEVEPTIER_KILLBKS_Pos)      /**< (DEVEPTIER) Kill IN Bank Mask */
+#define DEVEPTIER_FIFOCONS_Pos        14                                             /**< (DEVEPTIER) FIFO Control Position */
+#define DEVEPTIER_FIFOCONS            (_U_(0x1) << DEVEPTIER_FIFOCONS_Pos)     /**< (DEVEPTIER) FIFO Control Mask */
+#define DEVEPTIER_EPDISHDMAS_Pos      16                                             /**< (DEVEPTIER) Endpoint Interrupts Disable HDMA Request Enable Position */
+#define DEVEPTIER_EPDISHDMAS          (_U_(0x1) << DEVEPTIER_EPDISHDMAS_Pos)   /**< (DEVEPTIER) Endpoint Interrupts Disable HDMA Request Enable Mask */
+#define DEVEPTIER_RSTDTS_Pos          18                                             /**< (DEVEPTIER) Reset Data Toggle Enable Position */
+#define DEVEPTIER_RSTDTS              (_U_(0x1) << DEVEPTIER_RSTDTS_Pos)       /**< (DEVEPTIER) Reset Data Toggle Enable Mask */
+#define DEVEPTIER_Msk                 _U_(0x570A3)                                   /**< (DEVEPTIER) Register Mask  */
+
+/* CTRL mode */
+#define DEVEPTIER_CTRL_RXSTPES_Pos    2                                              /**< (DEVEPTIER) Received SETUP Interrupt Enable Position */
+#define DEVEPTIER_CTRL_RXSTPES        (_U_(0x1) << DEVEPTIER_CTRL_RXSTPES_Pos)  /**< (DEVEPTIER) Received SETUP Interrupt Enable Mask */
+#define DEVEPTIER_CTRL_NAKOUTES_Pos   3                                              /**< (DEVEPTIER) NAKed OUT Interrupt Enable Position */
+#define DEVEPTIER_CTRL_NAKOUTES       (_U_(0x1) << DEVEPTIER_CTRL_NAKOUTES_Pos)  /**< (DEVEPTIER) NAKed OUT Interrupt Enable Mask */
+#define DEVEPTIER_CTRL_NAKINES_Pos    4                                              /**< (DEVEPTIER) NAKed IN Interrupt Enable Position */
+#define DEVEPTIER_CTRL_NAKINES        (_U_(0x1) << DEVEPTIER_CTRL_NAKINES_Pos)  /**< (DEVEPTIER) NAKed IN Interrupt Enable Mask */
+#define DEVEPTIER_CTRL_STALLEDES_Pos  6                                              /**< (DEVEPTIER) STALLed Interrupt Enable Position */
+#define DEVEPTIER_CTRL_STALLEDES      (_U_(0x1) << DEVEPTIER_CTRL_STALLEDES_Pos)  /**< (DEVEPTIER) STALLed Interrupt Enable Mask */
+#define DEVEPTIER_CTRL_NYETDISS_Pos   17                                             /**< (DEVEPTIER) NYET Token Disable Enable Position */
+#define DEVEPTIER_CTRL_NYETDISS       (_U_(0x1) << DEVEPTIER_CTRL_NYETDISS_Pos)  /**< (DEVEPTIER) NYET Token Disable Enable Mask */
+#define DEVEPTIER_CTRL_STALLRQS_Pos   19                                             /**< (DEVEPTIER) STALL Request Enable Position */
+#define DEVEPTIER_CTRL_STALLRQS       (_U_(0x1) << DEVEPTIER_CTRL_STALLRQS_Pos)  /**< (DEVEPTIER) STALL Request Enable Mask */
+#define DEVEPTIER_CTRL_Msk            _U_(0xA005C)                                   /**< (DEVEPTIER_CTRL) Register Mask  */
+
+/* ISO mode */
+#define DEVEPTIER_ISO_UNDERFES_Pos    2                                              /**< (DEVEPTIER) Underflow Interrupt Enable Position */
+#define DEVEPTIER_ISO_UNDERFES        (_U_(0x1) << DEVEPTIER_ISO_UNDERFES_Pos)  /**< (DEVEPTIER) Underflow Interrupt Enable Mask */
+#define DEVEPTIER_ISO_HBISOINERRES_Pos 3                                              /**< (DEVEPTIER) High Bandwidth Isochronous IN Underflow Error Interrupt Enable Position */
+#define DEVEPTIER_ISO_HBISOINERRES     (_U_(0x1) << DEVEPTIER_ISO_HBISOINERRES_Pos)  /**< (DEVEPTIER) High Bandwidth Isochronous IN Underflow Error Interrupt Enable Mask */
+#define DEVEPTIER_ISO_HBISOFLUSHES_Pos 4                                              /**< (DEVEPTIER) High Bandwidth Isochronous IN Flush Interrupt Enable Position */
+#define DEVEPTIER_ISO_HBISOFLUSHES     (_U_(0x1) << DEVEPTIER_ISO_HBISOFLUSHES_Pos)  /**< (DEVEPTIER) High Bandwidth Isochronous IN Flush Interrupt Enable Mask */
+#define DEVEPTIER_ISO_CRCERRES_Pos    6                                              /**< (DEVEPTIER) CRC Error Interrupt Enable Position */
+#define DEVEPTIER_ISO_CRCERRES        (_U_(0x1) << DEVEPTIER_ISO_CRCERRES_Pos)  /**< (DEVEPTIER) CRC Error Interrupt Enable Mask */
+#define DEVEPTIER_ISO_MDATAES_Pos     8                                              /**< (DEVEPTIER) MData Interrupt Enable Position */
+#define DEVEPTIER_ISO_MDATAES         (_U_(0x1) << DEVEPTIER_ISO_MDATAES_Pos)  /**< (DEVEPTIER) MData Interrupt Enable Mask */
+#define DEVEPTIER_ISO_DATAXES_Pos     9                                              /**< (DEVEPTIER) DataX Interrupt Enable Position */
+#define DEVEPTIER_ISO_DATAXES         (_U_(0x1) << DEVEPTIER_ISO_DATAXES_Pos)  /**< (DEVEPTIER) DataX Interrupt Enable Mask */
+#define DEVEPTIER_ISO_ERRORTRANSES_Pos 10                                             /**< (DEVEPTIER) Transaction Error Interrupt Enable Position */
+#define DEVEPTIER_ISO_ERRORTRANSES     (_U_(0x1) << DEVEPTIER_ISO_ERRORTRANSES_Pos)  /**< (DEVEPTIER) Transaction Error Interrupt Enable Mask */
+#define DEVEPTIER_ISO_Msk             _U_(0x75C)                                     /**< (DEVEPTIER_ISO) Register Mask  */
+
+/* BLK mode */
+#define DEVEPTIER_BLK_RXSTPES_Pos     2                                              /**< (DEVEPTIER) Received SETUP Interrupt Enable Position */
+#define DEVEPTIER_BLK_RXSTPES         (_U_(0x1) << DEVEPTIER_BLK_RXSTPES_Pos)  /**< (DEVEPTIER) Received SETUP Interrupt Enable Mask */
+#define DEVEPTIER_BLK_NAKOUTES_Pos    3                                              /**< (DEVEPTIER) NAKed OUT Interrupt Enable Position */
+#define DEVEPTIER_BLK_NAKOUTES        (_U_(0x1) << DEVEPTIER_BLK_NAKOUTES_Pos)  /**< (DEVEPTIER) NAKed OUT Interrupt Enable Mask */
+#define DEVEPTIER_BLK_NAKINES_Pos     4                                              /**< (DEVEPTIER) NAKed IN Interrupt Enable Position */
+#define DEVEPTIER_BLK_NAKINES         (_U_(0x1) << DEVEPTIER_BLK_NAKINES_Pos)  /**< (DEVEPTIER) NAKed IN Interrupt Enable Mask */
+#define DEVEPTIER_BLK_STALLEDES_Pos   6                                              /**< (DEVEPTIER) STALLed Interrupt Enable Position */
+#define DEVEPTIER_BLK_STALLEDES       (_U_(0x1) << DEVEPTIER_BLK_STALLEDES_Pos)  /**< (DEVEPTIER) STALLed Interrupt Enable Mask */
+#define DEVEPTIER_BLK_NYETDISS_Pos    17                                             /**< (DEVEPTIER) NYET Token Disable Enable Position */
+#define DEVEPTIER_BLK_NYETDISS        (_U_(0x1) << DEVEPTIER_BLK_NYETDISS_Pos)  /**< (DEVEPTIER) NYET Token Disable Enable Mask */
+#define DEVEPTIER_BLK_STALLRQS_Pos    19                                             /**< (DEVEPTIER) STALL Request Enable Position */
+#define DEVEPTIER_BLK_STALLRQS        (_U_(0x1) << DEVEPTIER_BLK_STALLRQS_Pos)  /**< (DEVEPTIER) STALL Request Enable Mask */
+#define DEVEPTIER_BLK_Msk             _U_(0xA005C)                                   /**< (DEVEPTIER_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define DEVEPTIER_INTRPT_RXSTPES_Pos  2                                              /**< (DEVEPTIER) Received SETUP Interrupt Enable Position */
+#define DEVEPTIER_INTRPT_RXSTPES      (_U_(0x1) << DEVEPTIER_INTRPT_RXSTPES_Pos)  /**< (DEVEPTIER) Received SETUP Interrupt Enable Mask */
+#define DEVEPTIER_INTRPT_NAKOUTES_Pos 3                                              /**< (DEVEPTIER) NAKed OUT Interrupt Enable Position */
+#define DEVEPTIER_INTRPT_NAKOUTES     (_U_(0x1) << DEVEPTIER_INTRPT_NAKOUTES_Pos)  /**< (DEVEPTIER) NAKed OUT Interrupt Enable Mask */
+#define DEVEPTIER_INTRPT_NAKINES_Pos  4                                              /**< (DEVEPTIER) NAKed IN Interrupt Enable Position */
+#define DEVEPTIER_INTRPT_NAKINES      (_U_(0x1) << DEVEPTIER_INTRPT_NAKINES_Pos)  /**< (DEVEPTIER) NAKed IN Interrupt Enable Mask */
+#define DEVEPTIER_INTRPT_STALLEDES_Pos 6                                              /**< (DEVEPTIER) STALLed Interrupt Enable Position */
+#define DEVEPTIER_INTRPT_STALLEDES     (_U_(0x1) << DEVEPTIER_INTRPT_STALLEDES_Pos)  /**< (DEVEPTIER) STALLed Interrupt Enable Mask */
+#define DEVEPTIER_INTRPT_NYETDISS_Pos 17                                             /**< (DEVEPTIER) NYET Token Disable Enable Position */
+#define DEVEPTIER_INTRPT_NYETDISS     (_U_(0x1) << DEVEPTIER_INTRPT_NYETDISS_Pos)  /**< (DEVEPTIER) NYET Token Disable Enable Mask */
+#define DEVEPTIER_INTRPT_STALLRQS_Pos 19                                             /**< (DEVEPTIER) STALL Request Enable Position */
+#define DEVEPTIER_INTRPT_STALLRQS     (_U_(0x1) << DEVEPTIER_INTRPT_STALLRQS_Pos)  /**< (DEVEPTIER) STALL Request Enable Mask */
+#define DEVEPTIER_INTRPT_Msk          _U_(0xA005C)                                   /**< (DEVEPTIER_INTRPT) Register Mask  */
+
+
+/* -------- DEVEPTIDR : (USBHS Offset: 0x220) (/W 32) Device Endpoint Interrupt Disable Register -------- */
+
+#define DEVEPTIDR_OFFSET              (0x220)                                       /**<  (DEVEPTIDR) Device Endpoint Interrupt Disable Register  Offset */
+
+#define DEVEPTIDR_TXINEC_Pos          0                                              /**< (DEVEPTIDR) Transmitted IN Interrupt Clear Position */
+#define DEVEPTIDR_TXINEC              (_U_(0x1) << DEVEPTIDR_TXINEC_Pos)       /**< (DEVEPTIDR) Transmitted IN Interrupt Clear Mask */
+#define DEVEPTIDR_RXOUTEC_Pos         1                                              /**< (DEVEPTIDR) Received OUT Data Interrupt Clear Position */
+#define DEVEPTIDR_RXOUTEC             (_U_(0x1) << DEVEPTIDR_RXOUTEC_Pos)      /**< (DEVEPTIDR) Received OUT Data Interrupt Clear Mask */
+#define DEVEPTIDR_OVERFEC_Pos         5                                              /**< (DEVEPTIDR) Overflow Interrupt Clear Position */
+#define DEVEPTIDR_OVERFEC             (_U_(0x1) << DEVEPTIDR_OVERFEC_Pos)      /**< (DEVEPTIDR) Overflow Interrupt Clear Mask */
+#define DEVEPTIDR_SHORTPACKETEC_Pos   7                                              /**< (DEVEPTIDR) Shortpacket Interrupt Clear Position */
+#define DEVEPTIDR_SHORTPACKETEC       (_U_(0x1) << DEVEPTIDR_SHORTPACKETEC_Pos)  /**< (DEVEPTIDR) Shortpacket Interrupt Clear Mask */
+#define DEVEPTIDR_NBUSYBKEC_Pos       12                                             /**< (DEVEPTIDR) Number of Busy Banks Interrupt Clear Position */
+#define DEVEPTIDR_NBUSYBKEC           (_U_(0x1) << DEVEPTIDR_NBUSYBKEC_Pos)    /**< (DEVEPTIDR) Number of Busy Banks Interrupt Clear Mask */
+#define DEVEPTIDR_FIFOCONC_Pos        14                                             /**< (DEVEPTIDR) FIFO Control Clear Position */
+#define DEVEPTIDR_FIFOCONC            (_U_(0x1) << DEVEPTIDR_FIFOCONC_Pos)     /**< (DEVEPTIDR) FIFO Control Clear Mask */
+#define DEVEPTIDR_EPDISHDMAC_Pos      16                                             /**< (DEVEPTIDR) Endpoint Interrupts Disable HDMA Request Clear Position */
+#define DEVEPTIDR_EPDISHDMAC          (_U_(0x1) << DEVEPTIDR_EPDISHDMAC_Pos)   /**< (DEVEPTIDR) Endpoint Interrupts Disable HDMA Request Clear Mask */
+#define DEVEPTIDR_Msk                 _U_(0x150A3)                                   /**< (DEVEPTIDR) Register Mask  */
+
+/* CTRL mode */
+#define DEVEPTIDR_CTRL_RXSTPEC_Pos    2                                              /**< (DEVEPTIDR) Received SETUP Interrupt Clear Position */
+#define DEVEPTIDR_CTRL_RXSTPEC        (_U_(0x1) << DEVEPTIDR_CTRL_RXSTPEC_Pos)  /**< (DEVEPTIDR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTIDR_CTRL_NAKOUTEC_Pos   3                                              /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTIDR_CTRL_NAKOUTEC       (_U_(0x1) << DEVEPTIDR_CTRL_NAKOUTEC_Pos)  /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTIDR_CTRL_NAKINEC_Pos    4                                              /**< (DEVEPTIDR) NAKed IN Interrupt Clear Position */
+#define DEVEPTIDR_CTRL_NAKINEC        (_U_(0x1) << DEVEPTIDR_CTRL_NAKINEC_Pos)  /**< (DEVEPTIDR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTIDR_CTRL_STALLEDEC_Pos  6                                              /**< (DEVEPTIDR) STALLed Interrupt Clear Position */
+#define DEVEPTIDR_CTRL_STALLEDEC      (_U_(0x1) << DEVEPTIDR_CTRL_STALLEDEC_Pos)  /**< (DEVEPTIDR) STALLed Interrupt Clear Mask */
+#define DEVEPTIDR_CTRL_NYETDISC_Pos   17                                             /**< (DEVEPTIDR) NYET Token Disable Clear Position */
+#define DEVEPTIDR_CTRL_NYETDISC       (_U_(0x1) << DEVEPTIDR_CTRL_NYETDISC_Pos)  /**< (DEVEPTIDR) NYET Token Disable Clear Mask */
+#define DEVEPTIDR_CTRL_STALLRQC_Pos   19                                             /**< (DEVEPTIDR) STALL Request Clear Position */
+#define DEVEPTIDR_CTRL_STALLRQC       (_U_(0x1) << DEVEPTIDR_CTRL_STALLRQC_Pos)  /**< (DEVEPTIDR) STALL Request Clear Mask */
+#define DEVEPTIDR_CTRL_Msk            _U_(0xA005C)                                   /**< (DEVEPTIDR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define DEVEPTIDR_ISO_UNDERFEC_Pos    2                                              /**< (DEVEPTIDR) Underflow Interrupt Clear Position */
+#define DEVEPTIDR_ISO_UNDERFEC        (_U_(0x1) << DEVEPTIDR_ISO_UNDERFEC_Pos)  /**< (DEVEPTIDR) Underflow Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_HBISOINERREC_Pos 3                                              /**< (DEVEPTIDR) High Bandwidth Isochronous IN Underflow Error Interrupt Clear Position */
+#define DEVEPTIDR_ISO_HBISOINERREC     (_U_(0x1) << DEVEPTIDR_ISO_HBISOINERREC_Pos)  /**< (DEVEPTIDR) High Bandwidth Isochronous IN Underflow Error Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_HBISOFLUSHEC_Pos 4                                              /**< (DEVEPTIDR) High Bandwidth Isochronous IN Flush Interrupt Clear Position */
+#define DEVEPTIDR_ISO_HBISOFLUSHEC     (_U_(0x1) << DEVEPTIDR_ISO_HBISOFLUSHEC_Pos)  /**< (DEVEPTIDR) High Bandwidth Isochronous IN Flush Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_MDATAEC_Pos     8                                              /**< (DEVEPTIDR) MData Interrupt Clear Position */
+#define DEVEPTIDR_ISO_MDATAEC         (_U_(0x1) << DEVEPTIDR_ISO_MDATAEC_Pos)  /**< (DEVEPTIDR) MData Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_DATAXEC_Pos     9                                              /**< (DEVEPTIDR) DataX Interrupt Clear Position */
+#define DEVEPTIDR_ISO_DATAXEC         (_U_(0x1) << DEVEPTIDR_ISO_DATAXEC_Pos)  /**< (DEVEPTIDR) DataX Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_ERRORTRANSEC_Pos 10                                             /**< (DEVEPTIDR) Transaction Error Interrupt Clear Position */
+#define DEVEPTIDR_ISO_ERRORTRANSEC     (_U_(0x1) << DEVEPTIDR_ISO_ERRORTRANSEC_Pos)  /**< (DEVEPTIDR) Transaction Error Interrupt Clear Mask */
+#define DEVEPTIDR_ISO_Msk             _U_(0x71C)                                     /**< (DEVEPTIDR_ISO) Register Mask  */
+
+/* BLK mode */
+#define DEVEPTIDR_BLK_RXSTPEC_Pos     2                                              /**< (DEVEPTIDR) Received SETUP Interrupt Clear Position */
+#define DEVEPTIDR_BLK_RXSTPEC         (_U_(0x1) << DEVEPTIDR_BLK_RXSTPEC_Pos)  /**< (DEVEPTIDR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTIDR_BLK_NAKOUTEC_Pos    3                                              /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTIDR_BLK_NAKOUTEC        (_U_(0x1) << DEVEPTIDR_BLK_NAKOUTEC_Pos)  /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTIDR_BLK_NAKINEC_Pos     4                                              /**< (DEVEPTIDR) NAKed IN Interrupt Clear Position */
+#define DEVEPTIDR_BLK_NAKINEC         (_U_(0x1) << DEVEPTIDR_BLK_NAKINEC_Pos)  /**< (DEVEPTIDR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTIDR_BLK_STALLEDEC_Pos   6                                              /**< (DEVEPTIDR) STALLed Interrupt Clear Position */
+#define DEVEPTIDR_BLK_STALLEDEC       (_U_(0x1) << DEVEPTIDR_BLK_STALLEDEC_Pos)  /**< (DEVEPTIDR) STALLed Interrupt Clear Mask */
+#define DEVEPTIDR_BLK_NYETDISC_Pos    17                                             /**< (DEVEPTIDR) NYET Token Disable Clear Position */
+#define DEVEPTIDR_BLK_NYETDISC        (_U_(0x1) << DEVEPTIDR_BLK_NYETDISC_Pos)  /**< (DEVEPTIDR) NYET Token Disable Clear Mask */
+#define DEVEPTIDR_BLK_STALLRQC_Pos    19                                             /**< (DEVEPTIDR) STALL Request Clear Position */
+#define DEVEPTIDR_BLK_STALLRQC        (_U_(0x1) << DEVEPTIDR_BLK_STALLRQC_Pos)  /**< (DEVEPTIDR) STALL Request Clear Mask */
+#define DEVEPTIDR_BLK_Msk             _U_(0xA005C)                                   /**< (DEVEPTIDR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define DEVEPTIDR_INTRPT_RXSTPEC_Pos  2                                              /**< (DEVEPTIDR) Received SETUP Interrupt Clear Position */
+#define DEVEPTIDR_INTRPT_RXSTPEC      (_U_(0x1) << DEVEPTIDR_INTRPT_RXSTPEC_Pos)  /**< (DEVEPTIDR) Received SETUP Interrupt Clear Mask */
+#define DEVEPTIDR_INTRPT_NAKOUTEC_Pos 3                                              /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Position */
+#define DEVEPTIDR_INTRPT_NAKOUTEC     (_U_(0x1) << DEVEPTIDR_INTRPT_NAKOUTEC_Pos)  /**< (DEVEPTIDR) NAKed OUT Interrupt Clear Mask */
+#define DEVEPTIDR_INTRPT_NAKINEC_Pos  4                                              /**< (DEVEPTIDR) NAKed IN Interrupt Clear Position */
+#define DEVEPTIDR_INTRPT_NAKINEC      (_U_(0x1) << DEVEPTIDR_INTRPT_NAKINEC_Pos)  /**< (DEVEPTIDR) NAKed IN Interrupt Clear Mask */
+#define DEVEPTIDR_INTRPT_STALLEDEC_Pos 6                                              /**< (DEVEPTIDR) STALLed Interrupt Clear Position */
+#define DEVEPTIDR_INTRPT_STALLEDEC     (_U_(0x1) << DEVEPTIDR_INTRPT_STALLEDEC_Pos)  /**< (DEVEPTIDR) STALLed Interrupt Clear Mask */
+#define DEVEPTIDR_INTRPT_NYETDISC_Pos 17                                             /**< (DEVEPTIDR) NYET Token Disable Clear Position */
+#define DEVEPTIDR_INTRPT_NYETDISC     (_U_(0x1) << DEVEPTIDR_INTRPT_NYETDISC_Pos)  /**< (DEVEPTIDR) NYET Token Disable Clear Mask */
+#define DEVEPTIDR_INTRPT_STALLRQC_Pos 19                                             /**< (DEVEPTIDR) STALL Request Clear Position */
+#define DEVEPTIDR_INTRPT_STALLRQC     (_U_(0x1) << DEVEPTIDR_INTRPT_STALLRQC_Pos)  /**< (DEVEPTIDR) STALL Request Clear Mask */
+#define DEVEPTIDR_INTRPT_Msk          _U_(0xA005C)                                   /**< (DEVEPTIDR_INTRPT) Register Mask  */
+
+
+/* -------- HSTCTRL : (USBHS Offset: 0x400) (R/W 32) Host General Control Register -------- */
+
+#define HSTCTRL_OFFSET                (0x400)                                       /**<  (HSTCTRL) Host General Control Register  Offset */
+
+#define HSTCTRL_SOFE_Pos              8                                              /**< (HSTCTRL) Start of Frame Generation Enable Position */
+#define HSTCTRL_SOFE                  (_U_(0x1) << HSTCTRL_SOFE_Pos)           /**< (HSTCTRL) Start of Frame Generation Enable Mask */
+#define HSTCTRL_RESET_Pos             9                                              /**< (HSTCTRL) Send USB Reset Position */
+#define HSTCTRL_RESET                 (_U_(0x1) << HSTCTRL_RESET_Pos)          /**< (HSTCTRL) Send USB Reset Mask */
+#define HSTCTRL_RESUME_Pos            10                                             /**< (HSTCTRL) Send USB Resume Position */
+#define HSTCTRL_RESUME                (_U_(0x1) << HSTCTRL_RESUME_Pos)         /**< (HSTCTRL) Send USB Resume Mask */
+#define HSTCTRL_SPDCONF_Pos           12                                             /**< (HSTCTRL) Mode Configuration Position */
+#define HSTCTRL_SPDCONF               (_U_(0x3) << HSTCTRL_SPDCONF_Pos)        /**< (HSTCTRL) Mode Configuration Mask */
+#define   HSTCTRL_SPDCONF_NORMAL_Val  _U_(0x0)                                       /**< (HSTCTRL) The host starts in Full-speed mode and performs a high-speed reset to switch to High-speed mode if the downstream peripheral is high-speed capable.  */
+#define   HSTCTRL_SPDCONF_LOW_POWER_Val _U_(0x1)                                       /**< (HSTCTRL) For a better consumption, if high speed is not needed.  */
+#define   HSTCTRL_SPDCONF_HIGH_SPEED_Val _U_(0x2)                                       /**< (HSTCTRL) Forced high speed.  */
+#define   HSTCTRL_SPDCONF_FORCED_FS_Val _U_(0x3)                                       /**< (HSTCTRL) The host remains in Full-speed mode whatever the peripheral speed capability.  */
+#define HSTCTRL_SPDCONF_NORMAL        (HSTCTRL_SPDCONF_NORMAL_Val << HSTCTRL_SPDCONF_Pos)  /**< (HSTCTRL) The host starts in Full-speed mode and performs a high-speed reset to switch to High-speed mode if the downstream peripheral is high-speed capable. Position  */
+#define HSTCTRL_SPDCONF_LOW_POWER     (HSTCTRL_SPDCONF_LOW_POWER_Val << HSTCTRL_SPDCONF_Pos)  /**< (HSTCTRL) For a better consumption, if high speed is not needed. Position  */
+#define HSTCTRL_SPDCONF_HIGH_SPEED    (HSTCTRL_SPDCONF_HIGH_SPEED_Val << HSTCTRL_SPDCONF_Pos)  /**< (HSTCTRL) Forced high speed. Position  */
+#define HSTCTRL_SPDCONF_FORCED_FS     (HSTCTRL_SPDCONF_FORCED_FS_Val << HSTCTRL_SPDCONF_Pos)  /**< (HSTCTRL) The host remains in Full-speed mode whatever the peripheral speed capability. Position  */
+#define HSTCTRL_Msk                   _U_(0x3700)                                    /**< (HSTCTRL) Register Mask  */
+
+
+/* -------- HSTISR : (USBHS Offset: 0x404) (R/ 32) Host Global Interrupt Status Register -------- */
+
+#define HSTISR_OFFSET                 (0x404)                                       /**<  (HSTISR) Host Global Interrupt Status Register  Offset */
+
+#define HSTISR_DCONNI_Pos             0                                              /**< (HSTISR) Device Connection Interrupt Position */
+#define HSTISR_DCONNI                 (_U_(0x1) << HSTISR_DCONNI_Pos)          /**< (HSTISR) Device Connection Interrupt Mask */
+#define HSTISR_DDISCI_Pos             1                                              /**< (HSTISR) Device Disconnection Interrupt Position */
+#define HSTISR_DDISCI                 (_U_(0x1) << HSTISR_DDISCI_Pos)          /**< (HSTISR) Device Disconnection Interrupt Mask */
+#define HSTISR_RSTI_Pos               2                                              /**< (HSTISR) USB Reset Sent Interrupt Position */
+#define HSTISR_RSTI                   (_U_(0x1) << HSTISR_RSTI_Pos)            /**< (HSTISR) USB Reset Sent Interrupt Mask */
+#define HSTISR_RSMEDI_Pos             3                                              /**< (HSTISR) Downstream Resume Sent Interrupt Position */
+#define HSTISR_RSMEDI                 (_U_(0x1) << HSTISR_RSMEDI_Pos)          /**< (HSTISR) Downstream Resume Sent Interrupt Mask */
+#define HSTISR_RXRSMI_Pos             4                                              /**< (HSTISR) Upstream Resume Received Interrupt Position */
+#define HSTISR_RXRSMI                 (_U_(0x1) << HSTISR_RXRSMI_Pos)          /**< (HSTISR) Upstream Resume Received Interrupt Mask */
+#define HSTISR_HSOFI_Pos              5                                              /**< (HSTISR) Host Start of Frame Interrupt Position */
+#define HSTISR_HSOFI                  (_U_(0x1) << HSTISR_HSOFI_Pos)           /**< (HSTISR) Host Start of Frame Interrupt Mask */
+#define HSTISR_HWUPI_Pos              6                                              /**< (HSTISR) Host Wake-Up Interrupt Position */
+#define HSTISR_HWUPI                  (_U_(0x1) << HSTISR_HWUPI_Pos)           /**< (HSTISR) Host Wake-Up Interrupt Mask */
+#define HSTISR_PEP_0_Pos              8                                              /**< (HSTISR) Pipe 0 Interrupt Position */
+#define HSTISR_PEP_0                  (_U_(0x1) << HSTISR_PEP_0_Pos)           /**< (HSTISR) Pipe 0 Interrupt Mask */
+#define HSTISR_PEP_1_Pos              9                                              /**< (HSTISR) Pipe 1 Interrupt Position */
+#define HSTISR_PEP_1                  (_U_(0x1) << HSTISR_PEP_1_Pos)           /**< (HSTISR) Pipe 1 Interrupt Mask */
+#define HSTISR_PEP_2_Pos              10                                             /**< (HSTISR) Pipe 2 Interrupt Position */
+#define HSTISR_PEP_2                  (_U_(0x1) << HSTISR_PEP_2_Pos)           /**< (HSTISR) Pipe 2 Interrupt Mask */
+#define HSTISR_PEP_3_Pos              11                                             /**< (HSTISR) Pipe 3 Interrupt Position */
+#define HSTISR_PEP_3                  (_U_(0x1) << HSTISR_PEP_3_Pos)           /**< (HSTISR) Pipe 3 Interrupt Mask */
+#define HSTISR_PEP_4_Pos              12                                             /**< (HSTISR) Pipe 4 Interrupt Position */
+#define HSTISR_PEP_4                  (_U_(0x1) << HSTISR_PEP_4_Pos)           /**< (HSTISR) Pipe 4 Interrupt Mask */
+#define HSTISR_PEP_5_Pos              13                                             /**< (HSTISR) Pipe 5 Interrupt Position */
+#define HSTISR_PEP_5                  (_U_(0x1) << HSTISR_PEP_5_Pos)           /**< (HSTISR) Pipe 5 Interrupt Mask */
+#define HSTISR_PEP_6_Pos              14                                             /**< (HSTISR) Pipe 6 Interrupt Position */
+#define HSTISR_PEP_6                  (_U_(0x1) << HSTISR_PEP_6_Pos)           /**< (HSTISR) Pipe 6 Interrupt Mask */
+#define HSTISR_PEP_7_Pos              15                                             /**< (HSTISR) Pipe 7 Interrupt Position */
+#define HSTISR_PEP_7                  (_U_(0x1) << HSTISR_PEP_7_Pos)           /**< (HSTISR) Pipe 7 Interrupt Mask */
+#define HSTISR_PEP_8_Pos              16                                             /**< (HSTISR) Pipe 8 Interrupt Position */
+#define HSTISR_PEP_8                  (_U_(0x1) << HSTISR_PEP_8_Pos)           /**< (HSTISR) Pipe 8 Interrupt Mask */
+#define HSTISR_PEP_9_Pos              17                                             /**< (HSTISR) Pipe 9 Interrupt Position */
+#define HSTISR_PEP_9                  (_U_(0x1) << HSTISR_PEP_9_Pos)           /**< (HSTISR) Pipe 9 Interrupt Mask */
+#define HSTISR_DMA_0_Pos              25                                             /**< (HSTISR) DMA Channel 0 Interrupt Position */
+#define HSTISR_DMA_0                  (_U_(0x1) << HSTISR_DMA_0_Pos)           /**< (HSTISR) DMA Channel 0 Interrupt Mask */
+#define HSTISR_DMA_1_Pos              26                                             /**< (HSTISR) DMA Channel 1 Interrupt Position */
+#define HSTISR_DMA_1                  (_U_(0x1) << HSTISR_DMA_1_Pos)           /**< (HSTISR) DMA Channel 1 Interrupt Mask */
+#define HSTISR_DMA_2_Pos              27                                             /**< (HSTISR) DMA Channel 2 Interrupt Position */
+#define HSTISR_DMA_2                  (_U_(0x1) << HSTISR_DMA_2_Pos)           /**< (HSTISR) DMA Channel 2 Interrupt Mask */
+#define HSTISR_DMA_3_Pos              28                                             /**< (HSTISR) DMA Channel 3 Interrupt Position */
+#define HSTISR_DMA_3                  (_U_(0x1) << HSTISR_DMA_3_Pos)           /**< (HSTISR) DMA Channel 3 Interrupt Mask */
+#define HSTISR_DMA_4_Pos              29                                             /**< (HSTISR) DMA Channel 4 Interrupt Position */
+#define HSTISR_DMA_4                  (_U_(0x1) << HSTISR_DMA_4_Pos)           /**< (HSTISR) DMA Channel 4 Interrupt Mask */
+#define HSTISR_DMA_5_Pos              30                                             /**< (HSTISR) DMA Channel 5 Interrupt Position */
+#define HSTISR_DMA_5                  (_U_(0x1) << HSTISR_DMA_5_Pos)           /**< (HSTISR) DMA Channel 5 Interrupt Mask */
+#define HSTISR_DMA_6_Pos              31                                             /**< (HSTISR) DMA Channel 6 Interrupt Position */
+#define HSTISR_DMA_6                  (_U_(0x1) << HSTISR_DMA_6_Pos)           /**< (HSTISR) DMA Channel 6 Interrupt Mask */
+#define HSTISR_Msk                    _U_(0xFE03FF7F)                                /**< (HSTISR) Register Mask  */
+
+#define HSTISR_PEP__Pos               8                                              /**< (HSTISR Position) Pipe x Interrupt */
+#define HSTISR_PEP_                   (_U_(0x3FF) << HSTISR_PEP__Pos)          /**< (HSTISR Mask) PEP_ */
+#define HSTISR_DMA__Pos               25                                             /**< (HSTISR Position) DMA Channel 6 Interrupt */
+#define HSTISR_DMA_                   (_U_(0x7F) << HSTISR_DMA__Pos)           /**< (HSTISR Mask) DMA_ */
+
+/* -------- HSTICR : (USBHS Offset: 0x408) (/W 32) Host Global Interrupt Clear Register -------- */
+
+#define HSTICR_OFFSET                 (0x408)                                       /**<  (HSTICR) Host Global Interrupt Clear Register  Offset */
+
+#define HSTICR_DCONNIC_Pos            0                                              /**< (HSTICR) Device Connection Interrupt Clear Position */
+#define HSTICR_DCONNIC                (_U_(0x1) << HSTICR_DCONNIC_Pos)         /**< (HSTICR) Device Connection Interrupt Clear Mask */
+#define HSTICR_DDISCIC_Pos            1                                              /**< (HSTICR) Device Disconnection Interrupt Clear Position */
+#define HSTICR_DDISCIC                (_U_(0x1) << HSTICR_DDISCIC_Pos)         /**< (HSTICR) Device Disconnection Interrupt Clear Mask */
+#define HSTICR_RSTIC_Pos              2                                              /**< (HSTICR) USB Reset Sent Interrupt Clear Position */
+#define HSTICR_RSTIC                  (_U_(0x1) << HSTICR_RSTIC_Pos)           /**< (HSTICR) USB Reset Sent Interrupt Clear Mask */
+#define HSTICR_RSMEDIC_Pos            3                                              /**< (HSTICR) Downstream Resume Sent Interrupt Clear Position */
+#define HSTICR_RSMEDIC                (_U_(0x1) << HSTICR_RSMEDIC_Pos)         /**< (HSTICR) Downstream Resume Sent Interrupt Clear Mask */
+#define HSTICR_RXRSMIC_Pos            4                                              /**< (HSTICR) Upstream Resume Received Interrupt Clear Position */
+#define HSTICR_RXRSMIC                (_U_(0x1) << HSTICR_RXRSMIC_Pos)         /**< (HSTICR) Upstream Resume Received Interrupt Clear Mask */
+#define HSTICR_HSOFIC_Pos             5                                              /**< (HSTICR) Host Start of Frame Interrupt Clear Position */
+#define HSTICR_HSOFIC                 (_U_(0x1) << HSTICR_HSOFIC_Pos)          /**< (HSTICR) Host Start of Frame Interrupt Clear Mask */
+#define HSTICR_HWUPIC_Pos             6                                              /**< (HSTICR) Host Wake-Up Interrupt Clear Position */
+#define HSTICR_HWUPIC                 (_U_(0x1) << HSTICR_HWUPIC_Pos)          /**< (HSTICR) Host Wake-Up Interrupt Clear Mask */
+#define HSTICR_Msk                    _U_(0x7F)                                      /**< (HSTICR) Register Mask  */
+
+
+/* -------- HSTIFR : (USBHS Offset: 0x40c) (/W 32) Host Global Interrupt Set Register -------- */
+
+#define HSTIFR_OFFSET                 (0x40C)                                       /**<  (HSTIFR) Host Global Interrupt Set Register  Offset */
+
+#define HSTIFR_DCONNIS_Pos            0                                              /**< (HSTIFR) Device Connection Interrupt Set Position */
+#define HSTIFR_DCONNIS                (_U_(0x1) << HSTIFR_DCONNIS_Pos)         /**< (HSTIFR) Device Connection Interrupt Set Mask */
+#define HSTIFR_DDISCIS_Pos            1                                              /**< (HSTIFR) Device Disconnection Interrupt Set Position */
+#define HSTIFR_DDISCIS                (_U_(0x1) << HSTIFR_DDISCIS_Pos)         /**< (HSTIFR) Device Disconnection Interrupt Set Mask */
+#define HSTIFR_RSTIS_Pos              2                                              /**< (HSTIFR) USB Reset Sent Interrupt Set Position */
+#define HSTIFR_RSTIS                  (_U_(0x1) << HSTIFR_RSTIS_Pos)           /**< (HSTIFR) USB Reset Sent Interrupt Set Mask */
+#define HSTIFR_RSMEDIS_Pos            3                                              /**< (HSTIFR) Downstream Resume Sent Interrupt Set Position */
+#define HSTIFR_RSMEDIS                (_U_(0x1) << HSTIFR_RSMEDIS_Pos)         /**< (HSTIFR) Downstream Resume Sent Interrupt Set Mask */
+#define HSTIFR_RXRSMIS_Pos            4                                              /**< (HSTIFR) Upstream Resume Received Interrupt Set Position */
+#define HSTIFR_RXRSMIS                (_U_(0x1) << HSTIFR_RXRSMIS_Pos)         /**< (HSTIFR) Upstream Resume Received Interrupt Set Mask */
+#define HSTIFR_HSOFIS_Pos             5                                              /**< (HSTIFR) Host Start of Frame Interrupt Set Position */
+#define HSTIFR_HSOFIS                 (_U_(0x1) << HSTIFR_HSOFIS_Pos)          /**< (HSTIFR) Host Start of Frame Interrupt Set Mask */
+#define HSTIFR_HWUPIS_Pos             6                                              /**< (HSTIFR) Host Wake-Up Interrupt Set Position */
+#define HSTIFR_HWUPIS                 (_U_(0x1) << HSTIFR_HWUPIS_Pos)          /**< (HSTIFR) Host Wake-Up Interrupt Set Mask */
+#define HSTIFR_DMA_0_Pos              25                                             /**< (HSTIFR) DMA Channel 0 Interrupt Set Position */
+#define HSTIFR_DMA_0                  (_U_(0x1) << HSTIFR_DMA_0_Pos)           /**< (HSTIFR) DMA Channel 0 Interrupt Set Mask */
+#define HSTIFR_DMA_1_Pos              26                                             /**< (HSTIFR) DMA Channel 1 Interrupt Set Position */
+#define HSTIFR_DMA_1                  (_U_(0x1) << HSTIFR_DMA_1_Pos)           /**< (HSTIFR) DMA Channel 1 Interrupt Set Mask */
+#define HSTIFR_DMA_2_Pos              27                                             /**< (HSTIFR) DMA Channel 2 Interrupt Set Position */
+#define HSTIFR_DMA_2                  (_U_(0x1) << HSTIFR_DMA_2_Pos)           /**< (HSTIFR) DMA Channel 2 Interrupt Set Mask */
+#define HSTIFR_DMA_3_Pos              28                                             /**< (HSTIFR) DMA Channel 3 Interrupt Set Position */
+#define HSTIFR_DMA_3                  (_U_(0x1) << HSTIFR_DMA_3_Pos)           /**< (HSTIFR) DMA Channel 3 Interrupt Set Mask */
+#define HSTIFR_DMA_4_Pos              29                                             /**< (HSTIFR) DMA Channel 4 Interrupt Set Position */
+#define HSTIFR_DMA_4                  (_U_(0x1) << HSTIFR_DMA_4_Pos)           /**< (HSTIFR) DMA Channel 4 Interrupt Set Mask */
+#define HSTIFR_DMA_5_Pos              30                                             /**< (HSTIFR) DMA Channel 5 Interrupt Set Position */
+#define HSTIFR_DMA_5                  (_U_(0x1) << HSTIFR_DMA_5_Pos)           /**< (HSTIFR) DMA Channel 5 Interrupt Set Mask */
+#define HSTIFR_DMA_6_Pos              31                                             /**< (HSTIFR) DMA Channel 6 Interrupt Set Position */
+#define HSTIFR_DMA_6                  (_U_(0x1) << HSTIFR_DMA_6_Pos)           /**< (HSTIFR) DMA Channel 6 Interrupt Set Mask */
+#define HSTIFR_Msk                    _U_(0xFE00007F)                                /**< (HSTIFR) Register Mask  */
+
+#define HSTIFR_DMA__Pos               25                                             /**< (HSTIFR Position) DMA Channel 6 Interrupt Set */
+#define HSTIFR_DMA_                   (_U_(0x7F) << HSTIFR_DMA__Pos)           /**< (HSTIFR Mask) DMA_ */
+
+/* -------- HSTIMR : (USBHS Offset: 0x410) (R/ 32) Host Global Interrupt Mask Register -------- */
+
+#define HSTIMR_OFFSET                 (0x410)                                       /**<  (HSTIMR) Host Global Interrupt Mask Register  Offset */
+
+#define HSTIMR_DCONNIE_Pos            0                                              /**< (HSTIMR) Device Connection Interrupt Enable Position */
+#define HSTIMR_DCONNIE                (_U_(0x1) << HSTIMR_DCONNIE_Pos)         /**< (HSTIMR) Device Connection Interrupt Enable Mask */
+#define HSTIMR_DDISCIE_Pos            1                                              /**< (HSTIMR) Device Disconnection Interrupt Enable Position */
+#define HSTIMR_DDISCIE                (_U_(0x1) << HSTIMR_DDISCIE_Pos)         /**< (HSTIMR) Device Disconnection Interrupt Enable Mask */
+#define HSTIMR_RSTIE_Pos              2                                              /**< (HSTIMR) USB Reset Sent Interrupt Enable Position */
+#define HSTIMR_RSTIE                  (_U_(0x1) << HSTIMR_RSTIE_Pos)           /**< (HSTIMR) USB Reset Sent Interrupt Enable Mask */
+#define HSTIMR_RSMEDIE_Pos            3                                              /**< (HSTIMR) Downstream Resume Sent Interrupt Enable Position */
+#define HSTIMR_RSMEDIE                (_U_(0x1) << HSTIMR_RSMEDIE_Pos)         /**< (HSTIMR) Downstream Resume Sent Interrupt Enable Mask */
+#define HSTIMR_RXRSMIE_Pos            4                                              /**< (HSTIMR) Upstream Resume Received Interrupt Enable Position */
+#define HSTIMR_RXRSMIE                (_U_(0x1) << HSTIMR_RXRSMIE_Pos)         /**< (HSTIMR) Upstream Resume Received Interrupt Enable Mask */
+#define HSTIMR_HSOFIE_Pos             5                                              /**< (HSTIMR) Host Start of Frame Interrupt Enable Position */
+#define HSTIMR_HSOFIE                 (_U_(0x1) << HSTIMR_HSOFIE_Pos)          /**< (HSTIMR) Host Start of Frame Interrupt Enable Mask */
+#define HSTIMR_HWUPIE_Pos             6                                              /**< (HSTIMR) Host Wake-Up Interrupt Enable Position */
+#define HSTIMR_HWUPIE                 (_U_(0x1) << HSTIMR_HWUPIE_Pos)          /**< (HSTIMR) Host Wake-Up Interrupt Enable Mask */
+#define HSTIMR_PEP_0_Pos              8                                              /**< (HSTIMR) Pipe 0 Interrupt Enable Position */
+#define HSTIMR_PEP_0                  (_U_(0x1) << HSTIMR_PEP_0_Pos)           /**< (HSTIMR) Pipe 0 Interrupt Enable Mask */
+#define HSTIMR_PEP_1_Pos              9                                              /**< (HSTIMR) Pipe 1 Interrupt Enable Position */
+#define HSTIMR_PEP_1                  (_U_(0x1) << HSTIMR_PEP_1_Pos)           /**< (HSTIMR) Pipe 1 Interrupt Enable Mask */
+#define HSTIMR_PEP_2_Pos              10                                             /**< (HSTIMR) Pipe 2 Interrupt Enable Position */
+#define HSTIMR_PEP_2                  (_U_(0x1) << HSTIMR_PEP_2_Pos)           /**< (HSTIMR) Pipe 2 Interrupt Enable Mask */
+#define HSTIMR_PEP_3_Pos              11                                             /**< (HSTIMR) Pipe 3 Interrupt Enable Position */
+#define HSTIMR_PEP_3                  (_U_(0x1) << HSTIMR_PEP_3_Pos)           /**< (HSTIMR) Pipe 3 Interrupt Enable Mask */
+#define HSTIMR_PEP_4_Pos              12                                             /**< (HSTIMR) Pipe 4 Interrupt Enable Position */
+#define HSTIMR_PEP_4                  (_U_(0x1) << HSTIMR_PEP_4_Pos)           /**< (HSTIMR) Pipe 4 Interrupt Enable Mask */
+#define HSTIMR_PEP_5_Pos              13                                             /**< (HSTIMR) Pipe 5 Interrupt Enable Position */
+#define HSTIMR_PEP_5                  (_U_(0x1) << HSTIMR_PEP_5_Pos)           /**< (HSTIMR) Pipe 5 Interrupt Enable Mask */
+#define HSTIMR_PEP_6_Pos              14                                             /**< (HSTIMR) Pipe 6 Interrupt Enable Position */
+#define HSTIMR_PEP_6                  (_U_(0x1) << HSTIMR_PEP_6_Pos)           /**< (HSTIMR) Pipe 6 Interrupt Enable Mask */
+#define HSTIMR_PEP_7_Pos              15                                             /**< (HSTIMR) Pipe 7 Interrupt Enable Position */
+#define HSTIMR_PEP_7                  (_U_(0x1) << HSTIMR_PEP_7_Pos)           /**< (HSTIMR) Pipe 7 Interrupt Enable Mask */
+#define HSTIMR_PEP_8_Pos              16                                             /**< (HSTIMR) Pipe 8 Interrupt Enable Position */
+#define HSTIMR_PEP_8                  (_U_(0x1) << HSTIMR_PEP_8_Pos)           /**< (HSTIMR) Pipe 8 Interrupt Enable Mask */
+#define HSTIMR_PEP_9_Pos              17                                             /**< (HSTIMR) Pipe 9 Interrupt Enable Position */
+#define HSTIMR_PEP_9                  (_U_(0x1) << HSTIMR_PEP_9_Pos)           /**< (HSTIMR) Pipe 9 Interrupt Enable Mask */
+#define HSTIMR_DMA_0_Pos              25                                             /**< (HSTIMR) DMA Channel 0 Interrupt Enable Position */
+#define HSTIMR_DMA_0                  (_U_(0x1) << HSTIMR_DMA_0_Pos)           /**< (HSTIMR) DMA Channel 0 Interrupt Enable Mask */
+#define HSTIMR_DMA_1_Pos              26                                             /**< (HSTIMR) DMA Channel 1 Interrupt Enable Position */
+#define HSTIMR_DMA_1                  (_U_(0x1) << HSTIMR_DMA_1_Pos)           /**< (HSTIMR) DMA Channel 1 Interrupt Enable Mask */
+#define HSTIMR_DMA_2_Pos              27                                             /**< (HSTIMR) DMA Channel 2 Interrupt Enable Position */
+#define HSTIMR_DMA_2                  (_U_(0x1) << HSTIMR_DMA_2_Pos)           /**< (HSTIMR) DMA Channel 2 Interrupt Enable Mask */
+#define HSTIMR_DMA_3_Pos              28                                             /**< (HSTIMR) DMA Channel 3 Interrupt Enable Position */
+#define HSTIMR_DMA_3                  (_U_(0x1) << HSTIMR_DMA_3_Pos)           /**< (HSTIMR) DMA Channel 3 Interrupt Enable Mask */
+#define HSTIMR_DMA_4_Pos              29                                             /**< (HSTIMR) DMA Channel 4 Interrupt Enable Position */
+#define HSTIMR_DMA_4                  (_U_(0x1) << HSTIMR_DMA_4_Pos)           /**< (HSTIMR) DMA Channel 4 Interrupt Enable Mask */
+#define HSTIMR_DMA_5_Pos              30                                             /**< (HSTIMR) DMA Channel 5 Interrupt Enable Position */
+#define HSTIMR_DMA_5                  (_U_(0x1) << HSTIMR_DMA_5_Pos)           /**< (HSTIMR) DMA Channel 5 Interrupt Enable Mask */
+#define HSTIMR_DMA_6_Pos              31                                             /**< (HSTIMR) DMA Channel 6 Interrupt Enable Position */
+#define HSTIMR_DMA_6                  (_U_(0x1) << HSTIMR_DMA_6_Pos)           /**< (HSTIMR) DMA Channel 6 Interrupt Enable Mask */
+#define HSTIMR_Msk                    _U_(0xFE03FF7F)                                /**< (HSTIMR) Register Mask  */
+
+#define HSTIMR_PEP__Pos               8                                              /**< (HSTIMR Position) Pipe x Interrupt Enable */
+#define HSTIMR_PEP_                   (_U_(0x3FF) << HSTIMR_PEP__Pos)          /**< (HSTIMR Mask) PEP_ */
+#define HSTIMR_DMA__Pos               25                                             /**< (HSTIMR Position) DMA Channel 6 Interrupt Enable */
+#define HSTIMR_DMA_                   (_U_(0x7F) << HSTIMR_DMA__Pos)           /**< (HSTIMR Mask) DMA_ */
+
+/* -------- HSTIDR : (USBHS Offset: 0x414) (/W 32) Host Global Interrupt Disable Register -------- */
+
+#define HSTIDR_OFFSET                 (0x414)                                       /**<  (HSTIDR) Host Global Interrupt Disable Register  Offset */
+
+#define HSTIDR_DCONNIEC_Pos           0                                              /**< (HSTIDR) Device Connection Interrupt Disable Position */
+#define HSTIDR_DCONNIEC               (_U_(0x1) << HSTIDR_DCONNIEC_Pos)        /**< (HSTIDR) Device Connection Interrupt Disable Mask */
+#define HSTIDR_DDISCIEC_Pos           1                                              /**< (HSTIDR) Device Disconnection Interrupt Disable Position */
+#define HSTIDR_DDISCIEC               (_U_(0x1) << HSTIDR_DDISCIEC_Pos)        /**< (HSTIDR) Device Disconnection Interrupt Disable Mask */
+#define HSTIDR_RSTIEC_Pos             2                                              /**< (HSTIDR) USB Reset Sent Interrupt Disable Position */
+#define HSTIDR_RSTIEC                 (_U_(0x1) << HSTIDR_RSTIEC_Pos)          /**< (HSTIDR) USB Reset Sent Interrupt Disable Mask */
+#define HSTIDR_RSMEDIEC_Pos           3                                              /**< (HSTIDR) Downstream Resume Sent Interrupt Disable Position */
+#define HSTIDR_RSMEDIEC               (_U_(0x1) << HSTIDR_RSMEDIEC_Pos)        /**< (HSTIDR) Downstream Resume Sent Interrupt Disable Mask */
+#define HSTIDR_RXRSMIEC_Pos           4                                              /**< (HSTIDR) Upstream Resume Received Interrupt Disable Position */
+#define HSTIDR_RXRSMIEC               (_U_(0x1) << HSTIDR_RXRSMIEC_Pos)        /**< (HSTIDR) Upstream Resume Received Interrupt Disable Mask */
+#define HSTIDR_HSOFIEC_Pos            5                                              /**< (HSTIDR) Host Start of Frame Interrupt Disable Position */
+#define HSTIDR_HSOFIEC                (_U_(0x1) << HSTIDR_HSOFIEC_Pos)         /**< (HSTIDR) Host Start of Frame Interrupt Disable Mask */
+#define HSTIDR_HWUPIEC_Pos            6                                              /**< (HSTIDR) Host Wake-Up Interrupt Disable Position */
+#define HSTIDR_HWUPIEC                (_U_(0x1) << HSTIDR_HWUPIEC_Pos)         /**< (HSTIDR) Host Wake-Up Interrupt Disable Mask */
+#define HSTIDR_PEP_0_Pos              8                                              /**< (HSTIDR) Pipe 0 Interrupt Disable Position */
+#define HSTIDR_PEP_0                  (_U_(0x1) << HSTIDR_PEP_0_Pos)           /**< (HSTIDR) Pipe 0 Interrupt Disable Mask */
+#define HSTIDR_PEP_1_Pos              9                                              /**< (HSTIDR) Pipe 1 Interrupt Disable Position */
+#define HSTIDR_PEP_1                  (_U_(0x1) << HSTIDR_PEP_1_Pos)           /**< (HSTIDR) Pipe 1 Interrupt Disable Mask */
+#define HSTIDR_PEP_2_Pos              10                                             /**< (HSTIDR) Pipe 2 Interrupt Disable Position */
+#define HSTIDR_PEP_2                  (_U_(0x1) << HSTIDR_PEP_2_Pos)           /**< (HSTIDR) Pipe 2 Interrupt Disable Mask */
+#define HSTIDR_PEP_3_Pos              11                                             /**< (HSTIDR) Pipe 3 Interrupt Disable Position */
+#define HSTIDR_PEP_3                  (_U_(0x1) << HSTIDR_PEP_3_Pos)           /**< (HSTIDR) Pipe 3 Interrupt Disable Mask */
+#define HSTIDR_PEP_4_Pos              12                                             /**< (HSTIDR) Pipe 4 Interrupt Disable Position */
+#define HSTIDR_PEP_4                  (_U_(0x1) << HSTIDR_PEP_4_Pos)           /**< (HSTIDR) Pipe 4 Interrupt Disable Mask */
+#define HSTIDR_PEP_5_Pos              13                                             /**< (HSTIDR) Pipe 5 Interrupt Disable Position */
+#define HSTIDR_PEP_5                  (_U_(0x1) << HSTIDR_PEP_5_Pos)           /**< (HSTIDR) Pipe 5 Interrupt Disable Mask */
+#define HSTIDR_PEP_6_Pos              14                                             /**< (HSTIDR) Pipe 6 Interrupt Disable Position */
+#define HSTIDR_PEP_6                  (_U_(0x1) << HSTIDR_PEP_6_Pos)           /**< (HSTIDR) Pipe 6 Interrupt Disable Mask */
+#define HSTIDR_PEP_7_Pos              15                                             /**< (HSTIDR) Pipe 7 Interrupt Disable Position */
+#define HSTIDR_PEP_7                  (_U_(0x1) << HSTIDR_PEP_7_Pos)           /**< (HSTIDR) Pipe 7 Interrupt Disable Mask */
+#define HSTIDR_PEP_8_Pos              16                                             /**< (HSTIDR) Pipe 8 Interrupt Disable Position */
+#define HSTIDR_PEP_8                  (_U_(0x1) << HSTIDR_PEP_8_Pos)           /**< (HSTIDR) Pipe 8 Interrupt Disable Mask */
+#define HSTIDR_PEP_9_Pos              17                                             /**< (HSTIDR) Pipe 9 Interrupt Disable Position */
+#define HSTIDR_PEP_9                  (_U_(0x1) << HSTIDR_PEP_9_Pos)           /**< (HSTIDR) Pipe 9 Interrupt Disable Mask */
+#define HSTIDR_DMA_0_Pos              25                                             /**< (HSTIDR) DMA Channel 0 Interrupt Disable Position */
+#define HSTIDR_DMA_0                  (_U_(0x1) << HSTIDR_DMA_0_Pos)           /**< (HSTIDR) DMA Channel 0 Interrupt Disable Mask */
+#define HSTIDR_DMA_1_Pos              26                                             /**< (HSTIDR) DMA Channel 1 Interrupt Disable Position */
+#define HSTIDR_DMA_1                  (_U_(0x1) << HSTIDR_DMA_1_Pos)           /**< (HSTIDR) DMA Channel 1 Interrupt Disable Mask */
+#define HSTIDR_DMA_2_Pos              27                                             /**< (HSTIDR) DMA Channel 2 Interrupt Disable Position */
+#define HSTIDR_DMA_2                  (_U_(0x1) << HSTIDR_DMA_2_Pos)           /**< (HSTIDR) DMA Channel 2 Interrupt Disable Mask */
+#define HSTIDR_DMA_3_Pos              28                                             /**< (HSTIDR) DMA Channel 3 Interrupt Disable Position */
+#define HSTIDR_DMA_3                  (_U_(0x1) << HSTIDR_DMA_3_Pos)           /**< (HSTIDR) DMA Channel 3 Interrupt Disable Mask */
+#define HSTIDR_DMA_4_Pos              29                                             /**< (HSTIDR) DMA Channel 4 Interrupt Disable Position */
+#define HSTIDR_DMA_4                  (_U_(0x1) << HSTIDR_DMA_4_Pos)           /**< (HSTIDR) DMA Channel 4 Interrupt Disable Mask */
+#define HSTIDR_DMA_5_Pos              30                                             /**< (HSTIDR) DMA Channel 5 Interrupt Disable Position */
+#define HSTIDR_DMA_5                  (_U_(0x1) << HSTIDR_DMA_5_Pos)           /**< (HSTIDR) DMA Channel 5 Interrupt Disable Mask */
+#define HSTIDR_DMA_6_Pos              31                                             /**< (HSTIDR) DMA Channel 6 Interrupt Disable Position */
+#define HSTIDR_DMA_6                  (_U_(0x1) << HSTIDR_DMA_6_Pos)           /**< (HSTIDR) DMA Channel 6 Interrupt Disable Mask */
+#define HSTIDR_Msk                    _U_(0xFE03FF7F)                                /**< (HSTIDR) Register Mask  */
+
+#define HSTIDR_PEP__Pos               8                                              /**< (HSTIDR Position) Pipe x Interrupt Disable */
+#define HSTIDR_PEP_                   (_U_(0x3FF) << HSTIDR_PEP__Pos)          /**< (HSTIDR Mask) PEP_ */
+#define HSTIDR_DMA__Pos               25                                             /**< (HSTIDR Position) DMA Channel 6 Interrupt Disable */
+#define HSTIDR_DMA_                   (_U_(0x7F) << HSTIDR_DMA__Pos)           /**< (HSTIDR Mask) DMA_ */
+
+/* -------- HSTIER : (USBHS Offset: 0x418) (/W 32) Host Global Interrupt Enable Register -------- */
+
+#define HSTIER_OFFSET                 (0x418)                                       /**<  (HSTIER) Host Global Interrupt Enable Register  Offset */
+
+#define HSTIER_DCONNIES_Pos           0                                              /**< (HSTIER) Device Connection Interrupt Enable Position */
+#define HSTIER_DCONNIES               (_U_(0x1) << HSTIER_DCONNIES_Pos)        /**< (HSTIER) Device Connection Interrupt Enable Mask */
+#define HSTIER_DDISCIES_Pos           1                                              /**< (HSTIER) Device Disconnection Interrupt Enable Position */
+#define HSTIER_DDISCIES               (_U_(0x1) << HSTIER_DDISCIES_Pos)        /**< (HSTIER) Device Disconnection Interrupt Enable Mask */
+#define HSTIER_RSTIES_Pos             2                                              /**< (HSTIER) USB Reset Sent Interrupt Enable Position */
+#define HSTIER_RSTIES                 (_U_(0x1) << HSTIER_RSTIES_Pos)          /**< (HSTIER) USB Reset Sent Interrupt Enable Mask */
+#define HSTIER_RSMEDIES_Pos           3                                              /**< (HSTIER) Downstream Resume Sent Interrupt Enable Position */
+#define HSTIER_RSMEDIES               (_U_(0x1) << HSTIER_RSMEDIES_Pos)        /**< (HSTIER) Downstream Resume Sent Interrupt Enable Mask */
+#define HSTIER_RXRSMIES_Pos           4                                              /**< (HSTIER) Upstream Resume Received Interrupt Enable Position */
+#define HSTIER_RXRSMIES               (_U_(0x1) << HSTIER_RXRSMIES_Pos)        /**< (HSTIER) Upstream Resume Received Interrupt Enable Mask */
+#define HSTIER_HSOFIES_Pos            5                                              /**< (HSTIER) Host Start of Frame Interrupt Enable Position */
+#define HSTIER_HSOFIES                (_U_(0x1) << HSTIER_HSOFIES_Pos)         /**< (HSTIER) Host Start of Frame Interrupt Enable Mask */
+#define HSTIER_HWUPIES_Pos            6                                              /**< (HSTIER) Host Wake-Up Interrupt Enable Position */
+#define HSTIER_HWUPIES                (_U_(0x1) << HSTIER_HWUPIES_Pos)         /**< (HSTIER) Host Wake-Up Interrupt Enable Mask */
+#define HSTIER_PEP_0_Pos              8                                              /**< (HSTIER) Pipe 0 Interrupt Enable Position */
+#define HSTIER_PEP_0                  (_U_(0x1) << HSTIER_PEP_0_Pos)           /**< (HSTIER) Pipe 0 Interrupt Enable Mask */
+#define HSTIER_PEP_1_Pos              9                                              /**< (HSTIER) Pipe 1 Interrupt Enable Position */
+#define HSTIER_PEP_1                  (_U_(0x1) << HSTIER_PEP_1_Pos)           /**< (HSTIER) Pipe 1 Interrupt Enable Mask */
+#define HSTIER_PEP_2_Pos              10                                             /**< (HSTIER) Pipe 2 Interrupt Enable Position */
+#define HSTIER_PEP_2                  (_U_(0x1) << HSTIER_PEP_2_Pos)           /**< (HSTIER) Pipe 2 Interrupt Enable Mask */
+#define HSTIER_PEP_3_Pos              11                                             /**< (HSTIER) Pipe 3 Interrupt Enable Position */
+#define HSTIER_PEP_3                  (_U_(0x1) << HSTIER_PEP_3_Pos)           /**< (HSTIER) Pipe 3 Interrupt Enable Mask */
+#define HSTIER_PEP_4_Pos              12                                             /**< (HSTIER) Pipe 4 Interrupt Enable Position */
+#define HSTIER_PEP_4                  (_U_(0x1) << HSTIER_PEP_4_Pos)           /**< (HSTIER) Pipe 4 Interrupt Enable Mask */
+#define HSTIER_PEP_5_Pos              13                                             /**< (HSTIER) Pipe 5 Interrupt Enable Position */
+#define HSTIER_PEP_5                  (_U_(0x1) << HSTIER_PEP_5_Pos)           /**< (HSTIER) Pipe 5 Interrupt Enable Mask */
+#define HSTIER_PEP_6_Pos              14                                             /**< (HSTIER) Pipe 6 Interrupt Enable Position */
+#define HSTIER_PEP_6                  (_U_(0x1) << HSTIER_PEP_6_Pos)           /**< (HSTIER) Pipe 6 Interrupt Enable Mask */
+#define HSTIER_PEP_7_Pos              15                                             /**< (HSTIER) Pipe 7 Interrupt Enable Position */
+#define HSTIER_PEP_7                  (_U_(0x1) << HSTIER_PEP_7_Pos)           /**< (HSTIER) Pipe 7 Interrupt Enable Mask */
+#define HSTIER_PEP_8_Pos              16                                             /**< (HSTIER) Pipe 8 Interrupt Enable Position */
+#define HSTIER_PEP_8                  (_U_(0x1) << HSTIER_PEP_8_Pos)           /**< (HSTIER) Pipe 8 Interrupt Enable Mask */
+#define HSTIER_PEP_9_Pos              17                                             /**< (HSTIER) Pipe 9 Interrupt Enable Position */
+#define HSTIER_PEP_9                  (_U_(0x1) << HSTIER_PEP_9_Pos)           /**< (HSTIER) Pipe 9 Interrupt Enable Mask */
+#define HSTIER_DMA_0_Pos              25                                             /**< (HSTIER) DMA Channel 0 Interrupt Enable Position */
+#define HSTIER_DMA_0                  (_U_(0x1) << HSTIER_DMA_0_Pos)           /**< (HSTIER) DMA Channel 0 Interrupt Enable Mask */
+#define HSTIER_DMA_1_Pos              26                                             /**< (HSTIER) DMA Channel 1 Interrupt Enable Position */
+#define HSTIER_DMA_1                  (_U_(0x1) << HSTIER_DMA_1_Pos)           /**< (HSTIER) DMA Channel 1 Interrupt Enable Mask */
+#define HSTIER_DMA_2_Pos              27                                             /**< (HSTIER) DMA Channel 2 Interrupt Enable Position */
+#define HSTIER_DMA_2                  (_U_(0x1) << HSTIER_DMA_2_Pos)           /**< (HSTIER) DMA Channel 2 Interrupt Enable Mask */
+#define HSTIER_DMA_3_Pos              28                                             /**< (HSTIER) DMA Channel 3 Interrupt Enable Position */
+#define HSTIER_DMA_3                  (_U_(0x1) << HSTIER_DMA_3_Pos)           /**< (HSTIER) DMA Channel 3 Interrupt Enable Mask */
+#define HSTIER_DMA_4_Pos              29                                             /**< (HSTIER) DMA Channel 4 Interrupt Enable Position */
+#define HSTIER_DMA_4                  (_U_(0x1) << HSTIER_DMA_4_Pos)           /**< (HSTIER) DMA Channel 4 Interrupt Enable Mask */
+#define HSTIER_DMA_5_Pos              30                                             /**< (HSTIER) DMA Channel 5 Interrupt Enable Position */
+#define HSTIER_DMA_5                  (_U_(0x1) << HSTIER_DMA_5_Pos)           /**< (HSTIER) DMA Channel 5 Interrupt Enable Mask */
+#define HSTIER_DMA_6_Pos              31                                             /**< (HSTIER) DMA Channel 6 Interrupt Enable Position */
+#define HSTIER_DMA_6                  (_U_(0x1) << HSTIER_DMA_6_Pos)           /**< (HSTIER) DMA Channel 6 Interrupt Enable Mask */
+#define HSTIER_Msk                    _U_(0xFE03FF7F)                                /**< (HSTIER) Register Mask  */
+
+#define HSTIER_PEP__Pos               8                                              /**< (HSTIER Position) Pipe x Interrupt Enable */
+#define HSTIER_PEP_                   (_U_(0x3FF) << HSTIER_PEP__Pos)          /**< (HSTIER Mask) PEP_ */
+#define HSTIER_DMA__Pos               25                                             /**< (HSTIER Position) DMA Channel 6 Interrupt Enable */
+#define HSTIER_DMA_                   (_U_(0x7F) << HSTIER_DMA__Pos)           /**< (HSTIER Mask) DMA_ */
+
+/* -------- HSTPIP : (USBHS Offset: 0x41c) (R/W 32) Host Pipe Register -------- */
+
+#define HSTPIP_OFFSET                 (0x41C)                                       /**<  (HSTPIP) Host Pipe Register  Offset */
+
+#define HSTPIP_PEN0_Pos               0                                              /**< (HSTPIP) Pipe 0 Enable Position */
+#define HSTPIP_PEN0                   (_U_(0x1) << HSTPIP_PEN0_Pos)            /**< (HSTPIP) Pipe 0 Enable Mask */
+#define HSTPIP_PEN1_Pos               1                                              /**< (HSTPIP) Pipe 1 Enable Position */
+#define HSTPIP_PEN1                   (_U_(0x1) << HSTPIP_PEN1_Pos)            /**< (HSTPIP) Pipe 1 Enable Mask */
+#define HSTPIP_PEN2_Pos               2                                              /**< (HSTPIP) Pipe 2 Enable Position */
+#define HSTPIP_PEN2                   (_U_(0x1) << HSTPIP_PEN2_Pos)            /**< (HSTPIP) Pipe 2 Enable Mask */
+#define HSTPIP_PEN3_Pos               3                                              /**< (HSTPIP) Pipe 3 Enable Position */
+#define HSTPIP_PEN3                   (_U_(0x1) << HSTPIP_PEN3_Pos)            /**< (HSTPIP) Pipe 3 Enable Mask */
+#define HSTPIP_PEN4_Pos               4                                              /**< (HSTPIP) Pipe 4 Enable Position */
+#define HSTPIP_PEN4                   (_U_(0x1) << HSTPIP_PEN4_Pos)            /**< (HSTPIP) Pipe 4 Enable Mask */
+#define HSTPIP_PEN5_Pos               5                                              /**< (HSTPIP) Pipe 5 Enable Position */
+#define HSTPIP_PEN5                   (_U_(0x1) << HSTPIP_PEN5_Pos)            /**< (HSTPIP) Pipe 5 Enable Mask */
+#define HSTPIP_PEN6_Pos               6                                              /**< (HSTPIP) Pipe 6 Enable Position */
+#define HSTPIP_PEN6                   (_U_(0x1) << HSTPIP_PEN6_Pos)            /**< (HSTPIP) Pipe 6 Enable Mask */
+#define HSTPIP_PEN7_Pos               7                                              /**< (HSTPIP) Pipe 7 Enable Position */
+#define HSTPIP_PEN7                   (_U_(0x1) << HSTPIP_PEN7_Pos)            /**< (HSTPIP) Pipe 7 Enable Mask */
+#define HSTPIP_PEN8_Pos               8                                              /**< (HSTPIP) Pipe 8 Enable Position */
+#define HSTPIP_PEN8                   (_U_(0x1) << HSTPIP_PEN8_Pos)            /**< (HSTPIP) Pipe 8 Enable Mask */
+#define HSTPIP_PRST0_Pos              16                                             /**< (HSTPIP) Pipe 0 Reset Position */
+#define HSTPIP_PRST0                  (_U_(0x1) << HSTPIP_PRST0_Pos)           /**< (HSTPIP) Pipe 0 Reset Mask */
+#define HSTPIP_PRST1_Pos              17                                             /**< (HSTPIP) Pipe 1 Reset Position */
+#define HSTPIP_PRST1                  (_U_(0x1) << HSTPIP_PRST1_Pos)           /**< (HSTPIP) Pipe 1 Reset Mask */
+#define HSTPIP_PRST2_Pos              18                                             /**< (HSTPIP) Pipe 2 Reset Position */
+#define HSTPIP_PRST2                  (_U_(0x1) << HSTPIP_PRST2_Pos)           /**< (HSTPIP) Pipe 2 Reset Mask */
+#define HSTPIP_PRST3_Pos              19                                             /**< (HSTPIP) Pipe 3 Reset Position */
+#define HSTPIP_PRST3                  (_U_(0x1) << HSTPIP_PRST3_Pos)           /**< (HSTPIP) Pipe 3 Reset Mask */
+#define HSTPIP_PRST4_Pos              20                                             /**< (HSTPIP) Pipe 4 Reset Position */
+#define HSTPIP_PRST4                  (_U_(0x1) << HSTPIP_PRST4_Pos)           /**< (HSTPIP) Pipe 4 Reset Mask */
+#define HSTPIP_PRST5_Pos              21                                             /**< (HSTPIP) Pipe 5 Reset Position */
+#define HSTPIP_PRST5                  (_U_(0x1) << HSTPIP_PRST5_Pos)           /**< (HSTPIP) Pipe 5 Reset Mask */
+#define HSTPIP_PRST6_Pos              22                                             /**< (HSTPIP) Pipe 6 Reset Position */
+#define HSTPIP_PRST6                  (_U_(0x1) << HSTPIP_PRST6_Pos)           /**< (HSTPIP) Pipe 6 Reset Mask */
+#define HSTPIP_PRST7_Pos              23                                             /**< (HSTPIP) Pipe 7 Reset Position */
+#define HSTPIP_PRST7                  (_U_(0x1) << HSTPIP_PRST7_Pos)           /**< (HSTPIP) Pipe 7 Reset Mask */
+#define HSTPIP_PRST8_Pos              24                                             /**< (HSTPIP) Pipe 8 Reset Position */
+#define HSTPIP_PRST8                  (_U_(0x1) << HSTPIP_PRST8_Pos)           /**< (HSTPIP) Pipe 8 Reset Mask */
+#define HSTPIP_Msk                    _U_(0x1FF01FF)                                 /**< (HSTPIP) Register Mask  */
+
+#define HSTPIP_PEN_Pos                0                                              /**< (HSTPIP Position) Pipe x Enable */
+#define HSTPIP_PEN                    (_U_(0x1FF) << HSTPIP_PEN_Pos)           /**< (HSTPIP Mask) PEN */
+#define HSTPIP_PRST_Pos               16                                             /**< (HSTPIP Position) Pipe 8 Reset */
+#define HSTPIP_PRST                   (_U_(0x1FF) << HSTPIP_PRST_Pos)          /**< (HSTPIP Mask) PRST */
+
+/* -------- HSTFNUM : (USBHS Offset: 0x420) (R/W 32) Host Frame Number Register -------- */
+
+#define HSTFNUM_OFFSET                (0x420)                                       /**<  (HSTFNUM) Host Frame Number Register  Offset */
+
+#define HSTFNUM_MFNUM_Pos             0                                              /**< (HSTFNUM) Micro Frame Number Position */
+#define HSTFNUM_MFNUM                 (_U_(0x7) << HSTFNUM_MFNUM_Pos)          /**< (HSTFNUM) Micro Frame Number Mask */
+#define HSTFNUM_FNUM_Pos              3                                              /**< (HSTFNUM) Frame Number Position */
+#define HSTFNUM_FNUM                  (_U_(0x7FF) << HSTFNUM_FNUM_Pos)         /**< (HSTFNUM) Frame Number Mask */
+#define HSTFNUM_FLENHIGH_Pos          16                                             /**< (HSTFNUM) Frame Length Position */
+#define HSTFNUM_FLENHIGH              (_U_(0xFF) << HSTFNUM_FLENHIGH_Pos)      /**< (HSTFNUM) Frame Length Mask */
+#define HSTFNUM_Msk                   _U_(0xFF3FFF)                                  /**< (HSTFNUM) Register Mask  */
+
+
+/* -------- HSTADDR1 : (USBHS Offset: 0x424) (R/W 32) Host Address 1 Register -------- */
+
+#define HSTADDR1_OFFSET               (0x424)                                       /**<  (HSTADDR1) Host Address 1 Register  Offset */
+
+#define HSTADDR1_HSTADDRP0_Pos        0                                              /**< (HSTADDR1) USB Host Address Position */
+#define HSTADDR1_HSTADDRP0            (_U_(0x7F) << HSTADDR1_HSTADDRP0_Pos)    /**< (HSTADDR1) USB Host Address Mask */
+#define HSTADDR1_HSTADDRP1_Pos        8                                              /**< (HSTADDR1) USB Host Address Position */
+#define HSTADDR1_HSTADDRP1            (_U_(0x7F) << HSTADDR1_HSTADDRP1_Pos)    /**< (HSTADDR1) USB Host Address Mask */
+#define HSTADDR1_HSTADDRP2_Pos        16                                             /**< (HSTADDR1) USB Host Address Position */
+#define HSTADDR1_HSTADDRP2            (_U_(0x7F) << HSTADDR1_HSTADDRP2_Pos)    /**< (HSTADDR1) USB Host Address Mask */
+#define HSTADDR1_HSTADDRP3_Pos        24                                             /**< (HSTADDR1) USB Host Address Position */
+#define HSTADDR1_HSTADDRP3            (_U_(0x7F) << HSTADDR1_HSTADDRP3_Pos)    /**< (HSTADDR1) USB Host Address Mask */
+#define HSTADDR1_Msk                  _U_(0x7F7F7F7F)                                /**< (HSTADDR1) Register Mask  */
+
+
+/* -------- HSTADDR2 : (USBHS Offset: 0x428) (R/W 32) Host Address 2 Register -------- */
+
+#define HSTADDR2_OFFSET               (0x428)                                       /**<  (HSTADDR2) Host Address 2 Register  Offset */
+
+#define HSTADDR2_HSTADDRP4_Pos        0                                              /**< (HSTADDR2) USB Host Address Position */
+#define HSTADDR2_HSTADDRP4            (_U_(0x7F) << HSTADDR2_HSTADDRP4_Pos)    /**< (HSTADDR2) USB Host Address Mask */
+#define HSTADDR2_HSTADDRP5_Pos        8                                              /**< (HSTADDR2) USB Host Address Position */
+#define HSTADDR2_HSTADDRP5            (_U_(0x7F) << HSTADDR2_HSTADDRP5_Pos)    /**< (HSTADDR2) USB Host Address Mask */
+#define HSTADDR2_HSTADDRP6_Pos        16                                             /**< (HSTADDR2) USB Host Address Position */
+#define HSTADDR2_HSTADDRP6            (_U_(0x7F) << HSTADDR2_HSTADDRP6_Pos)    /**< (HSTADDR2) USB Host Address Mask */
+#define HSTADDR2_HSTADDRP7_Pos        24                                             /**< (HSTADDR2) USB Host Address Position */
+#define HSTADDR2_HSTADDRP7            (_U_(0x7F) << HSTADDR2_HSTADDRP7_Pos)    /**< (HSTADDR2) USB Host Address Mask */
+#define HSTADDR2_Msk                  _U_(0x7F7F7F7F)                                /**< (HSTADDR2) Register Mask  */
+
+
+/* -------- HSTADDR3 : (USBHS Offset: 0x42c) (R/W 32) Host Address 3 Register -------- */
+
+#define HSTADDR3_OFFSET               (0x42C)                                       /**<  (HSTADDR3) Host Address 3 Register  Offset */
+
+#define HSTADDR3_HSTADDRP8_Pos        0                                              /**< (HSTADDR3) USB Host Address Position */
+#define HSTADDR3_HSTADDRP8            (_U_(0x7F) << HSTADDR3_HSTADDRP8_Pos)    /**< (HSTADDR3) USB Host Address Mask */
+#define HSTADDR3_HSTADDRP9_Pos        8                                              /**< (HSTADDR3) USB Host Address Position */
+#define HSTADDR3_HSTADDRP9            (_U_(0x7F) << HSTADDR3_HSTADDRP9_Pos)    /**< (HSTADDR3) USB Host Address Mask */
+#define HSTADDR3_Msk                  _U_(0x7F7F)                                    /**< (HSTADDR3) Register Mask  */
+
+
+/* -------- HSTPIPCFG : (USBHS Offset: 0x500) (R/W 32) Host Pipe Configuration Register -------- */
+
+#define HSTPIPCFG_OFFSET              (0x500)                                       /**<  (HSTPIPCFG) Host Pipe Configuration Register  Offset */
+
+#define HSTPIPCFG_ALLOC_Pos           1                                              /**< (HSTPIPCFG) Pipe Memory Allocate Position */
+#define HSTPIPCFG_ALLOC               (_U_(0x1) << HSTPIPCFG_ALLOC_Pos)        /**< (HSTPIPCFG) Pipe Memory Allocate Mask */
+#define HSTPIPCFG_PBK_Pos             2                                              /**< (HSTPIPCFG) Pipe Banks Position */
+#define HSTPIPCFG_PBK                 (_U_(0x3) << HSTPIPCFG_PBK_Pos)          /**< (HSTPIPCFG) Pipe Banks Mask */
+#define   HSTPIPCFG_PBK_1_BANK_Val    _U_(0x0)                                       /**< (HSTPIPCFG) Single-bank pipe  */
+#define   HSTPIPCFG_PBK_2_BANK_Val    _U_(0x1)                                       /**< (HSTPIPCFG) Double-bank pipe  */
+#define   HSTPIPCFG_PBK_3_BANK_Val    _U_(0x2)                                       /**< (HSTPIPCFG) Triple-bank pipe  */
+#define HSTPIPCFG_PBK_1_BANK          (HSTPIPCFG_PBK_1_BANK_Val << HSTPIPCFG_PBK_Pos)  /**< (HSTPIPCFG) Single-bank pipe Position  */
+#define HSTPIPCFG_PBK_2_BANK          (HSTPIPCFG_PBK_2_BANK_Val << HSTPIPCFG_PBK_Pos)  /**< (HSTPIPCFG) Double-bank pipe Position  */
+#define HSTPIPCFG_PBK_3_BANK          (HSTPIPCFG_PBK_3_BANK_Val << HSTPIPCFG_PBK_Pos)  /**< (HSTPIPCFG) Triple-bank pipe Position  */
+#define HSTPIPCFG_PSIZE_Pos           4                                              /**< (HSTPIPCFG) Pipe Size Position */
+#define HSTPIPCFG_PSIZE               (_U_(0x7) << HSTPIPCFG_PSIZE_Pos)        /**< (HSTPIPCFG) Pipe Size Mask */
+#define   HSTPIPCFG_PSIZE_8_BYTE_Val  _U_(0x0)                                       /**< (HSTPIPCFG) 8 bytes  */
+#define   HSTPIPCFG_PSIZE_16_BYTE_Val _U_(0x1)                                       /**< (HSTPIPCFG) 16 bytes  */
+#define   HSTPIPCFG_PSIZE_32_BYTE_Val _U_(0x2)                                       /**< (HSTPIPCFG) 32 bytes  */
+#define   HSTPIPCFG_PSIZE_64_BYTE_Val _U_(0x3)                                       /**< (HSTPIPCFG) 64 bytes  */
+#define   HSTPIPCFG_PSIZE_128_BYTE_Val _U_(0x4)                                       /**< (HSTPIPCFG) 128 bytes  */
+#define   HSTPIPCFG_PSIZE_256_BYTE_Val _U_(0x5)                                       /**< (HSTPIPCFG) 256 bytes  */
+#define   HSTPIPCFG_PSIZE_512_BYTE_Val _U_(0x6)                                       /**< (HSTPIPCFG) 512 bytes  */
+#define   HSTPIPCFG_PSIZE_1024_BYTE_Val _U_(0x7)                                       /**< (HSTPIPCFG) 1024 bytes  */
+#define HSTPIPCFG_PSIZE_8_BYTE        (HSTPIPCFG_PSIZE_8_BYTE_Val << HSTPIPCFG_PSIZE_Pos)  /**< (HSTPIPCFG) 8 bytes Position  */
+#define HSTPIPCFG_PSIZE_16_BYTE       (HSTPIPCFG_PSIZE_16_BYTE_Val << HSTPIPCFG_PSIZE_Pos)  /**< (HSTPIPCFG) 16 bytes Position  */
+#define HSTPIPCFG_PSIZE_32_BYTE       (HSTPIPCFG_PSIZE_32_BYTE_Val << HSTPIPCFG_PSIZE_Pos)  /**< (HSTPIPCFG) 32 bytes Position  */
+#define HSTPIPCFG_PSIZE_64_BYTE       (HSTPIPCFG_PSIZE_64_BYTE_Val << HSTPIPCFG_PSIZE_Pos)  /**< (HSTPIPCFG) 64 bytes Position  */
+#define HSTPIPCFG_PSIZE_128_BYTE      (HSTPIPCFG_PSIZE_128_BYTE_Val << HSTPIPCFG_PSIZE_Pos)  /**< (HSTPIPCFG) 128 bytes Position  */
+#define HSTPIPCFG_PSIZE_256_BYTE      (HSTPIPCFG_PSIZE_256_BYTE_Val << HSTPIPCFG_PSIZE_Pos)  /**< (HSTPIPCFG) 256 bytes Position  */
+#define HSTPIPCFG_PSIZE_512_BYTE      (HSTPIPCFG_PSIZE_512_BYTE_Val << HSTPIPCFG_PSIZE_Pos)  /**< (HSTPIPCFG) 512 bytes Position  */
+#define HSTPIPCFG_PSIZE_1024_BYTE     (HSTPIPCFG_PSIZE_1024_BYTE_Val << HSTPIPCFG_PSIZE_Pos)  /**< (HSTPIPCFG) 1024 bytes Position  */
+#define HSTPIPCFG_PTOKEN_Pos          8                                              /**< (HSTPIPCFG) Pipe Token Position */
+#define HSTPIPCFG_PTOKEN              (_U_(0x3) << HSTPIPCFG_PTOKEN_Pos)       /**< (HSTPIPCFG) Pipe Token Mask */
+#define   HSTPIPCFG_PTOKEN_SETUP_Val  _U_(0x0)                                       /**< (HSTPIPCFG) SETUP  */
+#define   HSTPIPCFG_PTOKEN_IN_Val     _U_(0x1)                                       /**< (HSTPIPCFG) IN  */
+#define   HSTPIPCFG_PTOKEN_OUT_Val    _U_(0x2)                                       /**< (HSTPIPCFG) OUT  */
+#define HSTPIPCFG_PTOKEN_SETUP        (HSTPIPCFG_PTOKEN_SETUP_Val << HSTPIPCFG_PTOKEN_Pos)  /**< (HSTPIPCFG) SETUP Position  */
+#define HSTPIPCFG_PTOKEN_IN           (HSTPIPCFG_PTOKEN_IN_Val << HSTPIPCFG_PTOKEN_Pos)  /**< (HSTPIPCFG) IN Position  */
+#define HSTPIPCFG_PTOKEN_OUT          (HSTPIPCFG_PTOKEN_OUT_Val << HSTPIPCFG_PTOKEN_Pos)  /**< (HSTPIPCFG) OUT Position  */
+#define HSTPIPCFG_AUTOSW_Pos          10                                             /**< (HSTPIPCFG) Automatic Switch Position */
+#define HSTPIPCFG_AUTOSW              (_U_(0x1) << HSTPIPCFG_AUTOSW_Pos)       /**< (HSTPIPCFG) Automatic Switch Mask */
+#define HSTPIPCFG_PTYPE_Pos           12                                             /**< (HSTPIPCFG) Pipe Type Position */
+#define HSTPIPCFG_PTYPE               (_U_(0x3) << HSTPIPCFG_PTYPE_Pos)        /**< (HSTPIPCFG) Pipe Type Mask */
+#define   HSTPIPCFG_PTYPE_CTRL_Val    _U_(0x0)                                       /**< (HSTPIPCFG) Control  */
+#define   HSTPIPCFG_PTYPE_ISO_Val     _U_(0x1)                                       /**< (HSTPIPCFG) Isochronous  */
+#define   HSTPIPCFG_PTYPE_BLK_Val     _U_(0x2)                                       /**< (HSTPIPCFG) Bulk  */
+#define   HSTPIPCFG_PTYPE_INTRPT_Val  _U_(0x3)                                       /**< (HSTPIPCFG) Interrupt  */
+#define HSTPIPCFG_PTYPE_CTRL          (HSTPIPCFG_PTYPE_CTRL_Val << HSTPIPCFG_PTYPE_Pos)  /**< (HSTPIPCFG) Control Position  */
+#define HSTPIPCFG_PTYPE_ISO           (HSTPIPCFG_PTYPE_ISO_Val << HSTPIPCFG_PTYPE_Pos)  /**< (HSTPIPCFG) Isochronous Position  */
+#define HSTPIPCFG_PTYPE_BLK           (HSTPIPCFG_PTYPE_BLK_Val << HSTPIPCFG_PTYPE_Pos)  /**< (HSTPIPCFG) Bulk Position  */
+#define HSTPIPCFG_PTYPE_INTRPT        (HSTPIPCFG_PTYPE_INTRPT_Val << HSTPIPCFG_PTYPE_Pos)  /**< (HSTPIPCFG) Interrupt Position  */
+#define HSTPIPCFG_PEPNUM_Pos          16                                             /**< (HSTPIPCFG) Pipe Endpoint Number Position */
+#define HSTPIPCFG_PEPNUM              (_U_(0xF) << HSTPIPCFG_PEPNUM_Pos)       /**< (HSTPIPCFG) Pipe Endpoint Number Mask */
+#define HSTPIPCFG_INTFRQ_Pos          24                                             /**< (HSTPIPCFG) Pipe Interrupt Request Frequency Position */
+#define HSTPIPCFG_INTFRQ              (_U_(0xFF) << HSTPIPCFG_INTFRQ_Pos)      /**< (HSTPIPCFG) Pipe Interrupt Request Frequency Mask */
+#define HSTPIPCFG_Msk                 _U_(0xFF0F377E)                                /**< (HSTPIPCFG) Register Mask  */
+
+/* CTRL_BULK mode */
+#define HSTPIPCFG_CTRL_BULK_PINGEN_Pos 20                                             /**< (HSTPIPCFG) Ping Enable Position */
+#define HSTPIPCFG_CTRL_BULK_PINGEN     (_U_(0x1) << HSTPIPCFG_CTRL_BULK_PINGEN_Pos)  /**< (HSTPIPCFG) Ping Enable Mask */
+#define HSTPIPCFG_CTRL_BULK_BINTERVAL_Pos 24                                             /**< (HSTPIPCFG) bInterval Parameter for the Bulk-Out/Ping Transaction Position */
+#define HSTPIPCFG_CTRL_BULK_BINTERVAL     (_U_(0xFF) << HSTPIPCFG_CTRL_BULK_BINTERVAL_Pos)  /**< (HSTPIPCFG) bInterval Parameter for the Bulk-Out/Ping Transaction Mask */
+#define HSTPIPCFG_CTRL_BULK_Msk       _U_(0xFF100000)                                /**< (HSTPIPCFG_CTRL_BULK) Register Mask  */
+
+
+/* -------- HSTPIPISR : (USBHS Offset: 0x530) (R/ 32) Host Pipe Status Register -------- */
+
+#define HSTPIPISR_OFFSET              (0x530)                                       /**<  (HSTPIPISR) Host Pipe Status Register  Offset */
+
+#define HSTPIPISR_RXINI_Pos           0                                              /**< (HSTPIPISR) Received IN Data Interrupt Position */
+#define HSTPIPISR_RXINI               (_U_(0x1) << HSTPIPISR_RXINI_Pos)        /**< (HSTPIPISR) Received IN Data Interrupt Mask */
+#define HSTPIPISR_TXOUTI_Pos          1                                              /**< (HSTPIPISR) Transmitted OUT Data Interrupt Position */
+#define HSTPIPISR_TXOUTI              (_U_(0x1) << HSTPIPISR_TXOUTI_Pos)       /**< (HSTPIPISR) Transmitted OUT Data Interrupt Mask */
+#define HSTPIPISR_PERRI_Pos           3                                              /**< (HSTPIPISR) Pipe Error Interrupt Position */
+#define HSTPIPISR_PERRI               (_U_(0x1) << HSTPIPISR_PERRI_Pos)        /**< (HSTPIPISR) Pipe Error Interrupt Mask */
+#define HSTPIPISR_NAKEDI_Pos          4                                              /**< (HSTPIPISR) NAKed Interrupt Position */
+#define HSTPIPISR_NAKEDI              (_U_(0x1) << HSTPIPISR_NAKEDI_Pos)       /**< (HSTPIPISR) NAKed Interrupt Mask */
+#define HSTPIPISR_OVERFI_Pos          5                                              /**< (HSTPIPISR) Overflow Interrupt Position */
+#define HSTPIPISR_OVERFI              (_U_(0x1) << HSTPIPISR_OVERFI_Pos)       /**< (HSTPIPISR) Overflow Interrupt Mask */
+#define HSTPIPISR_SHORTPACKETI_Pos    7                                              /**< (HSTPIPISR) Short Packet Interrupt Position */
+#define HSTPIPISR_SHORTPACKETI        (_U_(0x1) << HSTPIPISR_SHORTPACKETI_Pos)  /**< (HSTPIPISR) Short Packet Interrupt Mask */
+#define HSTPIPISR_DTSEQ_Pos           8                                              /**< (HSTPIPISR) Data Toggle Sequence Position */
+#define HSTPIPISR_DTSEQ               (_U_(0x3) << HSTPIPISR_DTSEQ_Pos)        /**< (HSTPIPISR) Data Toggle Sequence Mask */
+#define   HSTPIPISR_DTSEQ_DATA0_Val   _U_(0x0)                                       /**< (HSTPIPISR) Data0 toggle sequence  */
+#define   HSTPIPISR_DTSEQ_DATA1_Val   _U_(0x1)                                       /**< (HSTPIPISR) Data1 toggle sequence  */
+#define HSTPIPISR_DTSEQ_DATA0         (HSTPIPISR_DTSEQ_DATA0_Val << HSTPIPISR_DTSEQ_Pos)  /**< (HSTPIPISR) Data0 toggle sequence Position  */
+#define HSTPIPISR_DTSEQ_DATA1         (HSTPIPISR_DTSEQ_DATA1_Val << HSTPIPISR_DTSEQ_Pos)  /**< (HSTPIPISR) Data1 toggle sequence Position  */
+#define HSTPIPISR_NBUSYBK_Pos         12                                             /**< (HSTPIPISR) Number of Busy Banks Position */
+#define HSTPIPISR_NBUSYBK             (_U_(0x3) << HSTPIPISR_NBUSYBK_Pos)      /**< (HSTPIPISR) Number of Busy Banks Mask */
+#define   HSTPIPISR_NBUSYBK_0_BUSY_Val _U_(0x0)                                       /**< (HSTPIPISR) 0 busy bank (all banks free)  */
+#define   HSTPIPISR_NBUSYBK_1_BUSY_Val _U_(0x1)                                       /**< (HSTPIPISR) 1 busy bank  */
+#define   HSTPIPISR_NBUSYBK_2_BUSY_Val _U_(0x2)                                       /**< (HSTPIPISR) 2 busy banks  */
+#define   HSTPIPISR_NBUSYBK_3_BUSY_Val _U_(0x3)                                       /**< (HSTPIPISR) 3 busy banks  */
+#define HSTPIPISR_NBUSYBK_0_BUSY      (HSTPIPISR_NBUSYBK_0_BUSY_Val << HSTPIPISR_NBUSYBK_Pos)  /**< (HSTPIPISR) 0 busy bank (all banks free) Position  */
+#define HSTPIPISR_NBUSYBK_1_BUSY      (HSTPIPISR_NBUSYBK_1_BUSY_Val << HSTPIPISR_NBUSYBK_Pos)  /**< (HSTPIPISR) 1 busy bank Position  */
+#define HSTPIPISR_NBUSYBK_2_BUSY      (HSTPIPISR_NBUSYBK_2_BUSY_Val << HSTPIPISR_NBUSYBK_Pos)  /**< (HSTPIPISR) 2 busy banks Position  */
+#define HSTPIPISR_NBUSYBK_3_BUSY      (HSTPIPISR_NBUSYBK_3_BUSY_Val << HSTPIPISR_NBUSYBK_Pos)  /**< (HSTPIPISR) 3 busy banks Position  */
+#define HSTPIPISR_CURRBK_Pos          14                                             /**< (HSTPIPISR) Current Bank Position */
+#define HSTPIPISR_CURRBK              (_U_(0x3) << HSTPIPISR_CURRBK_Pos)       /**< (HSTPIPISR) Current Bank Mask */
+#define   HSTPIPISR_CURRBK_BANK0_Val  _U_(0x0)                                       /**< (HSTPIPISR) Current bank is bank0  */
+#define   HSTPIPISR_CURRBK_BANK1_Val  _U_(0x1)                                       /**< (HSTPIPISR) Current bank is bank1  */
+#define   HSTPIPISR_CURRBK_BANK2_Val  _U_(0x2)                                       /**< (HSTPIPISR) Current bank is bank2  */
+#define HSTPIPISR_CURRBK_BANK0        (HSTPIPISR_CURRBK_BANK0_Val << HSTPIPISR_CURRBK_Pos)  /**< (HSTPIPISR) Current bank is bank0 Position  */
+#define HSTPIPISR_CURRBK_BANK1        (HSTPIPISR_CURRBK_BANK1_Val << HSTPIPISR_CURRBK_Pos)  /**< (HSTPIPISR) Current bank is bank1 Position  */
+#define HSTPIPISR_CURRBK_BANK2        (HSTPIPISR_CURRBK_BANK2_Val << HSTPIPISR_CURRBK_Pos)  /**< (HSTPIPISR) Current bank is bank2 Position  */
+#define HSTPIPISR_RWALL_Pos           16                                             /**< (HSTPIPISR) Read/Write Allowed Position */
+#define HSTPIPISR_RWALL               (_U_(0x1) << HSTPIPISR_RWALL_Pos)        /**< (HSTPIPISR) Read/Write Allowed Mask */
+#define HSTPIPISR_CFGOK_Pos           18                                             /**< (HSTPIPISR) Configuration OK Status Position */
+#define HSTPIPISR_CFGOK               (_U_(0x1) << HSTPIPISR_CFGOK_Pos)        /**< (HSTPIPISR) Configuration OK Status Mask */
+#define HSTPIPISR_PBYCT_Pos           20                                             /**< (HSTPIPISR) Pipe Byte Count Position */
+#define HSTPIPISR_PBYCT               (_U_(0x7FF) << HSTPIPISR_PBYCT_Pos)      /**< (HSTPIPISR) Pipe Byte Count Mask */
+#define HSTPIPISR_Msk                 _U_(0x7FF5F3BB)                                /**< (HSTPIPISR) Register Mask  */
+
+/* CTRL mode */
+#define HSTPIPISR_CTRL_TXSTPI_Pos     2                                              /**< (HSTPIPISR) Transmitted SETUP Interrupt Position */
+#define HSTPIPISR_CTRL_TXSTPI         (_U_(0x1) << HSTPIPISR_CTRL_TXSTPI_Pos)  /**< (HSTPIPISR) Transmitted SETUP Interrupt Mask */
+#define HSTPIPISR_CTRL_RXSTALLDI_Pos  6                                              /**< (HSTPIPISR) Received STALLed Interrupt Position */
+#define HSTPIPISR_CTRL_RXSTALLDI      (_U_(0x1) << HSTPIPISR_CTRL_RXSTALLDI_Pos)  /**< (HSTPIPISR) Received STALLed Interrupt Mask */
+#define HSTPIPISR_CTRL_Msk            _U_(0x44)                                      /**< (HSTPIPISR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define HSTPIPISR_ISO_UNDERFI_Pos     2                                              /**< (HSTPIPISR) Underflow Interrupt Position */
+#define HSTPIPISR_ISO_UNDERFI         (_U_(0x1) << HSTPIPISR_ISO_UNDERFI_Pos)  /**< (HSTPIPISR) Underflow Interrupt Mask */
+#define HSTPIPISR_ISO_CRCERRI_Pos     6                                              /**< (HSTPIPISR) CRC Error Interrupt Position */
+#define HSTPIPISR_ISO_CRCERRI         (_U_(0x1) << HSTPIPISR_ISO_CRCERRI_Pos)  /**< (HSTPIPISR) CRC Error Interrupt Mask */
+#define HSTPIPISR_ISO_Msk             _U_(0x44)                                      /**< (HSTPIPISR_ISO) Register Mask  */
+
+/* BLK mode */
+#define HSTPIPISR_BLK_TXSTPI_Pos      2                                              /**< (HSTPIPISR) Transmitted SETUP Interrupt Position */
+#define HSTPIPISR_BLK_TXSTPI          (_U_(0x1) << HSTPIPISR_BLK_TXSTPI_Pos)   /**< (HSTPIPISR) Transmitted SETUP Interrupt Mask */
+#define HSTPIPISR_BLK_RXSTALLDI_Pos   6                                              /**< (HSTPIPISR) Received STALLed Interrupt Position */
+#define HSTPIPISR_BLK_RXSTALLDI       (_U_(0x1) << HSTPIPISR_BLK_RXSTALLDI_Pos)  /**< (HSTPIPISR) Received STALLed Interrupt Mask */
+#define HSTPIPISR_BLK_Msk             _U_(0x44)                                      /**< (HSTPIPISR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define HSTPIPISR_INTRPT_UNDERFI_Pos  2                                              /**< (HSTPIPISR) Underflow Interrupt Position */
+#define HSTPIPISR_INTRPT_UNDERFI      (_U_(0x1) << HSTPIPISR_INTRPT_UNDERFI_Pos)  /**< (HSTPIPISR) Underflow Interrupt Mask */
+#define HSTPIPISR_INTRPT_RXSTALLDI_Pos 6                                              /**< (HSTPIPISR) Received STALLed Interrupt Position */
+#define HSTPIPISR_INTRPT_RXSTALLDI     (_U_(0x1) << HSTPIPISR_INTRPT_RXSTALLDI_Pos)  /**< (HSTPIPISR) Received STALLed Interrupt Mask */
+#define HSTPIPISR_INTRPT_Msk          _U_(0x44)                                      /**< (HSTPIPISR_INTRPT) Register Mask  */
+
+
+/* -------- HSTPIPICR : (USBHS Offset: 0x560) (/W 32) Host Pipe Clear Register -------- */
+
+#define HSTPIPICR_OFFSET              (0x560)                                       /**<  (HSTPIPICR) Host Pipe Clear Register  Offset */
+
+#define HSTPIPICR_RXINIC_Pos          0                                              /**< (HSTPIPICR) Received IN Data Interrupt Clear Position */
+#define HSTPIPICR_RXINIC              (_U_(0x1) << HSTPIPICR_RXINIC_Pos)       /**< (HSTPIPICR) Received IN Data Interrupt Clear Mask */
+#define HSTPIPICR_TXOUTIC_Pos         1                                              /**< (HSTPIPICR) Transmitted OUT Data Interrupt Clear Position */
+#define HSTPIPICR_TXOUTIC             (_U_(0x1) << HSTPIPICR_TXOUTIC_Pos)      /**< (HSTPIPICR) Transmitted OUT Data Interrupt Clear Mask */
+#define HSTPIPICR_NAKEDIC_Pos         4                                              /**< (HSTPIPICR) NAKed Interrupt Clear Position */
+#define HSTPIPICR_NAKEDIC             (_U_(0x1) << HSTPIPICR_NAKEDIC_Pos)      /**< (HSTPIPICR) NAKed Interrupt Clear Mask */
+#define HSTPIPICR_OVERFIC_Pos         5                                              /**< (HSTPIPICR) Overflow Interrupt Clear Position */
+#define HSTPIPICR_OVERFIC             (_U_(0x1) << HSTPIPICR_OVERFIC_Pos)      /**< (HSTPIPICR) Overflow Interrupt Clear Mask */
+#define HSTPIPICR_SHORTPACKETIC_Pos   7                                              /**< (HSTPIPICR) Short Packet Interrupt Clear Position */
+#define HSTPIPICR_SHORTPACKETIC       (_U_(0x1) << HSTPIPICR_SHORTPACKETIC_Pos)  /**< (HSTPIPICR) Short Packet Interrupt Clear Mask */
+#define HSTPIPICR_Msk                 _U_(0xB3)                                      /**< (HSTPIPICR) Register Mask  */
+
+/* CTRL mode */
+#define HSTPIPICR_CTRL_TXSTPIC_Pos    2                                              /**< (HSTPIPICR) Transmitted SETUP Interrupt Clear Position */
+#define HSTPIPICR_CTRL_TXSTPIC        (_U_(0x1) << HSTPIPICR_CTRL_TXSTPIC_Pos)  /**< (HSTPIPICR) Transmitted SETUP Interrupt Clear Mask */
+#define HSTPIPICR_CTRL_RXSTALLDIC_Pos 6                                              /**< (HSTPIPICR) Received STALLed Interrupt Clear Position */
+#define HSTPIPICR_CTRL_RXSTALLDIC     (_U_(0x1) << HSTPIPICR_CTRL_RXSTALLDIC_Pos)  /**< (HSTPIPICR) Received STALLed Interrupt Clear Mask */
+#define HSTPIPICR_CTRL_Msk            _U_(0x44)                                      /**< (HSTPIPICR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define HSTPIPICR_ISO_UNDERFIC_Pos    2                                              /**< (HSTPIPICR) Underflow Interrupt Clear Position */
+#define HSTPIPICR_ISO_UNDERFIC        (_U_(0x1) << HSTPIPICR_ISO_UNDERFIC_Pos)  /**< (HSTPIPICR) Underflow Interrupt Clear Mask */
+#define HSTPIPICR_ISO_CRCERRIC_Pos    6                                              /**< (HSTPIPICR) CRC Error Interrupt Clear Position */
+#define HSTPIPICR_ISO_CRCERRIC        (_U_(0x1) << HSTPIPICR_ISO_CRCERRIC_Pos)  /**< (HSTPIPICR) CRC Error Interrupt Clear Mask */
+#define HSTPIPICR_ISO_Msk             _U_(0x44)                                      /**< (HSTPIPICR_ISO) Register Mask  */
+
+/* BLK mode */
+#define HSTPIPICR_BLK_TXSTPIC_Pos     2                                              /**< (HSTPIPICR) Transmitted SETUP Interrupt Clear Position */
+#define HSTPIPICR_BLK_TXSTPIC         (_U_(0x1) << HSTPIPICR_BLK_TXSTPIC_Pos)  /**< (HSTPIPICR) Transmitted SETUP Interrupt Clear Mask */
+#define HSTPIPICR_BLK_RXSTALLDIC_Pos  6                                              /**< (HSTPIPICR) Received STALLed Interrupt Clear Position */
+#define HSTPIPICR_BLK_RXSTALLDIC      (_U_(0x1) << HSTPIPICR_BLK_RXSTALLDIC_Pos)  /**< (HSTPIPICR) Received STALLed Interrupt Clear Mask */
+#define HSTPIPICR_BLK_Msk             _U_(0x44)                                      /**< (HSTPIPICR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define HSTPIPICR_INTRPT_UNDERFIC_Pos 2                                              /**< (HSTPIPICR) Underflow Interrupt Clear Position */
+#define HSTPIPICR_INTRPT_UNDERFIC     (_U_(0x1) << HSTPIPICR_INTRPT_UNDERFIC_Pos)  /**< (HSTPIPICR) Underflow Interrupt Clear Mask */
+#define HSTPIPICR_INTRPT_RXSTALLDIC_Pos 6                                              /**< (HSTPIPICR) Received STALLed Interrupt Clear Position */
+#define HSTPIPICR_INTRPT_RXSTALLDIC     (_U_(0x1) << HSTPIPICR_INTRPT_RXSTALLDIC_Pos)  /**< (HSTPIPICR) Received STALLed Interrupt Clear Mask */
+#define HSTPIPICR_INTRPT_Msk          _U_(0x44)                                      /**< (HSTPIPICR_INTRPT) Register Mask  */
+
+
+/* -------- HSTPIPIFR : (USBHS Offset: 0x590) (/W 32) Host Pipe Set Register -------- */
+
+#define HSTPIPIFR_OFFSET              (0x590)                                       /**<  (HSTPIPIFR) Host Pipe Set Register  Offset */
+
+#define HSTPIPIFR_RXINIS_Pos          0                                              /**< (HSTPIPIFR) Received IN Data Interrupt Set Position */
+#define HSTPIPIFR_RXINIS              (_U_(0x1) << HSTPIPIFR_RXINIS_Pos)       /**< (HSTPIPIFR) Received IN Data Interrupt Set Mask */
+#define HSTPIPIFR_TXOUTIS_Pos         1                                              /**< (HSTPIPIFR) Transmitted OUT Data Interrupt Set Position */
+#define HSTPIPIFR_TXOUTIS             (_U_(0x1) << HSTPIPIFR_TXOUTIS_Pos)      /**< (HSTPIPIFR) Transmitted OUT Data Interrupt Set Mask */
+#define HSTPIPIFR_PERRIS_Pos          3                                              /**< (HSTPIPIFR) Pipe Error Interrupt Set Position */
+#define HSTPIPIFR_PERRIS              (_U_(0x1) << HSTPIPIFR_PERRIS_Pos)       /**< (HSTPIPIFR) Pipe Error Interrupt Set Mask */
+#define HSTPIPIFR_NAKEDIS_Pos         4                                              /**< (HSTPIPIFR) NAKed Interrupt Set Position */
+#define HSTPIPIFR_NAKEDIS             (_U_(0x1) << HSTPIPIFR_NAKEDIS_Pos)      /**< (HSTPIPIFR) NAKed Interrupt Set Mask */
+#define HSTPIPIFR_OVERFIS_Pos         5                                              /**< (HSTPIPIFR) Overflow Interrupt Set Position */
+#define HSTPIPIFR_OVERFIS             (_U_(0x1) << HSTPIPIFR_OVERFIS_Pos)      /**< (HSTPIPIFR) Overflow Interrupt Set Mask */
+#define HSTPIPIFR_SHORTPACKETIS_Pos   7                                              /**< (HSTPIPIFR) Short Packet Interrupt Set Position */
+#define HSTPIPIFR_SHORTPACKETIS       (_U_(0x1) << HSTPIPIFR_SHORTPACKETIS_Pos)  /**< (HSTPIPIFR) Short Packet Interrupt Set Mask */
+#define HSTPIPIFR_NBUSYBKS_Pos        12                                             /**< (HSTPIPIFR) Number of Busy Banks Set Position */
+#define HSTPIPIFR_NBUSYBKS            (_U_(0x1) << HSTPIPIFR_NBUSYBKS_Pos)     /**< (HSTPIPIFR) Number of Busy Banks Set Mask */
+#define HSTPIPIFR_Msk                 _U_(0x10BB)                                    /**< (HSTPIPIFR) Register Mask  */
+
+/* CTRL mode */
+#define HSTPIPIFR_CTRL_TXSTPIS_Pos    2                                              /**< (HSTPIPIFR) Transmitted SETUP Interrupt Set Position */
+#define HSTPIPIFR_CTRL_TXSTPIS        (_U_(0x1) << HSTPIPIFR_CTRL_TXSTPIS_Pos)  /**< (HSTPIPIFR) Transmitted SETUP Interrupt Set Mask */
+#define HSTPIPIFR_CTRL_RXSTALLDIS_Pos 6                                              /**< (HSTPIPIFR) Received STALLed Interrupt Set Position */
+#define HSTPIPIFR_CTRL_RXSTALLDIS     (_U_(0x1) << HSTPIPIFR_CTRL_RXSTALLDIS_Pos)  /**< (HSTPIPIFR) Received STALLed Interrupt Set Mask */
+#define HSTPIPIFR_CTRL_Msk            _U_(0x44)                                      /**< (HSTPIPIFR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define HSTPIPIFR_ISO_UNDERFIS_Pos    2                                              /**< (HSTPIPIFR) Underflow Interrupt Set Position */
+#define HSTPIPIFR_ISO_UNDERFIS        (_U_(0x1) << HSTPIPIFR_ISO_UNDERFIS_Pos)  /**< (HSTPIPIFR) Underflow Interrupt Set Mask */
+#define HSTPIPIFR_ISO_CRCERRIS_Pos    6                                              /**< (HSTPIPIFR) CRC Error Interrupt Set Position */
+#define HSTPIPIFR_ISO_CRCERRIS        (_U_(0x1) << HSTPIPIFR_ISO_CRCERRIS_Pos)  /**< (HSTPIPIFR) CRC Error Interrupt Set Mask */
+#define HSTPIPIFR_ISO_Msk             _U_(0x44)                                      /**< (HSTPIPIFR_ISO) Register Mask  */
+
+/* BLK mode */
+#define HSTPIPIFR_BLK_TXSTPIS_Pos     2                                              /**< (HSTPIPIFR) Transmitted SETUP Interrupt Set Position */
+#define HSTPIPIFR_BLK_TXSTPIS         (_U_(0x1) << HSTPIPIFR_BLK_TXSTPIS_Pos)  /**< (HSTPIPIFR) Transmitted SETUP Interrupt Set Mask */
+#define HSTPIPIFR_BLK_RXSTALLDIS_Pos  6                                              /**< (HSTPIPIFR) Received STALLed Interrupt Set Position */
+#define HSTPIPIFR_BLK_RXSTALLDIS      (_U_(0x1) << HSTPIPIFR_BLK_RXSTALLDIS_Pos)  /**< (HSTPIPIFR) Received STALLed Interrupt Set Mask */
+#define HSTPIPIFR_BLK_Msk             _U_(0x44)                                      /**< (HSTPIPIFR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define HSTPIPIFR_INTRPT_UNDERFIS_Pos 2                                              /**< (HSTPIPIFR) Underflow Interrupt Set Position */
+#define HSTPIPIFR_INTRPT_UNDERFIS     (_U_(0x1) << HSTPIPIFR_INTRPT_UNDERFIS_Pos)  /**< (HSTPIPIFR) Underflow Interrupt Set Mask */
+#define HSTPIPIFR_INTRPT_RXSTALLDIS_Pos 6                                              /**< (HSTPIPIFR) Received STALLed Interrupt Set Position */
+#define HSTPIPIFR_INTRPT_RXSTALLDIS     (_U_(0x1) << HSTPIPIFR_INTRPT_RXSTALLDIS_Pos)  /**< (HSTPIPIFR) Received STALLed Interrupt Set Mask */
+#define HSTPIPIFR_INTRPT_Msk          _U_(0x44)                                      /**< (HSTPIPIFR_INTRPT) Register Mask  */
+
+
+/* -------- HSTPIPIMR : (USBHS Offset: 0x5c0) (R/ 32) Host Pipe Mask Register -------- */
+
+#define HSTPIPIMR_OFFSET              (0x5C0)                                       /**<  (HSTPIPIMR) Host Pipe Mask Register  Offset */
+
+#define HSTPIPIMR_RXINE_Pos           0                                              /**< (HSTPIPIMR) Received IN Data Interrupt Enable Position */
+#define HSTPIPIMR_RXINE               (_U_(0x1) << HSTPIPIMR_RXINE_Pos)        /**< (HSTPIPIMR) Received IN Data Interrupt Enable Mask */
+#define HSTPIPIMR_TXOUTE_Pos          1                                              /**< (HSTPIPIMR) Transmitted OUT Data Interrupt Enable Position */
+#define HSTPIPIMR_TXOUTE              (_U_(0x1) << HSTPIPIMR_TXOUTE_Pos)       /**< (HSTPIPIMR) Transmitted OUT Data Interrupt Enable Mask */
+#define HSTPIPIMR_PERRE_Pos           3                                              /**< (HSTPIPIMR) Pipe Error Interrupt Enable Position */
+#define HSTPIPIMR_PERRE               (_U_(0x1) << HSTPIPIMR_PERRE_Pos)        /**< (HSTPIPIMR) Pipe Error Interrupt Enable Mask */
+#define HSTPIPIMR_NAKEDE_Pos          4                                              /**< (HSTPIPIMR) NAKed Interrupt Enable Position */
+#define HSTPIPIMR_NAKEDE              (_U_(0x1) << HSTPIPIMR_NAKEDE_Pos)       /**< (HSTPIPIMR) NAKed Interrupt Enable Mask */
+#define HSTPIPIMR_OVERFIE_Pos         5                                              /**< (HSTPIPIMR) Overflow Interrupt Enable Position */
+#define HSTPIPIMR_OVERFIE             (_U_(0x1) << HSTPIPIMR_OVERFIE_Pos)      /**< (HSTPIPIMR) Overflow Interrupt Enable Mask */
+#define HSTPIPIMR_SHORTPACKETIE_Pos   7                                              /**< (HSTPIPIMR) Short Packet Interrupt Enable Position */
+#define HSTPIPIMR_SHORTPACKETIE       (_U_(0x1) << HSTPIPIMR_SHORTPACKETIE_Pos)  /**< (HSTPIPIMR) Short Packet Interrupt Enable Mask */
+#define HSTPIPIMR_NBUSYBKE_Pos        12                                             /**< (HSTPIPIMR) Number of Busy Banks Interrupt Enable Position */
+#define HSTPIPIMR_NBUSYBKE            (_U_(0x1) << HSTPIPIMR_NBUSYBKE_Pos)     /**< (HSTPIPIMR) Number of Busy Banks Interrupt Enable Mask */
+#define HSTPIPIMR_FIFOCON_Pos         14                                             /**< (HSTPIPIMR) FIFO Control Position */
+#define HSTPIPIMR_FIFOCON             (_U_(0x1) << HSTPIPIMR_FIFOCON_Pos)      /**< (HSTPIPIMR) FIFO Control Mask */
+#define HSTPIPIMR_PDISHDMA_Pos        16                                             /**< (HSTPIPIMR) Pipe Interrupts Disable HDMA Request Enable Position */
+#define HSTPIPIMR_PDISHDMA            (_U_(0x1) << HSTPIPIMR_PDISHDMA_Pos)     /**< (HSTPIPIMR) Pipe Interrupts Disable HDMA Request Enable Mask */
+#define HSTPIPIMR_PFREEZE_Pos         17                                             /**< (HSTPIPIMR) Pipe Freeze Position */
+#define HSTPIPIMR_PFREEZE             (_U_(0x1) << HSTPIPIMR_PFREEZE_Pos)      /**< (HSTPIPIMR) Pipe Freeze Mask */
+#define HSTPIPIMR_RSTDT_Pos           18                                             /**< (HSTPIPIMR) Reset Data Toggle Position */
+#define HSTPIPIMR_RSTDT               (_U_(0x1) << HSTPIPIMR_RSTDT_Pos)        /**< (HSTPIPIMR) Reset Data Toggle Mask */
+#define HSTPIPIMR_Msk                 _U_(0x750BB)                                   /**< (HSTPIPIMR) Register Mask  */
+
+/* CTRL mode */
+#define HSTPIPIMR_CTRL_TXSTPE_Pos     2                                              /**< (HSTPIPIMR) Transmitted SETUP Interrupt Enable Position */
+#define HSTPIPIMR_CTRL_TXSTPE         (_U_(0x1) << HSTPIPIMR_CTRL_TXSTPE_Pos)  /**< (HSTPIPIMR) Transmitted SETUP Interrupt Enable Mask */
+#define HSTPIPIMR_CTRL_RXSTALLDE_Pos  6                                              /**< (HSTPIPIMR) Received STALLed Interrupt Enable Position */
+#define HSTPIPIMR_CTRL_RXSTALLDE      (_U_(0x1) << HSTPIPIMR_CTRL_RXSTALLDE_Pos)  /**< (HSTPIPIMR) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIMR_CTRL_Msk            _U_(0x44)                                      /**< (HSTPIPIMR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define HSTPIPIMR_ISO_UNDERFIE_Pos    2                                              /**< (HSTPIPIMR) Underflow Interrupt Enable Position */
+#define HSTPIPIMR_ISO_UNDERFIE        (_U_(0x1) << HSTPIPIMR_ISO_UNDERFIE_Pos)  /**< (HSTPIPIMR) Underflow Interrupt Enable Mask */
+#define HSTPIPIMR_ISO_CRCERRE_Pos     6                                              /**< (HSTPIPIMR) CRC Error Interrupt Enable Position */
+#define HSTPIPIMR_ISO_CRCERRE         (_U_(0x1) << HSTPIPIMR_ISO_CRCERRE_Pos)  /**< (HSTPIPIMR) CRC Error Interrupt Enable Mask */
+#define HSTPIPIMR_ISO_Msk             _U_(0x44)                                      /**< (HSTPIPIMR_ISO) Register Mask  */
+
+/* BLK mode */
+#define HSTPIPIMR_BLK_TXSTPE_Pos      2                                              /**< (HSTPIPIMR) Transmitted SETUP Interrupt Enable Position */
+#define HSTPIPIMR_BLK_TXSTPE          (_U_(0x1) << HSTPIPIMR_BLK_TXSTPE_Pos)   /**< (HSTPIPIMR) Transmitted SETUP Interrupt Enable Mask */
+#define HSTPIPIMR_BLK_RXSTALLDE_Pos   6                                              /**< (HSTPIPIMR) Received STALLed Interrupt Enable Position */
+#define HSTPIPIMR_BLK_RXSTALLDE       (_U_(0x1) << HSTPIPIMR_BLK_RXSTALLDE_Pos)  /**< (HSTPIPIMR) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIMR_BLK_Msk             _U_(0x44)                                      /**< (HSTPIPIMR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define HSTPIPIMR_INTRPT_UNDERFIE_Pos 2                                              /**< (HSTPIPIMR) Underflow Interrupt Enable Position */
+#define HSTPIPIMR_INTRPT_UNDERFIE     (_U_(0x1) << HSTPIPIMR_INTRPT_UNDERFIE_Pos)  /**< (HSTPIPIMR) Underflow Interrupt Enable Mask */
+#define HSTPIPIMR_INTRPT_RXSTALLDE_Pos 6                                              /**< (HSTPIPIMR) Received STALLed Interrupt Enable Position */
+#define HSTPIPIMR_INTRPT_RXSTALLDE     (_U_(0x1) << HSTPIPIMR_INTRPT_RXSTALLDE_Pos)  /**< (HSTPIPIMR) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIMR_INTRPT_Msk          _U_(0x44)                                      /**< (HSTPIPIMR_INTRPT) Register Mask  */
+
+
+/* -------- HSTPIPIER : (USBHS Offset: 0x5f0) (/W 32) Host Pipe Enable Register -------- */
+
+#define HSTPIPIER_OFFSET              (0x5F0)                                       /**<  (HSTPIPIER) Host Pipe Enable Register  Offset */
+
+#define HSTPIPIER_RXINES_Pos          0                                              /**< (HSTPIPIER) Received IN Data Interrupt Enable Position */
+#define HSTPIPIER_RXINES              (_U_(0x1) << HSTPIPIER_RXINES_Pos)       /**< (HSTPIPIER) Received IN Data Interrupt Enable Mask */
+#define HSTPIPIER_TXOUTES_Pos         1                                              /**< (HSTPIPIER) Transmitted OUT Data Interrupt Enable Position */
+#define HSTPIPIER_TXOUTES             (_U_(0x1) << HSTPIPIER_TXOUTES_Pos)      /**< (HSTPIPIER) Transmitted OUT Data Interrupt Enable Mask */
+#define HSTPIPIER_PERRES_Pos          3                                              /**< (HSTPIPIER) Pipe Error Interrupt Enable Position */
+#define HSTPIPIER_PERRES              (_U_(0x1) << HSTPIPIER_PERRES_Pos)       /**< (HSTPIPIER) Pipe Error Interrupt Enable Mask */
+#define HSTPIPIER_NAKEDES_Pos         4                                              /**< (HSTPIPIER) NAKed Interrupt Enable Position */
+#define HSTPIPIER_NAKEDES             (_U_(0x1) << HSTPIPIER_NAKEDES_Pos)      /**< (HSTPIPIER) NAKed Interrupt Enable Mask */
+#define HSTPIPIER_OVERFIES_Pos        5                                              /**< (HSTPIPIER) Overflow Interrupt Enable Position */
+#define HSTPIPIER_OVERFIES            (_U_(0x1) << HSTPIPIER_OVERFIES_Pos)     /**< (HSTPIPIER) Overflow Interrupt Enable Mask */
+#define HSTPIPIER_SHORTPACKETIES_Pos  7                                              /**< (HSTPIPIER) Short Packet Interrupt Enable Position */
+#define HSTPIPIER_SHORTPACKETIES      (_U_(0x1) << HSTPIPIER_SHORTPACKETIES_Pos)  /**< (HSTPIPIER) Short Packet Interrupt Enable Mask */
+#define HSTPIPIER_NBUSYBKES_Pos       12                                             /**< (HSTPIPIER) Number of Busy Banks Enable Position */
+#define HSTPIPIER_NBUSYBKES           (_U_(0x1) << HSTPIPIER_NBUSYBKES_Pos)    /**< (HSTPIPIER) Number of Busy Banks Enable Mask */
+#define HSTPIPIER_PDISHDMAS_Pos       16                                             /**< (HSTPIPIER) Pipe Interrupts Disable HDMA Request Enable Position */
+#define HSTPIPIER_PDISHDMAS           (_U_(0x1) << HSTPIPIER_PDISHDMAS_Pos)    /**< (HSTPIPIER) Pipe Interrupts Disable HDMA Request Enable Mask */
+#define HSTPIPIER_PFREEZES_Pos        17                                             /**< (HSTPIPIER) Pipe Freeze Enable Position */
+#define HSTPIPIER_PFREEZES            (_U_(0x1) << HSTPIPIER_PFREEZES_Pos)     /**< (HSTPIPIER) Pipe Freeze Enable Mask */
+#define HSTPIPIER_RSTDTS_Pos          18                                             /**< (HSTPIPIER) Reset Data Toggle Enable Position */
+#define HSTPIPIER_RSTDTS              (_U_(0x1) << HSTPIPIER_RSTDTS_Pos)       /**< (HSTPIPIER) Reset Data Toggle Enable Mask */
+#define HSTPIPIER_Msk                 _U_(0x710BB)                                   /**< (HSTPIPIER) Register Mask  */
+
+/* CTRL mode */
+#define HSTPIPIER_CTRL_TXSTPES_Pos    2                                              /**< (HSTPIPIER) Transmitted SETUP Interrupt Enable Position */
+#define HSTPIPIER_CTRL_TXSTPES        (_U_(0x1) << HSTPIPIER_CTRL_TXSTPES_Pos)  /**< (HSTPIPIER) Transmitted SETUP Interrupt Enable Mask */
+#define HSTPIPIER_CTRL_RXSTALLDES_Pos 6                                              /**< (HSTPIPIER) Received STALLed Interrupt Enable Position */
+#define HSTPIPIER_CTRL_RXSTALLDES     (_U_(0x1) << HSTPIPIER_CTRL_RXSTALLDES_Pos)  /**< (HSTPIPIER) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIER_CTRL_Msk            _U_(0x44)                                      /**< (HSTPIPIER_CTRL) Register Mask  */
+
+/* ISO mode */
+#define HSTPIPIER_ISO_UNDERFIES_Pos   2                                              /**< (HSTPIPIER) Underflow Interrupt Enable Position */
+#define HSTPIPIER_ISO_UNDERFIES       (_U_(0x1) << HSTPIPIER_ISO_UNDERFIES_Pos)  /**< (HSTPIPIER) Underflow Interrupt Enable Mask */
+#define HSTPIPIER_ISO_CRCERRES_Pos    6                                              /**< (HSTPIPIER) CRC Error Interrupt Enable Position */
+#define HSTPIPIER_ISO_CRCERRES        (_U_(0x1) << HSTPIPIER_ISO_CRCERRES_Pos)  /**< (HSTPIPIER) CRC Error Interrupt Enable Mask */
+#define HSTPIPIER_ISO_Msk             _U_(0x44)                                      /**< (HSTPIPIER_ISO) Register Mask  */
+
+/* BLK mode */
+#define HSTPIPIER_BLK_TXSTPES_Pos     2                                              /**< (HSTPIPIER) Transmitted SETUP Interrupt Enable Position */
+#define HSTPIPIER_BLK_TXSTPES         (_U_(0x1) << HSTPIPIER_BLK_TXSTPES_Pos)  /**< (HSTPIPIER) Transmitted SETUP Interrupt Enable Mask */
+#define HSTPIPIER_BLK_RXSTALLDES_Pos  6                                              /**< (HSTPIPIER) Received STALLed Interrupt Enable Position */
+#define HSTPIPIER_BLK_RXSTALLDES      (_U_(0x1) << HSTPIPIER_BLK_RXSTALLDES_Pos)  /**< (HSTPIPIER) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIER_BLK_Msk             _U_(0x44)                                      /**< (HSTPIPIER_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define HSTPIPIER_INTRPT_UNDERFIES_Pos 2                                              /**< (HSTPIPIER) Underflow Interrupt Enable Position */
+#define HSTPIPIER_INTRPT_UNDERFIES     (_U_(0x1) << HSTPIPIER_INTRPT_UNDERFIES_Pos)  /**< (HSTPIPIER) Underflow Interrupt Enable Mask */
+#define HSTPIPIER_INTRPT_RXSTALLDES_Pos 6                                              /**< (HSTPIPIER) Received STALLed Interrupt Enable Position */
+#define HSTPIPIER_INTRPT_RXSTALLDES     (_U_(0x1) << HSTPIPIER_INTRPT_RXSTALLDES_Pos)  /**< (HSTPIPIER) Received STALLed Interrupt Enable Mask */
+#define HSTPIPIER_INTRPT_Msk          _U_(0x44)                                      /**< (HSTPIPIER_INTRPT) Register Mask  */
+
+
+/* -------- HSTPIPIDR : (USBHS Offset: 0x620) (/W 32) Host Pipe Disable Register -------- */
+
+#define HSTPIPIDR_OFFSET              (0x620)                                       /**<  (HSTPIPIDR) Host Pipe Disable Register  Offset */
+
+#define HSTPIPIDR_RXINEC_Pos          0                                              /**< (HSTPIPIDR) Received IN Data Interrupt Disable Position */
+#define HSTPIPIDR_RXINEC              (_U_(0x1) << HSTPIPIDR_RXINEC_Pos)       /**< (HSTPIPIDR) Received IN Data Interrupt Disable Mask */
+#define HSTPIPIDR_TXOUTEC_Pos         1                                              /**< (HSTPIPIDR) Transmitted OUT Data Interrupt Disable Position */
+#define HSTPIPIDR_TXOUTEC             (_U_(0x1) << HSTPIPIDR_TXOUTEC_Pos)      /**< (HSTPIPIDR) Transmitted OUT Data Interrupt Disable Mask */
+#define HSTPIPIDR_PERREC_Pos          3                                              /**< (HSTPIPIDR) Pipe Error Interrupt Disable Position */
+#define HSTPIPIDR_PERREC              (_U_(0x1) << HSTPIPIDR_PERREC_Pos)       /**< (HSTPIPIDR) Pipe Error Interrupt Disable Mask */
+#define HSTPIPIDR_NAKEDEC_Pos         4                                              /**< (HSTPIPIDR) NAKed Interrupt Disable Position */
+#define HSTPIPIDR_NAKEDEC             (_U_(0x1) << HSTPIPIDR_NAKEDEC_Pos)      /**< (HSTPIPIDR) NAKed Interrupt Disable Mask */
+#define HSTPIPIDR_OVERFIEC_Pos        5                                              /**< (HSTPIPIDR) Overflow Interrupt Disable Position */
+#define HSTPIPIDR_OVERFIEC            (_U_(0x1) << HSTPIPIDR_OVERFIEC_Pos)     /**< (HSTPIPIDR) Overflow Interrupt Disable Mask */
+#define HSTPIPIDR_SHORTPACKETIEC_Pos  7                                              /**< (HSTPIPIDR) Short Packet Interrupt Disable Position */
+#define HSTPIPIDR_SHORTPACKETIEC      (_U_(0x1) << HSTPIPIDR_SHORTPACKETIEC_Pos)  /**< (HSTPIPIDR) Short Packet Interrupt Disable Mask */
+#define HSTPIPIDR_NBUSYBKEC_Pos       12                                             /**< (HSTPIPIDR) Number of Busy Banks Disable Position */
+#define HSTPIPIDR_NBUSYBKEC           (_U_(0x1) << HSTPIPIDR_NBUSYBKEC_Pos)    /**< (HSTPIPIDR) Number of Busy Banks Disable Mask */
+#define HSTPIPIDR_FIFOCONC_Pos        14                                             /**< (HSTPIPIDR) FIFO Control Disable Position */
+#define HSTPIPIDR_FIFOCONC            (_U_(0x1) << HSTPIPIDR_FIFOCONC_Pos)     /**< (HSTPIPIDR) FIFO Control Disable Mask */
+#define HSTPIPIDR_PDISHDMAC_Pos       16                                             /**< (HSTPIPIDR) Pipe Interrupts Disable HDMA Request Disable Position */
+#define HSTPIPIDR_PDISHDMAC           (_U_(0x1) << HSTPIPIDR_PDISHDMAC_Pos)    /**< (HSTPIPIDR) Pipe Interrupts Disable HDMA Request Disable Mask */
+#define HSTPIPIDR_PFREEZEC_Pos        17                                             /**< (HSTPIPIDR) Pipe Freeze Disable Position */
+#define HSTPIPIDR_PFREEZEC            (_U_(0x1) << HSTPIPIDR_PFREEZEC_Pos)     /**< (HSTPIPIDR) Pipe Freeze Disable Mask */
+#define HSTPIPIDR_Msk                 _U_(0x350BB)                                   /**< (HSTPIPIDR) Register Mask  */
+
+/* CTRL mode */
+#define HSTPIPIDR_CTRL_TXSTPEC_Pos    2                                              /**< (HSTPIPIDR) Transmitted SETUP Interrupt Disable Position */
+#define HSTPIPIDR_CTRL_TXSTPEC        (_U_(0x1) << HSTPIPIDR_CTRL_TXSTPEC_Pos)  /**< (HSTPIPIDR) Transmitted SETUP Interrupt Disable Mask */
+#define HSTPIPIDR_CTRL_RXSTALLDEC_Pos 6                                              /**< (HSTPIPIDR) Received STALLed Interrupt Disable Position */
+#define HSTPIPIDR_CTRL_RXSTALLDEC     (_U_(0x1) << HSTPIPIDR_CTRL_RXSTALLDEC_Pos)  /**< (HSTPIPIDR) Received STALLed Interrupt Disable Mask */
+#define HSTPIPIDR_CTRL_Msk            _U_(0x44)                                      /**< (HSTPIPIDR_CTRL) Register Mask  */
+
+/* ISO mode */
+#define HSTPIPIDR_ISO_UNDERFIEC_Pos   2                                              /**< (HSTPIPIDR) Underflow Interrupt Disable Position */
+#define HSTPIPIDR_ISO_UNDERFIEC       (_U_(0x1) << HSTPIPIDR_ISO_UNDERFIEC_Pos)  /**< (HSTPIPIDR) Underflow Interrupt Disable Mask */
+#define HSTPIPIDR_ISO_CRCERREC_Pos    6                                              /**< (HSTPIPIDR) CRC Error Interrupt Disable Position */
+#define HSTPIPIDR_ISO_CRCERREC        (_U_(0x1) << HSTPIPIDR_ISO_CRCERREC_Pos)  /**< (HSTPIPIDR) CRC Error Interrupt Disable Mask */
+#define HSTPIPIDR_ISO_Msk             _U_(0x44)                                      /**< (HSTPIPIDR_ISO) Register Mask  */
+
+/* BLK mode */
+#define HSTPIPIDR_BLK_TXSTPEC_Pos     2                                              /**< (HSTPIPIDR) Transmitted SETUP Interrupt Disable Position */
+#define HSTPIPIDR_BLK_TXSTPEC         (_U_(0x1) << HSTPIPIDR_BLK_TXSTPEC_Pos)  /**< (HSTPIPIDR) Transmitted SETUP Interrupt Disable Mask */
+#define HSTPIPIDR_BLK_RXSTALLDEC_Pos  6                                              /**< (HSTPIPIDR) Received STALLed Interrupt Disable Position */
+#define HSTPIPIDR_BLK_RXSTALLDEC      (_U_(0x1) << HSTPIPIDR_BLK_RXSTALLDEC_Pos)  /**< (HSTPIPIDR) Received STALLed Interrupt Disable Mask */
+#define HSTPIPIDR_BLK_Msk             _U_(0x44)                                      /**< (HSTPIPIDR_BLK) Register Mask  */
+
+/* INTRPT mode */
+#define HSTPIPIDR_INTRPT_UNDERFIEC_Pos 2                                              /**< (HSTPIPIDR) Underflow Interrupt Disable Position */
+#define HSTPIPIDR_INTRPT_UNDERFIEC     (_U_(0x1) << HSTPIPIDR_INTRPT_UNDERFIEC_Pos)  /**< (HSTPIPIDR) Underflow Interrupt Disable Mask */
+#define HSTPIPIDR_INTRPT_RXSTALLDEC_Pos 6                                              /**< (HSTPIPIDR) Received STALLed Interrupt Disable Position */
+#define HSTPIPIDR_INTRPT_RXSTALLDEC     (_U_(0x1) << HSTPIPIDR_INTRPT_RXSTALLDEC_Pos)  /**< (HSTPIPIDR) Received STALLed Interrupt Disable Mask */
+#define HSTPIPIDR_INTRPT_Msk          _U_(0x44)                                      /**< (HSTPIPIDR_INTRPT) Register Mask  */
+
+
+/* -------- HSTPIPINRQ : (USBHS Offset: 0x650) (R/W 32) Host Pipe IN Request Register -------- */
+
+#define HSTPIPINRQ_OFFSET             (0x650)                                       /**<  (HSTPIPINRQ) Host Pipe IN Request Register  Offset */
+
+#define HSTPIPINRQ_INRQ_Pos           0                                              /**< (HSTPIPINRQ) IN Request Number before Freeze Position */
+#define HSTPIPINRQ_INRQ               (_U_(0xFF) << HSTPIPINRQ_INRQ_Pos)       /**< (HSTPIPINRQ) IN Request Number before Freeze Mask */
+#define HSTPIPINRQ_INMODE_Pos         8                                              /**< (HSTPIPINRQ) IN Request Mode Position */
+#define HSTPIPINRQ_INMODE             (_U_(0x1) << HSTPIPINRQ_INMODE_Pos)      /**< (HSTPIPINRQ) IN Request Mode Mask */
+#define HSTPIPINRQ_Msk                _U_(0x1FF)                                     /**< (HSTPIPINRQ) Register Mask  */
+
+
+/* -------- HSTPIPERR : (USBHS Offset: 0x680) (R/W 32) Host Pipe Error Register -------- */
+
+#define HSTPIPERR_OFFSET              (0x680)                                       /**<  (HSTPIPERR) Host Pipe Error Register  Offset */
+
+#define HSTPIPERR_DATATGL_Pos         0                                              /**< (HSTPIPERR) Data Toggle Error Position */
+#define HSTPIPERR_DATATGL             (_U_(0x1) << HSTPIPERR_DATATGL_Pos)      /**< (HSTPIPERR) Data Toggle Error Mask */
+#define HSTPIPERR_DATAPID_Pos         1                                              /**< (HSTPIPERR) Data PID Error Position */
+#define HSTPIPERR_DATAPID             (_U_(0x1) << HSTPIPERR_DATAPID_Pos)      /**< (HSTPIPERR) Data PID Error Mask */
+#define HSTPIPERR_PID_Pos             2                                              /**< (HSTPIPERR) Data PID Error Position */
+#define HSTPIPERR_PID                 (_U_(0x1) << HSTPIPERR_PID_Pos)          /**< (HSTPIPERR) Data PID Error Mask */
+#define HSTPIPERR_TIMEOUT_Pos         3                                              /**< (HSTPIPERR) Time-Out Error Position */
+#define HSTPIPERR_TIMEOUT             (_U_(0x1) << HSTPIPERR_TIMEOUT_Pos)      /**< (HSTPIPERR) Time-Out Error Mask */
+#define HSTPIPERR_CRC16_Pos           4                                              /**< (HSTPIPERR) CRC16 Error Position */
+#define HSTPIPERR_CRC16               (_U_(0x1) << HSTPIPERR_CRC16_Pos)        /**< (HSTPIPERR) CRC16 Error Mask */
+#define HSTPIPERR_COUNTER_Pos         5                                              /**< (HSTPIPERR) Error Counter Position */
+#define HSTPIPERR_COUNTER             (_U_(0x3) << HSTPIPERR_COUNTER_Pos)      /**< (HSTPIPERR) Error Counter Mask */
+#define HSTPIPERR_Msk                 _U_(0x7F)                                      /**< (HSTPIPERR) Register Mask  */
+
+#define HSTPIPERR_CRC_Pos             4                                              /**< (HSTPIPERR Position) CRCx6 Error */
+#define HSTPIPERR_CRC                 (_U_(0x1) << HSTPIPERR_CRC_Pos)          /**< (HSTPIPERR Mask) CRC */
+
+/* -------- CTRL : (USBHS Offset: 0x800) (R/W 32) General Control Register -------- */
+
+#define CTRL_OFFSET                   (0x800)                                       /**<  (CTRL) General Control Register  Offset */
+
+#define CTRL_RDERRE_Pos               4                                              /**< (CTRL) Remote Device Connection Error Interrupt Enable Position */
+#define CTRL_RDERRE                   (_U_(0x1) << CTRL_RDERRE_Pos)            /**< (CTRL) Remote Device Connection Error Interrupt Enable Mask */
+#define CTRL_VBUSHWC_Pos              8                                              /**< (CTRL) VBUS Hardware Control Position */
+#define CTRL_VBUSHWC                  (_U_(0x1) << CTRL_VBUSHWC_Pos)           /**< (CTRL) VBUS Hardware Control Mask */
+#define CTRL_FRZCLK_Pos               14                                             /**< (CTRL) Freeze USB Clock Position */
+#define CTRL_FRZCLK                   (_U_(0x1) << CTRL_FRZCLK_Pos)            /**< (CTRL) Freeze USB Clock Mask */
+#define CTRL_USBE_Pos                 15                                             /**< (CTRL) USBHS Enable Position */
+#define CTRL_USBE                     (_U_(0x1) << CTRL_USBE_Pos)              /**< (CTRL) USBHS Enable Mask */
+#define CTRL_UID_Pos                  24                                             /**< (CTRL) UID Pin Enable Position */
+#define CTRL_UID                      (_U_(0x1) << CTRL_UID_Pos)               /**< (CTRL) UID Pin Enable Mask */
+#define CTRL_UIMOD_Pos                25                                             /**< (CTRL) USBHS Mode Position */
+#define CTRL_UIMOD                    (_U_(0x1) << CTRL_UIMOD_Pos)             /**< (CTRL) USBHS Mode Mask */
+#define   CTRL_UIMOD_HOST_Val         _U_(0x0)                                       /**< (CTRL) The module is in USB Host mode.  */
+#define   CTRL_UIMOD_DEVICE_Val       _U_(0x1)                                       /**< (CTRL) The module is in USB Device mode.  */
+#define CTRL_UIMOD_HOST               (CTRL_UIMOD_HOST_Val << CTRL_UIMOD_Pos)  /**< (CTRL) The module is in USB Host mode. Position  */
+#define CTRL_UIMOD_DEVICE             (CTRL_UIMOD_DEVICE_Val << CTRL_UIMOD_Pos)  /**< (CTRL) The module is in USB Device mode. Position  */
+#define CTRL_Msk                      _U_(0x300C110)                                 /**< (CTRL) Register Mask  */
+
+
+/* -------- SR : (USBHS Offset: 0x804) (R/ 32) General Status Register -------- */
+
+#define SR_OFFSET                     (0x804)                                       /**<  (SR) General Status Register  Offset */
+
+#define SR_RDERRI_Pos                 4                                              /**< (SR) Remote Device Connection Error Interrupt (Host mode only) Position */
+#define SR_RDERRI                     (_U_(0x1) << SR_RDERRI_Pos)              /**< (SR) Remote Device Connection Error Interrupt (Host mode only) Mask */
+#define SR_SPEED_Pos                  12                                             /**< (SR) Speed Status (Device mode only) Position */
+#define SR_SPEED                      (_U_(0x3) << SR_SPEED_Pos)               /**< (SR) Speed Status (Device mode only) Mask */
+#define   SR_SPEED_FULL_SPEED_Val     _U_(0x0)                                       /**< (SR) Full-Speed mode  */
+#define   SR_SPEED_HIGH_SPEED_Val     _U_(0x1)                                       /**< (SR) High-Speed mode  */
+#define   SR_SPEED_LOW_SPEED_Val      _U_(0x2)                                       /**< (SR) Low-Speed mode  */
+#define SR_SPEED_FULL_SPEED           (SR_SPEED_FULL_SPEED_Val << SR_SPEED_Pos)  /**< (SR) Full-Speed mode Position  */
+#define SR_SPEED_HIGH_SPEED           (SR_SPEED_HIGH_SPEED_Val << SR_SPEED_Pos)  /**< (SR) High-Speed mode Position  */
+#define SR_SPEED_LOW_SPEED            (SR_SPEED_LOW_SPEED_Val << SR_SPEED_Pos)  /**< (SR) Low-Speed mode Position  */
+#define SR_CLKUSABLE_Pos              14                                             /**< (SR) UTMI Clock Usable Position */
+#define SR_CLKUSABLE                  (_U_(0x1) << SR_CLKUSABLE_Pos)           /**< (SR) UTMI Clock Usable Mask */
+#define SR_Msk                        _U_(0x7010)                                    /**< (SR) Register Mask  */
+
+
+/* -------- SCR : (USBHS Offset: 0x808) (/W 32) General Status Clear Register -------- */
+
+#define SCR_OFFSET                    (0x808)                                       /**<  (SCR) General Status Clear Register  Offset */
+
+#define SCR_RDERRIC_Pos               4                                              /**< (SCR) Remote Device Connection Error Interrupt Clear Position */
+#define SCR_RDERRIC                   (_U_(0x1) << SCR_RDERRIC_Pos)            /**< (SCR) Remote Device Connection Error Interrupt Clear Mask */
+#define SCR_Msk                       _U_(0x10)                                      /**< (SCR) Register Mask  */
+
+
+/* -------- SFR : (USBHS Offset: 0x80c) (/W 32) General Status Set Register -------- */
+
+#define SFR_OFFSET                    (0x80C)                                       /**<  (SFR) General Status Set Register  Offset */
+
+#define SFR_RDERRIS_Pos               4                                              /**< (SFR) Remote Device Connection Error Interrupt Set Position */
+#define SFR_RDERRIS                   (_U_(0x1) << SFR_RDERRIS_Pos)            /**< (SFR) Remote Device Connection Error Interrupt Set Mask */
+#define SFR_VBUSRQS_Pos               9                                              /**< (SFR) VBUS Request Set Position */
+#define SFR_VBUSRQS                   (_U_(0x1) << SFR_VBUSRQS_Pos)            /**< (SFR) VBUS Request Set Mask */
+#define SFR_Msk                       _U_(0x210)                                     /**< (SFR) Register Mask  */
+
+
+/** \brief DEVDMA hardware registers */
+typedef struct
+{  
+  __IO uint32_t DEVDMANXTDSC; /**< (DEVDMA Offset: 0x00) Device DMA Channel Next Descriptor Address Register */
+  __IO uint32_t DEVDMAADDRESS; /**< (DEVDMA Offset: 0x04) Device DMA Channel Address Register */
+  __IO uint32_t DEVDMACONTROL; /**< (DEVDMA Offset: 0x08) Device DMA Channel Control Register */
+  __IO uint32_t DEVDMASTATUS; /**< (DEVDMA Offset: 0x0C) Device DMA Channel Status Register */
+} devdma_t;
+
+/** \brief HSTDMA hardware registers */
+typedef struct
+{  
+  __IO uint32_t HSTDMANXTDSC; /**< (HSTDMA Offset: 0x00) Host DMA Channel Next Descriptor Address Register */
+  __IO uint32_t HSTDMAADDRESS; /**< (HSTDMA Offset: 0x04) Host DMA Channel Address Register */
+  __IO uint32_t HSTDMACONTROL; /**< (HSTDMA Offset: 0x08) Host DMA Channel Control Register */
+  __IO uint32_t HSTDMASTATUS; /**< (HSTDMA Offset: 0x0C) Host DMA Channel Status Register */
+} hstdma_t;
+
+/** \brief USBHS hardware registers */
+typedef struct
+{  
+  __IO uint32_t DEVCTRL;  /**< (USBHS Offset: 0x00) Device General Control Register */
+  __I  uint32_t DEVISR;   /**< (USBHS Offset: 0x04) Device Global Interrupt Status Register */
+  __O  uint32_t DEVICR;   /**< (USBHS Offset: 0x08) Device Global Interrupt Clear Register */
+  __O  uint32_t DEVIFR;   /**< (USBHS Offset: 0x0C) Device Global Interrupt Set Register */
+  __I  uint32_t DEVIMR;   /**< (USBHS Offset: 0x10) Device Global Interrupt Mask Register */
+  __O  uint32_t DEVIDR;   /**< (USBHS Offset: 0x14) Device Global Interrupt Disable Register */
+  __O  uint32_t DEVIER;   /**< (USBHS Offset: 0x18) Device Global Interrupt Enable Register */
+  __IO uint32_t DEVEPT;   /**< (USBHS Offset: 0x1C) Device Endpoint Register */
+  __I  uint32_t DEVFNUM;  /**< (USBHS Offset: 0x20) Device Frame Number Register */
+  __I  uint8_t                        Reserved1[220];
+  __IO uint32_t DEVEPTCFG[10]; /**< (USBHS Offset: 0x100) Device Endpoint Configuration Register */
+  __I  uint8_t                        Reserved2[8];
+  __I  uint32_t DEVEPTISR[10]; /**< (USBHS Offset: 0x130) Device Endpoint Interrupt Status Register */
+  __I  uint8_t                        Reserved3[8];
+  __O  uint32_t DEVEPTICR[10]; /**< (USBHS Offset: 0x160) Device Endpoint Interrupt Clear Register */
+  __I  uint8_t                        Reserved4[8];
+  __O  uint32_t DEVEPTIFR[10]; /**< (USBHS Offset: 0x190) Device Endpoint Interrupt Set Register */
+  __I  uint8_t                        Reserved5[8];
+  __I  uint32_t DEVEPTIMR[10]; /**< (USBHS Offset: 0x1C0) Device Endpoint Interrupt Mask Register */
+  __I  uint8_t                        Reserved6[8];
+  __O  uint32_t DEVEPTIER[10]; /**< (USBHS Offset: 0x1F0) Device Endpoint Interrupt Enable Register */
+  __I  uint8_t                        Reserved7[8];
+  __O  uint32_t DEVEPTIDR[10]; /**< (USBHS Offset: 0x220) Device Endpoint Interrupt Disable Register */
+  __I  uint8_t                        Reserved8[200];
+       devdma_t DEVDMA[7]; /**< Offset: 0x310 Device DMA Channel Next Descriptor Address Register */
+  __I  uint8_t                        Reserved9[128];
+  __IO uint32_t HSTCTRL;  /**< (USBHS Offset: 0x400) Host General Control Register */
+  __I  uint32_t HSTISR;   /**< (USBHS Offset: 0x404) Host Global Interrupt Status Register */
+  __O  uint32_t HSTICR;   /**< (USBHS Offset: 0x408) Host Global Interrupt Clear Register */
+  __O  uint32_t HSTIFR;   /**< (USBHS Offset: 0x40C) Host Global Interrupt Set Register */
+  __I  uint32_t HSTIMR;   /**< (USBHS Offset: 0x410) Host Global Interrupt Mask Register */
+  __O  uint32_t HSTIDR;   /**< (USBHS Offset: 0x414) Host Global Interrupt Disable Register */
+  __O  uint32_t HSTIER;   /**< (USBHS Offset: 0x418) Host Global Interrupt Enable Register */
+  __IO uint32_t HSTPIP;   /**< (USBHS Offset: 0x41C) Host Pipe Register */
+  __IO uint32_t HSTFNUM;  /**< (USBHS Offset: 0x420) Host Frame Number Register */
+  __IO uint32_t HSTADDR1; /**< (USBHS Offset: 0x424) Host Address 1 Register */
+  __IO uint32_t HSTADDR2; /**< (USBHS Offset: 0x428) Host Address 2 Register */
+  __IO uint32_t HSTADDR3; /**< (USBHS Offset: 0x42C) Host Address 3 Register */
+  __I  uint8_t                        Reserved10[208];
+  __IO uint32_t HSTPIPCFG[10]; /**< (USBHS Offset: 0x500) Host Pipe Configuration Register */
+  __I  uint8_t                        Reserved11[8];
+  __I  uint32_t HSTPIPISR[10]; /**< (USBHS Offset: 0x530) Host Pipe Status Register */
+  __I  uint8_t                        Reserved12[8];
+  __O  uint32_t HSTPIPICR[10]; /**< (USBHS Offset: 0x560) Host Pipe Clear Register */
+  __I  uint8_t                        Reserved13[8];
+  __O  uint32_t HSTPIPIFR[10]; /**< (USBHS Offset: 0x590) Host Pipe Set Register */
+  __I  uint8_t                        Reserved14[8];
+  __I  uint32_t HSTPIPIMR[10]; /**< (USBHS Offset: 0x5C0) Host Pipe Mask Register */
+  __I  uint8_t                        Reserved15[8];
+  __O  uint32_t HSTPIPIER[10]; /**< (USBHS Offset: 0x5F0) Host Pipe Enable Register */
+  __I  uint8_t                        Reserved16[8];
+  __O  uint32_t HSTPIPIDR[10]; /**< (USBHS Offset: 0x620) Host Pipe Disable Register */
+  __I  uint8_t                        Reserved17[8];
+  __IO uint32_t HSTPIPINRQ[10]; /**< (USBHS Offset: 0x650) Host Pipe IN Request Register */
+  __I  uint8_t                        Reserved18[8];
+  __IO uint32_t HSTPIPERR[10]; /**< (USBHS Offset: 0x680) Host Pipe Error Register */
+  __I  uint8_t                        Reserved19[104];
+       hstdma_t HSTDMA[7]; /**< Offset: 0x710 Host DMA Channel Next Descriptor Address Register */
+  __I  uint8_t                        Reserved20[128];
+  __IO uint32_t CTRL;     /**< (USBHS Offset: 0x800) General Control Register */
+  __I  uint32_t SR;       /**< (USBHS Offset: 0x804) General Status Register */
+  __O  uint32_t SCR;      /**< (USBHS Offset: 0x808) General Status Clear Register */
+  __O  uint32_t SFR;      /**< (USBHS Offset: 0x80C) General Status Set Register */
+} dcd_registers_t;
+
+#define USB_REG           ((dcd_registers_t *)0x40038000U)         /**< \brief (USBHS) Base Address */
+
+#define EP_MAX            10
+
+#define FIFO_RAM_ADDR     0xA0100000u
+
+// Errata: The DMA feature is not available for Pipe/Endpoint 7
+#define EP_DMA_SUPPORT(epnum) (epnum >= 1 && epnum <= 6)
+
+#else // TODO : SAM3U
+
+
+#endif
+
+#endif /* _COMMON_USB_REGS_H_ */
diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c
new file mode 100644
index 0000000..9e3b438
--- /dev/null
+++ b/src/portable/microchip/samx7x/dcd_samx7x.c
@@ -0,0 +1,768 @@
+/*
+* The MIT License (MIT)
+*
+* Copyright (c) 2018, hathach (tinyusb.org)
+* Copyright (c) 2021, HiFiPhile
+*
+* 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_SAMX7X
+
+#include "device/dcd.h"
+#include "sam.h"
+#include "common_usb_regs.h"
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
+// We disable SOF for now until needed later on
+#ifndef USE_SOF
+#  define USE_SOF         0
+#endif
+
+// Dual bank can imporve performance, but need 2 times bigger packet buffer
+// As SAM7x has only 4KB packet buffer, use with caution !
+// Enable in FS mode as packets are smaller
+#ifndef USE_DUAL_BANK
+#  if TUD_OPT_HIGH_SPEED
+#    define USE_DUAL_BANK   0
+#  else
+#    define USE_DUAL_BANK   1
+#  endif
+#endif
+
+#define EP_GET_FIFO_PTR(ep, scale) (((TU_XSTRCAT(TU_STRCAT(uint, scale),_t) (*)[0x8000 / ((scale) / 8)])FIFO_RAM_ADDR)[(ep)])
+
+// DMA Channel Transfer Descriptor
+typedef struct {
+  volatile uint32_t next_desc;
+  volatile uint32_t buff_addr;
+  volatile uint32_t chnl_ctrl;
+  uint32_t padding;
+} dma_desc_t;
+
+// Transfer control context
+typedef struct {
+  uint8_t * buffer;
+  uint16_t total_len;
+  uint16_t queued_len;
+  uint16_t max_packet_size;
+  uint8_t interval;
+  tu_fifo_t * fifo;
+} xfer_ctl_t;
+
+static tusb_speed_t get_speed(void);
+static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix);
+
+// DMA descriptors shouldn't be placed in ITCM !
+CFG_TUSB_MEM_SECTION static dma_desc_t dma_desc[6];
+
+static xfer_ctl_t xfer_status[EP_MAX];
+
+static const tusb_desc_endpoint_t ep0_desc =
+{
+  .bEndpointAddress = 0x00,
+  .wMaxPacketSize   = CFG_TUD_ENDPOINT0_SIZE,
+};
+
+TU_ATTR_ALWAYS_INLINE static inline void CleanInValidateCache(uint32_t *addr, int32_t size)
+{
+  if (SCB->CCR & SCB_CCR_DC_Msk)
+  {
+    SCB_CleanInvalidateDCache_by_Addr(addr, size);
+  }
+  else
+  {
+    __DSB();
+    __ISB();
+  }
+}
+//------------------------------------------------------------------
+// Device API
+//------------------------------------------------------------------
+
+// Initialize controller to device mode
+void dcd_init (uint8_t rhport)
+{
+  dcd_connect(rhport);
+}
+
+// Enable device interrupt
+void dcd_int_enable (uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ((IRQn_Type) ID_USBHS);
+}
+
+// Disable device interrupt
+void dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ((IRQn_Type) ID_USBHS);
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+  (void) dev_addr;
+  // DCD can only set address after status for this request is complete
+  // do it at dcd_edpt0_status_complete()
+
+  // Response with zlp status
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+// Wake up host
+void dcd_remote_wakeup (uint8_t rhport)
+{
+  (void) rhport;
+  USB_REG->DEVCTRL |= DEVCTRL_RMWKUP;
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  dcd_int_disable(rhport);
+  // Enable the USB controller in device mode
+  USB_REG->CTRL = CTRL_UIMOD | CTRL_USBE;
+  while (!(USB_REG->SR & SR_CLKUSABLE));
+#if TUD_OPT_HIGH_SPEED
+  USB_REG->DEVCTRL &= ~DEVCTRL_SPDCONF;
+#else
+  USB_REG->DEVCTRL |= DEVCTRL_SPDCONF_LOW_POWER;
+#endif
+  // Enable the End Of Reset, Suspend & Wakeup interrupts
+  USB_REG->DEVIER = (DEVIER_EORSTES | DEVIER_SUSPES | DEVIER_WAKEUPES);
+#if USE_SOF
+  USB_REG->DEVIER = DEVIER_SOFES;
+#endif
+  // Clear the End Of Reset, SOF & Wakeup interrupts
+  USB_REG->DEVICR = (DEVICR_EORSTC | DEVICR_SOFC | DEVICR_WAKEUPC);
+  // Manually set the Suspend Interrupt
+  USB_REG->DEVIFR |= DEVIFR_SUSPS;
+  // Ack the Wakeup Interrupt
+  USB_REG->DEVICR = DEVICR_WAKEUPC;
+  // Attach the device
+  USB_REG->DEVCTRL &= ~DEVCTRL_DETACH;
+  // Freeze USB clock
+  USB_REG->CTRL |= CTRL_FRZCLK;
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  dcd_int_disable(rhport);
+  // Disable all endpoints
+  USB_REG->DEVEPT &= ~(0x3FF << DEVEPT_EPEN0_Pos);
+  // Unfreeze USB clock
+  USB_REG->CTRL &= ~CTRL_FRZCLK;
+  while (!(USB_REG->SR & SR_CLKUSABLE));
+  // Clear all the pending interrupts
+  USB_REG->DEVICR = DEVICR_Msk;
+  // Disable all interrupts
+  USB_REG->DEVIDR = DEVIDR_Msk;
+  // Detach the device
+  USB_REG->DEVCTRL |= DEVCTRL_DETACH;
+  // Disable the device address
+  USB_REG->DEVCTRL &=~(DEVCTRL_ADDEN | DEVCTRL_UADD);
+}
+
+static tusb_speed_t get_speed(void)
+{
+  switch (USB_REG->SR & SR_SPEED) {
+  case SR_SPEED_FULL_SPEED:
+  default:
+    return TUSB_SPEED_FULL;
+  case SR_SPEED_HIGH_SPEED:
+    return TUSB_SPEED_HIGH;
+  case SR_SPEED_LOW_SPEED:
+    return TUSB_SPEED_LOW;
+  }
+}
+
+static void dcd_ep_handler(uint8_t ep_ix)
+{
+  uint32_t int_status = USB_REG->DEVEPTISR[ep_ix];
+  int_status &= USB_REG->DEVEPTIMR[ep_ix];
+
+  uint16_t count = (USB_REG->DEVEPTISR[ep_ix] &
+                    DEVEPTISR_BYCT) >> DEVEPTISR_BYCT_Pos;
+  xfer_ctl_t *xfer = &xfer_status[ep_ix];
+
+  if (ep_ix == 0U)
+  {
+    static uint8_t ctrl_dir;
+
+    if (int_status & DEVEPTISR_CTRL_RXSTPI)
+    {
+      ctrl_dir = (USB_REG->DEVEPTISR[0] & DEVEPTISR_CTRL_CTRLDIR) >> DEVEPTISR_CTRL_CTRLDIR_Pos;
+      // Setup packet should always be 8 bytes. If not, ignore it, and try again.
+      if (count == 8)
+      {
+        uint8_t *ptr = EP_GET_FIFO_PTR(0,8);
+        dcd_event_setup_received(0, ptr, true);
+      }
+      // Ack and disable SETUP interrupt
+      USB_REG->DEVEPTICR[0] = DEVEPTICR_CTRL_RXSTPIC;
+      USB_REG->DEVEPTIDR[0] = DEVEPTIDR_CTRL_RXSTPEC;
+    }
+    if (int_status & DEVEPTISR_RXOUTI)
+    {
+      uint8_t *ptr = EP_GET_FIFO_PTR(0,8);
+      
+      if (count && xfer->total_len)
+      {
+        uint16_t remain = xfer->total_len - xfer->queued_len;
+        if (count > remain)
+        {
+          count = remain;
+        }
+        if (xfer->buffer)
+        {
+          memcpy(xfer->buffer + xfer->queued_len, ptr, count);
+        } else 
+        {
+          tu_fifo_write_n(xfer->fifo, ptr, count);
+        }
+        xfer->queued_len = (uint16_t)(xfer->queued_len + count);
+      }
+      // Acknowledge the interrupt
+      USB_REG->DEVEPTICR[0] = DEVEPTICR_RXOUTIC;
+      if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
+      {
+        // RX COMPLETE
+        dcd_event_xfer_complete(0, 0, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+        // Disable the interrupt
+        USB_REG->DEVEPTIDR[0] = DEVEPTIDR_RXOUTEC;
+        // Re-enable SETUP interrupt
+        if (ctrl_dir == 1)
+        {
+          USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
+        }
+      }
+    }
+    if (int_status & DEVEPTISR_TXINI)
+    {
+      // Disable the interrupt
+      USB_REG->DEVEPTIDR[0] = DEVEPTIDR_TXINEC;
+      if ((xfer->total_len != xfer->queued_len))
+      {
+        // TX not complete
+        dcd_transmit_packet(xfer, 0);
+      } else 
+      {
+        // TX complete
+        dcd_event_xfer_complete(0, 0x80 + 0, xfer->total_len, XFER_RESULT_SUCCESS, true);
+        // Re-enable SETUP interrupt
+        if (ctrl_dir == 0)
+        {
+          USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
+        }
+      }
+    }
+  } else 
+  {
+    if (int_status & DEVEPTISR_RXOUTI)
+    {
+      if (count && xfer->total_len)
+      {
+        uint16_t remain = xfer->total_len - xfer->queued_len;
+        if (count > remain)
+        {
+          count = remain;
+        }
+        uint8_t *ptr = EP_GET_FIFO_PTR(ep_ix,8);
+        if (xfer->buffer)
+        {
+          memcpy(xfer->buffer + xfer->queued_len, ptr, count);
+        } else {
+          tu_fifo_write_n(xfer->fifo, ptr, count);
+        }
+        xfer->queued_len = (uint16_t)(xfer->queued_len + count);
+      }
+      // Clear the FIFO control flag to receive more data.
+      USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_FIFOCONC;
+      // Acknowledge the interrupt
+      USB_REG->DEVEPTICR[ep_ix] = DEVEPTICR_RXOUTIC;
+      if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
+      {
+        // RX COMPLETE
+        dcd_event_xfer_complete(0, ep_ix, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+        // Disable the interrupt
+        USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_RXOUTEC;
+        // Though the host could still send, we don't know.
+      }
+    }
+    if (int_status & DEVEPTISR_TXINI)
+    {
+      // Acknowledge the interrupt
+      USB_REG->DEVEPTICR[ep_ix] = DEVEPTICR_TXINIC;
+      if ((xfer->total_len != xfer->queued_len))
+      {
+        // TX not complete
+        dcd_transmit_packet(xfer, ep_ix);
+      } else 
+      {
+        // TX complete
+        dcd_event_xfer_complete(0, 0x80 + ep_ix, xfer->total_len, XFER_RESULT_SUCCESS, true);
+        // Disable the interrupt
+        USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_TXINEC;
+      }
+    }
+  }
+}
+
+static void dcd_dma_handler(uint8_t ep_ix)
+{
+  uint32_t status = USB_REG->DEVDMA[ep_ix - 1].DEVDMASTATUS;
+  if (status & DEVDMASTATUS_CHANN_ENB)
+  {
+    return; // Ignore EOT_STA interrupt
+  }
+  // Disable DMA interrupt
+  USB_REG->DEVIDR = DEVIDR_DMA_1 << (ep_ix - 1);
+
+  xfer_ctl_t *xfer = &xfer_status[ep_ix];
+  uint16_t count = xfer->total_len - ((status & DEVDMASTATUS_BUFF_COUNT) >> DEVDMASTATUS_BUFF_COUNT_Pos);
+  if(USB_REG->DEVEPTCFG[ep_ix] & DEVEPTCFG_EPDIR)
+  {
+    dcd_event_xfer_complete(0, 0x80 + ep_ix, count, XFER_RESULT_SUCCESS, true);
+  } else 
+  {
+    dcd_event_xfer_complete(0, ep_ix, count, XFER_RESULT_SUCCESS, true);
+  }
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void) rhport;
+  uint32_t int_status = USB_REG->DEVISR;
+  int_status &= USB_REG->DEVIMR;
+  // End of reset interrupt
+  if (int_status & DEVISR_EORST)
+  {
+    // Unfreeze USB clock
+    USB_REG->CTRL &= ~CTRL_FRZCLK;
+    while(!(USB_REG->SR & SR_CLKUSABLE));
+    // Reset all endpoints
+    for (int ep_ix = 1; ep_ix < EP_MAX; ep_ix++)
+    {
+      USB_REG->DEVEPT |= 1 << (DEVEPT_EPRST0_Pos + ep_ix);
+      USB_REG->DEVEPT &=~(1 << (DEVEPT_EPRST0_Pos + ep_ix));
+    }
+    dcd_edpt_open (0, &ep0_desc);
+    USB_REG->DEVICR = DEVICR_EORSTC;
+    USB_REG->DEVICR = DEVICR_WAKEUPC;
+    USB_REG->DEVICR = DEVICR_SUSPC;
+    USB_REG->DEVIER = DEVIER_SUSPES;
+
+    dcd_event_bus_reset(rhport, get_speed(), true);
+  }
+  // End of Wakeup interrupt
+  if (int_status & DEVISR_WAKEUP)
+  {
+    USB_REG->CTRL &= ~CTRL_FRZCLK;
+    while (!(USB_REG->SR & SR_CLKUSABLE));
+    USB_REG->DEVICR = DEVICR_WAKEUPC;
+    USB_REG->DEVIDR = DEVIDR_WAKEUPEC;
+    USB_REG->DEVIER = DEVIER_SUSPES;
+
+    dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+  }
+  // Suspend interrupt
+  if (int_status & DEVISR_SUSP)
+  {
+    // Unfreeze USB clock
+    USB_REG->CTRL &= ~CTRL_FRZCLK;
+    while (!(USB_REG->SR & SR_CLKUSABLE));
+    USB_REG->DEVICR = DEVICR_SUSPC;
+    USB_REG->DEVIDR = DEVIDR_SUSPEC;
+    USB_REG->DEVIER = DEVIER_WAKEUPES;
+    USB_REG->CTRL |= CTRL_FRZCLK;
+
+    dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+  }
+#if USE_SOF
+  if(int_status & DEVISR_SOF)
+  {
+    USB_REG->DEVICR = DEVICR_SOFC;
+
+    dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+  }
+#endif
+  // Endpoints interrupt
+  for (int ep_ix = 0; ep_ix < EP_MAX; ep_ix++)
+  {
+    if (int_status & (DEVISR_PEP_0 << ep_ix))
+    {
+      dcd_ep_handler(ep_ix);
+    }
+  }
+  // Endpoints DMA interrupt
+  for (int ep_ix = 0; ep_ix < EP_MAX; ep_ix++)
+  {
+    if (EP_DMA_SUPPORT(ep_ix))
+    {
+      if (int_status & (DEVISR_DMA_1 << (ep_ix - 1)))
+      {
+        dcd_dma_handler(ep_ix);
+      }
+    }
+  }
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+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 &&
+        request->bRequest == TUSB_REQ_SET_ADDRESS )
+  {
+    uint8_t const dev_addr = (uint8_t) request->wValue;
+
+    USB_REG->DEVCTRL |= dev_addr | DEVCTRL_ADDEN;
+  }
+}
+
+// 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 epnum = tu_edpt_number(ep_desc->bEndpointAddress);
+  uint8_t const dir   = tu_edpt_dir(ep_desc->bEndpointAddress);
+  uint16_t const epMaxPktSize = tu_edpt_packet_size(ep_desc);
+  tusb_xfer_type_t const eptype = (tusb_xfer_type_t)ep_desc->bmAttributes.xfer;
+  uint8_t fifoSize = 0;                       // FIFO size
+  uint16_t defaultEndpointSize = 8;           // Default size of Endpoint
+  // Find upper 2 power number of epMaxPktSize
+  if (epMaxPktSize)
+  {
+    while (defaultEndpointSize < epMaxPktSize)
+    {
+      fifoSize++;
+      defaultEndpointSize <<= 1;
+    }
+  }
+  xfer_status[epnum].max_packet_size = epMaxPktSize;
+
+  USB_REG->DEVEPT |= 1 << (DEVEPT_EPRST0_Pos + epnum);
+  USB_REG->DEVEPT &=~(1 << (DEVEPT_EPRST0_Pos + epnum));
+
+  if (epnum == 0)
+  {
+    // Enable the control endpoint - Endpoint 0
+    USB_REG->DEVEPT |= DEVEPT_EPEN0;
+    // Configure the Endpoint 0 configuration register
+    USB_REG->DEVEPTCFG[0] =
+      (
+       (fifoSize << DEVEPTCFG_EPSIZE_Pos)            |
+       (TUSB_XFER_CONTROL << DEVEPTCFG_EPTYPE_Pos)   |
+       (DEVEPTCFG_EPBK_1_BANK << DEVEPTCFG_EPBK_Pos) |
+       DEVEPTCFG_ALLOC
+       );
+    USB_REG->DEVEPTIER[0] = DEVEPTIER_RSTDTS;
+    USB_REG->DEVEPTIDR[0] = DEVEPTIDR_CTRL_STALLRQC;
+    if (DEVEPTISR_CFGOK == (USB_REG->DEVEPTISR[0] & DEVEPTISR_CFGOK))
+    {
+      // Endpoint configuration is successful
+      USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
+      // Enable Endpoint 0 Interrupts
+      USB_REG->DEVIER = DEVIER_PEP_0;
+      return true;
+    } else 
+    {
+      // Endpoint configuration is not successful
+      return false;
+    }
+  } else 
+  {
+    // Enable the endpoint
+    USB_REG->DEVEPT |= ((0x01 << epnum) << DEVEPT_EPEN0_Pos);
+    // Set up the maxpacket size, fifo start address fifosize
+    // and enable the interrupt. CLear the data toggle.
+    // AUTOSW is needed for DMA ack !
+    USB_REG->DEVEPTCFG[epnum] =
+      (
+       (fifoSize << DEVEPTCFG_EPSIZE_Pos)            |
+       (eptype  << DEVEPTCFG_EPTYPE_Pos)             |
+       (DEVEPTCFG_EPBK_1_BANK << DEVEPTCFG_EPBK_Pos) |
+       DEVEPTCFG_AUTOSW |
+       ((dir & 0x01) << DEVEPTCFG_EPDIR_Pos)
+       );
+    if (eptype == TUSB_XFER_ISOCHRONOUS)
+    {
+      USB_REG->DEVEPTCFG[epnum] |= DEVEPTCFG_NBTRANS_1_TRANS;
+    }
+#if USE_DUAL_BANK
+    if (eptype == TUSB_XFER_ISOCHRONOUS || eptype == TUSB_XFER_BULK)
+    {
+      USB_REG->DEVEPTCFG[epnum] |= DEVEPTCFG_EPBK_2_BANK;
+    }
+#endif
+    USB_REG->DEVEPTCFG[epnum] |= DEVEPTCFG_ALLOC;
+    USB_REG->DEVEPTIER[epnum] = DEVEPTIER_RSTDTS;
+    USB_REG->DEVEPTIDR[epnum] = DEVEPTIDR_CTRL_STALLRQC;
+    if (DEVEPTISR_CFGOK == (USB_REG->DEVEPTISR[epnum] & DEVEPTISR_CFGOK))
+    {
+      USB_REG->DEVIER = ((0x01 << epnum) << DEVIER_PEP_0_Pos);
+      return true;
+    } else 
+    {
+      // Endpoint configuration is not successful
+      return false;
+    }
+  }
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  uint8_t const epnum  = tu_edpt_number(ep_addr);
+
+  // Disable endpoint interrupt
+  USB_REG->DEVIDR = 1 << (DEVIDR_PEP_0_Pos + epnum);
+  // Disable EP
+  USB_REG->DEVEPT &=~(1 << (DEVEPT_EPEN0_Pos + epnum));
+}
+
+static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix)
+{
+  uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len);
+  if (len)
+  {
+    if (len > xfer->max_packet_size)
+    {
+      len = xfer->max_packet_size;
+    }
+    uint8_t *ptr = EP_GET_FIFO_PTR(ep_ix,8);
+    if(xfer->buffer)
+    {
+      memcpy(ptr, xfer->buffer + xfer->queued_len, len);
+    }
+    else 
+    {
+      tu_fifo_read_n(xfer->fifo, ptr, len);
+    }
+    __DSB();
+    __ISB();
+    xfer->queued_len = (uint16_t)(xfer->queued_len + len);
+  }
+  if (ep_ix == 0U)
+  {
+    // Control endpoint: clear the interrupt flag to send the data
+    USB_REG->DEVEPTICR[0] = DEVEPTICR_TXINIC;
+  } else 
+  {
+    // Other endpoint types: clear the FIFO control flag to send the data
+    USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_FIFOCONC;
+  }
+  USB_REG->DEVEPTIER[ep_ix] = DEVEPTIER_TXINES;
+}
+
+// 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 const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  xfer_ctl_t * xfer = &xfer_status[epnum];
+
+  xfer->buffer = buffer;
+  xfer->total_len = total_bytes;
+  xfer->queued_len = 0;
+  xfer->fifo = NULL;
+  
+  if (EP_DMA_SUPPORT(epnum) && total_bytes != 0)
+  {
+    // Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the
+    // address to 32-byte boundaries.
+    CleanInValidateCache((uint32_t*) tu_align((uint32_t) buffer, 4), total_bytes + 31);
+    uint32_t udd_dma_ctrl = total_bytes << DEVDMACONTROL_BUFF_LENGTH_Pos;
+    if (dir == TUSB_DIR_OUT)
+    {
+      udd_dma_ctrl |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
+    } else {
+      udd_dma_ctrl |= DEVDMACONTROL_END_B_EN;
+    }
+    USB_REG->DEVDMA[epnum - 1].DEVDMAADDRESS = (uint32_t)buffer;
+    udd_dma_ctrl |= DEVDMACONTROL_END_BUFFIT | DEVDMACONTROL_CHANN_ENB;
+    // Disable IRQs to have a short sequence
+    // between read of EOT_STA and DMA enable
+    uint32_t irq_state = __get_PRIMASK();
+    __disable_irq();
+    if (!(USB_REG->DEVDMA[epnum - 1].DEVDMASTATUS & DEVDMASTATUS_END_TR_ST))
+    {
+      USB_REG->DEVDMA[epnum - 1].DEVDMACONTROL = udd_dma_ctrl;
+      USB_REG->DEVIER = DEVIER_DMA_1 << (epnum - 1);
+      __set_PRIMASK(irq_state);
+      return true;
+    }
+    __set_PRIMASK(irq_state);
+
+    // Here a ZLP has been recieved
+    // and the DMA transfer must be not started.
+    // It is the end of transfer
+    return false;
+  } else 
+  {
+    if (dir == TUSB_DIR_OUT)
+    {
+      USB_REG->DEVEPTIER[epnum] = DEVEPTIER_RXOUTES;
+    } else 
+    {
+      dcd_transmit_packet(xfer,epnum);
+    }
+  }
+  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)
+{
+  (void) rhport;
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  xfer_ctl_t * xfer = &xfer_status[epnum];
+  if(epnum == 0x80)
+    xfer = &xfer_status[EP_MAX];
+
+  xfer->buffer = NULL;
+  xfer->total_len = total_bytes;
+  xfer->queued_len = 0;
+  xfer->fifo = ff;
+
+  if (EP_DMA_SUPPORT(epnum) && total_bytes != 0)
+  {
+    tu_fifo_buffer_info_t info;
+    uint32_t udd_dma_ctrl_lin = DEVDMACONTROL_CHANN_ENB;
+    uint32_t udd_dma_ctrl_wrap = DEVDMACONTROL_CHANN_ENB | DEVDMACONTROL_END_BUFFIT;
+    if (dir == TUSB_DIR_OUT)
+    {
+      tu_fifo_get_write_info(ff, &info);
+      udd_dma_ctrl_lin |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
+      udd_dma_ctrl_wrap |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
+    } else {
+      tu_fifo_get_read_info(ff, &info);
+      if(info.len_wrap == 0)
+      {
+        udd_dma_ctrl_lin |= DEVDMACONTROL_END_B_EN;
+      }
+      udd_dma_ctrl_wrap |= DEVDMACONTROL_END_B_EN;
+    }
+
+    // Clean invalidate cache of linear part
+    CleanInValidateCache((uint32_t*) tu_align((uint32_t) info.ptr_lin, 4), info.len_lin + 31);
+    
+    USB_REG->DEVDMA[epnum - 1].DEVDMAADDRESS = (uint32_t)info.ptr_lin;
+    if (info.len_wrap)
+    {
+      // Clean invalidate cache of wrapped part
+      CleanInValidateCache((uint32_t*) tu_align((uint32_t) info.ptr_wrap, 4), info.len_wrap + 31);
+      
+      dma_desc[epnum - 1].next_desc = 0;
+      dma_desc[epnum - 1].buff_addr = (uint32_t)info.ptr_wrap;
+      dma_desc[epnum - 1].chnl_ctrl =
+        udd_dma_ctrl_wrap | (info.len_wrap << DEVDMACONTROL_BUFF_LENGTH_Pos);
+      // Clean cache of wrapped DMA descriptor
+      CleanInValidateCache((uint32_t*)&dma_desc[epnum - 1], sizeof(dma_desc_t));
+      
+      udd_dma_ctrl_lin |= DEVDMASTATUS_DESC_LDST;
+      USB_REG->DEVDMA[epnum - 1].DEVDMANXTDSC = (uint32_t)&dma_desc[epnum - 1];
+    } else {
+      udd_dma_ctrl_lin |= DEVDMACONTROL_END_BUFFIT;
+    }
+    udd_dma_ctrl_lin |= (info.len_lin << DEVDMACONTROL_BUFF_LENGTH_Pos);
+    // Disable IRQs to have a short sequence
+    // between read of EOT_STA and DMA enable
+    uint32_t irq_state = __get_PRIMASK();
+    __disable_irq();
+    if (!(USB_REG->DEVDMA[epnum - 1].DEVDMASTATUS & DEVDMASTATUS_END_TR_ST))
+    {
+      USB_REG->DEVDMA[epnum - 1].DEVDMACONTROL = udd_dma_ctrl_lin;
+      USB_REG->DEVIER = DEVIER_DMA_1 << (epnum - 1);
+      __set_PRIMASK(irq_state);
+      return true;
+    }
+    __set_PRIMASK(irq_state);
+
+    // Here a ZLP has been recieved
+    // and the DMA transfer must be not started.
+    // It is the end of transfer
+    return false;
+  } else
+  {
+    if (dir == TUSB_DIR_OUT)
+    {
+      USB_REG->DEVEPTIER[epnum] = DEVEPTIER_RXOUTES;
+    } else 
+    {
+      dcd_transmit_packet(xfer,epnum);
+    }
+  }
+  return true;
+}
+
+// Stall endpoint
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  USB_REG->DEVEPTIER[epnum] = DEVEPTIER_CTRL_STALLRQS;
+  // Re-enable SETUP interrupt
+  if (epnum == 0)
+  {
+    USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
+  }
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  USB_REG->DEVEPTIDR[epnum] = DEVEPTIDR_CTRL_STALLRQC;
+  USB_REG->DEVEPTIER[epnum] = HSTPIPIER_RSTDTS;
+}
+
+#endif
diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
new file mode 100644
index 0000000..a3b69b9
--- /dev/null
+++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
@@ -0,0 +1,477 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 SE TEAM
+ *
+ * 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_MM32F327X )
+
+#include "reg_usb_otg_fs.h"
+#include "mm32_device.h"
+#include "hal_conf.h"
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+  TOK_PID_OUT   = 0x1u,
+  TOK_PID_IN    = 0x9u,
+  TOK_PID_SETUP = 0xDu,
+};
+
+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" );
+
+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];
+    uint16_t            bda[512];
+  };
+  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) static dcd_data_t _dcd;
+
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
+
+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;
+  if (_dcd.bdt[0][0][out_odd].own) {
+    TU_LOG1("DCD fail to prepare the next SETUP %d %d\r\n", out_odd, in_odd);
+    return;
+  }
+  _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)
+{
+  if (USB_OTG_FS->EP_CTL[0] & USB_ENDPT_EPSTALL_MASK) {
+    /* clear stall condition of the control pipe */
+    prepare_next_setup_packet(rhport);
+    USB_OTG_FS->EP_CTL[0] &= ~USB_ENDPT_EPSTALL_MASK;
+  }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+  const unsigned s = USB_OTG_FS->STAT;
+  USB_OTG_FS->INT_STAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+  buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
+  endpoint_state_t    *ep = &_dcd.endpoint_unified[s >> 3];
+  unsigned odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
+  /* 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, bd->addr, true);
+    USB_OTG_FS->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
+    return;
+  }
+  if (s >> 4) {
+    TU_LOG1("TKDNE %x\r\n", s);
+  }
+
+  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;
+      __DSB();
+      bd->own   = 1; /* the own bit must set after addr */
+    }
+    return;
+  }
+  const unsigned length = ep->length;
+  dcd_event_xfer_complete(rhport,
+                          ((s & USB_STAT_TX_MASK) << 4) | (s >> USB_STAT_ENDP_SHIFT),
+                          length - remaining, XFER_RESULT_SUCCESS, true);
+  if (0 == (s & USB_STAT_ENDP_MASK) && 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. */
+      USB_OTG_FS->ADDR = _dcd.addr;
+      _dcd.addr  = 0;
+    }
+    prepare_next_setup_packet(rhport);
+  }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+  USB_OTG_FS->CTL     |= USB_CTL_ODDRST_MASK;
+  USB_OTG_FS->ADDR     = 0;
+  USB_OTG_FS->INT_ENB    = (USB_OTG_FS->INT_ENB & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+
+  USB_OTG_FS->EP_CTL[0] = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+  for (unsigned i = 1; i < 16; ++i) {
+    USB_OTG_FS->EP_CTL[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);
+  USB_OTG_FS->CTL &= ~USB_CTL_ODDRST_MASK;
+  dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_bus_inactive(uint8_t rhport)
+{
+  (void) rhport;
+  const unsigned inten = USB_OTG_FS->INT_ENB;
+  USB_OTG_FS->INT_ENB    = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
+  dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+}
+
+static void process_bus_active(uint8_t rhport)
+{
+  (void) rhport;
+  const unsigned inten = USB_OTG_FS->INT_ENB;
+  USB_OTG_FS->INT_ENB    = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+  dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  tu_memclr(&_dcd, sizeof(_dcd));
+  USB_OTG_FS->BDT_PAGE_01 = (uint8_t)((uintptr_t)_dcd.bdt >>  8);
+  USB_OTG_FS->BDT_PAGE_02 = (uint8_t)((uintptr_t)_dcd.bdt >> 16);
+  USB_OTG_FS->BDT_PAGE_03 = (uint8_t)((uintptr_t)_dcd.bdt >> 24);
+
+  dcd_connect(rhport);
+  NVIC_ClearPendingIRQ(USB_FS_IRQn);
+}
+#define USB_DEVICE_INTERRUPT_PRIORITY (3U)
+void dcd_int_enable(uint8_t rhport)
+{
+  uint8_t irqNumber;
+  irqNumber = USB_FS_IRQn;
+  (void) rhport;
+  USB_OTG_FS->INT_ENB = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK |
+    USB_INTEN_SLEEPEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
+  NVIC_SetPriority((IRQn_Type)irqNumber, USB_DEVICE_INTERRUPT_PRIORITY);
+  NVIC_EnableIRQ(USB_FS_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB_FS_IRQn);
+  USB_OTG_FS->INT_ENB = 0;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  (void) rhport;
+  _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);
+}
+extern u32 SystemCoreClock;
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+  unsigned cnt = SystemCoreClock / 100;
+  USB_OTG_FS->CTL |= USB_CTL_RESUME_MASK;
+  while (cnt--) __NOP();
+  USB_OTG_FS->CTL &= ~USB_CTL_RESUME_MASK;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  USB_OTG_FS->CTL     |= USB_CTL_USBENSOFEN_MASK;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  USB_OTG_FS->CTL      = 0;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+  (void) rhport;
+
+  const unsigned ep_addr  = ep_desc->bEndpointAddress;
+  const unsigned epn      = ep_addr & 0xFu;
+  const unsigned dir      = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+  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][0];
+
+  /* No support for control transfer */
+  TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
+
+  ep->max_packet_size = tu_edpt_packet_size(ep_desc);
+  unsigned val = USB_ENDPT_EPCTLDIS_MASK;
+  val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK: 0;
+  val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+  USB_OTG_FS->EP_CTL[epn] |= val;
+
+  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)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  const unsigned epn      = ep_addr & 0xFu;
+  const unsigned dir      = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+  endpoint_state_t *ep    = &_dcd.endpoint[epn][dir];
+  buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0];
+  const unsigned msk      = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+  USB_OTG_FS->EP_CTL[epn] &= ~msk;
+  ep->max_packet_size = 0;
+  ep->length          = 0;
+  ep->remaining       = 0;
+  bd->head            = 0;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB_FS_IRQn);
+  const unsigned epn = ep_addr & 0xFu;
+  const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+  endpoint_state_t    *ep = &_dcd.endpoint[epn][dir];
+  buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
+
+  if (bd->own) {
+    TU_LOG1("DCD XFER fail %x %d %lx %lx\r\n", ep_addr, total_bytes, ep->state, bd->head);
+    return false; /* The last transfer has not completed */
+  }
+  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 = buffer + mps;
+    next->own  = 1;
+  }
+  bd->bc        = total_bytes >= mps ? mps: total_bytes;
+  bd->addr      = buffer;
+  __DSB();
+  bd->own  = 1; /* the own bit must set after addr */
+  NVIC_EnableIRQ(USB_FS_IRQn);
+  return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  const unsigned epn = ep_addr & 0xFu;
+  if (0 == epn) {
+    USB_OTG_FS->EP_CTL[epn] |=  USB_ENDPT_EPSTALL_MASK;
+  } else {
+    const unsigned dir      = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+    buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+    bd[0].bdt_stall = 1;
+    bd[1].bdt_stall = 1;
+  }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  const unsigned epn      = ep_addr & 0xFu;
+  const unsigned dir      = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+  const unsigned odd      = _dcd.endpoint[epn][dir].odd;
+  buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+
+  bd[odd ^ 1].own       = 0;
+  bd[odd ^ 1].data      = 1;
+  bd[odd ^ 1].bdt_stall = 0;
+  bd[odd].own           = 0;
+  bd[odd].data          = 0;
+  bd[odd].bdt_stall     = 0;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void) rhport;
+
+  uint32_t is  = USB_OTG_FS->INT_STAT;
+  uint32_t msk = USB_OTG_FS->INT_ENB;
+  USB_OTG_FS->INT_STAT = is & ~msk;
+  is &= msk;
+  if (is & USB_ISTAT_ERROR_MASK) {
+    /* TODO: */
+    uint32_t es = USB_OTG_FS->ERR_STAT;
+    USB_OTG_FS->ERR_STAT = es;
+    USB_OTG_FS->INT_STAT   = is; /* discard any pending events */
+    return;
+  }
+
+  if (is & USB_ISTAT_USBRST_MASK) {
+    USB_OTG_FS->INT_STAT = is; /* discard any pending events */
+    process_bus_reset(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_SLEEP_MASK) {
+    USB_OTG_FS->INT_STAT = USB_ISTAT_SLEEP_MASK;
+    process_bus_inactive(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_RESUME_MASK) {
+    USB_OTG_FS->INT_STAT = USB_ISTAT_RESUME_MASK;
+    process_bus_active(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_SOFTOK_MASK) {
+    USB_OTG_FS->INT_STAT = USB_ISTAT_SOFTOK_MASK;
+    dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+    return;
+  }
+  if (is & USB_ISTAT_STALL_MASK) {
+    USB_OTG_FS->INT_STAT = USB_ISTAT_STALL_MASK;
+    process_stall(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_TOKDNE_MASK) {
+    process_tokdne(rhport);
+    return;
+  }
+}
+
+#endif
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
new file mode 100644
index 0000000..ed597a3
--- /dev/null
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -0,0 +1,1106 @@
+/* 
+ * 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 TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
+
+#include "nrf.h"
+#include "nrf_clock.h"
+#include "nrf_power.h"
+#include "nrfx_usbd_errata.h"
+#include "device/dcd.h"
+
+// TODO remove later
+#include "device/usbd.h"
+#include "device/usbd_pvt.h" // to use defer function helper
+
+/*------------------------------------------------------------------*/
+/* MACRO TYPEDEF CONSTANT ENUM
+ *------------------------------------------------------------------*/
+enum
+{
+  // Max allowed by USB specs
+  MAX_PACKET_SIZE   = 64,
+
+  // Mask of all END event (IN & OUT) for all endpoints. ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
+  EDPT_END_ALL_MASK = (0xff << USBD_INTEN_ENDEPIN0_Pos) | (0xff << USBD_INTEN_ENDEPOUT0_Pos) |
+                      USBD_INTENCLR_ENDISOIN_Msk | USBD_INTEN_ENDISOOUT_Msk
+};
+
+enum
+{
+  EP_ISO_NUM   = 8, // Endpoint number is fixed (8) for ISOOUT and ISOIN
+  EP_CBI_COUNT = 8  // Control Bulk Interrupt endpoints count
+};
+
+// Transfer Descriptor
+typedef struct
+{
+  uint8_t* buffer;
+  uint16_t total_len;
+  volatile uint16_t actual_len;
+  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;
+
+  // 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.
+  bool iso_in_transfer_ready;
+
+} xfer_td_t;
+
+// Data for managing dcd
+static struct
+{
+  // All 8 endpoints including control IN & OUT (offset 1)
+  // +1 for ISO endpoints
+  xfer_td_t xfer[EP_CBI_COUNT + 1][2];
+
+  // nRF can only carry one DMA at a time, this is used to guard the access to EasyDMA
+  volatile bool dma_running;
+}_dcd;
+
+/*------------------------------------------------------------------*/
+/* Control / Bulk / Interrupt (CBI) Transfer
+ *------------------------------------------------------------------*/
+
+// NVIC_GetEnableIRQ is only available in CMSIS v5
+#ifndef NVIC_GetEnableIRQ
+static inline uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn)
+{
+  if ((int32_t)(IRQn) >= 0)
+  {
+    return((uint32_t)(((NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
+  }
+  else
+  {
+    return(0U);
+  }
+}
+#endif
+
+// check if we are in ISR
+TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
+{
+  return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false;
+}
+
+// helper to start DMA
+static void start_dma(volatile uint32_t* reg_startep)
+{
+  _dcd.dma_running = true;
+
+  (*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) )
+  {
+    _dcd.dma_running = false;
+  }
+}
+
+// only 1 EasyDMA can be active at any time
+// 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)
+{
+  // Called in critical section i.e within USB ISR, or USB/Global interrupt disabled
+  if ( is_in_isr() || __get_PRIMASK() || !NVIC_GetEnableIRQ(USBD_IRQn) )
+  {
+    if (_dcd.dma_running)
+    {
+      //use usbd task to defer later
+      usbd_defer_func((osal_task_func_t) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
+    }else
+    {
+      start_dma(reg_startep);
+    }
+  }else
+  {
+    // Called in non-critical thread-mode, should be 99% of the time.
+    // Should be safe to blocking wait until previous DMA transfer complete
+    uint8_t const rhport = 0;
+    bool started = false;
+    while(!started)
+    {
+      // LDREX/STREX may be needed in form of std atomic (required C11) or
+      // use osal mutex to guard against multiple core MCUs such as nRF53
+      dcd_int_disable(rhport);
+
+      if ( !_dcd.dma_running )
+      {
+        start_dma(reg_startep);
+        started = true;
+      }
+
+      dcd_int_enable(rhport);
+
+      // osal_yield();
+    }
+  }
+}
+
+// DMA is complete
+static void edpt_dma_end(void)
+{
+  TU_ASSERT(_dcd.dma_running, );
+  _dcd.dma_running = false;
+}
+
+// helper getting td
+static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir)
+{
+  return &_dcd.xfer[epnum][dir];
+}
+
+// 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;
+
+  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;
+    }
+    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);
+    }
+  }
+  else
+  {
+    // limit xact len to remaining length
+    xact_len = tu_min16((uint16_t) NRF_USBD->SIZE.EPOUT[epnum], xfer->total_len - xfer->actual_len);
+
+    // Trigger DMA move data from Endpoint -> SRAM
+    NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
+    NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
+
+    edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
+  }
+}
+
+// Prepare for a CBI transaction IN, call at the start
+// it start DMA to transfer data from RAM -> Endpoint
+static void xact_in_dma(uint8_t epnum)
+{
+  xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
+
+  // Each transaction is up to Max Packet Size
+  uint16_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps);
+
+  NRF_USBD->EPIN[epnum].PTR    = (uint32_t) xfer->buffer;
+  NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
+
+  edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
+}
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+void dcd_init (uint8_t rhport)
+{
+  TU_LOG1("dcd init\r\n");
+  (void) rhport;
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USBD_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USBD_IRQn);
+}
+
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+  (void) rhport;
+  (void) dev_addr;
+  // Set Address is automatically update by hw controller, nothing to do
+
+  // Enable usbevent for suspend and resume detection
+  // Since the bus signal D+/D- are stable now.
+
+  // Clear current pending first
+  NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE;
+  NRF_USBD->EVENTS_USBEVENT = 0;
+
+  NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk;
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+
+  // Bring controller out of low power mode
+  // will start wakeup when USBWUALLOWED is set
+  NRF_USBD->LOWPOWER = 0;
+}
+
+// disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  NRF_USBD->USBPULLUP = 0;
+
+  // Disable Pull-up does not trigger Power USB Removed, in fact it have no
+  // impact on the USB Power status at all -> need to submit unplugged event to the stack.
+  dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, false);
+}
+
+// connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  NRF_USBD->USBPULLUP = 1;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
+{
+  (void) rhport;
+
+  uint8_t const ep_addr = desc_edpt->bEndpointAddress;
+  uint8_t const epnum   = tu_edpt_number(ep_addr);
+  uint8_t const dir     = tu_edpt_dir(ep_addr);
+
+  _dcd.xfer[epnum][dir].mps = tu_edpt_packet_size(desc_edpt);
+
+  if (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS)
+  {
+    if (dir == TUSB_DIR_OUT)
+    {
+      NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
+      NRF_USBD->EPOUTEN |= TU_BIT(epnum);
+
+      // Write any value to SIZE register will allow nRF to ACK/accept data
+      NRF_USBD->SIZE.EPOUT[epnum] = 0;
+    }else
+    {
+      NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
+      NRF_USBD->EPINEN  |= TU_BIT(epnum);
+    }
+  }
+  else
+  {
+    TU_ASSERT(epnum == EP_ISO_NUM);
+    if (dir == TUSB_DIR_OUT)
+    {
+      // SPLIT ISO buffer when ISO IN endpoint is already opened.
+      if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
+
+      // Clear old events
+      NRF_USBD->EVENTS_ENDISOOUT = 0;
+
+      // Clear SOF event in case interrupt was not enabled yet.
+      if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
+
+      // Enable SOF and ISOOUT interrupts, and ISOOUT endpoint.
+      NRF_USBD->INTENSET = USBD_INTENSET_ENDISOOUT_Msk | USBD_INTENSET_SOF_Msk;
+      NRF_USBD->EPOUTEN |= USBD_EPOUTEN_ISOOUT_Msk;
+    }
+    else
+    {
+      NRF_USBD->EVENTS_ENDISOIN = 0;
+
+      // SPLIT ISO buffer when ISO OUT endpoint is already opened.
+      if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
+
+      // Clear SOF event in case interrupt was not enabled yet.
+      if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
+
+      // Enable SOF and ISOIN interrupts, and ISOIN endpoint.
+      NRF_USBD->INTENSET = USBD_INTENSET_ENDISOIN_Msk | USBD_INTENSET_SOF_Msk;
+      NRF_USBD->EPINEN  |= USBD_EPINEN_ISOIN_Msk;
+    }
+  }
+
+  // clear stall and reset DataToggle
+  NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+  NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
+
+  __ISB(); __DSB();
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  // disable interrupt to prevent race condition
+  dcd_int_disable(rhport);
+
+  // disable all non-control (bulk + interrupt) endpoints
+  for ( uint8_t ep = 1; ep < EP_CBI_COUNT; ep++ )
+  {
+    NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + ep) | TU_BIT(USBD_INTEN_ENDEPIN0_Pos + ep);
+
+    NRF_USBD->TASKS_STARTEPIN[ep] = 0;
+    NRF_USBD->TASKS_STARTEPOUT[ep] = 0;
+
+    tu_memclr(_dcd.xfer[ep], 2*sizeof(xfer_td_t));
+  }
+
+  // disable both ISO
+  NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk | USBD_INTENCLR_ENDISOOUT_Msk | USBD_INTENCLR_ENDISOIN_Msk;
+  NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
+
+  NRF_USBD->TASKS_STARTISOIN  = 0;
+  NRF_USBD->TASKS_STARTISOOUT = 0;
+
+  tu_memclr(_dcd.xfer[EP_ISO_NUM], 2*sizeof(xfer_td_t));
+
+  // de-activate all non-control
+  NRF_USBD->EPOUTEN = 1UL;
+  NRF_USBD->EPINEN = 1UL;
+
+  dcd_int_enable(rhport);
+}
+
+void dcd_edpt_close (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 (epnum != EP_ISO_NUM)
+  {
+    // CBI
+    if (dir == TUSB_DIR_OUT)
+    {
+      NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
+      NRF_USBD->EPOUTEN &= ~TU_BIT(epnum);
+    }
+    else
+    {
+      NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
+      NRF_USBD->EPINEN &= ~TU_BIT(epnum);
+    }
+  }
+  else
+  {
+    _dcd.xfer[EP_ISO_NUM][dir].mps = 0;
+    // ISO
+    if (dir == TUSB_DIR_OUT)
+    {
+      NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOOUT_Msk;
+      NRF_USBD->EPOUTEN &= ~USBD_EPOUTEN_ISOOUT_Msk;
+      NRF_USBD->EVENTS_ENDISOOUT = 0;
+    }
+    else
+    {
+      NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOIN_Msk;
+      NRF_USBD->EPINEN &= ~USBD_EPINEN_ISOIN_Msk;
+    }
+    // One of the ISO endpoints closed, no need to split buffers any more.
+    NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
+    // 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;
+  }
+  __ISB(); __DSB();
+}
+
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  xfer_td_t* xfer = get_td(epnum, dir);
+
+  xfer->buffer     = buffer;
+  xfer->total_len  = total_bytes;
+  xfer->actual_len = 0;
+
+  // Control endpoint with zero-length packet and opposite direction to 1st request byte --> status stage
+  bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE));
+
+  if ( control_status )
+  {
+    // Status Phase also requires EasyDMA has to be available as well !!!!
+    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 )
+  {
+    if ( epnum == 0 )
+    {
+      // Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
+      edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
+    }else
+    {
+      if ( xfer->data_received )
+      {
+        // Data is already received previously
+        // start DMA to copy to SRAM
+        xfer->data_received = false;
+        xact_out_dma(epnum);
+      }
+      else
+      {
+        // nRF auto accept next Bulk/Interrupt OUT packet
+        // nothing to do
+      }
+    }
+  }
+  else
+  {
+    // Start DMA to copy data from RAM -> Endpoint
+    xact_in_dma(epnum);
+  }
+
+  return true;
+}
+
+void dcd_edpt_stall (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);
+
+  xfer_td_t* xfer = get_td(epnum, dir);
+
+  if ( epnum == 0 )
+  {
+    NRF_USBD->TASKS_EP0STALL = 1;
+  }else if (epnum != EP_ISO_NUM)
+  {
+    NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+
+    // Note: nRF can auto ACK packet OUT before get stalled.
+    // There maybe data in endpoint fifo already, we need to pull it out
+    if ( (dir == TUSB_DIR_OUT) && xfer->data_received )
+    {
+      xfer->data_received = false;
+      xact_out_dma(epnum);
+    }
+  }
+
+  __ISB(); __DSB();
+}
+
+void dcd_edpt_clear_stall (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 ( epnum != 0 && epnum != EP_ISO_NUM )
+  {
+    // reset data toggle to DATA0
+    // First write this register with VALUE=Nop to select the endpoint, then either read it to get the status from
+    // VALUE, or write it again with VALUE=Data0 or Data1
+    NRF_USBD->DTOGGLE = ep_addr;
+    NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
+
+    // clear stall
+    NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+
+    // Write any value to SIZE register will allow nRF to ACK/accept data
+    if (dir == TUSB_DIR_OUT) NRF_USBD->SIZE.EPOUT[epnum] = 0;
+
+    __ISB(); __DSB();
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* Interrupt Handler
+ *------------------------------------------------------------------*/
+void bus_reset(void)
+{
+  // 6.35.6 USB controller automatically disabled all endpoints (except control)
+  NRF_USBD->EPOUTEN = 1UL;
+  NRF_USBD->EPINEN = 1UL;
+
+  for(int i=0; i<8; i++)
+  {
+    NRF_USBD->TASKS_STARTEPIN[i] = 0;
+    NRF_USBD->TASKS_STARTEPOUT[i] = 0;
+  }
+
+  NRF_USBD->TASKS_STARTISOIN  = 0;
+  NRF_USBD->TASKS_STARTISOOUT = 0;
+
+  // Clear USB Event Interrupt
+  NRF_USBD->EVENTS_USBEVENT = 0;
+  NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE;
+
+  // Reset interrupt
+  NRF_USBD->INTENCLR = NRF_USBD->INTEN;
+  NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_EPDATA_Msk |
+          USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk;
+
+  tu_varclr(&_dcd);
+  _dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE;
+  _dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE;
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void) rhport;
+
+  uint32_t const inten  = NRF_USBD->INTEN;
+  uint32_t int_status = 0;
+
+  volatile uint32_t* regevt = &NRF_USBD->EVENTS_USBRESET;
+
+  for(uint8_t i=0; i<USBD_INTEN_EPDATA_Pos+1; i++)
+  {
+    if ( tu_bit_test(inten, i) && regevt[i]  )
+    {
+      int_status |= TU_BIT(i);
+
+      // event clear
+      regevt[i] = 0;
+      __ISB(); __DSB();
+    }
+  }
+
+  if ( int_status & USBD_INTEN_USBRESET_Msk )
+  {
+    bus_reset();
+    dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+  }
+
+  // ISOIN: Data was moved to endpoint buffer, client will be notified in SOF
+  if ( int_status & USBD_INTEN_ENDISOIN_Msk )
+  {
+    xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN);
+
+    xfer->actual_len = NRF_USBD->ISOIN.AMOUNT;
+    // Data transferred from RAM to endpoint output buffer.
+    // Next transfer can be scheduled after SOF.
+    xfer->iso_in_transfer_ready = true;
+  }
+
+  if ( int_status & USBD_INTEN_SOF_Msk )
+  {
+    bool iso_enabled = false;
+
+    // ISOOUT: Transfer data gathered in previous frame from buffer to RAM
+    if (NRF_USBD->EPOUTEN & USBD_EPOUTEN_ISOOUT_Msk)
+    {
+      iso_enabled = true;
+      xact_out_dma(EP_ISO_NUM);
+    }
+
+    // ISOIN: Notify client that data was transferred
+    if (NRF_USBD->EPINEN & USBD_EPINEN_ISOIN_Msk)
+    {
+      iso_enabled = true;
+
+      xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN);
+      if ( xfer->iso_in_transfer_ready )
+      {
+        xfer->iso_in_transfer_ready = false;
+        dcd_event_xfer_complete(0, EP_ISO_NUM | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
+      }
+    }
+
+    if ( !iso_enabled )
+    {
+      // ISO endpoint is not used, SOF is only enabled one-time for remote wakeup
+      // so we disable it now
+      NRF_USBD->INTENCLR = USBD_INTENSET_SOF_Msk;
+    }
+
+    dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+  }
+
+  if ( int_status & USBD_INTEN_USBEVENT_Msk )
+  {
+    TU_LOG(2, "EVENTCAUSE = 0x%04lX\r\n", NRF_USBD->EVENTCAUSE);
+
+    enum { EVT_CAUSE_MASK = USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk | USBD_EVENTCAUSE_USBWUALLOWED_Msk };
+    uint32_t const evt_cause = NRF_USBD->EVENTCAUSE & EVT_CAUSE_MASK;
+    NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt
+
+    if ( evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk )
+    {
+      // Put controller into low power mode
+      // Leave HFXO disable to application, since it may be used by other peripherals
+      NRF_USBD->LOWPOWER = 1;
+
+      dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+    }
+
+    if ( evt_cause & USBD_EVENTCAUSE_USBWUALLOWED_Msk )
+    {
+      // USB is out of low power mode, and wakeup is allowed
+      // Initiate RESUME signal
+      NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume;
+      NRF_USBD->TASKS_DPDMDRIVE = 1;
+
+      // There is no Resume interrupt for remote wakeup, enable SOF for to report bus ready state
+      // Clear SOF event in case interrupt was not enabled yet.
+      if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
+      NRF_USBD->INTENSET = USBD_INTENSET_SOF_Msk;
+    }
+
+    if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk )
+    {
+      dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+    }
+  }
+
+  // Setup tokens are specific to the Control endpoint.
+  if ( int_status & USBD_INTEN_EP0SETUP_Msk )
+  {
+    uint8_t const setup[8] =
+    {
+      NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH,
+      NRF_USBD->WINDEXL       , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
+    };
+
+    // nrf5x hw auto handle set address, there is no need to inform usb stack
+    tusb_control_request_t const * request = (tusb_control_request_t const *) setup;
+
+    if ( !(TUSB_REQ_RCPT_DEVICE   == request->bmRequestType_bit.recipient &&
+           TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type &&
+           TUSB_REQ_SET_ADDRESS   == request->bRequest) )
+    {
+      dcd_event_setup_received(0, setup, true);
+    }
+  }
+
+  if ( int_status & EDPT_END_ALL_MASK )
+  {
+    // DMA complete move data from SRAM <-> Endpoint
+    // Must before endpoint transfer handling
+    edpt_dma_end();
+  }
+
+  //--------------------------------------------------------------------+
+  /* Control/Bulk/Interrupt (CBI) Transfer
+   *
+   * Data flow is:
+   *           (bus)              (dma)
+   *    Host <-------> Endpoint <-------> RAM
+   *
+   * For CBI OUT:
+   *  - 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 (out_received flag).
+   *  - Endpoint -> RAM
+   *      ENDEPOUT[i] interrupted, transaction complete, sw prepare next transaction
+   *
+   * For CBI IN:
+   *  - RAM -> Endpoint
+   *      ENDEPIN[i] interrupted indicate DMA is complete. HW will start
+   *      to move data to host
+   *  - Endpoint -> Host
+   *      EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPIN[i].
+   *      Transaction is complete, sw prepare next transaction
+   *
+   * Note: in both Control In and Out of Data stage from Host <-> Endpoint
+   * EP0DATADONE will be set as interrupt source
+   */
+  //--------------------------------------------------------------------+
+
+  /* CBI OUT: Endpoint -> SRAM (aka transaction complete)
+   * Note: Since nRF controller auto ACK next packet without SW awareness
+   * We must handle this stage before Host -> Endpoint just in case 2 event happens at once
+   *
+   * ISO OUT: Transaction must fit in single packet, it can be shorter then total
+   * len if Host decides to sent fewer bytes, it this case transaction is also
+   * complete and next transfer is not initiated here like for CBI.
+   */
+  for(uint8_t epnum=0; epnum<EP_CBI_COUNT+1; epnum++)
+  {
+    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;
+
+      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) )
+      {
+        if ( epnum == 0 )
+        {
+          // Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
+          edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
+        }else
+        {
+          // nRF auto accept next Bulk/Interrupt OUT packet
+          // nothing to do
+        }
+      }else
+      {
+        xfer->total_len = xfer->actual_len;
+
+        // CBI OUT complete
+        dcd_event_xfer_complete(0, epnum, xfer->actual_len, XFER_RESULT_SUCCESS, true);
+      }
+    }
+
+    // Ended event for CBI IN : nothing to do
+  }
+
+  // Endpoint <-> Host ( In & OUT )
+  if ( int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk) )
+  {
+    uint32_t data_status = NRF_USBD->EPDATASTATUS;
+    NRF_USBD->EPDATASTATUS = data_status;
+    __ISB(); __DSB();
+
+    // EP0DATADONE is set with either Control Out on IN Data
+    // Since EPDATASTATUS cannot be used to determine whether it is control OUT or IN.
+    // We will use BMREQUESTTYPE in setup packet to determine the direction
+    bool const is_control_in = (int_status & USBD_INTEN_EP0DATADONE_Msk) && (NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK);
+    bool const is_control_out = (int_status & USBD_INTEN_EP0DATADONE_Msk) && !(NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK);
+
+    // CBI In: Endpoint -> Host (transaction complete)
+    for(uint8_t epnum=0; epnum<EP_CBI_COUNT; epnum++)
+    {
+      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->buffer     += xact_len;
+        xfer->actual_len += xact_len;
+
+        if ( xfer->actual_len < xfer->total_len )
+        {
+          // Start DMA to copy next data packet
+          xact_in_dma(epnum);
+        } else
+        {
+          // CBI IN complete
+          dcd_event_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
+        }
+      }
+    }
+
+    // CBI OUT: Host -> Endpoint
+    for(uint8_t epnum=0; epnum<EP_CBI_COUNT; epnum++)
+    {
+      if ( tu_bit_test(data_status, 16+epnum) || (epnum == 0 && is_control_out) )
+      {
+        xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
+
+        if (xfer->actual_len < xfer->total_len)
+        {
+          xact_out_dma(epnum);
+        }else
+        {
+          // Data overflow !!! Nah, nRF will auto accept next Bulk/Interrupt OUT packet
+          // Mark this endpoint with data received
+          xfer->data_received = true;
+        }
+      }
+    }
+  }
+}
+
+//--------------------------------------------------------------------+
+// HFCLK helper
+//--------------------------------------------------------------------+
+#ifdef SOFTDEVICE_PRESENT
+
+// For enable/disable hfclk with SoftDevice
+#include "nrf_mbr.h"
+#include "nrf_sdm.h"
+#include "nrf_soc.h"
+
+#ifndef SD_MAGIC_NUMBER
+  #define SD_MAGIC_NUMBER   0x51B1E5DB
+#endif
+
+static inline bool is_sd_existed(void)
+{
+  return *((uint32_t*)(SOFTDEVICE_INFO_STRUCT_ADDRESS+4)) == SD_MAGIC_NUMBER;
+}
+
+// check if SD is existed and enabled
+static inline bool is_sd_enabled(void)
+{
+  if ( !is_sd_existed() ) return false;
+
+  uint8_t sd_en = false;
+  (void) sd_softdevice_is_enabled(&sd_en);
+  return sd_en;
+}
+#endif
+
+static bool hfclk_running(void)
+{
+#ifdef SOFTDEVICE_PRESENT
+  if ( is_sd_enabled() )
+  {
+    uint32_t is_running = 0;
+    (void) sd_clock_hfclk_is_running(&is_running);
+    return (is_running ? true : false);
+  }
+#endif
+
+  return nrf_clock_hf_is_running(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY);
+}
+
+static void hfclk_enable(void)
+{
+  // already running, nothing to do
+  if ( hfclk_running() ) return;
+
+#ifdef SOFTDEVICE_PRESENT
+  if ( is_sd_enabled() )
+  {
+    (void)sd_clock_hfclk_request();
+    return;
+  }
+#endif
+
+  nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
+  nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
+}
+
+static void hfclk_disable(void)
+{
+#ifdef SOFTDEVICE_PRESENT
+  if ( is_sd_enabled() )
+  {
+    (void)sd_clock_hfclk_release();
+    return;
+  }
+#endif
+
+  nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
+}
+
+// Power & Clock Peripheral on nRF5x to manage USB
+//
+// USB Bus power is managed by Power module, there are 3 VBUS power events:
+// Detected, Ready, Removed. Upon these power events, This function will
+// enable ( or disable ) usb & hfclk peripheral, set the usb pin pull up
+// accordingly to the controller Startup/Standby Sequence in USBD 51.4 specs.
+//
+// Therefore this function must be called to handle USB power event by
+// - nrfx_power_usbevt_init() : if Softdevice is not used or enabled
+// - SoftDevice SOC event : if SD is used and enabled
+void tusb_hal_nrf_power_event (uint32_t event)
+{
+  // Value is chosen to be as same as NRFX_POWER_USB_EVT_* in nrfx_power.h
+  enum {
+    USB_EVT_DETECTED = 0,
+    USB_EVT_REMOVED = 1,
+    USB_EVT_READY = 2
+  };
+
+#if CFG_TUSB_DEBUG >= 2
+  const char* const power_evt_str[] = { "Detected", "Removed", "Ready" };
+  TU_LOG(2, "Power USB event: %s\r\n", power_evt_str[event]);
+#endif
+
+  switch ( event )
+  {
+    case USB_EVT_DETECTED:
+      if ( !NRF_USBD->ENABLE )
+      {
+        // Prepare for receiving READY event: disable interrupt since we will blocking wait
+        NRF_USBD->INTENCLR = USBD_INTEN_USBEVENT_Msk;
+        NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk;
+        __ISB(); __DSB(); // for sync
+
+#ifdef NRF52_SERIES // NRF53 does not need this errata
+        // ERRATA 171, 187, 166
+        if ( nrfx_usbd_errata_187() )
+        {
+          // CRITICAL_REGION_ENTER();
+          if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
+          {
+            *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
+            *((volatile uint32_t *) (0x4006ED14)) = 0x00000003;
+            *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
+          }
+          else
+          {
+            *((volatile uint32_t *) (0x4006ED14)) = 0x00000003;
+          }
+          // CRITICAL_REGION_EXIT();
+        }
+
+        if ( nrfx_usbd_errata_171() )
+        {
+          // CRITICAL_REGION_ENTER();
+          if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
+          {
+            *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
+            *((volatile uint32_t *) (0x4006EC14)) = 0x000000C0;
+            *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
+          }
+          else
+          {
+            *((volatile uint32_t *) (0x4006EC14)) = 0x000000C0;
+          }
+          // CRITICAL_REGION_EXIT();
+        }
+#endif
+
+        // Enable the peripheral (will cause Ready event)
+        NRF_USBD->ENABLE = 1;
+        __ISB(); __DSB(); // for sync
+
+        // Enable HFCLK
+        hfclk_enable();
+      }
+    break;
+
+    case USB_EVT_READY:
+      // Skip if pull-up is enabled and HCLK is already running.
+      // Application probably call this more than necessary.
+      if ( NRF_USBD->USBPULLUP && hfclk_running() ) break;
+
+      // Waiting for USBD peripheral enabled
+      while ( !(USBD_EVENTCAUSE_READY_Msk & NRF_USBD->EVENTCAUSE) ) { }
+
+      NRF_USBD->EVENTCAUSE = USBD_EVENTCAUSE_READY_Msk;
+      __ISB(); __DSB(); // for sync
+
+#ifdef NRF52_SERIES
+      if ( nrfx_usbd_errata_171() )
+      {
+        // CRITICAL_REGION_ENTER();
+        if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
+        {
+          *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
+          *((volatile uint32_t *) (0x4006EC14)) = 0x00000000;
+          *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
+        }
+        else
+        {
+          *((volatile uint32_t *) (0x4006EC14)) = 0x00000000;
+        }
+
+        // CRITICAL_REGION_EXIT();
+      }
+
+      if ( nrfx_usbd_errata_187() )
+      {
+        // CRITICAL_REGION_ENTER();
+        if ( *((volatile uint32_t *) (0x4006EC00)) == 0x00000000 )
+        {
+          *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
+          *((volatile uint32_t *) (0x4006ED14)) = 0x00000000;
+          *((volatile uint32_t *) (0x4006EC00)) = 0x00009375;
+        }
+        else
+        {
+          *((volatile uint32_t *) (0x4006ED14)) = 0x00000000;
+        }
+        // CRITICAL_REGION_EXIT();
+      }
+
+      if ( nrfx_usbd_errata_166() )
+      {
+        *((volatile uint32_t *) (NRF_USBD_BASE + 0x800)) = 0x7E3;
+        *((volatile uint32_t *) (NRF_USBD_BASE + 0x804)) = 0x40;
+
+        __ISB(); __DSB();
+      }
+#endif
+
+      // ISO buffer Lower half for IN, upper half for OUT
+      NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
+
+      // Enable bus-reset interrupt
+      NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk;
+
+      // Enable interrupt, priorities should be set by application
+      NVIC_ClearPendingIRQ(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() ) { }
+
+      // Enable pull up
+      NRF_USBD->USBPULLUP = 1;
+      __ISB(); __DSB(); // for sync
+    break;
+
+    case USB_EVT_REMOVED:
+      if ( NRF_USBD->ENABLE )
+      {
+        // Abort all transfers
+
+        // Disable pull up
+        NRF_USBD->USBPULLUP = 0;
+        __ISB(); __DSB(); // for sync
+
+        // Disable Interrupt
+        NVIC_DisableIRQ(USBD_IRQn);
+
+        // disable all interrupt
+        NRF_USBD->INTENCLR = NRF_USBD->INTEN;
+
+        NRF_USBD->ENABLE = 0;
+        __ISB(); __DSB(); // for sync
+
+        hfclk_disable();
+
+        dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr());
+      }
+    break;
+
+    default: break;
+  }
+}
+
+#endif
diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c
new file mode 100644
index 0000000..0d45090
--- /dev/null
+++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c
@@ -0,0 +1,500 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019-2020 Peter Lawrence
+ *
+ * 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.
+ */
+
+/*
+  Theory of operation:
+
+  The NUC100/NUC120 USBD peripheral has six "EP"s, but each is simplex, 
+  so two collectively (peripheral nomenclature of "EP0" and "EP1") are needed to 
+  implement USB EP0.  PERIPH_EP0 and PERIPH_EP1 are used by this driver for 
+  EP0_IN and EP0_OUT respectively.  This leaves up to four for user usage.
+*/
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC120)
+
+#include "device/dcd.h"
+#include "NUC100Series.h"
+
+/* allocation of USBD RAM for Setup, EP0_IN, and and EP_OUT */
+#define PERIPH_SETUP_BUF_BASE  0
+#define PERIPH_SETUP_BUF_LEN   8
+#define PERIPH_EP0_BUF_BASE    (PERIPH_SETUP_BUF_BASE + PERIPH_SETUP_BUF_LEN)
+#define PERIPH_EP0_BUF_LEN     CFG_TUD_ENDPOINT0_SIZE
+#define PERIPH_EP1_BUF_BASE    (PERIPH_EP0_BUF_BASE + PERIPH_EP0_BUF_LEN)
+#define PERIPH_EP1_BUF_LEN     CFG_TUD_ENDPOINT0_SIZE
+#define PERIPH_EP2_BUF_BASE    (PERIPH_EP1_BUF_BASE + PERIPH_EP1_BUF_LEN)
+
+/* rather important info unfortunately not provided by device include files: how much there is */
+#define USBD_BUF_SIZE          512
+
+enum ep_enum
+{
+  PERIPH_EP0 = 0,
+  PERIPH_EP1 = 1,
+  PERIPH_EP2 = 2,
+  PERIPH_EP3 = 3,
+  PERIPH_EP4 = 4,
+  PERIPH_EP5 = 5,
+  PERIPH_MAX_EP,
+};
+
+/* set by dcd_set_address() */
+static volatile uint8_t assigned_address;
+
+/* reset by dcd_init(), this is used by dcd_edpt_open() to assign USBD peripheral buffer addresses */
+static uint32_t bufseg_addr;
+
+/* used by dcd_edpt_xfer() and the ISR to reset the data sync (DATA0/DATA1) in an EP0_IN transfer */
+static bool active_ep0_xfer;
+
+/* RAM table needed to track ongoing transfers performed by dcd_edpt_xfer(), dcd_in_xfer(), and the ISR */
+static struct xfer_ctl_t
+{
+  uint8_t *data_ptr;         /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */
+  // tu_fifo_t * ff;         /* pointer to FIFO required for dcd_edpt_xfer_fifo() */ // TODO support dcd_edpt_xfer_fifo API
+  union {
+    uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */
+    uint16_t out_bytes_so_far;   /* but for OUT endpoints, we track how many bytes we've transferred so far */
+  };
+  uint16_t max_packet_size;  /* needed since device driver only finds out this at runtime */
+  uint16_t total_bytes;      /* quantity needed to pass as argument to dcd_event_xfer_complete() (for IN endpoints) */
+} xfer_table[PERIPH_MAX_EP];
+
+/*
+  local helper functions
+*/
+
+static void usb_attach(void)
+{
+  USBD->DRVSE0 &= ~USBD_DRVSE0_DRVSE0_Msk;
+}
+
+static void usb_detach(void)
+{
+  USBD->DRVSE0 |= USBD_DRVSE0_DRVSE0_Msk;
+}
+
+static inline void usb_memcpy(uint8_t *dest, uint8_t *src, uint16_t size)
+{
+  while(size--) *dest++ = *src++;
+}
+
+static void usb_control_send_zlp(void)
+{
+  USBD->EP[PERIPH_EP0].CFG |= USBD_CFG_DSQ_SYNC_Msk;
+  USBD->EP[PERIPH_EP0].MXPLD = 0;
+}
+
+/* reconstruct ep_addr from particular USB Configuration Register */
+static uint8_t decode_ep_addr(USBD_EP_T *ep)
+{
+  uint8_t ep_addr = ep->CFG & USBD_CFG_EP_NUM_Msk;
+  if ( USBD_CFG_EPMODE_IN == (ep->CFG & USBD_CFG_STATE_Msk) )
+    ep_addr |= TUSB_DIR_IN_MASK;
+  return ep_addr;
+}
+
+/* map 8-bit ep_addr into peripheral endpoint index (PERIPH_EP0...) */
+static USBD_EP_T *ep_entry(uint8_t ep_addr, bool add)
+{
+  USBD_EP_T *ep;
+  enum ep_enum ep_index;
+
+  for (ep_index = PERIPH_EP0, ep = USBD->EP; ep_index < PERIPH_MAX_EP; ep_index++, ep++)
+  {
+    if (add)
+    {
+      /* take first peripheral endpoint that is unused */
+      if (0 == (ep->CFG & USBD_CFG_STATE_Msk)) return ep;
+    }
+    else
+    {
+      /* find a peripheral endpoint that matches ep_addr */
+      uint8_t candidate_ep_addr = decode_ep_addr(ep);
+      if (candidate_ep_addr == ep_addr) return ep;
+    }
+  }
+
+  return NULL;
+}
+
+/* perform an IN endpoint transfer; this is called by dcd_edpt_xfer() and the ISR  */
+static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
+{
+  uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size);
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+  if (xfer->ff)
+  {
+    tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now);
+  }
+  else
+#endif
+  {
+    // USB SRAM seems to only support byte access and memcpy could possibly do it by words
+    usb_memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now);
+  }
+
+  ep->MXPLD = bytes_now;
+}
+
+/* called by dcd_init() as well as by the ISR during a USB bus reset */
+static void bus_reset(void)
+{
+  USBD->STBUFSEG = PERIPH_SETUP_BUF_BASE;
+
+  for (enum ep_enum ep_index = PERIPH_EP0; ep_index < PERIPH_MAX_EP; ep_index++)
+  {
+    USBD->EP[ep_index].CFG = 0;
+    USBD->EP[ep_index].CFGP = 0;
+  }
+
+  /* allocate the default EP0 endpoints */
+
+  USBD->EP[PERIPH_EP0].CFG = USBD_CFG_CSTALL_Msk | USBD_CFG_EPMODE_IN;
+  USBD->EP[PERIPH_EP0].BUFSEG = PERIPH_EP0_BUF_BASE;
+  xfer_table[PERIPH_EP0].max_packet_size = PERIPH_EP0_BUF_LEN;
+
+  USBD->EP[PERIPH_EP1].CFG = USBD_CFG_CSTALL_Msk | USBD_CFG_EPMODE_OUT;
+  USBD->EP[PERIPH_EP1].BUFSEG = PERIPH_EP1_BUF_BASE;
+  xfer_table[PERIPH_EP1].max_packet_size = PERIPH_EP1_BUF_LEN;
+
+  /* USB RAM beyond what we've allocated above is available to the user */
+  bufseg_addr = PERIPH_EP2_BUF_BASE;
+
+  /* Reset USB device address */
+  USBD->FADDR = 0;
+
+  /* reset EP0_IN flag */
+  active_ep0_xfer = false;
+}
+
+/* centralized location for USBD interrupt enable bit mask */
+static const uint32_t enabled_irqs = USBD_INTSTS_FLDET_STS_Msk | USBD_INTSTS_BUS_STS_Msk | USBD_INTSTS_SETUP_Msk | USBD_INTSTS_USB_STS_Msk;
+
+/*
+  NUC100/NUC120 TinyUSB API driver implementation
+*/
+
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  USBD->ATTR = 0x7D0;
+
+  usb_detach();
+
+  bus_reset();
+
+  usb_attach();
+
+  USBD->INTSTS = enabled_irqs;
+  USBD->INTEN  = enabled_irqs;
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USBD_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USBD_IRQn);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  (void) rhport;
+  usb_control_send_zlp(); /* SET_ADDRESS is the one exception where TinyUSB doesn't use dcd_edpt_xfer() to generate a ZLP */
+  assigned_address = dev_addr;
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+  USBD->ATTR = USBD_ATTR_RWAKEUP_Msk;
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+  (void) rhport;
+
+  USBD_EP_T *ep = ep_entry(p_endpoint_desc->bEndpointAddress, true);
+  TU_ASSERT(ep);
+
+  /* mine the data for the information we need */
+  int const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+  int const size = tu_edpt_packet_size(p_endpoint_desc);
+  tusb_xfer_type_t const type = (tusb_xfer_type_t) p_endpoint_desc->bmAttributes.xfer;
+  struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
+
+  /* allocate buffer from USB RAM */
+  ep->BUFSEG = bufseg_addr;
+  bufseg_addr += size;
+  TU_ASSERT(bufseg_addr <= USBD_BUF_SIZE);
+
+  /* construct USB Configuration Register value and then write it */
+  uint32_t cfg = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+  cfg |= (TUSB_DIR_IN == dir) ? USBD_CFG_EPMODE_IN : USBD_CFG_EPMODE_OUT;
+  if (TUSB_XFER_ISOCHRONOUS == type)
+    cfg |= USBD_CFG_TYPE_ISO;
+  ep->CFG = cfg;
+
+  /* make a note of the endpoint size */
+  xfer->max_packet_size = size;
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  /* mine the data for the information we need */
+  tusb_dir_t dir = tu_edpt_dir(ep_addr);
+  USBD_EP_T *ep = ep_entry(ep_addr, false);
+  struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
+
+  /* store away the information we'll needing now and later */
+  xfer->data_ptr = buffer;
+  // xfer->ff       = NULL; // TODO support dcd_edpt_xfer_fifo API
+  xfer->in_remaining_bytes = total_bytes;
+  xfer->total_bytes = total_bytes;
+
+  /* for the first of one or more EP0_IN packets in a message, the first must be DATA1 */
+  if ( (0x80 == ep_addr) && !active_ep0_xfer ) ep->CFG |= USBD_CFG_DSQ_SYNC_Msk;
+
+  if (TUSB_DIR_IN == dir)
+  {
+    dcd_in_xfer(xfer, ep);
+  }
+  else
+  {
+    xfer->out_bytes_so_far = 0;
+    ep->MXPLD = xfer->max_packet_size;
+  }
+
+  return true;
+}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  /* mine the data for the information we need */
+  tusb_dir_t dir = tu_edpt_dir(ep_addr);
+  USBD_EP_T *ep = ep_entry(ep_addr, false);
+  struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
+
+  /* store away the information we'll needing now and later */
+  xfer->data_ptr = NULL;      // Indicates a FIFO shall be used
+  xfer->ff       = ff;
+  xfer->in_remaining_bytes = total_bytes;
+  xfer->total_bytes = total_bytes;
+
+  if (TUSB_DIR_IN == dir)
+  {
+    dcd_in_xfer(xfer, ep);
+  }
+  else
+  {
+    xfer->out_bytes_so_far = 0;
+    ep->MXPLD = xfer->max_packet_size;
+  }
+
+  return true;
+}
+#endif
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  USBD_EP_T *ep = ep_entry(ep_addr, false);
+  ep->CFGP |= USBD_CFGP_SSTALL_Msk;
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  USBD_EP_T *ep = ep_entry(ep_addr, false);
+  ep->CFG |= USBD_CFG_CSTALL_Msk;
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void) rhport;
+
+  uint32_t status = USBD->INTSTS;
+  uint32_t state = USBD->ATTR & 0xf;
+
+  if(status & USBD_INTSTS_FLDET_STS_Msk)
+  {
+    if(USBD->FLDET & USBD_FLDET_FLDET_Msk)
+    {
+      /* USB connect */
+      USBD->ATTR |= USBD_ATTR_USB_EN_Msk | USBD_ATTR_PHY_EN_Msk;
+    }
+    else
+    {
+      /* USB disconnect */
+      USBD->ATTR &= ~USBD_ATTR_USB_EN_Msk;
+    }
+  }
+
+  if(status & USBD_INTSTS_BUS_STS_Msk)
+  {
+    if(state & USBD_STATE_USBRST)
+    {
+      /* USB bus reset */
+      USBD->ATTR |= USBD_ATTR_USB_EN_Msk | USBD_ATTR_PHY_EN_Msk;
+
+      bus_reset();
+      dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+    }
+
+    if(state & USBD_STATE_SUSPEND)
+    {
+      /* Enable USB but disable PHY */
+      USBD->ATTR &= ~USBD_ATTR_PHY_EN_Msk;
+      dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+    }
+
+    if(state & USBD_STATE_RESUME)
+    {
+      /* Enable USB and enable PHY */
+      USBD->ATTR |= USBD_ATTR_USB_EN_Msk | USBD_ATTR_PHY_EN_Msk;
+      dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+    }
+  }
+
+  if(status & USBD_INTSTS_SETUP_Msk)
+  {
+    /* clear the data ready flag of control endpoints */
+    USBD->EP[PERIPH_EP0].CFGP |= USBD_CFGP_CLRRDY_Msk;
+    USBD->EP[PERIPH_EP1].CFGP |= USBD_CFGP_CLRRDY_Msk;
+
+    /* get SETUP packet from USB buffer */
+    dcd_event_setup_received(0, (uint8_t *)USBD_BUF_BASE, true);
+  }
+
+  if(status & USBD_INTSTS_USB_STS_Msk)
+  {
+    if (status & (1UL << USBD_INTSTS_EPEVT_Pos)) /* PERIPH_EP0 (EP0_IN) event: this is treated separately from the rest */
+    {
+      /* given ACK from host has happened, we can now set the address (if not already done) */
+      if((USBD->FADDR != assigned_address) && (USBD->FADDR == 0)) USBD->FADDR = assigned_address;
+
+      uint16_t const available_bytes = USBD->EP[PERIPH_EP0].MXPLD;
+
+      active_ep0_xfer = (available_bytes == xfer_table[PERIPH_EP0].max_packet_size);
+
+      dcd_event_xfer_complete(0, 0x80, available_bytes, XFER_RESULT_SUCCESS, true);
+    }
+
+    /* service PERIPH_EP1 through PERIPH_EP7 */
+    enum ep_enum ep_index;
+    uint32_t mask;
+    struct xfer_ctl_t *xfer;
+    USBD_EP_T *ep;
+    for (ep_index = PERIPH_EP1, mask = (2UL << USBD_INTSTS_EPEVT_Pos), xfer = &xfer_table[PERIPH_EP1], ep = &USBD->EP[PERIPH_EP1]; ep_index < PERIPH_MAX_EP; ep_index++, mask <<= 1, xfer++, ep++)
+    {
+      if(status & mask)
+      {
+        USBD->INTSTS = mask;
+
+        uint16_t const available_bytes = ep->MXPLD;
+        uint8_t const ep_addr = decode_ep_addr(ep);
+        bool const out_ep = !(ep_addr & TUSB_DIR_IN_MASK);
+
+        if (out_ep)
+        {
+          /* copy the data from the PC to the previously provided buffer */
+#if 0 // // TODO support dcd_edpt_xfer_fifo API
+          if (xfer->ff)
+          {
+            tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes);
+          }
+          else
+#endif
+          {
+            // USB SRAM seems to only support byte access and memcpy could possibly do it by words
+            usb_memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes);
+            xfer->data_ptr += available_bytes;
+          }
+
+          xfer->out_bytes_so_far += available_bytes;
+
+          /* when the transfer is finished, alert TinyUSB; otherwise, accept more data */
+          if ( (xfer->total_bytes == xfer->out_bytes_so_far) || (available_bytes < xfer->max_packet_size) )
+            dcd_event_xfer_complete(0, ep_addr, xfer->out_bytes_so_far, XFER_RESULT_SUCCESS, true);
+          else
+            ep->MXPLD = xfer->max_packet_size;
+        }
+        else
+        {
+          /* update the bookkeeping to reflect the data that has now been sent to the PC */
+          xfer->in_remaining_bytes -= available_bytes;
+
+          xfer->data_ptr += available_bytes;
+
+          /* if more data to send, send it; otherwise, alert TinyUSB that we've finished */
+          if (xfer->in_remaining_bytes)
+            dcd_in_xfer(xfer, ep);
+          else
+            dcd_event_xfer_complete(0, ep_addr, xfer->total_bytes, XFER_RESULT_SUCCESS, true);
+        }
+      }
+    }
+  }
+
+  /* acknowledge all interrupts */
+  USBD->INTSTS = status & enabled_irqs;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  usb_detach();
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  usb_attach();
+}
+
+#endif
diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c
new file mode 100644
index 0000000..fc71505
--- /dev/null
+++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c
@@ -0,0 +1,554 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Peter Lawrence
+ *
+ * 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.
+ */
+
+/*
+  Theory of operation:
+
+  The NUC121/NUC125/NUC126 USBD peripheral has eight "EP"s, but each is simplex, 
+  so two collectively (peripheral nomenclature of "EP0" and "EP1") are needed to 
+  implement USB EP0.  PERIPH_EP0 and PERIPH_EP1 are used by this driver for 
+  EP0_IN and EP0_OUT respectively.  This leaves up to six for user usage.
+*/
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && ( (CFG_TUSB_MCU == OPT_MCU_NUC121) || (CFG_TUSB_MCU == OPT_MCU_NUC126) )
+
+#include "device/dcd.h"
+#include "NuMicro.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
+#ifndef USE_SOF
+#  define USE_SOF     0
+#endif
+
+/* allocation of USBD RAM for Setup, EP0_IN, and and EP_OUT */
+#define PERIPH_SETUP_BUF_BASE  0
+#define PERIPH_SETUP_BUF_LEN   8
+#define PERIPH_EP0_BUF_BASE    (PERIPH_SETUP_BUF_BASE + PERIPH_SETUP_BUF_LEN)
+#define PERIPH_EP0_BUF_LEN     CFG_TUD_ENDPOINT0_SIZE
+#define PERIPH_EP1_BUF_BASE    (PERIPH_EP0_BUF_BASE + PERIPH_EP0_BUF_LEN)
+#define PERIPH_EP1_BUF_LEN     CFG_TUD_ENDPOINT0_SIZE
+#define PERIPH_EP2_BUF_BASE    (PERIPH_EP1_BUF_BASE + PERIPH_EP1_BUF_LEN)
+
+/* rather important info unfortunately not provided by device include files: how much there is */
+#define USBD_BUF_SIZE          ((CFG_TUSB_MCU == OPT_MCU_NUC121) ? 768 : 512)
+
+enum ep_enum
+{
+  PERIPH_EP0 = 0,
+  PERIPH_EP1 = 1,
+  PERIPH_EP2 = 2,
+  PERIPH_EP3 = 3,
+  PERIPH_EP4 = 4,
+  PERIPH_EP5 = 5,
+  PERIPH_EP6 = 6,
+  PERIPH_EP7 = 7,
+  PERIPH_MAX_EP,
+};
+
+/* reset by dcd_init(), this is used by dcd_edpt_open() to assign USBD peripheral buffer addresses */
+static uint32_t bufseg_addr;
+
+/* used by dcd_edpt_xfer() and the ISR to reset the data sync (DATA0/DATA1) in an EP0_IN transfer */
+static bool active_ep0_xfer;
+
+/* RAM table needed to track ongoing transfers performed by dcd_edpt_xfer(), dcd_in_xfer(), and the ISR */
+static struct xfer_ctl_t
+{
+  uint8_t *data_ptr;         /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */
+  // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
+  union {
+    uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */
+    uint16_t out_bytes_so_far;   /* but for OUT endpoints, we track how many bytes we've transferred so far */
+  };
+  uint16_t max_packet_size;  /* needed since device driver only finds out this at runtime */
+  uint16_t total_bytes;      /* quantity needed to pass as argument to dcd_event_xfer_complete() (for IN endpoints) */
+} xfer_table[PERIPH_MAX_EP];
+
+/*
+  local helper functions
+*/
+
+static void usb_attach(void)
+{
+  USBD->SE0 &= ~USBD_SE0_SE0_Msk;
+}
+
+static void usb_detach(void)
+{
+  USBD->SE0 |= USBD_SE0_SE0_Msk;
+}
+
+static inline void usb_memcpy(uint8_t *dest, uint8_t *src, uint16_t size)
+{
+  while(size--) *dest++ = *src++;
+}
+
+static void usb_control_send_zlp(void)
+{
+  USBD->EP[PERIPH_EP0].CFG |= USBD_CFG_DSQSYNC_Msk;
+  USBD->EP[PERIPH_EP0].MXPLD = 0;
+}
+
+/* reconstruct ep_addr from particular USB Configuration Register */
+static uint8_t decode_ep_addr(USBD_EP_T *ep)
+{
+  uint8_t ep_addr = ep->CFG & USBD_CFG_EPNUM_Msk;
+  if ( USBD_CFG_EPMODE_IN == (ep->CFG & USBD_CFG_STATE_Msk) )
+    ep_addr |= TUSB_DIR_IN_MASK;
+  return ep_addr;
+}
+
+/* map 8-bit ep_addr into peripheral endpoint index (PERIPH_EP0...) */
+static USBD_EP_T *ep_entry(uint8_t ep_addr, bool add)
+{
+  USBD_EP_T *ep;
+  enum ep_enum ep_index;
+
+  for (ep_index = PERIPH_EP0, ep = USBD->EP; ep_index < PERIPH_MAX_EP; ep_index++, ep++)
+  {
+    if (add)
+    {
+      /* take first peripheral endpoint that is unused */
+      if (0 == (ep->CFG & USBD_CFG_STATE_Msk)) return ep;
+    }
+    else
+    {
+      /* find a peripheral endpoint that matches ep_addr */
+      uint8_t candidate_ep_addr = decode_ep_addr(ep);
+      if (candidate_ep_addr == ep_addr) return ep;
+    }
+  }
+
+  return NULL;
+}
+
+/* perform an IN endpoint transfer; this is called by dcd_edpt_xfer() and the ISR  */
+static void dcd_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
+{
+  uint16_t bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size);
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+  if (xfer->ff)
+  {
+    tu_fifo_read_n(xfer->ff, (void *) (USBD_BUF_BASE + ep->BUFSEG), bytes_now);
+  }
+  else
+#endif
+  {
+    // USB SRAM seems to only support byte access and memcpy could possibly do it by words
+    usb_memcpy((uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), xfer->data_ptr, bytes_now);
+  }
+
+  ep->MXPLD = bytes_now;
+}
+
+/* called by dcd_init() as well as by the ISR during a USB bus reset */
+static void bus_reset(void)
+{
+  USBD->STBUFSEG = PERIPH_SETUP_BUF_BASE;
+
+  for (enum ep_enum ep_index = PERIPH_EP0; ep_index < PERIPH_MAX_EP; ep_index++)
+  {
+    USBD->EP[ep_index].CFG = 0;
+    USBD->EP[ep_index].CFGP = 0;
+  }
+
+  /* allocate the default EP0 endpoints */
+
+  USBD->EP[PERIPH_EP0].CFG = USBD_CFG_CSTALL_Msk | USBD_CFG_EPMODE_IN;
+  USBD->EP[PERIPH_EP0].BUFSEG = PERIPH_EP0_BUF_BASE;
+  xfer_table[PERIPH_EP0].max_packet_size = PERIPH_EP0_BUF_LEN;
+
+  USBD->EP[PERIPH_EP1].CFG = USBD_CFG_CSTALL_Msk | USBD_CFG_EPMODE_OUT;
+  USBD->EP[PERIPH_EP1].BUFSEG = PERIPH_EP1_BUF_BASE;
+  xfer_table[PERIPH_EP1].max_packet_size = PERIPH_EP1_BUF_LEN;
+
+  /* USB RAM beyond what we've allocated above is available to the user */
+  bufseg_addr = PERIPH_EP2_BUF_BASE;
+
+  /* Reset USB device address */
+  USBD->FADDR = 0;
+
+  /* reset EP0_IN flag */
+  active_ep0_xfer = false;
+}
+
+/* centralized location for USBD interrupt enable bit mask */
+enum {
+  ENABLED_IRQS = USBD_INTSTS_VBDETIF_Msk | USBD_INTSTS_BUSIF_Msk | USBD_INTSTS_SETUP_Msk |
+                 USBD_INTSTS_USBIF_Msk   | (USE_SOF ? USBD_INTSTS_SOFIF_Msk : 0)
+};
+
+/*
+  NUC121/NUC125/NUC126 TinyUSB API driver implementation
+*/
+
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+#ifdef SUPPORT_LPM
+  USBD->ATTR = 0x7D0 | USBD_LPMACK;
+#else
+  USBD->ATTR = 0x7D0;
+#endif
+
+  usb_detach();
+
+  bus_reset();
+
+  usb_attach();
+
+  USBD->INTSTS = ENABLED_IRQS;
+  USBD->INTEN  = ENABLED_IRQS;
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USBD_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USBD_IRQn);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  (void) rhport;
+  (void) dev_addr;
+  usb_control_send_zlp(); /* SET_ADDRESS is the one exception where TinyUSB doesn't use dcd_edpt_xfer() to generate a ZLP */
+
+  // DCD can only set address after status for this request is complete.
+  // do it at dcd_edpt0_status_complete()
+}
+
+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;
+  // Enable PHY before sending Resume('K') state
+  USBD->ATTR |= USBD_ATTR_PHYEN_Msk;
+  USBD->ATTR |= USBD_ATTR_RWAKEUP_Msk;
+
+  // Per specs: remote wakeup signal bit must be clear within 1-15ms
+  remote_wakeup_delay();
+  USBD->ATTR &=~USBD_ATTR_RWAKEUP_Msk;
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+  (void) rhport;
+
+  USBD_EP_T *ep = ep_entry(p_endpoint_desc->bEndpointAddress, true);
+  TU_ASSERT(ep);
+
+  /* mine the data for the information we need */
+  int const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+  int const size = tu_edpt_packet_size(p_endpoint_desc);
+  tusb_xfer_type_t const type = (tusb_xfer_type_t) p_endpoint_desc->bmAttributes.xfer;
+  struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
+
+  /* allocate buffer from USB RAM */
+  ep->BUFSEG = bufseg_addr;
+  bufseg_addr += size;
+  TU_ASSERT(bufseg_addr <= USBD_BUF_SIZE);
+
+  /* construct USB Configuration Register value and then write it */
+  uint32_t cfg = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+  cfg |= (TUSB_DIR_IN == dir) ? USBD_CFG_EPMODE_IN : USBD_CFG_EPMODE_OUT;
+  if (TUSB_XFER_ISOCHRONOUS == type)
+    cfg |= USBD_CFG_TYPE_ISO;
+  ep->CFG = cfg;
+
+  /* make a note of the endpoint size */
+  xfer->max_packet_size = size;
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  /* mine the data for the information we need */
+  tusb_dir_t dir = tu_edpt_dir(ep_addr);
+  USBD_EP_T *ep = ep_entry(ep_addr, false);
+  struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
+
+  /* store away the information we'll needing now and later */
+  xfer->data_ptr = buffer;
+  // xfer->ff       = NULL; // TODO support dcd_edpt_xfer_fifo API
+  xfer->in_remaining_bytes = total_bytes;
+  xfer->total_bytes = total_bytes;
+
+  /* for the first of one or more EP0_IN packets in a message, the first must be DATA1 */
+  if ( (0x80 == ep_addr) && !active_ep0_xfer ) ep->CFG |= USBD_CFG_DSQSYNC_Msk;
+
+  if (TUSB_DIR_IN == dir)
+  {
+    dcd_in_xfer(xfer, ep);
+  }
+  else
+  {
+    xfer->out_bytes_so_far = 0;
+    ep->MXPLD = xfer->max_packet_size;
+  }
+
+  return true;
+}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  /* mine the data for the information we need */
+  tusb_dir_t dir = tu_edpt_dir(ep_addr);
+  USBD_EP_T *ep = ep_entry(ep_addr, false);
+  struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
+
+  /* store away the information we'll needing now and later */
+  xfer->data_ptr = NULL;      // Indicates a FIFO shall be used
+  xfer->ff       = ff;
+  xfer->in_remaining_bytes = total_bytes;
+  xfer->total_bytes = total_bytes;
+
+  if (TUSB_DIR_IN == dir)
+  {
+    dcd_in_xfer(xfer, ep);
+  }
+  else
+  {
+    xfer->out_bytes_so_far = 0;
+    ep->MXPLD = xfer->max_packet_size;
+  }
+
+  return true;
+}
+#endif
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  USBD_EP_T *ep = ep_entry(ep_addr, false);
+  ep->CFGP |= USBD_CFGP_SSTALL_Msk;
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  USBD_EP_T *ep = ep_entry(ep_addr, false);
+  ep->CFG = (ep->CFG & ~USBD_CFG_DSQSYNC_Msk) | USBD_CFG_CSTALL_Msk;
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void) rhport;
+
+  // Mask non-enabled irqs, ex. SOF
+  uint32_t status = USBD->INTSTS & (ENABLED_IRQS | 0xffffff00);
+
+#ifdef SUPPORT_LPM
+  uint32_t state = USBD->ATTR & 0x300f;
+#else
+  uint32_t state = USBD->ATTR & 0xf;
+#endif
+
+  if(status & USBD_INTSTS_VBDETIF_Msk)
+  {
+    if(USBD->VBUSDET & USBD_VBUSDET_VBUSDET_Msk)
+    {
+      /* USB connect */
+      USBD->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
+    }
+    else
+    {
+      /* USB disconnect */
+      USBD->ATTR &= ~USBD_ATTR_USBEN_Msk;
+    }
+  }
+
+  if(status & USBD_INTSTS_BUSIF_Msk)
+  {
+    if(state & USBD_ATTR_USBRST_Msk)
+    {
+      /* USB bus reset */
+      USBD->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
+
+      bus_reset();
+
+      dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+    }
+
+    if(state & USBD_ATTR_SUSPEND_Msk)
+    {
+      /* Enable USB but disable PHY */
+      USBD->ATTR &= ~USBD_ATTR_PHYEN_Msk;
+      dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+    }
+
+    if(state & USBD_ATTR_RESUME_Msk)
+    {
+      /* Enable USB and enable PHY */
+      USBD->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
+      dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+    }
+  }
+
+  if(status & USBD_INTSTS_SETUP_Msk)
+  {
+    /* clear the data ready flag of control endpoints */
+    USBD->EP[PERIPH_EP0].CFGP |= USBD_CFGP_CLRRDY_Msk;
+    USBD->EP[PERIPH_EP1].CFGP |= USBD_CFGP_CLRRDY_Msk;
+
+    /* get SETUP packet from USB buffer */
+    dcd_event_setup_received(0, (uint8_t *)USBD_BUF_BASE, true);
+  }
+
+  if(status & USBD_INTSTS_USBIF_Msk)
+  {
+    if (status & USBD_INTSTS_EPEVT0_Msk) /* PERIPH_EP0 (EP0_IN) event: this is treated separately from the rest */
+    {
+      uint16_t const available_bytes = USBD->EP[PERIPH_EP0].MXPLD;
+
+      active_ep0_xfer = (available_bytes == xfer_table[PERIPH_EP0].max_packet_size);
+
+      dcd_event_xfer_complete(0, 0x80, available_bytes, XFER_RESULT_SUCCESS, true);
+    }
+
+    /* service PERIPH_EP1 through PERIPH_EP7 */
+    enum ep_enum ep_index;
+    uint32_t mask;
+    struct xfer_ctl_t *xfer;
+    USBD_EP_T *ep;
+    for (ep_index = PERIPH_EP1, mask = USBD_INTSTS_EPEVT1_Msk, xfer = &xfer_table[PERIPH_EP1], ep = &USBD->EP[PERIPH_EP1]; ep_index <= PERIPH_EP7; ep_index++, mask <<= 1, xfer++, ep++)
+    {
+      if(status & mask)
+      {
+        USBD->INTSTS = mask;
+
+        uint16_t const available_bytes = ep->MXPLD;
+        uint8_t const ep_addr = decode_ep_addr(ep);
+        bool const out_ep = !(ep_addr & TUSB_DIR_IN_MASK);
+
+        if (out_ep)
+        {
+          /* copy the data from the PC to the previously provided buffer */
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+          if (xfer->ff)
+          {
+            tu_fifo_write_n(xfer->ff, (const void *) (USBD_BUF_BASE + ep->BUFSEG), available_bytes);
+          }
+          else
+#endif
+          {
+            // USB SRAM seems to only support byte access and memcpy could possibly do it by words
+            usb_memcpy(xfer->data_ptr, (uint8_t *)(USBD_BUF_BASE + ep->BUFSEG), available_bytes);
+            xfer->data_ptr += available_bytes;
+          }
+
+          xfer->out_bytes_so_far += available_bytes;
+
+          /* when the transfer is finished, alert TinyUSB; otherwise, accept more data */
+          if ( (xfer->total_bytes == xfer->out_bytes_so_far) || (available_bytes < xfer->max_packet_size) )
+            dcd_event_xfer_complete(0, ep_addr, xfer->out_bytes_so_far, XFER_RESULT_SUCCESS, true);
+          else
+            ep->MXPLD = xfer->max_packet_size;
+        }
+        else
+        {
+          /* update the bookkeeping to reflect the data that has now been sent to the PC */
+          xfer->in_remaining_bytes -= available_bytes;
+          xfer->data_ptr += available_bytes;
+
+          /* if more data to send, send it; otherwise, alert TinyUSB that we've finished */
+          if (xfer->in_remaining_bytes)
+            dcd_in_xfer(xfer, ep);
+          else
+            dcd_event_xfer_complete(0, ep_addr, xfer->total_bytes, XFER_RESULT_SUCCESS, true);
+        }
+      }
+    }
+  }
+
+  if(status & USBD_INTSTS_SOFIF_Msk)
+  {
+    /* Start-Of-Frame event */
+    dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+  }
+
+  /* acknowledge all interrupts */
+  USBD->INTSTS = status & ENABLED_IRQS;
+}
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+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 &&
+      request->bRequest == TUSB_REQ_SET_ADDRESS )
+  {
+    uint8_t const dev_addr = (uint8_t) request->wValue;
+
+    // Setting new address after the whole request is complete
+    USBD->FADDR = dev_addr;
+  }
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  usb_detach();
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  usb_attach();
+}
+
+#endif
diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c
new file mode 100644
index 0000000..aefb09f
--- /dev/null
+++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c
@@ -0,0 +1,723 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Peter Lawrence
+ *
+ * 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.
+ */
+
+/*
+  Theory of operation:
+
+  The NUC505 USBD peripheral has twelve "EP"s, where each is simplex, in addition 
+  to dedicated support for the control endpoint (EP0).  The non-user endpoints
+  are referred to as "user" EPs in this code, and follow the datasheet 
+  nomenclature of EPA through EPL.
+*/
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_NUC505)
+
+#include "device/dcd.h"
+#include "NUC505Series.h"
+
+/*
+ * The DMA functionality of the USBD peripheral does not appear to succeed with
+ * transfer lengths that are longer (> 64 bytes) and are not a multiple of 4.
+ * Keep disabled for now.
+ */
+#define USE_DMA     0
+
+/* rather important info unfortunately not provided by device include files */
+#define USBD_BUF_SIZE          2048 /* how much USB buffer space there is */
+#define USBD_MAX_DMA_LEN     0x1000 /* max bytes that can be DMAed at one time */
+
+enum ep_enum
+{
+  PERIPH_EPA = 0,
+  PERIPH_EPB = 1,
+  PERIPH_EPC = 2,
+  PERIPH_EPD = 3,
+  PERIPH_EPE = 4,
+  PERIPH_EPF = 5,
+  PERIPH_EPG = 6,
+  PERIPH_EPH = 7,
+  PERIPH_EPI = 8,
+  PERIPH_EPJ = 9,
+  PERIPH_EPK = 10,
+  PERIPH_EPL = 11,
+  PERIPH_MAX_EP,
+};
+
+static const uint8_t epcfg_eptype_table[] =
+{
+  [TUSB_XFER_CONTROL]     = 0, /* won't happen, since control EPs have dedicated registers */
+  [TUSB_XFER_ISOCHRONOUS] = 3 << USBD_EPCFG_EPTYPE_Pos,
+  [TUSB_XFER_BULK]        = 1 << USBD_EPCFG_EPTYPE_Pos,
+  [TUSB_XFER_INTERRUPT]   = 2 << USBD_EPCFG_EPTYPE_Pos,
+};
+
+static const uint8_t eprspctl_eptype_table[] =
+{
+  [TUSB_XFER_CONTROL]     = 0, /* won't happen, since control EPs have dedicated registers */
+  [TUSB_XFER_ISOCHRONOUS] = 2 << USBD_EPRSPCTL_MODE_Pos, /* Fly Mode */
+  [TUSB_XFER_BULK]        = 0 << USBD_EPRSPCTL_MODE_Pos, /* Auto-Validate Mode */
+  [TUSB_XFER_INTERRUPT]   = 1 << USBD_EPRSPCTL_MODE_Pos, /* Manual-Validate Mode */
+};
+
+/* set by dcd_set_address() */
+static volatile uint8_t assigned_address;
+
+/* reset by bus_reset(), this is used by dcd_edpt_open() to assign USBD peripheral buffer addresses */
+static uint32_t bufseg_addr;
+
+/* RAM table needed to track ongoing transfers performed by dcd_edpt_xfer(), dcd_userEP_in_xfer(), and the ISR */
+static struct xfer_ctl_t
+{
+  uint8_t *data_ptr;         /* data_ptr tracks where to next copy data to (for OUT) or from (for IN) */
+  // tu_fifo_t* ff; // TODO support dcd_edpt_xfer_fifo API
+  union {
+    uint16_t in_remaining_bytes; /* for IN endpoints, we track how many bytes are left to transfer */
+    uint16_t out_bytes_so_far;   /* but for OUT endpoints, we track how many bytes we've transferred so far */
+  };
+  uint16_t max_packet_size;  /* needed since device driver only finds out this at runtime */
+  uint16_t total_bytes;      /* quantity needed to pass as argument to dcd_event_xfer_complete() (for IN endpoints) */
+  uint8_t ep_addr;
+  bool dma_requested;
+} xfer_table[PERIPH_MAX_EP];
+
+/* in addition to xfer_table, additional bespoke bookkeeping is maintained for control EP0 IN */
+static struct
+{
+  uint8_t *data_ptr;
+  uint16_t in_remaining_bytes;
+  uint16_t total_bytes;
+} ctrl_in_xfer;
+
+static volatile struct xfer_ctl_t *current_dma_xfer;
+
+
+/*
+  local helper functions
+*/
+
+static void usb_attach(void)
+{
+  USBD->PHYCTL |= USBD_PHYCTL_DPPUEN_Msk;
+}
+
+static void usb_detach(void)
+{
+  USBD->PHYCTL &= ~USBD_PHYCTL_DPPUEN_Msk;
+}
+
+static void usb_control_send_zlp(void)
+{
+  USBD->CEPINTSTS = USBD_CEPINTSTS_STSDONEIF_Msk;
+  USBD->CEPCTL = 0; /* clear NAKCLR bit */
+  USBD->CEPINTEN = USBD_CEPINTEN_STSDONEIEN_Msk;
+}
+
+/* map 8-bit ep_addr into peripheral endpoint index (PERIPH_EPA...) */
+static USBD_EP_T *ep_entry(uint8_t ep_addr, bool add)
+{
+  USBD_EP_T *ep;
+  enum ep_enum ep_index;
+  struct xfer_ctl_t *xfer;
+
+  for (ep_index = PERIPH_EPA, xfer = &xfer_table[PERIPH_EPA], ep = USBD->EP;
+       ep_index < PERIPH_MAX_EP;
+       ep_index++, xfer++, ep++)
+  {
+    if (add)
+    {
+      /* take first peripheral endpoint that is unused */
+      if (0 == (ep->EPCFG & USBD_EPCFG_EPEN_Msk)) return ep;
+    }
+    else
+    {
+      /* find a peripheral endpoint that matches ep_addr */
+      if (xfer->ep_addr == ep_addr) return ep;
+    }
+  }
+
+  return NULL;
+}
+
+/* perform a non-control IN endpoint transfer; this is called by the ISR  */
+static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
+{
+  uint16_t const bytes_now = tu_min16(xfer->in_remaining_bytes, xfer->max_packet_size);
+
+  /* precompute what amount of data will be left */
+  xfer->in_remaining_bytes -= bytes_now;
+
+  /*
+  if there will be no more data to send, we replace the BUFEMPTYIF EP interrupt with TXPKIF;
+  that way, we alert TinyUSB as soon as this last packet has been sent
+  */
+  if (0 == xfer->in_remaining_bytes)
+  {
+    ep->EPINTSTS = USBD_EPINTSTS_TXPKIF_Msk;
+    ep->EPINTEN = USBD_EPINTEN_TXPKIEN_Msk;
+  }
+
+  /* provided buffers are thankfully 32-bit aligned, allowing most data to be transfered as 32-bit */
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+  if (xfer->ff)
+  {
+    tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now);
+  }
+  else
+#endif
+  {
+    uint16_t countdown = bytes_now;
+    while (countdown > 3)
+    {
+      uint32_t u32;
+      memcpy(&u32, xfer->data_ptr, 4);
+
+      ep->EPDAT = u32;
+      xfer->data_ptr += 4; countdown -= 4;
+    }
+
+    while (countdown--) ep->EPDAT_BYTE = *xfer->data_ptr++;
+  }
+
+  /* for short packets, we must nudge the peripheral to say 'that's all folks' */
+  if (bytes_now != xfer->max_packet_size) ep->EPRSPCTL = USBD_EPRSPCTL_SHORTTXEN_Msk;
+}
+
+/* called by dcd_init() as well as by the ISR during a USB bus reset */
+static void bus_reset(void)
+{
+  for (enum ep_enum ep_index = PERIPH_EPA; ep_index < PERIPH_MAX_EP; ep_index++)
+  {
+    USBD->EP[ep_index].EPCFG = 0;
+    xfer_table[ep_index].dma_requested = false;
+  }
+
+  USBD->DMACNT = 0;
+  USBD->DMACTL = USBD_DMACTL_DMARST_Msk;
+  USBD->DMACTL = 0;
+
+  /* allocate the default EP0 endpoints */
+
+  USBD->CEPBUFSTART = 0;
+  USBD->CEPBUFEND = 0 + CFG_TUD_ENDPOINT0_SIZE - 1;
+
+  /* USB RAM beyond what we've allocated above is available to the user */
+  bufseg_addr = CFG_TUD_ENDPOINT0_SIZE;
+
+  /* Reset USB device address */
+  USBD->FADDR = 0;
+
+  current_dma_xfer = NULL;
+}
+
+#if USE_DMA
+/* this must only be called by the ISR; it does its best to share the single DMA engine across all user EPs (IN and OUT) */
+static void service_dma(void)
+{
+  if (current_dma_xfer)
+    return;
+
+  enum ep_enum ep_index;
+  struct xfer_ctl_t *xfer;
+  USBD_EP_T *ep;
+
+  for (ep_index = PERIPH_EPA, xfer = &xfer_table[PERIPH_EPA], ep = &USBD->EP[PERIPH_EPA]; ep_index < PERIPH_MAX_EP; ep_index++, xfer++, ep++)
+  {
+    uint16_t const available_bytes = ep->EPDATCNT & USBD_EPDATCNT_DATCNT_Msk;
+
+    if (!xfer->dma_requested || !available_bytes)
+      continue;
+
+    /*
+    instruct DMA to copy the data from the PC to the previously provided buffer
+    when the bus interrupt DMADONEIEN subsequently fires, the transfer will have finished
+    */
+    USBD->DMACTL = xfer->ep_addr & USBD_DMACTL_EPNUM_Msk;
+    USBD->DMAADDR = (uint32_t)xfer->data_ptr;
+    USBD->DMACNT = available_bytes;
+    USBD->BUSINTSTS = USBD_BUSINTSTS_DMADONEIF_Msk;
+    xfer->out_bytes_so_far += available_bytes;
+    current_dma_xfer = xfer;
+    USBD->DMACTL |= USBD_DMACTL_DMAEN_Msk;
+
+    return;
+  }
+}
+#endif
+
+/* centralized location for USBD interrupt enable bit masks */
+static const uint32_t enabled_irqs = USBD_GINTEN_USBIEN_Msk | \
+  USBD_GINTEN_EPAIEN_Msk | USBD_GINTEN_EPBIEN_Msk | USBD_GINTEN_EPCIEN_Msk | USBD_GINTEN_EPDIEN_Msk | USBD_GINTEN_EPEIEN_Msk | USBD_GINTEN_EPFIEN_Msk | \
+  USBD_GINTEN_EPGIEN_Msk | USBD_GINTEN_EPHIEN_Msk | USBD_GINTEN_EPIIEN_Msk | USBD_GINTEN_EPJIEN_Msk | USBD_GINTEN_EPKIEN_Msk | USBD_GINTEN_EPLIEN_Msk | \
+  USBD_GINTEN_CEPIEN_Msk;
+
+/*
+  NUC505 TinyUSB API driver implementation
+*/
+
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  /* configure interrupts in their initial state; BUSINTEN and CEPINTEN will be subsequently and dynamically re-written as needed */
+  USBD->GINTEN = enabled_irqs;
+  USBD->BUSINTEN = USBD_BUSINTEN_RSTIEN_Msk | USBD_BUSINTEN_VBUSDETIEN_Msk | USBD_BUSINTEN_RESUMEIEN_Msk | USBD_BUSINTEN_DMADONEIEN_Msk;
+  USBD->CEPINTEN = 0;
+
+  bus_reset();
+
+  usb_attach();
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USBD_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USBD_IRQn);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  (void) rhport;
+  usb_control_send_zlp(); /* SET_ADDRESS is the one exception where TinyUSB doesn't use dcd_edpt_xfer() to generate a ZLP */
+  assigned_address = dev_addr;
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+  USBD->OPER |= USBD_OPER_RESUMEEN_Msk;
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+  (void) rhport;
+
+  USBD_EP_T *ep = ep_entry(p_endpoint_desc->bEndpointAddress, true);
+  TU_ASSERT(ep);
+
+  /* mine the data for the information we need */
+  int const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+  int const size = tu_edpt_packet_size(p_endpoint_desc);
+  tusb_xfer_type_t const type = p_endpoint_desc->bmAttributes.xfer;
+  struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
+
+  /* allocate buffer from USB RAM */
+  ep->EPBUFSTART = bufseg_addr;
+  bufseg_addr += size;
+  ep->EPBUFEND = bufseg_addr - 1;
+  TU_ASSERT(bufseg_addr <= USBD_BUF_SIZE);
+
+  ep->EPMPS = size;
+
+  ep->EPRSPCTL = USB_EP_RSPCTL_FLUSH | eprspctl_eptype_table[type];
+
+  /* construct USB Configuration Register value and then write it */
+  uint32_t cfg = (uint32_t)tu_edpt_number(p_endpoint_desc->bEndpointAddress) << USBD_EPCFG_EPNUM_Pos;
+  if (TUSB_DIR_IN == dir)
+    cfg |= USBD_EPCFG_EPDIR_Msk;
+  cfg |= epcfg_eptype_table[type] | USBD_EPCFG_EPEN_Msk;
+  ep->EPCFG = cfg;
+
+  /* make a note of the endpoint particulars */
+  xfer->max_packet_size = size;
+  xfer->ep_addr = p_endpoint_desc->bEndpointAddress;
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  if (0x80 == ep_addr) /* control EP0 IN */
+  {
+    if (total_bytes)
+    {
+      USBD->CEPCTL = USBD_CEPCTL_FLUSH_Msk;
+      ctrl_in_xfer.data_ptr = buffer;
+      ctrl_in_xfer.in_remaining_bytes = total_bytes;
+      ctrl_in_xfer.total_bytes = total_bytes;
+      USBD->CEPINTSTS = USBD_CEPINTSTS_INTKIF_Msk;
+      USBD->CEPINTEN = USBD_CEPINTEN_INTKIEN_Msk;
+    }
+    else
+    {
+      usb_control_send_zlp();
+    }
+  }
+  else if (0x00 == ep_addr) /* control EP0 OUT */
+  {
+    if (total_bytes)
+    {
+      /* if TinyUSB is asking for EP0 OUT data, it is almost certainly already in the buffer */
+      while (total_bytes < USBD->CEPRXCNT);
+      for (int count = 0; count < total_bytes; count++)
+        *buffer++ = USBD->CEPDAT_BYTE;
+      
+      dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, true);
+    }
+  }
+  else
+  {
+    /* mine the data for the information we need */
+    tusb_dir_t dir = tu_edpt_dir(ep_addr);
+    USBD_EP_T *ep = ep_entry(ep_addr, false);
+    TU_ASSERT(ep);
+    struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
+
+    /* store away the information we'll needing now and later */
+    xfer->data_ptr = buffer;
+    // xfer->ff       = NULL; // TODO support dcd_edpt_xfer_fifo API
+    xfer->in_remaining_bytes = total_bytes;
+    xfer->total_bytes = total_bytes;
+
+    if (TUSB_DIR_IN == dir)
+    {
+      ep->EPINTEN = USBD_EPINTEN_BUFEMPTYIEN_Msk;
+    }
+    else
+    {
+      xfer->out_bytes_so_far = 0;
+      ep->EPINTEN = USBD_EPINTEN_RXPKIEN_Msk;
+    }
+  }
+
+  return true;
+}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  TU_ASSERT(0x80 != ep_addr && 0x00 != ep_addr);  // Must not be used for control stuff
+
+  /* mine the data for the information we need */
+  tusb_dir_t dir = tu_edpt_dir(ep_addr);
+  USBD_EP_T *ep = ep_entry(ep_addr, false);
+  struct xfer_ctl_t *xfer = &xfer_table[ep - USBD->EP];
+
+  /* store away the information we'll needing now and later */
+  xfer->data_ptr = NULL;      // Indicates a FIFO shall be used
+  xfer->ff       = ff;
+  xfer->in_remaining_bytes = total_bytes;
+  xfer->total_bytes = total_bytes;
+
+  if (TUSB_DIR_IN == dir)
+  {
+    ep->EPINTEN = USBD_EPINTEN_BUFEMPTYIEN_Msk;
+  }
+  else
+  {
+    xfer->out_bytes_so_far = 0;
+    ep->EPINTEN = USBD_EPINTEN_RXPKIEN_Msk;
+  }
+
+  return true;
+}
+#endif
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  if (tu_edpt_number(ep_addr))
+  {
+    USBD_EP_T *ep = ep_entry(ep_addr, false);
+    TU_ASSERT(ep, );
+    ep->EPRSPCTL = (ep->EPRSPCTL & 0xf7) | USBD_EPRSPCTL_HALT_Msk;
+  }
+  else
+  {
+    USBD->CEPCTL = USBD_CEPCTL_STALLEN_Msk;
+  }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  if (tu_edpt_number(ep_addr))
+  {
+    USBD_EP_T *ep = ep_entry(ep_addr, false);
+    TU_ASSERT(ep, );
+    ep->EPRSPCTL = USBD_EPRSPCTL_TOGGLE_Msk;
+  }
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void) rhport;
+
+  uint32_t status = USBD->GINTSTS;
+
+  /* USB interrupt */
+  if (status & USBD_GINTSTS_USBIF_Msk)
+  {
+    uint32_t bus_state = USBD->BUSINTSTS;
+
+    if (bus_state & USBD_BUSINTSTS_SOFIF_Msk)
+    {
+      /* Start-Of-Frame event */
+      dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+    }
+
+    if (bus_state & USBD_BUSINTSTS_RSTIF_Msk)
+    {
+      bus_reset();
+
+      USBD->CEPINTEN = USBD_CEPINTEN_SETUPPKIEN_Msk;
+      USBD->BUSINTEN = USBD_BUSINTEN_RSTIEN_Msk | USBD_BUSINTEN_RESUMEIEN_Msk | USBD_BUSINTEN_SUSPENDIEN_Msk | USBD_BUSINTEN_DMADONEIEN_Msk;
+      USBD->CEPINTSTS = 0x1ffc;
+
+      tusb_speed_t speed = (USBD->OPER & USBD_OPER_CURSPD_Msk) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
+      dcd_event_bus_reset(0, speed, true);
+    }
+
+    if (bus_state & USBD_BUSINTSTS_RESUMEIF_Msk)
+    {
+      USBD->BUSINTEN = USBD_BUSINTEN_RSTIEN_Msk | USBD_BUSINTEN_SUSPENDIEN_Msk | USBD_BUSINTEN_DMADONEIEN_Msk;
+      dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+    }
+
+    if (bus_state & USBD_BUSINTSTS_SUSPENDIF_Msk)
+    {
+      USBD->BUSINTEN = USBD_BUSINTEN_RSTIEN_Msk | USBD_BUSINTEN_RESUMEIEN_Msk | USBD_BUSINTEN_DMADONEIEN_Msk;
+      dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+    }
+
+    if (bus_state & USBD_BUSINTSTS_HISPDIF_Msk)
+    {
+      USBD->CEPINTEN = USBD_CEPINTEN_SETUPPKIEN_Msk;
+    }
+
+    if (bus_state & USBD_BUSINTSTS_DMADONEIF_Msk)
+    {
+#if USE_DMA
+      if (current_dma_xfer)
+      {
+        current_dma_xfer->dma_requested = false;
+
+        uint16_t available_bytes = USBD->DMACNT & USBD_DMACNT_DMACNT_Msk;
+
+        /* if the most recent DMA finishes the transfer, alert TinyUSB; otherwise, the next RXPKIF/INTKIF endpoint interrupt will prompt the next DMA */
+        if ( (current_dma_xfer->total_bytes == current_dma_xfer->out_bytes_so_far) || (available_bytes < current_dma_xfer->max_packet_size) )
+        {
+          dcd_event_xfer_complete(0, current_dma_xfer->ep_addr, current_dma_xfer->out_bytes_so_far, XFER_RESULT_SUCCESS, true);
+        }
+
+        current_dma_xfer = NULL;
+        service_dma();
+      }
+#endif
+    }
+
+    if (bus_state & USBD_BUSINTSTS_VBUSDETIF_Msk)
+    {
+      if (USBD->PHYCTL & USBD_PHYCTL_VBUSDET_Msk)
+      {
+        /* USB connect */
+        USBD->PHYCTL |= USBD_PHYCTL_PHYEN_Msk | USBD_PHYCTL_DPPUEN_Msk;
+      }
+      else
+      {
+        /* USB disconnect */
+        USBD->PHYCTL &= ~USBD_PHYCTL_DPPUEN_Msk;
+      }
+    }
+
+    USBD->BUSINTSTS = bus_state & (USBD_BUSINTSTS_SOFIF_Msk | USBD_BUSINTSTS_RSTIF_Msk | USBD_BUSINTSTS_RESUMEIF_Msk | USBD_BUSINTSTS_SUSPENDIF_Msk | USBD_BUSINTSTS_HISPDIF_Msk | USBD_BUSINTSTS_DMADONEIF_Msk | USBD_BUSINTSTS_PHYCLKVLDIF_Msk | USBD_BUSINTSTS_VBUSDETIF_Msk);
+  }
+
+  if (status & USBD_GINTSTS_CEPIF_Msk)
+  {
+    uint32_t cep_state = USBD->CEPINTSTS & USBD->CEPINTEN;
+
+    if (cep_state & USBD_CEPINTSTS_SETUPPKIF_Msk)
+    {
+      /* get SETUP packet from USB buffer */
+      uint8_t setup_packet[8];
+      setup_packet[0] = (uint8_t)(USBD->SETUP1_0 >> 0);
+      setup_packet[1] = (uint8_t)(USBD->SETUP1_0 >> 8);
+      setup_packet[2] = (uint8_t)(USBD->SETUP3_2 >> 0);
+      setup_packet[3] = (uint8_t)(USBD->SETUP3_2 >> 8);
+      setup_packet[4] = (uint8_t)(USBD->SETUP5_4 >> 0);
+      setup_packet[5] = (uint8_t)(USBD->SETUP5_4 >> 8);
+      setup_packet[6] = (uint8_t)(USBD->SETUP7_6 >> 0);
+      setup_packet[7] = (uint8_t)(USBD->SETUP7_6 >> 8);
+      dcd_event_setup_received(0, setup_packet, true);
+    }
+    else if (cep_state & USBD_CEPINTSTS_INTKIF_Msk)
+    {
+      USBD->CEPINTSTS = USBD_CEPINTSTS_TXPKIF_Msk;
+
+      if (!(cep_state & USBD_CEPINTSTS_STSDONEIF_Msk))
+      {
+        USBD->CEPINTEN = USBD_CEPINTEN_TXPKIEN_Msk;
+        uint16_t bytes_now = tu_min16(ctrl_in_xfer.in_remaining_bytes, CFG_TUD_ENDPOINT0_SIZE);
+        for (int count = 0; count < bytes_now; count++)
+          USBD->CEPDAT_BYTE = *ctrl_in_xfer.data_ptr++;
+        ctrl_in_xfer.in_remaining_bytes -= bytes_now;
+        USBD_START_CEP_IN(bytes_now);
+      }
+      else
+      {
+        USBD->CEPINTEN = USBD_CEPINTEN_TXPKIEN_Msk | USBD_CEPINTEN_STSDONEIEN_Msk;
+      }
+    }
+    else if (cep_state & USBD_CEPINTSTS_TXPKIF_Msk)
+    {
+      USBD->CEPINTSTS = USBD_CEPINTSTS_STSDONEIF_Msk;
+      USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR);
+
+      /* alert TinyUSB that the EP0 IN transfer has finished */
+      if ( (0 == ctrl_in_xfer.in_remaining_bytes) || (0 == ctrl_in_xfer.total_bytes) )
+        dcd_event_xfer_complete(0, 0x80, ctrl_in_xfer.total_bytes, XFER_RESULT_SUCCESS, true);
+
+      if (ctrl_in_xfer.in_remaining_bytes)
+      {
+        USBD->CEPINTSTS = USBD_CEPINTSTS_INTKIF_Msk;
+        USBD->CEPINTEN = USBD_CEPINTEN_INTKIEN_Msk;
+      }
+      else
+      {
+        /* TinyUSB does its own fragmentation and ZLP for EP0; a transfer of zero means a ZLP */
+        if (0 == ctrl_in_xfer.total_bytes) USBD->CEPCTL = USBD_CEPCTL_ZEROLEN_Msk;
+
+        USBD->CEPINTSTS = USBD_CEPINTSTS_STSDONEIF_Msk;
+        USBD->CEPINTEN = USBD_CEPINTEN_SETUPPKIEN_Msk | USBD_CEPINTEN_STSDONEIEN_Msk;
+      }
+    }
+    else if (cep_state & USBD_CEPINTSTS_STSDONEIF_Msk)
+    {
+      /* given ACK from host has happened, we can now set the address (if not already done) */
+      if((USBD->FADDR != assigned_address) && (USBD->FADDR == 0))
+      {
+        USBD->FADDR = assigned_address;
+
+        for (enum ep_enum ep_index = PERIPH_EPA; ep_index < PERIPH_MAX_EP; ep_index++)
+        {
+          if (USBD->EP[ep_index].EPCFG & USBD_EPCFG_EPEN_Msk) USBD->EP[ep_index].EPRSPCTL = USBD_EPRSPCTL_TOGGLE_Msk;
+        }
+      }
+
+      USBD->CEPINTEN = USBD_CEPINTEN_SETUPPKIEN_Msk;
+    }
+
+    USBD->CEPINTSTS = cep_state;
+
+    return;
+  }
+
+  if (status & (USBD_GINTSTS_EPAIF_Msk | USBD_GINTSTS_EPBIF_Msk | USBD_GINTSTS_EPCIF_Msk | USBD_GINTSTS_EPDIF_Msk | USBD_GINTSTS_EPEIF_Msk | USBD_GINTSTS_EPFIF_Msk | USBD_GINTSTS_EPGIF_Msk | USBD_GINTSTS_EPHIF_Msk | USBD_GINTSTS_EPIIF_Msk | USBD_GINTSTS_EPJIF_Msk | USBD_GINTSTS_EPKIF_Msk | USBD_GINTSTS_EPLIF_Msk))
+  {
+    /* service PERIPH_EPA through PERIPH_EPL */
+    enum ep_enum ep_index;
+    uint32_t mask;
+    struct xfer_ctl_t *xfer;
+    USBD_EP_T *ep;
+    for (ep_index = PERIPH_EPA, mask = USBD_GINTSTS_EPAIF_Msk, xfer = &xfer_table[PERIPH_EPA], ep = &USBD->EP[PERIPH_EPA]; ep_index < PERIPH_MAX_EP; ep_index++, mask <<= 1, xfer++, ep++)
+    {
+      if(status & mask)
+      {
+        uint8_t const ep_addr = xfer->ep_addr;
+        bool const out_ep = !(ep_addr & TUSB_DIR_IN_MASK);
+        uint32_t ep_state = ep->EPINTSTS & ep->EPINTEN;
+
+        if (out_ep)
+        {
+#if USE_DMA
+          xfer->dma_requested = true;
+          service_dma();
+#else
+          uint16_t const available_bytes = ep->EPDATCNT & USBD_EPDATCNT_DATCNT_Msk;
+          /* copy the data from the PC to the previously provided buffer */
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+          if (xfer->ff)
+          {
+            tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far));
+          }
+          else
+#endif
+          {
+            for (int count = 0; (count < available_bytes) && (xfer->out_bytes_so_far < xfer->total_bytes); count++, xfer->out_bytes_so_far++)
+            {
+              *xfer->data_ptr++ = ep->EPDAT_BYTE;
+            }
+          }
+
+          /* when the transfer is finished, alert TinyUSB; otherwise, continue accepting more data */
+          if ( (xfer->total_bytes == xfer->out_bytes_so_far) || (available_bytes < xfer->max_packet_size) )
+          {
+            dcd_event_xfer_complete(0, ep_addr, xfer->out_bytes_so_far, XFER_RESULT_SUCCESS, true);
+          }
+#endif
+
+        }
+        else if (ep_state & USBD_EPINTSTS_BUFEMPTYIF_Msk)
+        {
+          /* send any remaining data */
+          dcd_userEP_in_xfer(xfer, ep);
+        }
+        else if (ep_state & USBD_EPINTSTS_TXPKIF_Msk)
+        {
+          /* alert TinyUSB that we've finished */
+          dcd_event_xfer_complete(0, ep_addr, xfer->total_bytes, XFER_RESULT_SUCCESS, true);
+          ep->EPINTEN = 0;
+        }
+
+        ep->EPINTSTS = ep_state;
+      }
+    }
+  }
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  usb_detach();
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  usb_attach();
+}
+
+#endif
diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c
new file mode 100644
index 0000000..8de924f
--- /dev/null
+++ b/src/portable/nxp/khci/dcd_khci.c
@@ -0,0 +1,557 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 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 TUSB_OPT_DEVICE_ENABLED && ( \
+      ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX ) || ( CFG_TUSB_MCU == OPT_MCU_K32L2BXX ) \
+    )
+
+#include "fsl_device_registers.h"
+#define KHCI        USB0
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+  TOK_PID_OUT   = 0x1u,
+  TOK_PID_IN    = 0x9u,
+  TOK_PID_SETUP = 0xDu,
+};
+
+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 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];
+    uint16_t            bda[512];
+  };
+  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) static dcd_data_t _dcd;
+
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
+
+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 = KHCI->ENDPOINT[i].ENDPT;
+
+    if (endpt & USB_ENDPT_EPSTALL_MASK) {
+      // prepare next setup if endpoint0
+      if ( i == 0 ) prepare_next_setup_packet(rhport);
+
+      // clear stall bit
+      KHCI->ENDPOINT[i].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK;
+    }
+  }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+  const unsigned s = KHCI->STAT;
+  KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+
+  uint8_t const epnum = (s >> USB_STAT_ENDP_SHIFT);
+  uint8_t const dir   = (s & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT;
+  unsigned const odd  = (s & USB_STAT_ODD_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, bd->addr, true);
+    KHCI->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
+    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;
+      __DSB();
+      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. */
+      KHCI->ADDR = _dcd.addr;
+      _dcd.addr  = 0;
+    }
+    prepare_next_setup_packet(rhport);
+  }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+  KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+  KHCI->CTL     |= USB_CTL_ODDRST_MASK;
+  KHCI->ADDR     = 0;
+  KHCI->INTEN    = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK |
+                   USB_INTEN_ERROREN_MASK  | USB_INTEN_STALLEN_MASK;
+
+  KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+  for (unsigned i = 1; i < 16; ++i) {
+    KHCI->ENDPOINT[i].ENDPT = 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);
+  KHCI->CTL &= ~USB_CTL_ODDRST_MASK;
+  dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_bus_sleep(uint8_t rhport)
+{
+  // Enable resume & disable suspend interrupt
+  const unsigned inten = KHCI->INTEN;
+
+  KHCI->INTEN    = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
+  KHCI->USBTRC0 |= USB_USBTRC0_USBRESMEN_MASK;
+  KHCI->USBCTRL |= USB_USBCTRL_SUSP_MASK;
+
+  dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+}
+
+static void process_bus_resume(uint8_t rhport)
+{
+  // Enable suspend & disable resume interrupt
+  const unsigned inten = KHCI->INTEN;
+
+  KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; // will also clear USB_USBTRC0_USB_RESUME_INT_MASK
+  KHCI->USBTRC0 &= ~USB_USBTRC0_USBRESMEN_MASK;
+  KHCI->INTEN    = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+
+  dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+  while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+  tu_memclr(&_dcd, sizeof(_dcd));
+  KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
+  KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_dcd.bdt >>  8);
+  KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_dcd.bdt >> 16);
+  KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_dcd.bdt >> 24);
+
+  KHCI->INTEN = USB_INTEN_USBRSTEN_MASK;
+
+  dcd_connect(rhport);
+  NVIC_ClearPendingIRQ(USB0_IRQn);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB0_IRQn);
+}
+
+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)
+{
+  (void) rhport;
+
+  KHCI->CTL |= USB_CTL_RESUME_MASK;
+
+  unsigned cnt = SystemCoreClock / 1000;
+  while (cnt--) __NOP();
+
+  KHCI->CTL &= ~USB_CTL_RESUME_MASK;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  KHCI->USBCTRL  = 0;
+  KHCI->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK;
+  KHCI->CTL     |= USB_CTL_USBENSOFEN_MASK;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  KHCI->CTL      = 0;
+  KHCI->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+  (void) rhport;
+
+  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 = USB_ENDPT_EPCTLDIS_MASK;
+  val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK: 0;
+  val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+  KHCI->ENDPOINT[epn].ENDPT |= val;
+
+  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)
+{
+  (void) rhport;
+  const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  for (unsigned i = 1; i < 16; ++i) {
+    KHCI->ENDPOINT[i].ENDPT = 0;
+  }
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+  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)
+{
+  (void) rhport;
+
+  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 ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+  const unsigned ie       = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  KHCI->ENDPOINT[epn].ENDPT &= ~msk;
+  ep->max_packet_size = 0;
+  ep->length          = 0;
+  ep->remaining       = 0;
+  bd[0].head          = 0;
+  bd[1].head          = 0;
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+  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 = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+
+  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 = buffer + mps;
+    next->own  = 1;
+  }
+  bd->bc   = total_bytes >= mps ? mps: total_bytes;
+  bd->addr = buffer;
+  __DSB();
+  bd->own  = 1; /* This bit must be set last */
+
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+  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) {
+    KHCI->ENDPOINT[epn].ENDPT |=  USB_ENDPT_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       = NVIC_GetEnableIRQ(USB0_IRQn);
+    NVIC_DisableIRQ(USB0_IRQn);
+
+    bd->bdt_stall = 1;
+    __DSB();
+    bd->own       = 1; /* This bit must be set last */
+
+    if (ie) NVIC_EnableIRQ(USB0_IRQn);
+  }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  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       = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+
+  bd[odd].own = 0;
+  __DSB();
+
+  // 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 = KHCI->ENDPOINT[epn].ENDPT;
+  if (endpt & USB_ENDPT_EPSTALL_MASK) {
+    KHCI->ENDPOINT[epn].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK;
+  }
+
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+  uint32_t is  = KHCI->ISTAT;
+  uint32_t msk = KHCI->INTEN;
+
+  // clear non-enabled interrupts
+  KHCI->ISTAT = is & ~msk;
+  is &= msk;
+
+  if (is & USB_ISTAT_ERROR_MASK) {
+    /* TODO: */
+    uint32_t es = KHCI->ERRSTAT;
+    KHCI->ERRSTAT = es;
+    KHCI->ISTAT   = is; /* discard any pending events */
+  }
+
+  if (is & USB_ISTAT_USBRST_MASK) {
+    KHCI->ISTAT = is; /* discard any pending events */
+    process_bus_reset(rhport);
+  }
+
+  if (is & USB_ISTAT_SLEEP_MASK) {
+    // TU_LOG2("Suspend: "); TU_LOG2_HEX(is);
+
+    // 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
+    KHCI->ISTAT = USB_ISTAT_SLEEP_MASK;
+    process_bus_sleep(rhport);
+  }
+
+#if 0 // ISTAT_RESUME never trigger, probably for host mode ?
+  if (is & USB_ISTAT_RESUME_MASK) {
+    // TU_LOG2("ISTAT Resume: "); TU_LOG2_HEX(is);
+    KHCI->ISTAT = USB_ISTAT_RESUME_MASK;
+    process_bus_resume(rhport);
+  }
+#endif
+
+  if (KHCI->USBTRC0 & USB_USBTRC0_USB_RESUME_INT_MASK) {
+     // TU_LOG2("USBTRC0 Resume: "); TU_LOG2_HEX(is); TU_LOG2_HEX(KHCI->USBTRC0);
+    process_bus_resume(rhport);
+  }
+
+  if (is & USB_ISTAT_SOFTOK_MASK) {
+    KHCI->ISTAT = USB_ISTAT_SOFTOK_MASK;
+    dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+  }
+
+  if (is & USB_ISTAT_STALL_MASK) {
+    KHCI->ISTAT = USB_ISTAT_STALL_MASK;
+    process_stall(rhport);
+  }
+
+  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
new file mode 100644
index 0000000..0f500a8
--- /dev/null
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
@@ -0,0 +1,589 @@
+/* 
+ * 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 TUSB_OPT_DEVICE_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"
+#include "dcd_lpc17_40.h"
+#include "chip.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+#define DCD_ENDPOINT_MAX 32
+
+typedef struct TU_ATTR_ALIGNED(4)
+{
+  //------------- Word 0 -------------//
+  uint32_t next;
+
+  //------------- Word 1 -------------//
+  uint16_t atle_mode       : 2; // 00: normal, 01: ATLE (auto length extraction)
+  uint16_t next_valid      : 1;
+  uint16_t                 : 1; ///< reserved
+  uint16_t isochronous     : 1; // is an iso endpoint
+  uint16_t max_packet_size : 11;
+
+  volatile uint16_t buflen; // bytes for non-iso, number of packets for iso endpoint
+
+  //------------- Word 2 -------------//
+  volatile uint32_t buffer;
+
+  //------------- Word 3 -------------//
+  volatile uint16_t retired                : 1; // initialized to zero
+  volatile uint16_t status                 : 4;
+  volatile uint16_t iso_last_packet_valid  : 1;
+  volatile uint16_t atle_lsb_extracted     : 1;	// used in ATLE mode
+  volatile uint16_t atle_msb_extracted     : 1;	// used in ATLE mode
+  volatile uint16_t atle_mess_len_position : 6; // used in ATLE mode
+  uint16_t                                 : 2;
+
+  volatile uint16_t present_count;  // For non-iso : The number of bytes transferred by the DMA engine
+                                    // For iso : number of packets
+
+  //------------- Word 4 -------------//
+  //	uint32_t iso_packet_size_addr;		// iso only, can be omitted for non-iso
+}dma_desc_t;
+
+TU_VERIFY_STATIC( sizeof(dma_desc_t) == 16, "size is not correct"); // TODO not support ISO for now
+
+typedef struct
+{
+  // must be 128 byte aligned
+  volatile dma_desc_t* udca[DCD_ENDPOINT_MAX];
+
+  // TODO DMA does not support control transfer (0-1 are not used, offset to reduce memory)
+  dma_desc_t dd[DCD_ENDPOINT_MAX];
+
+  struct
+  {
+    uint8_t* out_buffer;
+    uint8_t  out_bytes;
+    volatile bool out_received; // indicate if data is already received in endpoint
+
+    uint8_t  in_bytes;
+  } control;
+
+} dcd_data_t;
+
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(128) static dcd_data_t _dcd;
+
+
+//--------------------------------------------------------------------+
+// SIE Command
+//--------------------------------------------------------------------+
+static void sie_cmd_code (sie_cmdphase_t phase, uint8_t code_data)
+{
+  LPC_USB->DevIntClr = (DEV_INT_COMMAND_CODE_EMPTY_MASK | DEV_INT_COMMAND_DATA_FULL_MASK);
+  LPC_USB->CmdCode   = (phase << 8) | (code_data << 16);
+
+  uint32_t const wait_flag = (phase == SIE_CMDPHASE_READ) ? DEV_INT_COMMAND_DATA_FULL_MASK : DEV_INT_COMMAND_CODE_EMPTY_MASK;
+  while ((LPC_USB->DevIntSt & wait_flag) == 0) {}
+
+  LPC_USB->DevIntClr = wait_flag;
+}
+
+static void sie_write (uint8_t cmd_code, uint8_t data_len, uint8_t data)
+{
+  sie_cmd_code(SIE_CMDPHASE_COMMAND, cmd_code);
+
+  if (data_len)
+  {
+    sie_cmd_code(SIE_CMDPHASE_WRITE, data);
+  }
+}
+
+static uint8_t sie_read (uint8_t cmd_code)
+{
+  sie_cmd_code(SIE_CMDPHASE_COMMAND , cmd_code);
+  sie_cmd_code(SIE_CMDPHASE_READ    , cmd_code);
+  return (uint8_t) LPC_USB->CmdData;
+}
+
+//--------------------------------------------------------------------+
+// PIPE HELPER
+//--------------------------------------------------------------------+
+static inline uint8_t ep_addr2idx(uint8_t ep_addr)
+{
+  return 2*(ep_addr & 0x0F) + ((ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0);
+}
+
+static void set_ep_size(uint8_t ep_id, uint16_t max_packet_size)
+{
+  // follows example in 11.10.4.2
+  LPC_USB->ReEp    |= TU_BIT(ep_id);
+  LPC_USB->EpInd    = ep_id; // select index before setting packet size
+  LPC_USB->MaxPSize = max_packet_size;
+
+  while ((LPC_USB->DevIntSt & DEV_INT_ENDPOINT_REALIZED_MASK) == 0) {}
+  LPC_USB->DevIntClr = DEV_INT_ENDPOINT_REALIZED_MASK;
+}
+
+
+//--------------------------------------------------------------------+
+// CONTROLLER API
+//--------------------------------------------------------------------+
+static void bus_reset(void)
+{
+  // step 7 : slave mode set up
+  LPC_USB->EpIntClr     = 0xFFFFFFFF; // clear all pending interrupt
+  LPC_USB->DevIntClr    = 0xFFFFFFFF; // clear all pending interrupt
+  LPC_USB->EpIntEn      = 0x03UL;     // control endpoint cannot use DMA, non-control all use DMA
+  LPC_USB->EpIntPri     = 0x03UL;     // fast for control endpoint
+
+  // step 8 : DMA set up
+  LPC_USB->EpDMADis     = 0xFFFFFFFF; // firstly disable all dma
+  LPC_USB->DMARClr      = 0xFFFFFFFF; // clear all pending interrupt
+  LPC_USB->EoTIntClr    = 0xFFFFFFFF;
+  LPC_USB->NDDRIntClr   = 0xFFFFFFFF;
+  LPC_USB->SysErrIntClr = 0xFFFFFFFF;
+
+  tu_memclr(&_dcd, sizeof(dcd_data_t));
+}
+
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  //------------- user manual 11.13 usb device controller initialization -------------//
+  // step 6 : set up control endpoint
+  set_ep_size(0, CFG_TUD_ENDPOINT0_SIZE);
+  set_ep_size(1, CFG_TUD_ENDPOINT0_SIZE);
+
+  bus_reset();
+
+  LPC_USB->DevIntEn = (DEV_INT_DEVICE_STATUS_MASK | DEV_INT_ENDPOINT_FAST_MASK | DEV_INT_ENDPOINT_SLOW_MASK | DEV_INT_ERROR_MASK);
+  LPC_USB->UDCAH = (uint32_t) _dcd.udca;
+  LPC_USB->DMAIntEn = (DMA_INT_END_OF_XFER_MASK /*| DMA_INT_NEW_DD_REQUEST_MASK*/ | DMA_INT_ERROR_MASK);
+
+  dcd_connect(rhport);
+
+  // Clear pending IRQ
+  NVIC_ClearPendingIRQ(USB_IRQn);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USB_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB_IRQn);
+}
+
+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);
+
+  sie_write(SIE_CMDCODE_SET_ADDRESS, 1, 0x80 | dev_addr); // 7th bit is : device_enable
+
+  // Also Set Configure Device to enable non-control endpoint response
+  sie_write(SIE_CMDCODE_CONFIGURE_DEVICE, 1, 1);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, SIE_DEV_STATUS_CONNECT_STATUS_MASK);
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  sie_write(SIE_CMDCODE_DEVICE_STATUS, 1, 0);
+}
+
+//--------------------------------------------------------------------+
+// CONTROL HELPER
+//--------------------------------------------------------------------+
+static inline uint8_t byte2dword(uint8_t bytes)
+{
+  return (bytes + 3) / 4; // length in dwords
+}
+
+static void control_ep_write(void const * buffer, uint8_t len)
+{
+  uint32_t const * buf32 = (uint32_t const *) buffer;
+
+  LPC_USB->Ctrl   = USBCTRL_WRITE_ENABLE_MASK; // logical endpoint = 0
+  LPC_USB->TxPLen = (uint32_t) len;
+
+  for (uint8_t count = 0; count < byte2dword(len); count++)
+  {
+    LPC_USB->TxData = *buf32; // NOTE: cortex M3 have no problem with alignment
+    buf32++;
+  }
+
+  LPC_USB->Ctrl = 0;
+
+  // select control IN & validate the endpoint
+  sie_write(SIE_CMDCODE_ENDPOINT_SELECT+1, 0, 0);
+  sie_write(SIE_CMDCODE_BUFFER_VALIDATE  , 0, 0);
+}
+
+static uint8_t control_ep_read(void * buffer, uint8_t len)
+{
+  LPC_USB->Ctrl = USBCTRL_READ_ENABLE_MASK; // logical endpoint = 0
+  while ((LPC_USB->RxPLen & USBRXPLEN_PACKET_READY_MASK) == 0) {} // TODO blocking, should have timeout
+
+  len = tu_min8(len, (uint8_t) (LPC_USB->RxPLen & USBRXPLEN_PACKET_LENGTH_MASK) );
+  uint32_t *buf32 = (uint32_t*) buffer;
+
+  for (uint8_t count=0; count < byte2dword(len); count++)
+  {
+    *buf32 = LPC_USB->RxData;
+    buf32++;
+  }
+
+  LPC_USB->Ctrl = 0;
+
+  // select control OUT & clear the endpoint
+  sie_write(SIE_CMDCODE_ENDPOINT_SELECT+0, 0, 0);
+  sie_write(SIE_CMDCODE_BUFFER_CLEAR     , 0, 0);
+
+  return len;
+}
+
+//--------------------------------------------------------------------+
+// DCD Endpoint Port
+//--------------------------------------------------------------------+
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+  uint8_t const ep_id = ep_addr2idx(p_endpoint_desc->bEndpointAddress);
+
+  // Endpoint type is fixed to endpoint number
+  // 1: interrupt, 2: Bulk, 3: Iso and so on
+  switch ( p_endpoint_desc->bmAttributes.xfer )
+  {
+    case TUSB_XFER_INTERRUPT:
+      TU_ASSERT((epnum % 3) == 1);
+      break;
+
+    case TUSB_XFER_BULK:
+      TU_ASSERT((epnum % 3) == 2 || (epnum == 15));
+      break;
+
+    case TUSB_XFER_ISOCHRONOUS:
+      TU_ASSERT((epnum % 3) == 0 && (epnum != 0) && (epnum != 15));
+      break;
+
+    default:
+      break;
+  }
+
+  //------------- Realize Endpoint with Max Packet Size -------------//
+  const uint16_t ep_size = tu_edpt_packet_size(p_endpoint_desc);
+  set_ep_size(ep_id, ep_size);
+
+  //------------- first DD prepare -------------//
+  dma_desc_t* const dd = &_dcd.dd[ep_id];
+  tu_memclr(dd, sizeof(dma_desc_t));
+
+  dd->isochronous = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
+  dd->max_packet_size = ep_size;
+  dd->retired = 1; // invalid at first
+
+  sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS + ep_id, 1, 0);    // clear all endpoint status
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  if ( tu_edpt_number(ep_addr) == 0 )
+  {
+    sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+0, 1, SIE_SET_ENDPOINT_STALLED_MASK | SIE_SET_ENDPOINT_CONDITION_STALLED_MASK);
+  }else
+  {
+    uint8_t ep_id = ep_addr2idx( ep_addr );
+    sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, SIE_SET_ENDPOINT_STALLED_MASK);
+  }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  uint8_t ep_id = ep_addr2idx(ep_addr);
+
+  sie_write(SIE_CMDCODE_ENDPOINT_SET_STATUS+ep_id, 1, 0);
+}
+
+static bool control_xact(uint8_t rhport, uint8_t dir, uint8_t * buffer, uint8_t len)
+{
+  (void) rhport;
+
+  if ( dir )
+  {
+    _dcd.control.in_bytes = len;
+    control_ep_write(buffer, len);
+  }else
+  {
+    if ( _dcd.control.out_received )
+    {
+      // Already received the DATA OUT packet
+      _dcd.control.out_received = false;
+      _dcd.control.out_buffer = NULL;
+      _dcd.control.out_bytes  = 0;
+
+      uint8_t received = control_ep_read(buffer, len);
+      dcd_event_xfer_complete(0, 0, received, XFER_RESULT_SUCCESS, true);
+    }else
+    {
+      _dcd.control.out_buffer = buffer;
+      _dcd.control.out_bytes  = len;
+    }
+  }
+
+  return true;
+}
+
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+  // Control transfer is not DMA support, and must be done in slave mode
+  if ( tu_edpt_number(ep_addr) == 0 )
+  {
+    return control_xact(rhport, tu_edpt_dir(ep_addr), buffer, (uint8_t) total_bytes);
+  }
+  else
+  {
+    uint8_t ep_id = ep_addr2idx(ep_addr);
+    dma_desc_t* dd = &_dcd.dd[ep_id];
+
+    // Prepare DMA descriptor
+    // Isochronous & max packet size must be preserved, Other fields of dd should be clear
+    uint16_t const ep_size = dd->max_packet_size;
+    uint8_t  is_iso = dd->isochronous;
+
+    tu_memclr(dd, sizeof(dma_desc_t));
+    dd->isochronous = is_iso;
+    dd->max_packet_size = ep_size;
+    dd->buffer = (uint32_t) buffer;
+    dd->buflen = total_bytes;
+
+    _dcd.udca[ep_id] = dd;
+
+    if ( ep_id % 2 )
+    {
+      // Clear EP interrupt before Enable DMA
+      LPC_USB->EpIntEn &= ~TU_BIT(ep_id);
+      LPC_USB->EpDMAEn = TU_BIT(ep_id);
+
+      // endpoint IN need to actively raise DMA request
+      LPC_USB->DMARSet = TU_BIT(ep_id);
+    }else
+    {
+      // Enable DMA
+      LPC_USB->EpDMAEn = TU_BIT(ep_id);
+    }
+
+    return true;
+  }
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+
+// handle control xfer (slave mode)
+static void control_xfer_isr(uint8_t rhport, uint32_t ep_int_status)
+{
+  // Control out complete
+  if ( ep_int_status & TU_BIT(0) )
+  {
+    bool is_setup = sie_read(SIE_CMDCODE_ENDPOINT_SELECT+0) & SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK;
+
+    LPC_USB->EpIntClr = TU_BIT(0);
+
+    if (is_setup)
+    {
+      uint8_t setup_packet[8];
+      control_ep_read(setup_packet, 8); // TODO read before clear setup above
+
+      dcd_event_setup_received(rhport, setup_packet, true);
+    }
+    else if ( _dcd.control.out_buffer )
+    {
+      // software queued transfer previously
+      uint8_t received = control_ep_read(_dcd.control.out_buffer, _dcd.control.out_bytes);
+
+      _dcd.control.out_buffer = NULL;
+      _dcd.control.out_bytes = 0;
+
+      dcd_event_xfer_complete(rhport, 0, received, XFER_RESULT_SUCCESS, true);
+    }else
+    {
+      // hardware auto ack packet -> mark as received
+      _dcd.control.out_received = true;
+    }
+  }
+
+  // Control In complete
+  if ( ep_int_status & TU_BIT(1) )
+  {
+    LPC_USB->EpIntClr = TU_BIT(1);
+    dcd_event_xfer_complete(rhport, TUSB_DIR_IN_MASK, _dcd.control.in_bytes, XFER_RESULT_SUCCESS, true);
+  }
+}
+
+// handle bus event signal
+static void bus_event_isr(uint8_t rhport)
+{
+  uint8_t const dev_status = sie_read(SIE_CMDCODE_DEVICE_STATUS);
+  if (dev_status & SIE_DEV_STATUS_RESET_MASK)
+  {
+    bus_reset();
+    dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+  }
+
+  if (dev_status & SIE_DEV_STATUS_CONNECT_CHANGE_MASK)
+  {
+    // device is disconnected, require using VBUS (P1_30)
+    dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+  }
+
+  if (dev_status & SIE_DEV_STATUS_SUSPEND_CHANGE_MASK)
+  {
+    if (dev_status & SIE_DEV_STATUS_SUSPEND_MASK)
+    {
+      dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+    }
+    else
+    {
+      dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+    }
+  }
+}
+
+// Helper to complete a DMA descriptor for non-control transfer
+static void dd_complete_isr(uint8_t rhport, uint8_t ep_id)
+{
+  dma_desc_t* const dd = &_dcd.dd[ep_id];
+  uint8_t result = (dd->status == DD_STATUS_NORMAL || dd->status == DD_STATUS_DATA_UNDERUN) ? XFER_RESULT_SUCCESS : XFER_RESULT_FAILED;
+  uint8_t const ep_addr = (ep_id / 2) | ((ep_id & 0x01) ? TUSB_DIR_IN_MASK : 0);
+
+  dcd_event_xfer_complete(rhport, ep_addr, dd->present_count, result, true);
+}
+
+// main USB IRQ handler
+void dcd_int_handler(uint8_t rhport)
+{
+  uint32_t const dev_int_status = LPC_USB->DevIntSt & LPC_USB->DevIntEn;
+  LPC_USB->DevIntClr = dev_int_status;// Acknowledge handled interrupt
+
+  // Bus event
+  if (dev_int_status & DEV_INT_DEVICE_STATUS_MASK)
+  {
+    bus_event_isr(rhport);
+  }
+
+  // Endpoint interrupt
+  uint32_t const ep_int_status = LPC_USB->EpIntSt & LPC_USB->EpIntEn;
+
+  // Control Endpoint are fast
+  if (dev_int_status & DEV_INT_ENDPOINT_FAST_MASK)
+  {
+    // Note clear USBEpIntClr will also clear the setup received bit --> clear after handle setup packet
+    // Only clear USBEpIntClr 1 endpoint each, and should wait for CDFULL bit set
+    control_xfer_isr(rhport, ep_int_status);
+  }
+
+  // non-control IN are slow
+  if (dev_int_status & DEV_INT_ENDPOINT_SLOW_MASK)
+  {
+    for ( uint8_t ep_id = 3; ep_id < DCD_ENDPOINT_MAX; ep_id += 2 )
+    {
+      if ( tu_bit_test(ep_int_status, ep_id) )
+      {
+        LPC_USB->EpIntClr = TU_BIT(ep_id);
+
+        // Clear Ep interrupt for next DMA
+        LPC_USB->EpIntEn &= ~TU_BIT(ep_id);
+
+        dd_complete_isr(rhport, ep_id);
+      }
+    }
+  }
+
+  // DMA transfer complete (RAM <-> EP) for Non-Control
+  // OUT: USB transfer is fully complete
+  // IN : UBS transfer is still on-going -> enable EpIntEn to know when it is complete
+  uint32_t const dma_int_status = LPC_USB->DMAIntSt & LPC_USB->DMAIntEn;
+  if (dma_int_status & DMA_INT_END_OF_XFER_MASK)
+  {
+    uint32_t const eot = LPC_USB->EoTIntSt;
+    LPC_USB->EoTIntClr = eot; // acknowledge interrupt source
+
+    for ( uint8_t ep_id = 2; ep_id < DCD_ENDPOINT_MAX; ep_id++ )
+    {
+      if ( tu_bit_test(eot, ep_id) )
+      {
+        if ( ep_id & 0x01 )
+        {
+          // IN enable EpInt for end of usb transfer
+          LPC_USB->EpIntEn |= TU_BIT(ep_id);
+        }else
+        {
+          // OUT
+          dd_complete_isr(rhport, ep_id);
+        }
+      }
+    }
+  }
+
+  // Errors
+  if ( (dev_int_status & DEV_INT_ERROR_MASK) || (dma_int_status & DMA_INT_ERROR_MASK) )
+  {
+    uint32_t error_status = sie_read(SIE_CMDCODE_READ_ERROR_STATUS);
+    (void) error_status;
+    TU_BREAKPOINT();
+  }
+}
+
+#endif
diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.h b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h
new file mode 100644
index 0000000..07daa32
--- /dev/null
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.h
@@ -0,0 +1,152 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_DCD_LPC17_40_H_
+#define _TUSB_DCD_LPC17_40_H_
+
+#include "common/tusb_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Register Interface
+//--------------------------------------------------------------------+
+
+//------------- USB Interrupt USBIntSt -------------//
+//enum {
+//  DCD_USB_REQ_LOW_PRIO_MASK   = TU_BIT(0),
+//  DCD_USB_REQ_HIGH_PRIO_MASK  = TU_BIT(1),
+//  DCD_USB_REQ_DMA_MASK        = TU_BIT(2),
+//  DCD_USB_REQ_NEED_CLOCK_MASK = TU_BIT(8),
+//  DCD_USB_REQ_ENABLE_MASK     = TU_BIT(31)
+//};
+
+//------------- Device Interrupt USBDevInt -------------//
+enum {
+  DEV_INT_FRAME_MASK              = TU_BIT(0),
+  DEV_INT_ENDPOINT_FAST_MASK      = TU_BIT(1),
+  DEV_INT_ENDPOINT_SLOW_MASK      = TU_BIT(2),
+  DEV_INT_DEVICE_STATUS_MASK      = TU_BIT(3),
+  DEV_INT_COMMAND_CODE_EMPTY_MASK = TU_BIT(4),
+  DEV_INT_COMMAND_DATA_FULL_MASK  = TU_BIT(5),
+  DEV_INT_RX_ENDPOINT_PACKET_MASK = TU_BIT(6),
+  DEV_INT_TX_ENDPOINT_PACKET_MASK = TU_BIT(7),
+  DEV_INT_ENDPOINT_REALIZED_MASK  = TU_BIT(8),
+  DEV_INT_ERROR_MASK              = TU_BIT(9)
+};
+
+//------------- DMA Interrupt USBDMAInt-------------//
+enum {
+  DMA_INT_END_OF_XFER_MASK    = TU_BIT(0),
+  DMA_INT_NEW_DD_REQUEST_MASK = TU_BIT(1),
+  DMA_INT_ERROR_MASK          = TU_BIT(2)
+};
+
+//------------- USBCtrl -------------//
+enum {
+  USBCTRL_READ_ENABLE_MASK  = TU_BIT(0),
+  USBCTRL_WRITE_ENABLE_MASK = TU_BIT(1),
+};
+
+//------------- USBRxPLen -------------//
+enum {
+  USBRXPLEN_PACKET_LENGTH_MASK = (TU_BIT(10)-1),
+  USBRXPLEN_DATA_VALID_MASK    = TU_BIT(10),
+  USBRXPLEN_PACKET_READY_MASK  = TU_BIT(11),
+};
+
+//------------- SIE Command Code -------------//
+typedef enum
+{
+  SIE_CMDPHASE_WRITE   = 1,
+  SIE_CMDPHASE_READ    = 2,
+  SIE_CMDPHASE_COMMAND = 5
+} sie_cmdphase_t;
+
+enum {
+  // device commands
+  SIE_CMDCODE_SET_ADDRESS                     = 0xd0,
+  SIE_CMDCODE_CONFIGURE_DEVICE                = 0xd8,
+  SIE_CMDCODE_SET_MODE                        = 0xf3,
+  SIE_CMDCODE_READ_FRAME_NUMBER               = 0xf5,
+  SIE_CMDCODE_READ_TEST_REGISTER              = 0xfd,
+  SIE_CMDCODE_DEVICE_STATUS                   = 0xfe,
+  SIE_CMDCODE_GET_ERROR                       = 0xff,
+  SIE_CMDCODE_READ_ERROR_STATUS               = 0xfb,
+
+  // endpoint commands
+  SIE_CMDCODE_ENDPOINT_SELECT                 = 0x00, // + endpoint index
+  SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT = 0x40, // + endpoint index, should use USBEpIntClr instead
+  SIE_CMDCODE_ENDPOINT_SET_STATUS             = 0x40, // + endpoint index
+  SIE_CMDCODE_BUFFER_CLEAR                    = 0xf2,
+  SIE_CMDCODE_BUFFER_VALIDATE                 = 0xfa
+};
+
+//------------- SIE Device Status (get/set from SIE_CMDCODE_DEVICE_STATUS) -------------//
+enum {
+  SIE_DEV_STATUS_CONNECT_STATUS_MASK = TU_BIT(0),
+  SIE_DEV_STATUS_CONNECT_CHANGE_MASK = TU_BIT(1),
+  SIE_DEV_STATUS_SUSPEND_MASK        = TU_BIT(2),
+  SIE_DEV_STATUS_SUSPEND_CHANGE_MASK = TU_BIT(3),
+  SIE_DEV_STATUS_RESET_MASK          = TU_BIT(4)
+};
+
+//------------- SIE Select Endpoint Command -------------//
+enum {
+  SIE_SELECT_ENDPOINT_FULL_EMPTY_MASK         = TU_BIT(0), // 0: empty, 1 full. IN endpoint checks empty, OUT endpoint check full
+  SIE_SELECT_ENDPOINT_STALL_MASK              = TU_BIT(1),
+  SIE_SELECT_ENDPOINT_SETUP_RECEIVED_MASK     = TU_BIT(2), // clear by SIE_CMDCODE_ENDPOINT_SELECT_CLEAR_INTERRUPT
+  SIE_SELECT_ENDPOINT_PACKET_OVERWRITTEN_MASK = TU_BIT(3), // previous packet is overwritten by a SETUP packet
+  SIE_SELECT_ENDPOINT_NAK_MASK                = TU_BIT(4), // last packet response is NAK (auto clear by an ACK)
+  SIE_SELECT_ENDPOINT_BUFFER1_FULL_MASK       = TU_BIT(5),
+  SIE_SELECT_ENDPOINT_BUFFER2_FULL_MASK       = TU_BIT(6)
+};
+
+typedef enum
+{
+  SIE_SET_ENDPOINT_STALLED_MASK           = TU_BIT(0),
+  SIE_SET_ENDPOINT_DISABLED_MASK          = TU_BIT(5),
+  SIE_SET_ENDPOINT_RATE_FEEDBACK_MASK     = TU_BIT(6),
+  SIE_SET_ENDPOINT_CONDITION_STALLED_MASK = TU_BIT(7),
+}sie_endpoint_set_status_mask_t;
+
+//------------- DMA Descriptor Status -------------//
+enum {
+  DD_STATUS_NOT_SERVICED = 0,
+  DD_STATUS_BEING_SERVICED,
+  DD_STATUS_NORMAL,
+  DD_STATUS_DATA_UNDERUN, // short packet
+  DD_STATUS_DATA_OVERRUN,
+  DD_STATUS_SYSTEM_ERROR
+};
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
new file mode 100644
index 0000000..1c1faed
--- /dev/null
+++ b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
@@ -0,0 +1,47 @@
+/* 
+ * 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 TUSB_OPT_HOST_ENABLED && \
+    (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
+
+#include "chip.h"
+
+void hcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USB_IRQn);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB_IRQn);
+}
+
+#endif
+
diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
new file mode 100644
index 0000000..1bdf72d
--- /dev/null
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -0,0 +1,543 @@
+/* 
+ * 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"
+
+/* Since 2012 starting with LPC11uxx, NXP start to use common USB Device Controller with code name LPC IP3511
+ * for almost their new MCUs. Currently supported and tested families are
+ * - LPC11U68, LPC11U37
+ * - LPC1347
+ * - LPC51U68
+ * - LPC54114
+ * - LPC55s69
+ */
+#if TUSB_OPT_DEVICE_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 || \
+                                 CFG_TUSB_MCU == OPT_MCU_LPC54XXX || \
+                                 CFG_TUSB_MCU == OPT_MCU_LPC55XX)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13XX || CFG_TUSB_MCU == OPT_MCU_LPC15XX
+  // LPCOpen
+  #include "chip.h"
+#else
+  // SDK
+  #include "fsl_device_registers.h"
+  #define INCLUDE_FSL_DEVICE_REGISTERS
+#endif
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// IP3511 Registers
+//--------------------------------------------------------------------+
+
+typedef struct {
+  __IO uint32_t DEVCMDSTAT;    // Device Command/Status register, offset: 0x0
+  __I  uint32_t INFO;          // Info register, offset: 0x4
+  __IO uint32_t EPLISTSTART;   // EP Command/Status List start address, offset: 0x8
+  __IO uint32_t DATABUFSTART;  // Data buffer start address, offset: 0xC
+  __IO uint32_t LPM;           // Link Power Management register, offset: 0x10
+  __IO uint32_t EPSKIP;        // Endpoint skip, offset: 0x14
+  __IO uint32_t EPINUSE;       // Endpoint Buffer in use, offset: 0x18
+  __IO uint32_t EPBUFCFG;      // Endpoint Buffer Configuration register, offset: 0x1C
+  __IO uint32_t INTSTAT;       // interrupt status register, offset: 0x20
+  __IO uint32_t INTEN;         // interrupt enable register, offset: 0x24
+  __IO uint32_t INTSETSTAT;    // set interrupt status register, offset: 0x28
+       uint8_t RESERVED_0[8];
+  __I  uint32_t EPTOGGLE;      // Endpoint toggle register, offset: 0x34
+} dcd_registers_t;
+
+// 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
+};
+
+enum {
+  INT_SOF_MASK           = TU_BIT(30),
+  INT_DEVICE_STATUS_MASK = TU_BIT(31)
+};
+
+enum {
+  CMDSTAT_DEVICE_ADDR_MASK    = TU_BIT(7 )-1,
+  CMDSTAT_DEVICE_ENABLE_MASK  = TU_BIT(7 ),
+  CMDSTAT_SETUP_RECEIVED_MASK = TU_BIT(8 ),
+  CMDSTAT_DEVICE_CONNECT_MASK = TU_BIT(16), // reflect the soft-connect only, does not reflect the actual attached state
+  CMDSTAT_DEVICE_SUSPEND_MASK = TU_BIT(17),
+                                            // 23-22 is link speed (only available for HighSpeed port)
+  CMDSTAT_CONNECT_CHANGE_MASK = TU_BIT(24),
+  CMDSTAT_SUSPEND_CHANGE_MASK = TU_BIT(25),
+  CMDSTAT_RESET_CHANGE_MASK   = TU_BIT(26),
+  CMDSTAT_VBUS_DEBOUNCED_MASK = TU_BIT(28),
+};
+
+enum {
+  CMDSTAT_SPEED_SHIFT = 22
+};
+
+//--------------------------------------------------------------------+
+// Endpoint Command/Status List
+//--------------------------------------------------------------------+
+
+// Endpoint Command/Status
+typedef union TU_ATTR_PACKED
+{
+  // Full and High speed has different bit layout for buffer_offset and nbytes
+
+  // Buffer (aligned 64) = DATABUFSTART [31:22]  | buffer_offset [21:6]
+  volatile struct {
+    uint32_t offset      : 16;
+    uint32_t nbytes      : 10;
+    uint32_t TU_RESERVED : 6;
+  } buffer_fs;
+
+  // Buffer (aligned 64) = USB_RAM [31:17] | buffer_offset [16:6]
+  volatile struct {
+    uint32_t offset      : 11 ;
+    uint32_t nbytes      : 15 ;
+    uint32_t TU_RESERVED : 6  ;
+  } buffer_hs;
+
+  volatile struct {
+    uint32_t TU_RESERVED  : 26;
+    uint32_t is_iso       : 1 ;
+    uint32_t toggle_mode  : 1 ;
+    uint32_t toggle_reset : 1 ;
+    uint32_t stall        : 1 ;
+    uint32_t disable      : 1 ;
+    uint32_t active       : 1 ;
+  };
+}ep_cmd_sts_t;
+
+TU_VERIFY_STATIC( sizeof(ep_cmd_sts_t) == 4, "size is not correct" );
+
+// Software transfer management
+typedef struct
+{
+  uint16_t total_bytes;
+  uint16_t xferred_bytes;
+
+  uint16_t nbytes;
+
+  // prevent unaligned access on Highspeed port on USB_SRAM
+  uint16_t TU_RESERVED;
+}xfer_dma_t;
+
+// Absolute max of endpoints pairs for all port
+// - 11 13 15 51 54 has 5x2 endpoints
+// - 55 usb0 (FS) has 5x2 endpoints, usb1 (HS) has 6x2 endpoints
+#define MAX_EP_PAIRS  6
+
+// NOTE data will be transferred as soon as dcd get request by dcd_pipe(_queue)_xfer using double buffering.
+// current_td is used to keep track of number of remaining & xferred bytes of the current request.
+typedef struct
+{
+  // 256 byte aligned, 2 for double buffer (not used)
+  // Each cmd_sts can only transfer up to DMA_NBYTES_MAX bytes each
+  ep_cmd_sts_t ep[2*MAX_EP_PAIRS][2];
+  xfer_dma_t dma[2*MAX_EP_PAIRS];
+
+  TU_ATTR_ALIGNED(64) uint8_t setup_packet[8];
+}dcd_data_t;
+
+// EP list must be 256-byte aligned
+//    Some MCU controller may require this variable to be placed in specific SRAM region.
+//    For example: LPC55s69 port1 Highspeed must be USB_RAM (0x40100000)
+//    Use CFG_TUSB_MEM_SECTION to place it accordingly.
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
+
+//--------------------------------------------------------------------+
+// Multiple Controllers
+//--------------------------------------------------------------------+
+
+typedef struct
+{
+  dcd_registers_t* regs;        // registers
+  const tusb_speed_t max_speed; // max link speed
+  const IRQn_Type irqnum;       // IRQ number
+  const uint8_t ep_pairs;       // Max bi-directional Endpoints
+}dcd_controller_t;
+
+#ifdef INCLUDE_FSL_DEVICE_REGISTERS
+
+static const dcd_controller_t _dcd_controller[] =
+{
+    { .regs = (dcd_registers_t*) USB0_BASE  , .max_speed = TUSB_SPEED_FULL, .irqnum = USB0_IRQn, .ep_pairs = FSL_FEATURE_USB_EP_NUM    },
+  #if defined(FSL_FEATURE_SOC_USBHSD_COUNT) && FSL_FEATURE_SOC_USBHSD_COUNT
+    { .regs = (dcd_registers_t*) USBHSD_BASE, .max_speed = TUSB_SPEED_HIGH, .irqnum = USB1_IRQn, .ep_pairs = FSL_FEATURE_USBHSD_EP_NUM }
+  #endif
+};
+
+#else
+
+static const dcd_controller_t _dcd_controller[] =
+{
+  { .regs = (dcd_registers_t*) LPC_USB0_BASE, .max_speed = TUSB_SPEED_FULL, .irqnum = USB0_IRQn, .ep_pairs = 5 },
+};
+
+#endif
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+
+static inline uint16_t get_buf_offset(void const * buffer)
+{
+  uint32_t addr = (uint32_t) buffer;
+  TU_ASSERT( (addr & 0x3f) == 0, 0 );
+  return ( (addr >> 6) & 0xFFFFUL ) ;
+}
+
+static inline uint8_t ep_addr2id(uint8_t ep_addr)
+{
+  return 2*(ep_addr & 0x0F) + ((ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0);
+}
+
+//--------------------------------------------------------------------+
+// CONTROLLER API
+//--------------------------------------------------------------------+
+void dcd_init(uint8_t rhport)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+
+  dcd_reg->EPLISTSTART  = (uint32_t) _dcd.ep;
+  dcd_reg->DATABUFSTART = tu_align((uint32_t) &_dcd, TU_BIT(22)); // 22-bit alignment
+  dcd_reg->INTSTAT     |= dcd_reg->INTSTAT; // clear all pending interrupt
+  dcd_reg->INTEN        = INT_DEVICE_STATUS_MASK;
+  dcd_reg->DEVCMDSTAT  |= CMDSTAT_DEVICE_ENABLE_MASK | CMDSTAT_DEVICE_CONNECT_MASK |
+                           CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
+
+  NVIC_ClearPendingIRQ(_dcd_controller[rhport].irqnum);
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  NVIC_EnableIRQ(_dcd_controller[rhport].irqnum);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  NVIC_DisableIRQ(_dcd_controller[rhport].irqnum);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+
+  // Response with status first before changing device address
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+
+  dcd_reg->DEVCMDSTAT &= ~CMDSTAT_DEVICE_ADDR_MASK;
+  dcd_reg->DEVCMDSTAT |= dev_addr;
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  dcd_reg->DEVCMDSTAT |= CMDSTAT_DEVICE_CONNECT_MASK;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  dcd_reg->DEVCMDSTAT &= ~CMDSTAT_DEVICE_CONNECT_MASK;
+}
+
+//--------------------------------------------------------------------+
+// DCD Endpoint Port
+//--------------------------------------------------------------------+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  // TODO cannot able to STALL Control OUT endpoint !!!!! FIXME try some walk-around
+  uint8_t const ep_id = ep_addr2id(ep_addr);
+  _dcd.ep[ep_id][0].stall = 1;
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  uint8_t const ep_id = ep_addr2id(ep_addr);
+
+  _dcd.ep[ep_id][0].stall        = 0;
+  _dcd.ep[ep_id][0].toggle_reset = 1;
+  _dcd.ep[ep_id][0].toggle_mode  = 0;
+}
+
+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));
+  _dcd.ep[ep_id][0].is_iso = (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
+
+  // Enable EP interrupt
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  dcd_reg->INTEN |= TU_BIT(ep_id);
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+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 prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes)
+{
+  uint16_t nbytes;
+
+  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);
+    _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);
+    _dcd.ep[ep_id][0].buffer_hs.offset = buf_offset;
+    _dcd.ep[ep_id][0].buffer_hs.nbytes = nbytes;
+  }
+
+  _dcd.dma[ep_id].nbytes = nbytes;
+
+  _dcd.ep[ep_id][0].active = 1;
+}
+
+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;
+
+  prepare_ep_xfer(rhport, ep_id, get_buf_offset(buffer), total_bytes);
+
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// IRQ
+//--------------------------------------------------------------------+
+static void bus_reset(uint8_t rhport)
+{
+  tu_memclr(&_dcd, sizeof(dcd_data_t));
+
+  // disable all non-control endpoints on bus reset
+  for(uint8_t ep_id = 2; 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;
+  dcd_reg->EPBUFCFG     = 0;
+  dcd_reg->EPSKIP       = 0xFFFFFFFF;
+
+  dcd_reg->INTSTAT      = dcd_reg->INTSTAT;                               // clear all pending interrupt
+  dcd_reg->DEVCMDSTAT  |= CMDSTAT_SETUP_RECEIVED_MASK;                    // clear setup received interrupt
+  dcd_reg->INTEN        = INT_DEVICE_STATUS_MASK | TU_BIT(0) | TU_BIT(1); // enable device status & control endpoints
+}
+
+static void process_xfer_isr(uint8_t rhport, uint32_t int_status)
+{
+  uint8_t const max_ep = 2*_dcd_controller[rhport].ep_pairs;
+
+  for(uint8_t ep_id = 0; ep_id < max_ep; ep_id++ )
+  {
+    if ( tu_bit_test(int_status, ep_id) )
+    {
+      ep_cmd_sts_t * ep_cs = &_dcd.ep[ep_id][0];
+      xfer_dma_t* xfer_dma = &_dcd.dma[ep_id];
+
+      if ( ep_id == 0 || ep_id == 1)
+      {
+        // For control endpoint, we need to manually clear Active bit
+        ep_cs->active = 0;
+      }
+
+      uint16_t buf_offset;
+      uint16_t buf_nbytes;
+
+      if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL)
+      {
+        buf_offset = ep_cs->buffer_fs.offset;
+        buf_nbytes = ep_cs->buffer_fs.nbytes;
+      }else
+      {
+        buf_offset = ep_cs->buffer_hs.offset;
+        buf_nbytes = ep_cs->buffer_hs.nbytes;
+      }
+
+      xfer_dma->xferred_bytes += xfer_dma->nbytes - buf_nbytes;
+
+      if ( (buf_nbytes == 0) && (xfer_dma->total_bytes > xfer_dma->xferred_bytes) )
+      {
+        // There is more data to transfer
+        // buff_offset has been already increased by hw to correct value for next transfer
+        prepare_ep_xfer(rhport, ep_id, buf_offset, xfer_dma->total_bytes - xfer_dma->xferred_bytes);
+      }
+      else
+      {
+        // for detecting ZLP
+        xfer_dma->total_bytes = xfer_dma->xferred_bytes;
+
+        uint8_t const ep_addr = tu_edpt_addr(ep_id / 2, ep_id & 0x01);
+
+        // TODO no way determine if the transfer is failed or not
+        dcd_event_xfer_complete(rhport, ep_addr, xfer_dma->xferred_bytes, XFER_RESULT_SUCCESS, true);
+      }
+    }
+  }
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+
+  uint32_t const cmd_stat = dcd_reg->DEVCMDSTAT;
+
+  uint32_t int_status = dcd_reg->INTSTAT & dcd_reg->INTEN;
+  dcd_reg->INTSTAT = int_status; // Acknowledge handled interrupt
+
+  if (int_status == 0) return;
+
+  //------------- Device Status -------------//
+  if ( int_status & INT_DEVICE_STATUS_MASK )
+  {
+    dcd_reg->DEVCMDSTAT |= CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
+
+    if ( cmd_stat & CMDSTAT_RESET_CHANGE_MASK) // bus reset
+    {
+      bus_reset(rhport);
+
+      tusb_speed_t speed = TUSB_SPEED_FULL;
+
+      if (_dcd_controller[rhport].max_speed == TUSB_SPEED_HIGH)
+      {
+        // 0 : reserved, 1 : full, 2 : high, 3: super
+        if ( 2 == ((cmd_stat >> CMDSTAT_SPEED_SHIFT) & 0x3UL) )
+        {
+          speed= TUSB_SPEED_HIGH;
+        }
+      }
+
+      dcd_event_bus_reset(rhport, speed, true);
+    }
+
+    if (cmd_stat & CMDSTAT_CONNECT_CHANGE_MASK)
+    {
+      // device disconnect
+      if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
+      {
+        // debouncing as this can be set when device is powering
+        dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+      }
+    }
+
+    // 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);
+        }
+      }
+    }
+//        else
+//      { // resume signal
+//    dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+//      }
+//    }
+  }
+
+  // Setup Receive
+  if ( tu_bit_test(int_status, 0) && (cmd_stat & CMDSTAT_SETUP_RECEIVED_MASK) )
+  {
+    // Follow UM flowchart to clear Active & Stall on both Control IN/OUT endpoints
+    _dcd.ep[0][0].active = _dcd.ep[1][0].active = 0;
+    _dcd.ep[0][0].stall = _dcd.ep[1][0].stall = 0;
+
+    dcd_reg->DEVCMDSTAT |= CMDSTAT_SETUP_RECEIVED_MASK;
+
+    dcd_event_setup_received(rhport, _dcd.setup_packet, true);
+
+    // keep waiting for next setup
+    prepare_setup_packet(rhport);
+
+    // clear bit0
+    int_status = tu_bit_clear(int_status, 0);
+  }
+
+  // Endpoint transfer complete interrupt
+  process_xfer_isr(rhport, int_status);
+}
+
+#endif
+
diff --git a/src/portable/nxp/transdimension/common_transdimension.h b/src/portable/nxp/transdimension/common_transdimension.h
new file mode 100644
index 0000000..69074de
--- /dev/null
+++ b/src/portable/nxp/transdimension/common_transdimension.h
@@ -0,0 +1,136 @@
+/* 
+ * 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 COMMON_TRANSDIMENSION_H_
+#define COMMON_TRANSDIMENSION_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-------------//
+  __I  uint32_t TU_RESERVED[64]; ///< For iMX RT10xx, but not used by LPC18XX/LPC43XX
+
+  //------------- Capability Registers-------------//
+  __I  uint8_t  CAPLENGTH;       ///< Capability Registers Length
+  __I  uint8_t  TU_RESERVED[1];
+  __I  uint16_t HCIVERSION;      ///< Host Controller Interface Version
+
+  __I  uint32_t HCSPARAMS;       ///< Host Controller Structural Parameters
+  __I  uint32_t HCCPARAMS;       ///< Host Controller Capability Parameters
+  __I  uint32_t TU_RESERVED[5];
+
+  __I  uint16_t DCIVERSION;      ///< Device Controller Interface Version
+  __I  uint8_t  TU_RESERVED[2];
+
+  __I  uint32_t DCCPARAMS;       ///< Device Controller Capability Parameters
+  __I  uint32_t TU_RESERVED[6];
+
+  //------------- Operational Registers -------------//
+  __IO uint32_t USBCMD;          ///< USB Command Register
+  __IO uint32_t USBSTS;          ///< USB Status Register
+  __IO uint32_t USBINTR;         ///< Interrupt Enable Register
+  __IO uint32_t FRINDEX;         ///< USB Frame Index
+  __I  uint32_t TU_RESERVED;
+  __IO uint32_t DEVICEADDR;      ///< Device Address
+  __IO uint32_t ENDPTLISTADDR;   ///< Endpoint List Address
+  __I  uint32_t TU_RESERVED;
+  __IO uint32_t BURSTSIZE;       ///< Programmable Burst Size
+  __IO uint32_t TXFILLTUNING;    ///< TX FIFO Fill Tuning
+       uint32_t TU_RESERVED[4];
+  __IO uint32_t ENDPTNAK;        ///< Endpoint NAK
+  __IO uint32_t ENDPTNAKEN;      ///< Endpoint NAK Enable
+  __I  uint32_t TU_RESERVED;
+  __IO uint32_t PORTSC1;         ///< Port Status & Control
+  __I  uint32_t TU_RESERVED[7];
+  __IO uint32_t OTGSC;           ///< On-The-Go Status & control
+  __IO uint32_t USBMODE;         ///< USB Device Mode
+  __IO uint32_t ENDPTSETUPSTAT;  ///< Endpoint Setup Status
+  __IO uint32_t ENDPTPRIME;      ///< Endpoint Prime
+  __IO uint32_t ENDPTFLUSH;      ///< Endpoint Flush
+  __I  uint32_t ENDPTSTAT;       ///< Endpoint Status
+  __IO uint32_t ENDPTCOMPLETE;   ///< Endpoint Complete
+  __IO uint32_t ENDPTCTRL[8];    ///< Endpoint Control 0 - 7
+} dcd_registers_t, hcd_registers_t;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* COMMON_TRANSDIMENSION_H_ */
diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c
new file mode 100644
index 0000000..f643329
--- /dev/null
+++ b/src/portable/nxp/transdimension/dcd_transdimension.c
@@ -0,0 +1,664 @@
+/*
+ * 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 TUSB_OPT_DEVICE_ENABLED && \
+    (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
+
+#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
+  #include "fsl_device_registers.h"
+  #define INCLUDE_FSL_DEVICE_REGISTERS
+#else
+  // LPCOpen for 18xx & 43xx
+  #include "chip.h"
+#endif
+
+#include "common/tusb_common.h"
+#include "device/dcd.h"
+#include "common_transdimension.h"
+
+#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
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+// 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
+//--------------------------------------------------------------------+
+
+typedef struct
+{
+  dcd_registers_t* regs;  // registers
+  const IRQn_Type irqnum; // IRQ number
+  const uint8_t ep_count; // Max bi-directional Endpoints
+}dcd_controller_t;
+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+  static const dcd_controller_t _dcd_controller[] =
+  {
+    // RT1010 and RT1020 only has 1 USB controller
+    #if FSL_FEATURE_SOC_USBHS_COUNT == 1
+      { .regs = (dcd_registers_t*) USB_BASE , .irqnum = USB_OTG1_IRQn, .ep_count = 8 }
+    #else
+      { .regs = (dcd_registers_t*) USB1_BASE, .irqnum = USB_OTG1_IRQn, .ep_count = 8 },
+      { .regs = (dcd_registers_t*) USB2_BASE, .irqnum = USB_OTG2_IRQn, .ep_count = 8 }
+    #endif
+  };
+
+#else
+  static const dcd_controller_t _dcd_controller[] =
+  {
+    { .regs = (dcd_registers_t*) LPC_USB0_BASE, .irqnum = USB0_IRQn, .ep_count = 6 },
+    { .regs = (dcd_registers_t*) LPC_USB1_BASE, .irqnum = USB1_IRQn, .ep_count = 4 }
+  };
+#endif
+
+#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[DCD_ATTR_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
+  dcd_qtd_t qtd[DCD_ATTR_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)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+
+  // 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 < _dcd_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));
+
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+
+  // 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)
+{
+  NVIC_EnableIRQ(_dcd_controller[rhport].irqnum);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  NVIC_DisableIRQ(_dcd_controller[rhport].irqnum);
+}
+
+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);
+
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  dcd_reg->PORTSC1 |= PORTSC1_FORCE_PORT_RESUME;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  dcd_reg->USBCMD |= USBCMD_RUN_STOP;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  dcd_reg->USBCMD &= ~USBCMD_RUN_STOP;
+}
+
+//--------------------------------------------------------------------+
+// 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);
+
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  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
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  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 < _dcd_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
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+
+  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)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+
+  // Disable all non-control endpoints
+  for( uint8_t epnum=1; epnum < _dcd_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);
+
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+
+  _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)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+  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 )
+  {
+    dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+    // 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)
+{
+  dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
+
+  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 < DCD_ATTR_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/nxp/transdimension/hcd_transdimension.c b/src/portable/nxp/transdimension/hcd_transdimension.c
new file mode 100644
index 0000000..81ad315
--- /dev/null
+++ b/src/portable/nxp/transdimension/hcd_transdimension.c
@@ -0,0 +1,119 @@
+/* 
+ * 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"
+
+// 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)
+
+#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
+  #include "fsl_device_registers.h"
+#else
+  // LPCOpen for 18xx & 43xx
+  #include "chip.h"
+#endif
+
+#include "common/tusb_common.h"
+#include "common_transdimension.h"
+#include "portable/ehci/ehci_api.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+
+// TODO can be merged with dcd_controller_t
+typedef struct
+{
+  uint32_t regs_base;     // registers base
+  const IRQn_Type irqnum; // IRQ number
+}hcd_controller_t;
+
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+  static const hcd_controller_t _hcd_controller[] =
+  {
+    // RT1010 and RT1020 only has 1 USB controller
+    #if FSL_FEATURE_SOC_USBHS_COUNT == 1
+      { .regs_base = USB_BASE , .irqnum = USB_OTG1_IRQn }
+    #else
+      { .regs_base = USB1_BASE, .irqnum = USB_OTG1_IRQn },
+      { .regs_base = USB2_BASE, .irqnum = USB_OTG2_IRQn }
+    #endif
+  };
+
+#else
+  static const hcd_controller_t _hcd_controller[] =
+  {
+    { .regs_base = LPC_USB0_BASE, .irqnum = USB0_IRQn },
+    { .regs_base = LPC_USB1_BASE, .irqnum = USB1_IRQn }
+  };
+#endif
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+bool hcd_init(uint8_t rhport)
+{
+  hcd_registers_t* hcd_reg = (hcd_registers_t*) _hcd_controller[rhport].regs_base;
+
+  // 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)
+{
+  NVIC_EnableIRQ(_hcd_controller[rhport].irqnum);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+  NVIC_DisableIRQ(_hcd_controller[rhport].irqnum);
+}
+
+#endif
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
new file mode 100644
index 0000000..daa8075
--- /dev/null
+++ b/src/portable/ohci/ohci.c
@@ -0,0 +1,657 @@
+/* 
+ * 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 "host/hcd_attr.h"
+
+#if TUSB_OPT_HOST_ENABLED && defined(HCD_ATTR_OHCI)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "osal/osal.h"
+
+#include "host/hcd.h"
+#include "ohci.h"
+
+// TODO remove
+#include "chip.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+#define OHCI_REG               ((ohci_registers_t *) LPC_USB_BASE)
+
+enum {
+  OHCI_CONTROL_FUNCSTATE_RESET = 0,
+  OHCI_CONTROL_FUNCSTATE_RESUME,
+  OHCI_CONTROL_FUNCSTATE_OPERATIONAL,
+  OHCI_CONTROL_FUNCSTATE_SUSPEND
+};
+
+enum {
+  OHCI_CONTROL_CONTROL_BULK_RATIO           = 3, ///< This specifies the service ratio between Control and Bulk EDs. 0 = 1:1, 3 = 4:1
+  OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK    = TU_BIT(2),
+  OHCI_CONTROL_LIST_ISOCHRONOUS_ENABLE_MASK = TU_BIT(3),
+  OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK     = TU_BIT(4),
+  OHCI_CONTROL_LIST_BULK_ENABLE_MASK        = TU_BIT(5),
+};
+
+enum {
+  OHCI_FMINTERVAL_FI    = 0x2EDF, // 7.3.1 nominal (reset) value
+  OHCI_FMINTERVAL_FSMPS = (6*(OHCI_FMINTERVAL_FI-210)) / 7, // 5.4 calculated based on maximum overhead + bit stuffing
+};
+
+enum {
+  OHCI_PERIODIC_START = 0x3E67
+};
+
+enum {
+  OHCI_INT_SCHEDULING_OVERUN_MASK    = TU_BIT(0),
+  OHCI_INT_WRITEBACK_DONEHEAD_MASK   = TU_BIT(1),
+  OHCI_INT_SOF_MASK                  = TU_BIT(2),
+  OHCI_INT_RESUME_DETECTED_MASK      = TU_BIT(3),
+  OHCI_INT_UNRECOVERABLE_ERROR_MASK  = TU_BIT(4),
+  OHCI_INT_FRAME_OVERFLOW_MASK       = TU_BIT(5),
+  OHCI_INT_RHPORT_STATUS_CHANGE_MASK = TU_BIT(6),
+
+  OHCI_INT_OWNERSHIP_CHANGE_MASK     = TU_BIT(30),
+  OHCI_INT_MASTER_ENABLE_MASK        = TU_BIT(31),
+};
+
+enum {
+  RHPORT_CURRENT_CONNECT_STATUS_MASK      = TU_BIT(0),
+  RHPORT_PORT_ENABLE_STATUS_MASK          = TU_BIT(1),
+  RHPORT_PORT_SUSPEND_STATUS_MASK         = TU_BIT(2),
+  RHPORT_PORT_OVER_CURRENT_INDICATOR_MASK = TU_BIT(3),
+  RHPORT_PORT_RESET_STATUS_MASK           = TU_BIT(4), ///< write '1' to reset port
+
+  RHPORT_PORT_POWER_STATUS_MASK           = TU_BIT(8),
+  RHPORT_LOW_SPEED_DEVICE_ATTACHED_MASK   = TU_BIT(9),
+
+  RHPORT_CONNECT_STATUS_CHANGE_MASK       = TU_BIT(16),
+  RHPORT_PORT_ENABLE_CHANGE_MASK          = TU_BIT(17),
+  RHPORT_PORT_SUSPEND_CHANGE_MASK         = TU_BIT(18),
+  RHPORT_OVER_CURRENT_CHANGE_MASK         = TU_BIT(19),
+  RHPORT_PORT_RESET_CHANGE_MASK           = TU_BIT(20),
+
+  RHPORT_ALL_CHANGE_MASK = RHPORT_CONNECT_STATUS_CHANGE_MASK | RHPORT_PORT_ENABLE_CHANGE_MASK |
+    RHPORT_PORT_SUSPEND_CHANGE_MASK | RHPORT_OVER_CURRENT_CHANGE_MASK | RHPORT_PORT_RESET_CHANGE_MASK
+};
+
+enum {
+  OHCI_CCODE_NO_ERROR              = 0,
+  OHCI_CCODE_CRC                   = 1,
+	OHCI_CCODE_BIT_STUFFING          = 2,
+	OHCI_CCODE_DATA_TOGGLE_MISMATCH  = 3,
+	OHCI_CCODE_STALL                 = 4,
+	OHCI_CCODE_DEVICE_NOT_RESPONDING = 5,
+	OHCI_CCODE_PID_CHECK_FAILURE     = 6,
+	OHCI_CCODE_UNEXPECTED_PID        = 7,
+	OHCI_CCODE_DATA_OVERRUN          = 8,
+	OHCI_CCODE_DATA_UNDERRUN         = 9,
+	OHCI_CCODE_BUFFER_OVERRUN        = 12,
+	OHCI_CCODE_BUFFER_UNDERRUN       = 13,
+	OHCI_CCODE_NOT_ACCESSED          = 14,
+};
+
+enum {
+  OHCI_INT_ON_COMPLETE_YES = 0,
+  OHCI_INT_ON_COMPLETE_NO  = TU_BIN8(111)
+};
+
+enum {
+  GTD_DT_TOGGLE_CARRY = 0,
+  GTD_DT_DATA0 = TU_BIT(1) | 0,
+  GTD_DT_DATA1 = TU_BIT(1) | 1,
+};
+
+enum {
+  PID_SETUP = 0,
+  PID_OUT,
+  PID_IN,
+};
+
+enum {
+  PID_FROM_TD = 0,
+};
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static ohci_data_t ohci_data;
+
+static ohci_ed_t * const p_ed_head[] =
+{
+    [TUSB_XFER_CONTROL]     = &ohci_data.control[0].ed,
+    [TUSB_XFER_BULK   ]     = &ohci_data.bulk_head_ed,
+    [TUSB_XFER_INTERRUPT]   = &ohci_data.period_head_ed,
+    [TUSB_XFER_ISOCHRONOUS] = NULL // TODO Isochronous
+};
+
+static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed);
+static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr);
+
+//--------------------------------------------------------------------+
+// USBH-HCD API
+//--------------------------------------------------------------------+
+// Initialization according to 5.1.1.4
+bool hcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  //------------- Data Structure init -------------//
+  tu_memclr(&ohci_data, sizeof(ohci_data_t));
+  for(uint8_t i=0; i<32; i++)
+  { // assign all interrupt pointes to period head ed
+    ohci_data.hcca.interrupt_table[i] = (uint32_t) &ohci_data.period_head_ed;
+  }
+
+  ohci_data.control[0].ed.skip  = 1;
+  ohci_data.bulk_head_ed.skip   = 1;
+  ohci_data.period_head_ed.skip = 1;
+
+  // reset controller
+  OHCI_REG->command_status_bit.controller_reset = 1;
+  while( OHCI_REG->command_status_bit.controller_reset ) {} // should not take longer than 10 us
+
+  //------------- init ohci registers -------------//
+  OHCI_REG->control_head_ed = (uint32_t) &ohci_data.control[0].ed;
+  OHCI_REG->bulk_head_ed    = (uint32_t) &ohci_data.bulk_head_ed;
+  OHCI_REG->hcca            = (uint32_t) &ohci_data.hcca;
+
+  OHCI_REG->interrupt_disable = OHCI_REG->interrupt_enable; // disable all interrupts
+  OHCI_REG->interrupt_status  = OHCI_REG->interrupt_status; // clear current set bits
+  OHCI_REG->interrupt_enable  = OHCI_INT_WRITEBACK_DONEHEAD_MASK | OHCI_INT_RESUME_DETECTED_MASK |
+      OHCI_INT_UNRECOVERABLE_ERROR_MASK | OHCI_INT_FRAME_OVERFLOW_MASK | OHCI_INT_RHPORT_STATUS_CHANGE_MASK |
+      OHCI_INT_MASTER_ENABLE_MASK;
+
+  OHCI_REG->control |= OHCI_CONTROL_CONTROL_BULK_RATIO | OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK |
+       OHCI_CONTROL_LIST_BULK_ENABLE_MASK | OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK; // TODO Isochronous
+
+  OHCI_REG->frame_interval = (OHCI_FMINTERVAL_FSMPS << 16) | OHCI_FMINTERVAL_FI;
+  OHCI_REG->periodic_start = (OHCI_FMINTERVAL_FI * 9) / 10; // Periodic start is 90% of frame interval
+
+  OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power)
+  OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports
+
+  return true;
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+  (void) rhport;
+  return (ohci_data.frame_number_hi << 16) | OHCI_REG->frame_number;
+}
+
+
+//--------------------------------------------------------------------+
+// PORT API
+//--------------------------------------------------------------------+
+void hcd_port_reset(uint8_t hostid)
+{
+  (void) hostid;
+  OHCI_REG->rhport_status[0] = RHPORT_PORT_RESET_STATUS_MASK;
+}
+
+bool hcd_port_connect_status(uint8_t hostid)
+{
+  (void) hostid;
+  return OHCI_REG->rhport_status_bit[0].current_connect_status;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t hostid)
+{
+  (void) hostid;
+  return OHCI_REG->rhport_status_bit[0].low_speed_device_attached ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
+}
+
+// endpoints are tied to an address, which only reclaim after a long delay when enumerating
+// thus there is no need to make sure ED is not in HC's cahed as it will not for sure
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+  // TODO OHCI
+  (void) rhport;
+
+  // addr0 serves as static head --> only set skip bit
+  if ( dev_addr == 0 )
+  {
+    ohci_data.control[0].ed.skip = 1;
+  }else
+  {
+    // remove control
+    ed_list_remove_by_addr( p_ed_head[TUSB_XFER_CONTROL], dev_addr);
+
+    // remove bulk
+    ed_list_remove_by_addr(p_ed_head[TUSB_XFER_BULK], dev_addr);
+
+    // remove interrupt
+    ed_list_remove_by_addr(p_ed_head[TUSB_XFER_INTERRUPT], dev_addr);
+
+    // TODO remove ISO
+  }
+}
+
+//--------------------------------------------------------------------+
+// Controller API
+//--------------------------------------------------------------------+
+
+//--------------------------------------------------------------------+
+// List Helper
+//--------------------------------------------------------------------+
+static inline tusb_xfer_type_t ed_get_xfer_type(ohci_ed_t const * const p_ed)
+{
+  return (p_ed->ep_number == 0   ) ? TUSB_XFER_CONTROL     :
+         (p_ed->is_iso           ) ? TUSB_XFER_ISOCHRONOUS :
+         (p_ed->is_interrupt_xfer) ? TUSB_XFER_INTERRUPT   : TUSB_XFER_BULK;
+}
+
+static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t ep_addr, uint8_t xfer_type, uint8_t interval)
+{
+  (void) interval;
+
+  // address 0 is used as async head, which always on the list --> cannot be cleared
+  if (dev_addr != 0)
+  {
+    tu_memclr(p_ed, sizeof(ohci_ed_t));
+  }
+
+  hcd_devtree_info_t devtree_info;
+  hcd_devtree_get_info(dev_addr, &devtree_info);
+
+  p_ed->dev_addr          = dev_addr;
+  p_ed->ep_number         = ep_addr & 0x0F;
+  p_ed->pid               = (xfer_type == TUSB_XFER_CONTROL) ? PID_FROM_TD : (tu_edpt_dir(ep_addr) ? PID_IN : PID_OUT);
+  p_ed->speed             = devtree_info.speed;
+  p_ed->is_iso            = (xfer_type == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
+  p_ed->max_packet_size   = ep_size;
+
+  p_ed->used              = 1;
+  p_ed->is_interrupt_xfer = (xfer_type == TUSB_XFER_INTERRUPT ? 1 : 0);
+}
+
+static void gtd_init(ohci_gtd_t* p_td, uint8_t* data_ptr, uint16_t total_bytes)
+{
+  tu_memclr(p_td, sizeof(ohci_gtd_t));
+
+  p_td->used                   = 1;
+  p_td->expected_bytes         = total_bytes;
+
+  p_td->buffer_rounding        = 1; // less than queued length is not a error
+  p_td->delay_interrupt        = OHCI_INT_ON_COMPLETE_NO;
+  p_td->condition_code         = OHCI_CCODE_NOT_ACCESSED;
+
+  p_td->current_buffer_pointer = data_ptr;
+  p_td->buffer_end             = total_bytes ? (data_ptr + total_bytes-1) : data_ptr;
+}
+
+static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
+{
+  if ( tu_edpt_number(ep_addr) == 0 ) return &ohci_data.control[dev_addr].ed;
+
+  ohci_ed_t* ed_pool = ohci_data.ed_pool;
+
+  for(uint32_t i=0; i<HCD_MAX_ENDPOINT; 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) )
+    {
+      return &ed_pool[i];
+    }
+  }
+
+  return NULL;
+}
+
+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++)
+  {
+    if ( !ed_pool[i].used ) return &ed_pool[i];
+  }
+
+  return NULL;
+}
+
+static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed)
+{
+  p_ed->next = p_pre->next;
+  p_pre->next = (uint32_t) p_ed;
+}
+
+static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr)
+{
+  ohci_ed_t* p_prev = p_head;
+
+  while( p_prev->next )
+  {
+    ohci_ed_t* ed = (ohci_ed_t*) p_prev->next;
+
+    if (ed->dev_addr == dev_addr)
+    {
+      // unlink ed
+      p_prev->next = ed->next;
+
+      // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED
+      ed->next = (uint32_t) p_head;
+      ed->used = 0;
+    }
+
+    // check next valid since we could remove it
+    if (p_prev->next) p_prev = (ohci_ed_t*) p_prev->next;
+  }
+}
+
+static ohci_gtd_t * gtd_find_free(void)
+{
+  for(uint8_t i=0; i < HCD_MAX_XFER; i++)
+  {
+    if ( !ohci_data.gtd_pool[i].used ) return &ohci_data.gtd_pool[i];
+  }
+
+  return NULL;
+}
+
+static void td_insert_to_ed(ohci_ed_t* p_ed, ohci_gtd_t * p_gtd)
+{
+  // tail is always NULL
+  if ( tu_align16(p_ed->td_head.address) == 0 )
+  { // TD queue is empty --> head = TD
+    p_ed->td_head.address |= (uint32_t) p_gtd;
+  }
+  else
+  { // TODO currently only support queue up to 2 TD each endpoint at a time
+    ((ohci_gtd_t*) tu_align16(p_ed->td_head.address))->next = (uint32_t) p_gtd;
+  }
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+  (void) rhport;
+
+  // TODO iso support
+  TU_ASSERT(ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
+
+  //------------- Prepare Queue Head -------------//
+  ohci_ed_t * p_ed;
+
+  if ( ep_desc->bEndpointAddress == 0 )
+  {
+    p_ed = &ohci_data.control[dev_addr].ed;
+  }else
+  {
+    p_ed = ed_find_free();
+  }
+  TU_ASSERT(p_ed);
+
+  ed_init( p_ed, dev_addr, tu_edpt_packet_size(ep_desc), ep_desc->bEndpointAddress,
+            ep_desc->bmAttributes.xfer, ep_desc->bInterval );
+
+  // control of dev0 is used as static async head
+  if ( dev_addr == 0 )
+  {
+    p_ed->skip = 0; // only need to clear skip bit
+    return true;
+  }
+
+  ed_list_insert( p_ed_head[ep_desc->bmAttributes.xfer], p_ed );
+
+  return true;
+}
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+  (void) rhport;
+
+  ohci_ed_t* ed   = &ohci_data.control[dev_addr].ed;
+  ohci_gtd_t *qtd = &ohci_data.control[dev_addr].gtd;
+
+  gtd_init(qtd, (uint8_t*) setup_packet, 8);
+  qtd->index           = dev_addr;
+  qtd->pid             = PID_SETUP;
+  qtd->data_toggle     = GTD_DT_DATA0;
+  qtd->delay_interrupt = 0;
+
+  //------------- Attach TDs list to Control Endpoint -------------//
+  ed->td_head.address = (uint32_t) qtd;
+
+  OHCI_REG->command_status_bit.control_list_filled = 1;
+
+  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;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  if ( epnum == 0 )
+  {
+    ohci_ed_t*  ed  = &ohci_data.control[dev_addr].ed;
+    ohci_gtd_t* gtd = &ohci_data.control[dev_addr].gtd;
+
+    gtd_init(gtd, buffer, buflen);
+
+    gtd->index           = dev_addr;
+    gtd->pid             = dir ? PID_IN : PID_OUT;
+    gtd->data_toggle     = GTD_DT_DATA1; // Both Data and Ack stage start with DATA1
+    gtd->delay_interrupt = 0;
+
+    ed->td_head.address = (uint32_t) gtd;
+
+    OHCI_REG->command_status_bit.control_list_filled = 1;
+  }else
+  {
+    ohci_ed_t * ed = ed_from_addr(dev_addr, ep_addr);
+    ohci_gtd_t* gtd = gtd_find_free();
+
+    TU_ASSERT(gtd);
+
+    gtd_init(gtd, buffer, buflen);
+    gtd->index = ed-ohci_data.ed_pool;
+    gtd->delay_interrupt = 0;
+
+    td_insert_to_ed(ed, gtd);
+
+    tusb_xfer_type_t xfer_type = ed_get_xfer_type( ed_from_addr(dev_addr, ep_addr) );
+    if (TUSB_XFER_BULK == xfer_type) OHCI_REG->command_status_bit.bulk_list_filled = 1;
+  }
+
+  return true;
+}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+  ohci_ed_t * const p_ed = ed_from_addr(dev_addr, ep_addr);
+
+  p_ed->is_stalled = 0;
+  p_ed->td_tail    &= 0x0Ful; // set tail pointer back to NULL
+
+  p_ed->td_head.toggle = 0; // reset data toggle
+  p_ed->td_head.halted = 0;
+
+  if ( TUSB_XFER_BULK == ed_get_xfer_type(p_ed) ) OHCI_REG->command_status_bit.bulk_list_filled = 1;
+
+  return true;
+}
+
+
+//--------------------------------------------------------------------+
+// OHCI Interrupt Handler
+//--------------------------------------------------------------------+
+static ohci_td_item_t* list_reverse(ohci_td_item_t* td_head)
+{
+  ohci_td_item_t* td_reverse_head = NULL;
+
+  while(td_head != NULL)
+  {
+    uint32_t next = td_head->next;
+
+    // make current's item become reverse's first item
+    td_head->next = (uint32_t) td_reverse_head;
+    td_reverse_head  = td_head;
+
+    td_head = (ohci_td_item_t*) next; // advance to next item
+  }
+
+  return td_reverse_head;
+}
+
+static inline bool gtd_is_control(ohci_gtd_t const * const p_qtd)
+{
+  return ((uint32_t) p_qtd) < ((uint32_t) ohci_data.gtd_pool); // check ohci_data_t for memory layout
+}
+
+static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd)
+{
+  if ( gtd_is_control(p_qtd) )
+  {
+    return &ohci_data.control[p_qtd->index].ed;
+  }else
+  {
+    return &ohci_data.ed_pool[p_qtd->index];
+  }
+}
+
+static inline uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer)
+{
+  // 5.2.9 OHCI sample code
+
+  // CBP is 0 mean all data is transferred
+  if (current_buffer == 0) return 0;
+
+  return (tu_align4k(buffer_end ^ current_buffer) ? 0x1000 : 0) +
+      tu_offset4k(buffer_end) - tu_offset4k(current_buffer) + 1;
+}
+
+static void done_queue_isr(uint8_t hostid)
+{
+  (void) hostid;
+
+  // done head is written in reversed order of completion --> need to reverse the done queue first
+  ohci_td_item_t* td_head = list_reverse ( (ohci_td_item_t*) tu_align16(ohci_data.hcca.done_head) );
+
+  while( td_head != NULL )
+  {
+    // TODO check if td_head is iso td
+    //------------- Non ISO transfer -------------//
+    ohci_gtd_t * const qtd = (ohci_gtd_t *) td_head;
+    xfer_result_t const event = (qtd->condition_code == OHCI_CCODE_NO_ERROR) ? XFER_RESULT_SUCCESS :
+                                (qtd->condition_code == OHCI_CCODE_STALL) ? XFER_RESULT_STALLED : XFER_RESULT_FAILED;
+
+    qtd->used = 0; // free TD
+    if ( (qtd->delay_interrupt == OHCI_INT_ON_COMPLETE_YES) || (event != XFER_RESULT_SUCCESS) )
+    {
+      ohci_ed_t * const ed  = gtd_get_ed(qtd);
+
+      uint32_t const xferred_bytes = qtd->expected_bytes - gtd_xfer_byte_left((uint32_t) qtd->buffer_end, (uint32_t) qtd->current_buffer_pointer);
+
+      // NOTE Assuming the current list is BULK and there is no other EDs in the list has queued TDs.
+      // When there is a error resulting this ED is halted, and this EP still has other queued TD
+      // --> the Bulk list only has this halted EP queueing TDs (remaining)
+      // --> Bulk list will be considered as not empty by HC !!! while there is no attempt transaction on this list
+      // --> HC will not process Control list (due to service ratio when Bulk list not empty)
+      // To walk-around this, the halted ED will have TailP = HeadP (empty list condition), when clearing halt
+      // the TailP must be set back to NULL for processing remaining TDs
+      if ((event != XFER_RESULT_SUCCESS))
+      {
+        ed->td_tail &= 0x0Ful;
+        ed->td_tail |= tu_align16(ed->td_head.address); // mark halted EP as empty queue
+        if ( event == XFER_RESULT_STALLED ) ed->is_stalled = 1;
+      }
+
+      uint8_t dir = (ed->ep_number == 0) ? (qtd->pid == PID_IN) : (ed->pid == PID_IN);
+
+      hcd_event_xfer_complete(ed->dev_addr, tu_edpt_addr(ed->ep_number, dir), xferred_bytes, event, true);
+    }
+
+    td_head = (ohci_td_item_t*) td_head->next;
+  }
+}
+
+void hcd_int_handler(uint8_t hostid)
+{
+  uint32_t const int_en     = OHCI_REG->interrupt_enable;
+  uint32_t const int_status = OHCI_REG->interrupt_status & int_en;
+
+  if (int_status == 0) return;
+
+  // Frame number overflow
+  if ( int_status & OHCI_INT_FRAME_OVERFLOW_MASK )
+  {
+    ohci_data.frame_number_hi++;
+  }
+
+  //------------- RootHub status -------------//
+  if ( int_status & OHCI_INT_RHPORT_STATUS_CHANGE_MASK )
+  {
+    uint32_t const rhport_status = OHCI_REG->rhport_status[0] & RHPORT_ALL_CHANGE_MASK;
+
+    // TODO dual port is not yet supported
+    if ( rhport_status & RHPORT_CONNECT_STATUS_CHANGE_MASK )
+    {
+      // TODO check if remote wake-up
+      if ( OHCI_REG->rhport_status_bit[0].current_connect_status )
+      {
+        // TODO reset port immediately, without this controller will got 2-3 (debouncing connection status change)
+        OHCI_REG->rhport_status[0] = RHPORT_PORT_RESET_STATUS_MASK;
+        hcd_event_device_attach(hostid, true);
+      }else
+      {
+        hcd_event_device_remove(hostid, true);
+      }
+    }
+
+    if ( rhport_status & RHPORT_PORT_SUSPEND_CHANGE_MASK)
+    {
+
+    }
+
+    OHCI_REG->rhport_status[0] = rhport_status; // acknowledge all interrupt
+  }
+
+  //------------- Transfer Complete -------------//
+  if (int_status & OHCI_INT_WRITEBACK_DONEHEAD_MASK)
+  {
+    done_queue_isr(hostid);
+  }
+
+  OHCI_REG->interrupt_status = int_status; // Acknowledge handled interrupt
+}
+//--------------------------------------------------------------------+
+// HELPER
+//--------------------------------------------------------------------+
+
+
+#endif
+
diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h
new file mode 100644
index 0000000..cd90aa4
--- /dev/null
+++ b/src/portable/ohci/ohci.h
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+#ifndef _TUSB_OHCI_H_
+#define _TUSB_OHCI_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// OHCI CONFIGURATION & CONSTANTS
+//--------------------------------------------------------------------+
+#define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enalbed
+#define OHCI_PERIODIC_LIST (defined HOST_HCD_XFER_INTERRUPT || defined HOST_HCD_XFER_ISOCHRONOUS)
+
+// TODO merge OHCI with EHCI
+enum {
+  OHCI_MAX_ITD = 4
+};
+
+//--------------------------------------------------------------------+
+// OHCI Data Structure
+//--------------------------------------------------------------------+
+typedef struct {
+  uint32_t interrupt_table[32];
+  volatile uint16_t frame_number;
+  volatile uint16_t frame_pad;
+  volatile uint32_t done_head;
+  uint8_t reserved[116+4];  // TODO try to make use of this area if possible, extra 4 byte to make the whole struct size = 256
+}ohci_hcca_t; // TU_ATTR_ALIGNED(256)
+
+TU_VERIFY_STATIC( sizeof(ohci_hcca_t) == 256, "size is not correct" );
+
+typedef struct {
+  uint32_t reserved[2];
+  volatile uint32_t next;
+  uint32_t reserved2;
+}ohci_td_item_t;
+
+typedef struct TU_ATTR_ALIGNED(16)
+{
+	// Word 0
+	uint32_t used                    : 1;
+	uint32_t index                   : 4;  // endpoint index the td belongs to, or device address in case of control xfer
+  uint32_t expected_bytes          : 13; // TODO available for hcd
+
+  uint32_t buffer_rounding         : 1;
+  uint32_t pid                     : 2;
+  uint32_t delay_interrupt         : 3;
+  volatile uint32_t data_toggle    : 2;
+  volatile uint32_t error_count    : 2;
+  volatile uint32_t condition_code : 4;
+
+	// Word 1
+	volatile uint8_t* current_buffer_pointer;
+
+	// Word 2 : next TD
+	volatile uint32_t next;
+
+	// Word 3
+	uint8_t* buffer_end;
+} ohci_gtd_t;
+
+TU_VERIFY_STATIC( sizeof(ohci_gtd_t) == 16, "size is not correct" );
+
+typedef struct TU_ATTR_ALIGNED(16)
+{
+  // Word 0
+	uint32_t dev_addr          : 7;
+	uint32_t ep_number         : 4;
+	uint32_t pid               : 2;
+	uint32_t speed             : 1;
+	uint32_t skip              : 1;
+	uint32_t is_iso            : 1;
+	uint32_t max_packet_size   : 11;
+	      // HCD: make use of 5 reserved bits
+	uint32_t used              : 1;
+	uint32_t is_interrupt_xfer : 1;
+	uint32_t is_stalled        : 1;
+	uint32_t                   : 2;
+
+	// Word 1
+	uint32_t td_tail;
+
+	// Word 2
+	volatile union {
+		uint32_t address;
+		struct {
+			uint32_t halted : 1;
+			uint32_t toggle : 1;
+			uint32_t : 30;
+		};
+	}td_head;
+
+	// Word 3: next ED
+	uint32_t next;
+} ohci_ed_t;
+
+TU_VERIFY_STATIC( sizeof(ohci_ed_t) == 16, "size is not correct" );
+
+typedef struct TU_ATTR_ALIGNED(32)
+{
+	/*---------- Word 1 ----------*/
+  uint32_t starting_frame          : 16;
+  uint32_t                         : 5; // can be used
+  uint32_t delay_interrupt         : 3;
+  uint32_t frame_count             : 3;
+  uint32_t                         : 1; // can be used
+  volatile uint32_t condition_code : 4;
+
+	/*---------- Word 2 ----------*/
+	uint32_t buffer_page0;	// 12 lsb bits can be used
+
+	/*---------- Word 3 ----------*/
+	volatile uint32_t next;
+
+	/*---------- Word 4 ----------*/
+	uint32_t buffer_end;
+
+	/*---------- Word 5-8 ----------*/
+	volatile uint16_t offset_packetstatus[8];
+} ochi_itd_t;
+
+TU_VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" );
+
+// structure with member alignment required from large to small
+typedef struct TU_ATTR_ALIGNED(256)
+{
+  ohci_hcca_t hcca;
+
+  ohci_ed_t bulk_head_ed; // static bulk head (dummy)
+  ohci_ed_t period_head_ed; // static periodic list head (dummy)
+
+  // control endpoints has reserved resources
+  struct {
+    ohci_ed_t ed;
+    ohci_gtd_t gtd;
+  }control[CFG_TUH_DEVICE_MAX+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];
+
+  volatile uint16_t frame_number_hi;
+
+} ohci_data_t;
+
+//--------------------------------------------------------------------+
+// OHCI Operational Register
+//--------------------------------------------------------------------+
+
+
+//--------------------------------------------------------------------+
+// OHCI Data Organization
+//--------------------------------------------------------------------+
+typedef volatile struct
+{
+  uint32_t revision;
+
+  union {
+    uint32_t control;
+    struct {
+      uint32_t control_bulk_service_ratio : 2;
+      uint32_t periodic_list_enable       : 1;
+      uint32_t isochronous_enable         : 1;
+      uint32_t control_list_enable        : 1;
+      uint32_t bulk_list_enable           : 1;
+      uint32_t hc_functional_state        : 2;
+      uint32_t interrupt_routing          : 1;
+      uint32_t remote_wakeup_connected    : 1;
+      uint32_t remote_wakeup_enale        : 1;
+      uint32_t TU_RESERVED                : 21;
+    }control_bit;
+  };
+
+  union {
+    uint32_t command_status;
+    struct {
+      uint32_t controller_reset         : 1;
+      uint32_t control_list_filled      : 1;
+      uint32_t bulk_list_filled         : 1;
+      uint32_t ownership_change_request : 1;
+      uint32_t                          : 12;
+      uint32_t scheduling_overrun_count : 2;
+    }command_status_bit;
+  };
+
+  uint32_t interrupt_status;
+  uint32_t interrupt_enable;
+  uint32_t interrupt_disable;
+
+  uint32_t hcca;
+  uint32_t period_current_ed;
+  uint32_t control_head_ed;
+  uint32_t control_current_ed;
+  uint32_t bulk_head_ed;
+  uint32_t bulk_current_ed;
+  uint32_t done_head;
+
+  uint32_t frame_interval;
+  uint32_t frame_remaining;
+  uint32_t frame_number;
+  uint32_t periodic_start;
+  uint32_t lowspeed_threshold;
+
+  uint32_t rh_descriptorA;
+  uint32_t rh_descriptorB;
+
+  union {
+    uint32_t rh_status;
+    struct {
+      uint32_t local_power_status            : 1; // read Local Power Status; write: Clear Global Power
+      uint32_t over_current_indicator        : 1;
+      uint32_t                               : 13;
+      uint32_t device_remote_wakeup_enable   : 1;
+      uint32_t local_power_status_change     : 1;
+      uint32_t over_current_indicator_change : 1;
+      uint32_t                               : 13;
+      uint32_t clear_remote_wakeup_enable    : 1;
+    }rh_status_bit;
+  };
+
+  union {
+    uint32_t rhport_status[2]; // TODO NXP OHCI controller only has 2 ports
+    struct {
+      uint32_t current_connect_status             : 1;
+      uint32_t port_enable_status                 : 1;
+      uint32_t port_suspend_status                : 1;
+      uint32_t port_over_current_indicator        : 1;
+      uint32_t port_reset_status                  : 1;
+      uint32_t                                    : 3;
+      uint32_t port_power_status                  : 1;
+      uint32_t low_speed_device_attached          : 1;
+      uint32_t                                    : 6;
+      uint32_t connect_status_change              : 1;
+      uint32_t port_enable_status_change          : 1;
+      uint32_t port_suspend_status_change         : 1;
+      uint32_t port_over_current_indicator_change : 1;
+      uint32_t port_reset_status_change           : 1;
+      uint32_t TU_RESERVED                        : 11;
+    }rhport_status_bit[2];
+  };
+}ohci_registers_t;
+
+TU_VERIFY_STATIC( sizeof(ohci_registers_t) == 0x5c, "size is not correct");
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_OHCI_H_ */
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
new file mode 100644
index 0000000..42add31
--- /dev/null
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -0,0 +1,510 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Raspberry Pi (Trading) 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.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040
+
+#include "pico.h"
+#include "rp2040_usb.h"
+
+#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
+#include "pico/fix/rp2040_usb_device_enumeration.h"
+#endif
+
+#include "device/dcd.h"
+
+// Current implementation force vbus detection as always present, causing device think it is always plugged into host.
+// Therefore it cannot detect disconnect event, mistaken it as suspend.
+// Note: won't work if change to 0 (for now)
+#define FORCE_VBUS_DETECT   1
+
+/*------------------------------------------------------------------*/
+/* Low level controller
+ *------------------------------------------------------------------*/
+
+#define usb_hw_set hw_set_alias(usb_hw)
+#define usb_hw_clear hw_clear_alias(usb_hw)
+
+// Init these in dcd_init
+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)
+{
+  return &hw_endpoints[num][dir];
+}
+
+static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
+{
+  uint8_t num = tu_edpt_number(ep_addr);
+  tusb_dir_t dir = tu_edpt_dir(ep_addr);
+  return hw_endpoint_get_by_num(num, dir);
+}
+
+static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
+{
+  // size must be multiple of 64
+  uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
+
+  // double buffered Bulk endpoint
+  if ( transfer_type == TUSB_XFER_BULK )
+  {
+    size *= 2u;
+  }
+
+  ep->hw_data_buf = next_buffer_ptr;
+  next_buffer_ptr += size;
+
+  assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0);
+  uint dpram_offset = hw_data_offset(ep->hw_data_buf);
+  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);
+
+  // 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;
+
+  *ep->endpoint_control = reg;
+}
+
+static void _hw_endpoint_close(struct hw_endpoint *ep)
+{
+    // Clear hardware registers and then zero the struct
+    // Clears endpoint enable
+    *ep->endpoint_control = 0;
+    // Clears buffer available, etc
+    *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)
+{
+    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+    _hw_endpoint_close(ep);
+}
+
+static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
+{
+  struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+
+  const uint8_t num = tu_edpt_number(ep_addr);
+  const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+
+  ep->ep_addr = ep_addr;
+
+  // For device, IN is a tx transfer and OUT is an rx transfer
+  ep->rx = (dir == TUSB_DIR_OUT);
+
+  ep->next_pid = 0u;
+  ep->wMaxPacketSize = wMaxPacketSize;
+  ep->transfer_type = transfer_type;
+
+  // Every endpoint has a buffer control register in dpram
+  if ( dir == TUSB_DIR_IN )
+  {
+    ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
+  }
+  else
+  {
+    ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
+  }
+
+  // Clear existing buffer control state
+  *ep->buffer_control = 0;
+
+  if ( num == 0 )
+  {
+    // EP0 has no endpoint control register because the buffer offsets are fixed
+    ep->endpoint_control = NULL;
+
+    // Buffer offset is fixed (also double buffered)
+    ep->hw_data_buf = (uint8_t*) &usb_dpram->ep0_buf_a[0];
+  }
+  else
+  {
+    // Set the endpoint control register (starts at EP1, hence num-1)
+    if ( dir == TUSB_DIR_IN )
+    {
+      ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].in;
+    }
+    else
+    {
+      ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
+    }
+
+    // alloc a buffer and fill in endpoint control register
+    _hw_endpoint_alloc(ep, transfer_type);
+  }
+}
+
+static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+    hw_endpoint_xfer_start(ep, buffer, total_bytes);
+}
+
+static void hw_handle_buff_status(void)
+{
+    uint32_t remaining_buffers = usb_hw->buf_status;
+    pico_trace("buf_status = 0x%08x\n", remaining_buffers);
+    uint bit = 1u;
+    for (uint8_t i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++)
+    {
+        if (remaining_buffers & bit)
+        {
+            // clear this in advance
+            usb_hw_clear->buf_status = bit;
+
+            // IN transfer for even i, OUT transfer for odd i
+            struct hw_endpoint *ep = hw_endpoint_get_by_num(i >> 1u, !(i & 1u));
+
+            // Continue xfer
+            bool done = hw_endpoint_xfer_continue(ep);
+            if (done)
+            {
+                // Notify
+                dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true);
+                hw_endpoint_reset_transfer(ep);
+            }
+            remaining_buffers &= ~bit;
+        }
+        bit <<= 1u;
+    }
+}
+
+static 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
+    uint8_t addrs[] = {0x0, 0x80};
+    for (uint i = 0 ; i < TU_ARRAY_SIZE(addrs); i++)
+    {
+        struct hw_endpoint *ep = hw_endpoint_get_by_addr(addrs[i]);
+        ep->next_pid = 1u;
+    }
+}
+
+static void reset_non_control_endpoints(void)
+{
+  // Disable all non-control
+  for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS-1; i++ )
+  {
+    usb_dpram->ep_ctrl[i].in = 0;
+    usb_dpram->ep_ctrl[i].out = 0;
+  }
+
+  // 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)
+{
+    uint32_t const status = usb_hw->ints;
+    uint32_t handled = 0;
+
+    // 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;
+        uint8_t const *setup = (uint8_t const *)&usb_dpram->setup_packet;
+
+        // reset pid to both 1 (data and ack)
+        reset_ep0_pid();
+
+        // Pass setup packet to tiny usb
+        dcd_event_setup_received(0, setup, true);
+        usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
+    }
+
+#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
+    if (status & USB_INTS_DEV_CONN_DIS_BITS)
+    {
+        handled |= USB_INTS_DEV_CONN_DIS_BITS;
+
+        if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
+        {
+          // Connected: nothing to do
+        }else
+        {
+          // Disconnected
+          dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
+        }
+
+        usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
+    }
+#endif
+
+    // SE0 for 2.5 us or more (will last at least 10ms)
+    if (status & USB_INTS_BUS_RESET_BITS)
+    {
+        pico_trace("BUS RESET\n");
+
+        handled |= USB_INTS_BUS_RESET_BITS;
+
+        usb_hw->dev_addr_ctrl = 0;
+        reset_non_control_endpoints();
+        dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+        usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
+
+#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
+        // Only run enumeration walk-around if pull up is enabled
+        if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix();
+#endif
+    }
+
+    /* Note from pico datasheet 4.1.2.6.4 (v1.2)
+     * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
+     * the device is first connected but the bus is idle. The bus can be idle for a few ms before
+     * the host begins sending start of frame packets. You will also see a suspend interrupt
+     * when the device is disconnected if you do not have a VBUS detect circuit connected. This is
+     * because without VBUS detection, it is impossible to tell the difference between
+     * being disconnected and suspended.
+     */
+    if (status & USB_INTS_DEV_SUSPEND_BITS)
+    {
+        handled |= USB_INTS_DEV_SUSPEND_BITS;
+        dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+        usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
+    }
+
+    if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS)
+    {
+        handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
+        dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+        usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
+    }
+
+    if (status ^ handled)
+    {
+        panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
+    }
+}
+
+#define USB_INTS_ERROR_BITS ( \
+    USB_INTS_ERROR_DATA_SEQ_BITS      |  \
+    USB_INTS_ERROR_BIT_STUFF_BITS     |  \
+    USB_INTS_ERROR_CRC_BITS           |  \
+    USB_INTS_ERROR_RX_OVERFLOW_BITS   |  \
+    USB_INTS_ERROR_RX_TIMEOUT_BITS)
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+
+void dcd_init (uint8_t rhport)
+{
+  assert(rhport == 0);
+
+  // Reset hardware to default state
+  rp2040_usb_init();
+
+#if FORCE_VBUS_DETECT
+  // Force VBUS detect so the device thinks it is plugged into a host
+  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);
+
+  // Init control endpoints
+  tu_memclr(hw_endpoints[0], 2*sizeof(hw_endpoint_t));
+  hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
+  hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
+
+  // Init non-control endpoints
+  reset_non_control_endpoints();
+
+  // Initializes the USB peripheral for device mode and enables it.
+  // Don't need to enable the pull up here. Force VBUS
+  usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
+
+  // Enable individual controller IRQS here. Processor interrupt enable will be used
+  // for the global interrupt enable...
+  // Note: Force VBUS detect cause disconnection not detectable
+  usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS;
+  usb_hw->inte     = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
+                     USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS |
+                     (FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS);
+
+  dcd_connect(rhport);
+}
+
+void dcd_int_enable(__unused uint8_t rhport)
+{
+    assert(rhport == 0);
+    irq_set_enabled(USBCTRL_IRQ, true);
+}
+
+void dcd_int_disable(__unused uint8_t rhport)
+{
+    assert(rhport == 0);
+    irq_set_enabled(USBCTRL_IRQ, false);
+}
+
+void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr)
+{
+  assert(rhport == 0);
+
+  // Can't set device address in hardware until status xfer has complete
+  // Send 0len complete response on EP0 IN
+  hw_endpoint_xfer(0x80, NULL, 0);
+}
+
+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;
+}
+
+// disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(__unused uint8_t rhport)
+{
+  (void) rhport;
+  usb_hw_clear->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
+}
+
+// connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(__unused uint8_t rhport)
+{
+  (void) rhport;
+  usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
+}
+
+/*------------------------------------------------------------------*/
+/* DCD Endpoint port
+ *------------------------------------------------------------------*/
+
+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 &&
+       request->bRequest == TUSB_REQ_SET_ADDRESS )
+  {
+    usb_hw->dev_addr_ctrl = (uint8_t) request->wValue;
+  }
+}
+
+bool dcd_edpt_open (__unused uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
+{
+    assert(rhport == 0);
+    hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
+    return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+
+  // may need to use EP Abort
+  reset_non_control_endpoints();
+}
+
+bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+    assert(rhport == 0);
+    hw_endpoint_xfer(ep_addr, buffer, total_bytes);
+    return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  if ( tu_edpt_number(ep_addr) == 0 )
+  {
+    // A stall on EP0 has to be armed so it can be cleared on the next setup packet
+    usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
+  }
+
+  struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+
+  // stall and clear current pending buffer
+  // may need to use EP_ABORT
+  _hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_STALL);
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  if (tu_edpt_number(ep_addr))
+  {
+    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+
+    // clear stall also reset toggle to DATA0, ready for next transfer
+    ep->next_pid = 0;
+    _hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL);
+  }
+}
+
+void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
+{
+    (void) rhport;
+
+    pico_trace("dcd_edpt_close %02x\n", ep_addr);
+    hw_endpoint_close(ep_addr);
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void) rhport;
+  dcd_rp2040_irq();
+}
+
+#endif
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
new file mode 100644
index 0000000..3e80dd8
--- /dev/null
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -0,0 +1,580 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * 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 && CFG_TUSB_MCU == OPT_MCU_RP2040
+
+#include "pico.h"
+#include "rp2040_usb.h"
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "osal/osal.h"
+
+#include "host/hcd.h"
+#include "host/usbh.h"
+
+#define ROOT_PORT 0
+
+//--------------------------------------------------------------------+
+// Low level rp2040 controller functions
+//--------------------------------------------------------------------+
+
+#ifndef PICO_USB_HOST_INTERRUPT_ENDPOINTS
+#define PICO_USB_HOST_INTERRUPT_ENDPOINTS (USB_MAX_ENDPOINTS - 1)
+#endif
+static_assert(PICO_USB_HOST_INTERRUPT_ENDPOINTS <= USB_MAX_ENDPOINTS, "");
+
+// Host mode uses one shared endpoint register for non-interrupt endpoint
+static struct hw_endpoint ep_pool[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS];
+#define epx (ep_pool[0])
+
+#define usb_hw_set   hw_set_alias(usb_hw)
+#define usb_hw_clear hw_clear_alias(usb_hw)
+
+// Flags we set by default in sie_ctrl (we add other bits on top)
+enum {
+  SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS      | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
+                  USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
+};
+
+static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
+{
+  uint8_t num = tu_edpt_number(ep_addr);
+  if ( num == 0 ) return &epx;
+
+  for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ )
+  {
+    struct hw_endpoint *ep = &ep_pool[i];
+    if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep;
+  }
+
+  return NULL;
+}
+
+static inline uint8_t dev_speed(void)
+{
+    return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
+}
+
+static bool need_pre(uint8_t dev_addr)
+{
+    // If this device is different to the speed of the root device
+    // (i.e. is a low speed device on a full speed hub) then need pre
+    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)
+{
+    // Mark transfer as done before we tell the tinyusb stack
+    uint8_t dev_addr = ep->dev_addr;
+    uint8_t ep_addr = ep->ep_addr;
+    uint xferred_len = ep->xferred_len;
+    hw_endpoint_reset_transfer(ep);
+    hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true);
+}
+
+static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep)
+{
+    usb_hw_clear->buf_status = bit;
+    bool done = hw_endpoint_xfer_continue(ep);
+    if (done)
+    {
+        hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
+    }
+}
+
+static void hw_handle_buff_status(void)
+{
+    uint32_t remaining_buffers = usb_hw->buf_status;
+    pico_trace("buf_status 0x%08x\n", remaining_buffers);
+
+    // Check EPX first
+    uint bit = 0b1;
+    if (remaining_buffers & bit)
+    {
+        remaining_buffers &= ~bit;
+        struct hw_endpoint *ep = &epx;
+
+        uint32_t ep_ctrl = *ep->endpoint_control;
+        if (ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS)
+        {
+          TU_LOG(3, "Double Buffered: ");
+        }else
+        {
+          TU_LOG(3, "Single Buffered: ");
+        }
+        TU_LOG_HEX(3, ep_ctrl);
+
+        _handle_buff_status_bit(bit, ep);
+    }
+
+    // Check interrupt endpoints
+    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
+        // etc
+        bit = 1 << (i*2);
+
+        if (remaining_buffers & bit)
+        {
+            remaining_buffers &= ~bit;
+            _handle_buff_status_bit(bit, &ep_pool[i]);
+        }
+    }
+
+    if (remaining_buffers)
+    {
+        panic("Unhandled buffer %d\n", remaining_buffers);
+    }
+}
+
+static void 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);
+    hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
+  }
+  else
+  {
+    // Don't care. Will handle this in buff status
+    return;
+  }
+}
+
+static void hcd_rp2040_irq(void)
+{
+    uint32_t status = usb_hw->ints;
+    uint32_t handled = 0;
+
+    if (status & USB_INTS_HOST_CONN_DIS_BITS)
+    {
+        handled |= USB_INTS_HOST_CONN_DIS_BITS;
+        
+        if (dev_speed())
+        {
+            hcd_event_device_attach(ROOT_PORT, true);
+        }
+        else
+        {
+            hcd_event_device_remove(ROOT_PORT, true);
+        }
+
+        // Clear speed change interrupt
+        usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS;
+    }
+
+    if (status & USB_INTS_BUFF_STATUS_BITS)
+    {
+        handled |= USB_INTS_BUFF_STATUS_BITS;
+        TU_LOG(2, "Buffer complete\n");
+        hw_handle_buff_status();
+    }
+
+    if (status & USB_INTS_TRANS_COMPLETE_BITS)
+    {
+        handled |= USB_INTS_TRANS_COMPLETE_BITS;
+        usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS;
+        TU_LOG(2, "Transfer complete\n");
+        hw_trans_complete();
+    }
+
+    if (status & USB_INTS_STALL_BITS)
+    {
+        // We have rx'd a stall from the device
+        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;
+        usb_hw_clear->sie_status = USB_SIE_STATUS_RX_TIMEOUT_BITS;
+    }
+
+    if (status & USB_INTS_ERROR_DATA_SEQ_BITS)
+    {
+        usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS;
+        TU_LOG(3, "  Seq Error: [0] = 0x%04u  [1] = 0x%04x\r\n", tu_u32_low16(*epx.buffer_control), tu_u32_high16(*epx.buffer_control));
+        panic("Data Seq Error \n");
+    }
+
+    if (status ^ handled)
+    {
+        panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
+    }
+}
+
+static struct hw_endpoint *_next_free_interrupt_ep(void)
+{
+    struct hw_endpoint *ep = NULL;
+    for (uint i = 1; i < TU_ARRAY_SIZE(ep_pool); i++)
+    {
+        ep = &ep_pool[i];
+        if (!ep->configured)
+        {
+            // Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
+            ep->interrupt_num = i - 1;
+            return ep;
+        }
+    }
+    return ep;
+}
+
+static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
+{
+    struct hw_endpoint *ep = NULL;
+
+    if (transfer_type == TUSB_XFER_INTERRUPT)
+    {
+        ep = _next_free_interrupt_ep();
+        pico_info("Allocate interrupt ep %d\n", 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;
+        // 0 for epx (double buffered): TODO increase to 1024 for ISO
+        // 2x64 for intep0
+        // 3x64 for intep1
+        // etc
+        ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 2)];
+    }
+    else
+    {
+        ep = &epx;
+        ep->buffer_control = &usbh_dpram->epx_buf_ctrl;
+        ep->endpoint_control = &usbh_dpram->epx_ctrl;
+        ep->hw_data_buf = &usbh_dpram->epx_data[0];
+    }
+
+    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)
+{
+    // Already has data buffer, endpoint control, and buffer control allocated at this point
+    assert(ep->endpoint_control);
+    assert(ep->buffer_control);
+    assert(ep->hw_data_buf);
+
+    uint8_t const num = tu_edpt_number(ep_addr);
+    tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+
+    ep->ep_addr = ep_addr;
+    ep->dev_addr = dev_addr;
+
+    // For host, IN to host == RX, anything else rx == false
+    ep->rx = (dir == TUSB_DIR_IN);
+
+    // Response to a setup packet on EP0 starts with pid of 1
+    ep->next_pid = (num == 0 ? 1u : 0u);
+    ep->wMaxPacketSize = wMaxPacketSize;
+    ep->transfer_type = transfer_type;
+
+    pico_trace("hw_endpoint_init dev %d ep %d %s xfer %d\n", ep->dev_addr, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->transfer_type);
+    pico_trace("dev %d ep %d %s setup buffer @ 0x%p\n", ep->dev_addr, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->hw_data_buf);
+    uint dpram_offset = hw_data_offset(ep->hw_data_buf);
+    // Bits 0-5 should be 0
+    assert(!(dpram_offset & 0b111111));
+
+    // Fill in endpoint control register with buffer offset
+    uint32_t ep_reg =  EP_CTRL_ENABLE_BITS
+                  | 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;
+    *ep->endpoint_control = ep_reg;
+    pico_trace("endpoint control (0x%p) <- 0x%x\n", ep->endpoint_control, ep_reg);
+    ep->configured = true;
+
+    if (bmInterval)
+    {
+        // 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);
+
+        if (need_pre(dev_addr))
+        {
+            reg |= USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS;
+        }
+        usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = reg;
+
+        // Finally, enable interrupt that endpoint
+        usb_hw_set->int_ep_ctrl = 1 << (ep->interrupt_num + 1);
+
+        // If it's an interrupt endpoint we need to set up the buffer control
+        // register
+    }
+}
+
+//--------------------------------------------------------------------+
+// HCD API
+//--------------------------------------------------------------------+
+bool hcd_init(uint8_t rhport)
+{
+    pico_trace("hcd_init %d\n", rhport);
+    assert(rhport == 0);
+
+    // 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;
+
+    irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
+
+    // clear epx and interrupt eps
+    memset(&ep_pool, 0, sizeof(ep_pool));
+
+    // Enable in host mode with SOF / Keep alive on
+    usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
+    usb_hw->sie_ctrl = SIE_CTRL_BASE;
+    usb_hw->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?
+}
+
+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;
+}
+
+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;
+    }
+}
+
+// Close all opened endpoint belong to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+  pico_trace("hcd_device_close %d\n", dev_addr);
+  (void) rhport;
+
+  if (dev_addr == 0) return;
+
+  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)
+{
+    (void) rhport;
+    return usb_hw->sof_rd;
+}
+
+void hcd_int_enable(uint8_t 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);
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+    (void) rhport;
+
+    pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress);
+
+    // Allocated differently based on if it's an interrupt endpoint or not
+    struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
+
+    _hw_endpoint_init(ep,
+        dev_addr,
+        ep_desc->bEndpointAddress,
+        tu_edpt_packet_size(ep_desc),
+        ep_desc->bmAttributes.xfer,
+        ep_desc->bInterval);
+
+    return true;
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
+{
+    (void) rhport;
+
+    pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen);
+    
+    uint8_t const ep_num = tu_edpt_number(ep_addr);
+    tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr);
+
+    // Get appropriate ep. Either EPX or interrupt endpoint
+    struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
+    assert(ep);
+
+    // Control endpoint can change direction 0x00 <-> 0x80
+    if ( ep_addr != ep->ep_addr )
+    {
+      assert(ep_num == 0);
+
+      // Direction has flipped on endpoint control so re init it but with same properties
+      _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0);
+    }
+
+    // If a normal transfer (non-interrupt) then initiate using
+    // sie ctrl registers. Otherwise interrupt ep registers should
+    // already be configured
+    if (ep == &epx) {
+        hw_endpoint_xfer_start(ep, buffer, buflen);
+
+        // That has set up buffer control, endpoint control etc
+        // for host we have to initiate the transfer
+        usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB);
+
+        uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE |
+                         (ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS);
+        // Set pre if we are a low speed device on full speed hub
+        flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0;
+
+        usb_hw->sie_ctrl = flags;
+    }else
+    {
+      hw_endpoint_xfer_start(ep, buffer, buflen);
+    }
+
+    return true;
+}
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+    (void) rhport;
+
+    // Copy data into setup packet buffer
+    memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8);
+
+    // Configure EP0 struct with setup info for the trans complete
+    struct hw_endpoint *ep = _hw_endpoint_allocate(0);
+
+    // EP0 out
+    _hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
+    assert(ep->configured);
+
+    ep->remaining_len = 8;
+    ep->active        = true;
+
+    // Set device address
+    usb_hw->dev_addr_ctrl = dev_addr;
+
+    // Set pre if we are a low speed device on full speed hub
+    uint32_t const flags = SIE_CTRL_BASE | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS |
+                           (need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0);
+
+    usb_hw->sie_ctrl = flags;
+
+    return true;
+}
+
+
+//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;
+
+    panic("hcd_clear_stall");
+    return true;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
new file mode 100644
index 0000000..9d833e6
--- /dev/null
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -0,0 +1,323 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * 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_TUSB_MCU == OPT_MCU_RP2040
+
+#include <stdlib.h>
+#include "rp2040_usb.h"
+
+// Direction strings for debug
+const char *ep_dir_string[] = {
+        "out",
+        "in",
+};
+
+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.
+}
+
+static void _hw_endpoint_xfer_sync(struct hw_endpoint *ep);
+static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+void rp2040_usb_init(void)
+{
+  // Reset usb controller
+  reset_block(RESETS_RESET_USBCTRL_BITS);
+  unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
+
+  // Clear any previous state just in case
+  memset(usb_hw, 0, sizeof(*usb_hw));
+  memset(usb_dpram, 0, sizeof(*usb_dpram));
+
+  // Mux the controller to the onboard usb phy
+  usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
+}
+
+void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
+{
+  ep->active = false;
+  ep->remaining_len = 0;
+  ep->xferred_len = 0;
+  ep->user_buf = 0;
+}
+
+void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
+    uint32_t value = 0;
+    if (and_mask) {
+        value = *ep->buffer_control & and_mask;
+    }
+    if (or_mask) {
+        value |= or_mask;
+        if (or_mask & USB_BUF_CTRL_AVAIL) {
+            if (*ep->buffer_control & USB_BUF_CTRL_AVAIL) {
+                panic("ep %d %s was already available", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
+            }
+            *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
+            __asm volatile (
+                    "b 1f\n"
+                    "1: b 1f\n"
+                    "1: b 1f\n"
+                    "1: b 1f\n"
+                    "1: b 1f\n"
+                    "1: b 1f\n"
+                    "1:\n"
+                    : : : "memory");
+#endif
+        }
+    }
+    *ep->buffer_control = value;
+}
+
+// prepare buffer, return buffer control
+static uint32_t 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);
+
+  uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL;
+
+  // PID
+  buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
+  ep->next_pid ^= 1u;
+
+  if ( !ep->rx )
+  {
+    // Copy data from user buffer to hw buffer
+    memcpy(ep->hw_data_buf + buf_id*64, ep->user_buf, buflen);
+    ep->user_buf += buflen;
+
+    // Mark as full
+    buf_ctrl |= USB_BUF_CTRL_FULL;
+  }
+
+  // Is this the last buffer? Only really matters for host mode. Will trigger
+  // the trans complete irq but also stop it polling. We only really care about
+  // trans complete for setup packets being sent
+  if (ep->remaining_len == 0)
+  {
+    buf_ctrl |= USB_BUF_CTRL_LAST;
+  }
+
+  if (buf_id) buf_ctrl = buf_ctrl << 16;
+
+  return buf_ctrl;
+}
+
+// Prepare buffer control register value
+static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
+{
+  uint32_t ep_ctrl = *ep->endpoint_control;
+
+  // always compute and start with buffer 0
+  uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL;
+
+  // For now: skip double buffered for Device mode, OUT endpoint since
+  // host could send < 64 bytes and cause short packet on buffer0
+  // NOTE this could happen to Host mode IN endpoint
+  bool const force_single = !(usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) && !tu_edpt_dir(ep->ep_addr);
+
+  if(ep->remaining_len && !force_single)
+  {
+    // Use buffer 1 (double buffered) if there is still data
+    // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
+
+    buf_ctrl |= prepare_ep_buffer(ep, 1);
+
+    // Set endpoint control double buffered bit if needed
+    ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
+    ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER;
+  }else
+  {
+    // Single buffered since 1 is enough
+    ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
+    ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
+  }
+
+  *ep->endpoint_control = ep_ctrl;
+
+  TU_LOG(3, "  Prepare BufCtrl: [0] = 0x%04u  [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
+  _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
+}
+
+void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
+{
+  _hw_endpoint_lock_update(ep, 1);
+
+  if ( ep->active )
+  {
+    // TODO: Is this acceptable for interrupt packets?
+    TU_LOG(1, "WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr),
+              ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
+
+    hw_endpoint_reset_transfer(ep);
+  }
+
+  // Fill in info now that we're kicking off the hw
+  ep->remaining_len = total_len;
+  ep->xferred_len   = 0;
+  ep->active        = true;
+  ep->user_buf      = buffer;
+
+  _hw_endpoint_start_next_buffer(ep);
+  _hw_endpoint_lock_update(ep, -1);
+}
+
+// sync endpoint buffer and return transferred bytes
+static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
+{
+  uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
+  if (buf_id)  buf_ctrl = buf_ctrl >> 16;
+
+  uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
+
+  if ( !ep->rx )
+  {
+    // We are continuing a transfer here. If we are TX, we have successfully
+    // sent some data can increase the length we have sent
+    assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
+
+    ep->xferred_len = (uint16_t)(ep->xferred_len + xferred_bytes);
+  }else
+  {
+    // If we have received some data, so can increase the length
+    // we have received AFTER we have copied it to the user buffer at the appropriate offset
+    assert(buf_ctrl & USB_BUF_CTRL_FULL);
+
+    memcpy(ep->user_buf, ep->hw_data_buf + buf_id*64, xferred_bytes);
+    ep->xferred_len = (uint16_t)(ep->xferred_len + xferred_bytes);
+    ep->user_buf += xferred_bytes;
+  }
+
+  // Short packet
+  if (xferred_bytes < ep->wMaxPacketSize)
+  {
+    pico_trace("  Short packet on buffer %d with %u bytes\n", buf_id, xferred_bytes);
+    // Reduce total length as this is last packet
+    ep->remaining_len = 0;
+  }
+
+  return xferred_bytes;
+}
+
+static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
+{
+  // Update hw endpoint struct with info from hardware
+  // after a buff status interrupt
+
+  uint32_t __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));
+
+  // always sync buffer 0
+  uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
+
+  // sync buffer 1 if double buffered
+  if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS )
+  {
+    if (buf0_bytes == ep->wMaxPacketSize)
+    {
+      // sync buffer 1 if not short packet
+      sync_ep_buffer(ep, 1);
+    }else
+    {
+      // short packet on buffer 0
+      // TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example
+      // At this time (currently trigger per 2 buffer), the buffer1 is probably filled with data from
+      // the next transfer (not current one). For now we disable double buffered for device OUT
+      // NOTE this could happen to Host IN
+#if 0
+      uint8_t const ep_num = tu_edpt_number(ep->ep_addr);
+      uint8_t const dir =  (uint8_t) tu_edpt_dir(ep->ep_addr);
+      uint8_t const ep_id = 2*ep_num + (dir ? 0 : 1);
+
+      // abort queued transfer on buffer 1
+      usb_hw->abort |= TU_BIT(ep_id);
+
+      while ( !(usb_hw->abort_done & TU_BIT(ep_id)) ) {}
+
+      uint32_t ep_ctrl = *ep->endpoint_control;
+      ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
+      ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
+
+      _hw_endpoint_buffer_control_set_value32(ep, 0);
+
+      usb_hw->abort &= ~TU_BIT(ep_id);
+
+      TU_LOG(3, "----SHORT PACKET buffer0 on EP %02X:\r\n", ep->ep_addr);
+      TU_LOG(3, "  BufCtrl: [0] = 0x%04u  [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)
+{
+  _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[tu_edpt_dir(ep->ep_addr)]);
+  }
+
+  // Update EP struct from hardware state
+  _hw_endpoint_xfer_sync(ep);
+
+  // Now we have synced our state with the hardware. Is there more data to transfer?
+  // If we are done then notify tinyusb
+  if (ep->remaining_len == 0)
+  {
+    pico_trace("Completed transfer of %d bytes on ep %d %s\n",
+               ep->xferred_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
+    // Notify caller we are done so it can notify the tinyusb stack
+    _hw_endpoint_lock_update(ep, -1);
+    return true;
+  }
+  else
+  {
+    _hw_endpoint_start_next_buffer(ep);
+  }
+
+  _hw_endpoint_lock_update(ep, -1);
+  // More work to do
+  return false;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
new file mode 100644
index 0000000..a9cf1dd
--- /dev/null
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -0,0 +1,96 @@
+#ifndef RP2040_COMMON_H_
+#define RP2040_COMMON_H_
+
+#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE)
+#error TinyUSB device and host mode not supported at the same time
+#endif
+
+#include "common/tusb_common.h"
+
+#include "pico.h"
+#include "hardware/structs/usb.h"
+#include "hardware/irq.h"
+#include "hardware/resets.h"
+
+#if defined(PICO_RP2040_USB_DEVICE_ENUMERATION_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX)
+#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
+#endif
+
+
+#define pico_info(...)  TU_LOG(2, __VA_ARGS__)
+#define pico_trace(...) TU_LOG(3, __VA_ARGS__)
+
+// Hardware information per endpoint
+typedef struct hw_endpoint
+{
+    // Is this a valid struct
+    bool configured;
+    
+    // Transfer direction (i.e. IN is rx for host but tx for device)
+    // allows us to common up transfer functions
+    bool rx;
+    
+    uint8_t ep_addr;
+    uint8_t next_pid;
+
+    // Endpoint control register
+    io_rw_32 *endpoint_control;
+
+    // Buffer control register
+    io_rw_32 *buffer_control;
+
+    // Buffer pointer in usb dpram
+    uint8_t *hw_data_buf;
+
+    // Current transfer information
+    bool active;
+    uint16_t remaining_len;
+    uint16_t xferred_len;
+
+    // User buffer in main memory
+    uint8_t *user_buf;
+
+    // Data needed from EP descriptor
+    uint16_t wMaxPacketSize;
+
+    // Interrupt, bulk, etc
+    uint8_t transfer_type;
+    
+#if TUSB_OPT_HOST_ENABLED
+    // Only needed for host
+    uint8_t dev_addr;
+
+    // If interrupt endpoint
+    uint8_t interrupt_num;
+#endif
+} hw_endpoint_t;
+
+void rp2040_usb_init(void);
+
+void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
+bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
+void hw_endpoint_reset_transfer(struct hw_endpoint *ep);
+
+void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask);
+static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) {
+    return *ep->buffer_control;
+}
+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) {
+    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) {
+    return _hw_endpoint_buffer_control_update32(ep, ~value, 0);
+}
+
+static inline uintptr_t hw_data_offset(uint8_t *buf)
+{
+    // Remove usb base from buffer pointer
+    return (uintptr_t)buf ^ (uintptr_t)usb_dpram;
+}
+
+extern const char *ep_dir_string[];
+
+#endif
diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c
new file mode 100644
index 0000000..ae7d2fd
--- /dev/null
+++ b/src/portable/renesas/usba/dcd_usba.c
@@ -0,0 +1,903 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 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"
+
+// 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
+
+#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
+                                 CFG_TUSB_MCU == OPT_MCU_RX65X || \
+                                 CFG_TUSB_MCU == OPT_MCU_RX72N )
+#include "device/dcd.h"
+#include "iodefine.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+#define SYSTEM_PRCR_PRC1     (1<<1)
+#define SYSTEM_PRCR_PRKEY    (0xA5u<<8)
+
+#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_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 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 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
+{
+  pipe_state_t pipe[10];
+  uint8_t ep[2][16];   /* a lookup table for a pipe index from an endpoint address */
+} dcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+static dcd_data_t _dcd;
+
+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 == _dcd.pipe[i].ep) return  i;
+    }
+    break;
+  case TUSB_XFER_BULK:
+    for (int i = 3; i <= 5; ++i) {
+      if (0 == _dcd.pipe[i].ep) return  i;
+    }
+    for (int i = 1; i <= 1; ++i) {
+      if (0 == _dcd.pipe[i].ep) return  i;
+    }
+    break;
+  case TUSB_XFER_INTERRUPT:
+    for (int i = 6; i <= 9; ++i) {
+      if (0 == _dcd.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* ep_addr_to_pipectr(uint8_t rhport, unsigned ep_addr)
+{
+  (void)rhport;
+  volatile uint16_t *ctr = NULL;
+  const unsigned epn   = tu_edpt_number(ep_addr);
+  if (epn) {
+    const unsigned dir = tu_edpt_dir(ep_addr);
+    const unsigned num = _dcd.ep[dir][epn];
+    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.WORD;
+}
+
+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 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);
+}
+
+static bool pipe0_xfer_in(void)
+{
+  pipe_state_t *pipe = &_dcd.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) {
+    if (pipe->ff) {
+      pipe_read_write_packet_ff((tu_fifo_t*)buf, (volatile void*)&USB0.CFIFO.WORD, len, TUSB_DIR_IN);
+    } else {
+      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 pipe0_xfer_out(void)
+{
+  pipe_state_t *pipe = &_dcd.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) {
+    if (pipe->ff) {
+      pipe_read_write_packet_ff((tu_fifo_t*)buf, (volatile void*)&USB0.CFIFO.WORD, len, TUSB_DIR_OUT);
+    } else {
+      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;
+  }
+  return false;
+}
+
+static bool pipe_xfer_in(unsigned num)
+{
+  pipe_state_t  *pipe = &_dcd.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) {
+    if (pipe->ff) {
+      pipe_read_write_packet_ff((tu_fifo_t*)buf, (volatile void*)&USB0.D0FIFO.WORD, len, TUSB_DIR_IN);
+    } else {
+      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 pipe_xfer_out(unsigned num)
+{
+  pipe_state_t  *pipe = &_dcd.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) {
+    if (pipe->ff) {
+      pipe_read_write_packet_ff((tu_fifo_t*)buf, (volatile void*)&USB0.D0FIFO.WORD, len, TUSB_DIR_OUT);
+    } else {
+      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 void process_setup_packet(uint8_t rhport)
+{
+  uint16_t setup_packet[4];
+  if (0 == (USB0.INTSTS0.WORD & USB_IS0_VALID)) return;
+  USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR;
+  setup_packet[0] = tu_le16toh(USB0.USBREQ.WORD);
+  setup_packet[1] = USB0.USBVAL;
+  setup_packet[2] = USB0.USBINDX;
+  setup_packet[3] = USB0.USBLENG;
+  USB0.INTSTS0.WORD = ~USB_IS0_VALID;
+  dcd_event_setup_received(rhport, (const uint8_t*)&setup_packet[0], true);
+}
+
+static void process_status_completion(uint8_t rhport)
+{
+  uint8_t ep_addr;
+  /* Check the data stage direction */
+  if (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) {
+    /* IN transfer. */
+    ep_addr = tu_edpt_addr(0, TUSB_DIR_IN);
+  } else {
+    /* OUT transfer. */
+    ep_addr = tu_edpt_addr(0, TUSB_DIR_OUT);
+  }
+  dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true);
+}
+
+static bool process_pipe0_xfer(int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes)
+{
+  /* configure fifo direction and access unit settings */
+  if (ep_addr) { /* IN, 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)) ;
+  } else {       /* OUT, a byte */
+    USB0.CFIFOSEL.WORD = USB_FIFOSEL_MBW_8;
+    while (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) ;
+  }
+
+  pipe_state_t *pipe = &_dcd.pipe[0];
+  pipe->ff        = buffer_type;
+  pipe->length    = total_bytes;
+  pipe->remaining = total_bytes;
+  if (total_bytes) {
+    pipe->buf     = buffer;
+    if (ep_addr) { /* IN */
+      TU_ASSERT(USB0.DCPCTR.BIT.BSTS && (USB0.USBREQ.WORD & 0x80));
+      pipe0_xfer_in();
+    }
+    USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF;
+  } else {
+    /* ZLP */
+    pipe->buf        = NULL;
+    USB0.DCPCTR.WORD = USB_PIPECTR_CCPL | USB_PIPECTR_PID_BUF;
+  }
+  return true;
+}
+
+static bool process_pipe_xfer(int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes)
+{
+  const unsigned epn = tu_edpt_number(ep_addr);
+  const unsigned dir = tu_edpt_dir(ep_addr);
+  const unsigned num = _dcd.ep[dir][epn];
+
+  TU_ASSERT(num);
+
+  pipe_state_t *pipe  = &_dcd.pipe[num];
+  pipe->ff        = buffer_type;
+  pipe->buf       = buffer;
+  pipe->length    = total_bytes;
+  pipe->remaining = total_bytes;
+  if (dir) { /* IN */
+    if (total_bytes) {
+      pipe_xfer_in(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 reg_pipetre_t *pt = get_pipetre(num);
+    if (pt) {
+      const unsigned     mps = edpt_max_packet_size(num);
+      volatile uint16_t *ctr = get_pipectr(num);
+      if (*ctr & 0x3) *ctr = USB_PIPECTR_PID_NAK;
+      pt->TRE   = TU_BIT(8);
+      pt->TRN   = (total_bytes + mps - 1) / mps;
+      pt->TRENB = 1;
+      *ctr = USB_PIPECTR_PID_BUF;
+    }
+  }
+  //  TU_LOG1("X %x %d %d\r\n", ep_addr, total_bytes, buffer_type);
+  return true;
+}
+
+static bool process_edpt_xfer(int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes)
+{
+  const unsigned epn = tu_edpt_number(ep_addr);
+  if (0 == epn) {
+    return process_pipe0_xfer(buffer_type, ep_addr, buffer, total_bytes);
+  } else {
+    return process_pipe_xfer(buffer_type, ep_addr, buffer, total_bytes);
+  }
+}
+
+static void process_pipe0_bemp(uint8_t rhport)
+{
+  bool completed = pipe0_xfer_in();
+  if (completed) {
+    pipe_state_t *pipe = &_dcd.pipe[0];
+    dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN),
+                            pipe->length, XFER_RESULT_SUCCESS, true);
+  }
+}
+
+static void process_pipe_brdy(uint8_t rhport, unsigned num)
+{
+  pipe_state_t  *pipe = &_dcd.pipe[num];
+  const unsigned dir  = tu_edpt_dir(pipe->ep);
+  bool completed;
+
+  if (dir) { /* IN */
+    completed = pipe_xfer_in(num);
+  } else {
+    if (num) {
+      completed = pipe_xfer_out(num);
+    } else {
+      completed = pipe0_xfer_out();
+    }
+  }
+  if (completed) {
+    dcd_event_xfer_complete(rhport, pipe->ep,
+                            pipe->length - pipe->remaining,
+                            XFER_RESULT_SUCCESS, true);
+    //  TU_LOG1("C %d %d\r\n", num, pipe->length - pipe->remaining);
+  }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+  USB0.BEMPENB.WORD   = 1;
+  USB0.BRDYENB.WORD   = 1;
+  USB0.CFIFOCTR.WORD  = USB_FIFOCTR_BCLR;
+  USB0.D0FIFOSEL.WORD = 0;
+  while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+  USB0.D1FIFOSEL.WORD = 0;
+  while (USB0.D1FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
+  volatile uint16_t *ctr = (volatile uint16_t*)((uintptr_t)(&USB0.PIPE1CTR.WORD));
+  volatile uint16_t *tre = (volatile uint16_t*)((uintptr_t)(&USB0.PIPE1TRE.WORD));
+  for (int i = 1; i <= 5; ++i) {
+    USB0.PIPESEL.WORD  = i;
+    USB0.PIPECFG.WORD  = 0;
+    *ctr = USB_PIPECTR_ACLRM;
+    *ctr = 0;
+    ++ctr;
+    *tre = TU_BIT(8);
+    tre += 2;
+  }
+  for (int i = 6; i <= 9; ++i) {
+    USB0.PIPESEL.WORD  = i;
+    USB0.PIPECFG.WORD  = 0;
+    *ctr = USB_PIPECTR_ACLRM;
+    *ctr = 0;
+    ++ctr;
+  }
+  tu_varclr(&_dcd);
+  dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_set_address(uint8_t rhport)
+{
+  const uint32_t addr = USB0.USBADDR.BIT.USBADDR;
+  if (!addr) return;
+  const tusb_control_request_t setup_packet = {
+#if defined(__CCRX__)
+      .bmRequestType = { 0 },  /* Note: CCRX needs the braces over this struct member */
+#else
+      .bmRequestType = 0,
+#endif
+      .bRequest      = TUSB_REQ_SET_ADDRESS,
+      .wValue        = addr,
+      .wIndex        = 0,
+      .wLength       = 0,
+    };
+  dcd_event_setup_received(rhport, (const uint8_t*)&setup_packet, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_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.DRPD = 0;
+  USB0.SYSCFG.BIT.DCFM = 0;
+  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.DCPMAXP.BIT.MXPS  = 64;
+  USB0.INTENB0.WORD = USB_IS0_VBINT | USB_IS0_BRDY | USB_IS0_BEMP |
+    USB_IS0_DVST | USB_IS0_CTRT | (USE_SOF ? USB_IS0_SOFR: 0) | USB_IS0_RESM;
+  USB0.BEMPENB.WORD = 1;
+  USB0.BRDYENB.WORD = 1;
+
+  if (USB0.INTSTS0.BIT.VBSTS) {
+    dcd_connect(rhport);
+  }
+}
+
+void dcd_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 dcd_int_disable(uint8_t rhport)
+{
+  (void)rhport;
+#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
+  IEN(PERIB, INTB185) = 0;
+#else
+  IEN(USB0, USBI0) = 0;
+#endif
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  (void)rhport;
+  (void)dev_addr;
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void)rhport;
+  USB0.DVSTCTR0.BIT.WKUP = 1;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void)rhport;
+  USB0.SYSCFG.BIT.DPRPU = 1;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void)rhport;
+  USB0.SYSCFG.BIT.DPRPU = 0;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+  (void)rhport;
+
+  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;
+
+  const unsigned mps = tu_edpt_packet_size(ep_desc);
+  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;
+  _dcd.pipe[num].ep = ep_addr;
+  _dcd.ep[dir][epn] = num;
+
+  /* setup pipe */
+  dcd_int_disable(rhport);
+  USB0.PIPESEL.WORD  = num;
+  USB0.PIPEMAXP.WORD = mps;
+  volatile uint16_t *ctr = get_pipectr(num);
+  *ctr = USB_PIPECTR_ACLRM | USB_PIPECTR_SQCLR;
+  *ctr = 0;
+  unsigned cfg = (dir << 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.BRDYENB.WORD |= TU_BIT(num);
+  if (dir || (xfer != TUSB_XFER_BULK)) {
+    *ctr = USB_PIPECTR_PID_BUF;
+  }
+  // TU_LOG1("O %d %x %x\r\n", USB0.PIPESEL.WORD, USB0.PIPECFG.WORD, USB0.PIPEMAXP.WORD);
+  dcd_int_enable(rhport);
+
+  return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+  unsigned i = TU_ARRAY_SIZE(_dcd.pipe);
+  dcd_int_disable(rhport);
+  while (--i) { /* Close all pipes except 0 */
+    const unsigned ep_addr = _dcd.pipe[i].ep;
+    if (!ep_addr) continue;
+    dcd_edpt_close(rhport, ep_addr);
+  }
+  dcd_int_enable(rhport);
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+  (void)rhport;
+  const unsigned epn = tu_edpt_number(ep_addr);
+  const unsigned dir = tu_edpt_dir(ep_addr);
+  const unsigned num = _dcd.ep[dir][epn];
+
+  USB0.BRDYENB.WORD &= ~TU_BIT(num);
+  volatile uint16_t *ctr = get_pipectr(num);
+  *ctr = 0;
+  USB0.PIPESEL.WORD = num;
+  USB0.PIPECFG.WORD = 0;
+  _dcd.pipe[num].ep = 0;
+  _dcd.ep[dir][epn] = 0;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+  bool r;
+  dcd_int_disable(rhport);
+  r = process_edpt_xfer(0, ep_addr, buffer, total_bytes);
+  dcd_int_enable(rhport);
+  return r;
+}
+
+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);
+  bool r;
+  dcd_int_disable(rhport);
+  r = process_edpt_xfer(1, ep_addr, ff, total_bytes);
+  dcd_int_enable(rhport);
+  return r;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
+  if (!ctr) return;
+  dcd_int_disable(rhport);
+  const uint32_t pid = *ctr & 0x3;
+  *ctr = pid | USB_PIPECTR_PID_STALL;
+  *ctr = USB_PIPECTR_PID_STALL;
+  dcd_int_enable(rhport);
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
+  if (!ctr) return;
+  dcd_int_disable(rhport);
+  *ctr = USB_PIPECTR_SQCLR;
+
+  if (tu_edpt_dir(ep_addr)) { /* IN */
+    *ctr = USB_PIPECTR_PID_BUF;
+  } else {
+    const unsigned num = _dcd.ep[0][tu_edpt_number(ep_addr)];
+    USB0.PIPESEL.WORD  = num;
+    if (USB0.PIPECFG.BIT.TYPE != 1) {
+      *ctr = USB_PIPECTR_PID_BUF;
+    }
+  }
+  dcd_int_enable(rhport);
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void)rhport;
+
+  unsigned is0 = USB0.INTSTS0.WORD;
+  /* clear active bits except VALID (don't write 0 to already cleared bits according to the HW manual) */
+  USB0.INTSTS0.WORD = ~((USB_IS0_CTRT | USB_IS0_DVST | USB_IS0_SOFR | USB_IS0_RESM | USB_IS0_VBINT) & is0) | USB_IS0_VALID;
+  if (is0 & USB_IS0_VBINT) {
+    if (USB0.INTSTS0.BIT.VBSTS) {
+      dcd_connect(rhport);
+    } else {
+      dcd_disconnect(rhport);
+    }
+  }
+  if (is0 & USB_IS0_RESM) {
+    dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+#if (0==USE_SOF)
+    USB0.INTENB0.BIT.SOFE = 0;
+#endif
+  }
+  if ((is0 & USB_IS0_SOFR) && USB0.INTENB0.BIT.SOFE) {
+    // USBD will exit suspended mode when SOF event is received
+    dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+#if (0==USE_SOF)
+    USB0.INTENB0.BIT.SOFE = 0;
+#endif
+  }
+  if (is0 & USB_IS0_DVST) {
+    switch (is0 & USB_IS0_DVSQ) {
+    case USB_IS0_DVSQ_DEF:
+      process_bus_reset(rhport);
+      break;
+    case USB_IS0_DVSQ_ADDR:
+      process_set_address(rhport);
+      break;
+    case USB_IS0_DVSQ_SUSP0:
+    case USB_IS0_DVSQ_SUSP1:
+    case USB_IS0_DVSQ_SUSP2:
+    case USB_IS0_DVSQ_SUSP3:
+       dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+#if (0==USE_SOF)
+       USB0.INTENB0.BIT.SOFE = 1;
+#endif
+    default:
+      break;
+    }
+  }
+  if (is0 & USB_IS0_CTRT) {
+    if (is0 & USB_IS0_CTSQ_SETUP) {
+      /* A setup packet has been received. */
+      process_setup_packet(rhport);
+    } else if (0 == (is0 & USB_IS0_CTSQ_MSK)) {
+      /* A ZLP has been sent/received. */
+      process_status_completion(rhport);
+    }
+  }
+  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_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__)
+      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
+      };
+
+      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
new file mode 100644
index 0000000..dfe4093
--- /dev/null
+++ b/src/portable/sony/cxd56/dcd_cxd56.c
@@ -0,0 +1,416 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright 2019 Sony Semiconductor Solutions Corporation
+ *
+ * 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_CXD56
+
+#include <errno.h>
+#include <nuttx/usb/usbdev.h>
+#include <nuttx/arch.h>
+
+#include "device/dcd.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);
+
+struct usbdcd_driver_s
+{
+  struct usbdevclass_driver_s usbdevclass_driver;
+  FAR struct usbdev_ep_s *ep[CXD56_EPNUM];
+  FAR struct usbdev_req_s *req[CXD56_EPNUM];
+  osal_queue_t setup_queue;
+  bool setup_processed;
+  FAR uint8_t dataout[CXD56_MAX_DATA_OUT_SIZE];
+  size_t outlen;
+};
+
+static struct usbdcd_driver_s usbdcd_driver;
+static struct usbdev_s *usbdev;
+
+static int  _dcd_bind       (FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev);
+static void _dcd_unbind     (FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev);
+static int  _dcd_setup      (FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev,
+                             FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, size_t outlen);
+static void _dcd_disconnect (FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev);
+static void _dcd_suspend    (FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev);
+static void _dcd_resume     (FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev);
+
+static const struct usbdevclass_driverops_s g_driverops =
+{
+  _dcd_bind,       /* bind */
+  _dcd_unbind,     /* unbind */
+  _dcd_setup,      /* setup */
+  _dcd_disconnect, /* disconnect */
+  _dcd_suspend,    /* suspend */
+  _dcd_resume,     /* resume */
+};
+
+static void usbdcd_ep0incomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
+{
+  (void) ep;
+
+  uint8_t ep_addr = (uint32_t)req->priv;
+
+  if (req->result || req->xfrd != req->len)
+  {
+    if (req->len)
+    {
+      dcd_event_xfer_complete(0, ep_addr, req->xfrd, XFER_RESULT_SUCCESS, true);
+    }
+  }
+  else
+  {
+    if (req->xfrd)
+    {
+      dcd_event_xfer_complete(0, ep_addr, req->xfrd, XFER_RESULT_SUCCESS, true);
+    }
+  }
+}
+
+static int _dcd_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev)
+{
+  (void) driver;
+
+  usbdev = dev;
+  usbdcd_driver.ep[0] = dev->ep0;
+
+  usbdcd_driver.req[0] = EP_ALLOCREQ(usbdcd_driver.ep[0]);
+  if (usbdcd_driver.req[0] != NULL)
+  {
+    usbdcd_driver.req[0]->len = 64;
+    usbdcd_driver.req[0]->buf = EP_ALLOCBUFFER(usbdcd_driver.ep[0], 64);
+    if (!usbdcd_driver.req[0]->buf)
+    {
+      EP_FREEREQ(usbdcd_driver.ep[0], usbdcd_driver.req[0]);
+      usbdcd_driver.req[0] = NULL;
+    }
+  }
+
+  usbdcd_driver.req[0]->callback = usbdcd_ep0incomplete;
+
+  DEV_CONNECT(dev);
+  return 0;
+}
+
+static void _dcd_unbind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev)
+{
+  (void) driver;
+  (void) dev;
+}
+
+static int _dcd_setup(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev,
+                      FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, size_t outlen)
+{
+  (void) driver;
+  (void) dev;
+
+  if (usbdcd_driver.setup_processed)
+  {
+    usbdcd_driver.setup_processed = false;
+    dcd_event_setup_received(0, (uint8_t const *) ctrl, true);
+  }
+  else
+  {
+    osal_queue_send(usbdcd_driver.setup_queue, ctrl, true);
+  }
+
+  if (outlen > 0 && outlen <= CXD56_MAX_DATA_OUT_SIZE)
+  {
+    memcpy(usbdcd_driver.dataout, dataout, outlen);
+    usbdcd_driver.outlen = outlen;
+  }
+
+  return 0;
+}
+
+static void _dcd_disconnect(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev)
+{
+  (void) driver;
+
+  tusb_speed_t speed;
+
+  switch (dev->speed)
+  {
+    case USB_SPEED_LOW:
+      speed = TUSB_SPEED_LOW;
+      break;
+    case USB_SPEED_FULL:
+      speed = TUSB_SPEED_FULL;
+      break;
+    case USB_SPEED_HIGH:
+      speed = TUSB_SPEED_HIGH;
+      break;
+    default:
+      speed = TUSB_SPEED_HIGH;
+      break;
+  }
+
+  dcd_event_bus_reset(0, speed, true);
+  DEV_CONNECT(dev);
+}
+
+static void _dcd_suspend(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev)
+{
+  (void) driver;
+  (void) dev;
+
+  dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+}
+
+static void _dcd_resume(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev)
+{
+  (void) driver;
+  (void) dev;
+
+  dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+}
+
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  usbdcd_driver.usbdevclass_driver.speed = USB_SPEED_HIGH;
+  usbdcd_driver.usbdevclass_driver.ops = &g_driverops;
+  usbdcd_driver.setup_processed = true;
+  usbdcd_driver.setup_queue = osal_queue_create(&_setup_queue_def);
+
+  usbdev_register(&usbdcd_driver.usbdevclass_driver);
+}
+
+// Enable device interrupt
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+
+  up_enable_irq(CXD56_IRQ_USB_INT);
+}
+
+// Disable device interrupt
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+
+  up_disable_irq(CXD56_IRQ_USB_INT);
+}
+
+// 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;
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+
+  DEV_WAKEUP(usbdev);
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  DEV_CONNECT(usbdev);
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  DEV_DISCONNECT(usbdev);
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
+{
+  (void) rhport;
+
+  uint8_t epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+  uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+  uint8_t xfrtype = 0;
+  uint16_t const ep_mps = tu_edpt_packet_size(p_endpoint_desc);
+
+  struct usb_epdesc_s epdesc;
+
+  if (epnum >= CXD56_EPNUM)
+  {
+    return false;
+  }
+
+  switch (p_endpoint_desc->bmAttributes.xfer)
+  {
+  case 1:
+    xfrtype = USB_EP_ATTR_XFER_ISOC;
+    break;
+  case 2:
+    xfrtype = USB_EP_ATTR_XFER_BULK;
+    break;
+  case 3:
+    xfrtype = USB_EP_ATTR_XFER_INT;
+    break;
+  }
+
+  usbdcd_driver.ep[epnum] = DEV_ALLOCEP(usbdev, epnum, dir == TUSB_DIR_IN, xfrtype);
+  if (usbdcd_driver.ep[epnum] == NULL)
+  {
+    return false;
+  }
+
+  usbdcd_driver.req[epnum] = NULL;
+  usbdcd_driver.req[epnum] = EP_ALLOCREQ(usbdcd_driver.ep[epnum]);
+  if (usbdcd_driver.req[epnum] != NULL)
+  {
+    usbdcd_driver.req[epnum]->len = ep_mps;
+  }
+  else
+  {
+    return false;
+  }
+
+  usbdcd_driver.req[epnum]->callback = usbdcd_ep0incomplete;
+
+  epdesc.len = p_endpoint_desc->bLength;
+  epdesc.type = p_endpoint_desc->bDescriptorType;
+  epdesc.addr = p_endpoint_desc->bEndpointAddress;
+  epdesc.attr = xfrtype;
+  epdesc.mxpacketsize[0] = LSBYTE(ep_mps);
+  epdesc.mxpacketsize[1] = MSBYTE(ep_mps);
+  epdesc.interval = p_endpoint_desc->bInterval;
+
+  if (EP_CONFIGURE(usbdcd_driver.ep[epnum], &epdesc, false) < 0)
+  {
+    return false;
+  }
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  bool ret = true;
+  uint8_t epnum = tu_edpt_number(ep_addr);
+
+  if (epnum >= CXD56_EPNUM)
+  {
+    return false;
+  }
+
+  if (epnum == 0)
+  {
+    if (total_bytes == 0)
+    {
+      usbdcd_driver.setup_processed = true;
+      dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, false);
+    }
+    else if (ep_addr == 0x00 && total_bytes == usbdcd_driver.outlen)
+    {
+      memcpy(buffer, usbdcd_driver.dataout, usbdcd_driver.outlen);
+      dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
+      usbdcd_driver.outlen = 0;
+    }
+    else
+    {
+      usbdcd_driver.req[epnum]->len = total_bytes;
+      usbdcd_driver.req[epnum]->priv = (void *)((uint32_t)ep_addr);
+      usbdcd_driver.req[epnum]->flags = total_bytes < usbdcd_driver.ep[epnum]->maxpacket ? USBDEV_REQFLAGS_NULLPKT : 0;
+      usbdcd_driver.req[epnum]->buf = buffer;
+
+      if (EP_SUBMIT(usbdcd_driver.ep[epnum], usbdcd_driver.req[epnum]) < 0)
+      {
+        ret = false;
+      }
+    }
+
+    struct usb_ctrlreq_s ctrl;
+
+    if (usbdcd_driver.setup_processed)
+    {
+      if (osal_queue_receive(usbdcd_driver.setup_queue, &ctrl))
+      {
+        usbdcd_driver.setup_processed = false;
+        dcd_event_setup_received(0, (uint8_t *)&ctrl, false);
+      }
+    }
+  }
+  else
+  {
+    usbdcd_driver.req[epnum]->len = total_bytes;
+    usbdcd_driver.req[epnum]->priv = (void *)((uint32_t)ep_addr);
+    usbdcd_driver.req[epnum]->flags = total_bytes < usbdcd_driver.ep[epnum]->maxpacket ? USBDEV_REQFLAGS_NULLPKT : 0;
+    usbdcd_driver.req[epnum]->buf = buffer;
+
+    if (EP_SUBMIT(usbdcd_driver.ep[epnum], usbdcd_driver.req[epnum]) < 0)
+    {
+      ret = false;
+    }
+  }
+
+  return ret;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  uint8_t epnum = tu_edpt_number(ep_addr);
+
+  if (epnum >= CXD56_EPNUM)
+  {
+    return;
+  }
+
+  EP_STALL(usbdcd_driver.ep[epnum]);
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  uint8_t epnum = tu_edpt_number(ep_addr);
+
+  if (epnum >= CXD56_EPNUM)
+  {
+    return;
+  }
+
+  EP_RESUME(usbdcd_driver.ep[epnum]);
+}
+
+#endif
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
new file mode 100644
index 0000000..177a7ad
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -0,0 +1,1146 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Nathan Conrad
+ *
+ * Portions:
+ * Copyright (c) 2016 STMicroelectronics
+ * 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.
+ */
+
+/**********************************************
+ * This driver has been tested with the following MCUs:
+ *  - F070, F072, L053, F042F6
+ *
+ * It also should work with minimal changes for any ST MCU with an "USB A"/"PCD"/"HCD" peripheral. This
+ *  covers:
+ *
+ * F04x, F072, F078, 070x6/B      1024 byte buffer
+ * F102, F103                      512 byte buffer; no internal D+ pull-up (maybe many more changes?)
+ * F302xB/C, F303xB/C, F373        512 byte buffer; no internal D+ pull-up
+ * F302x6/8, F302xD/E2, F303xD/E  1024 byte buffer; no internal D+ pull-up
+ * L0x2, L0x3                     1024 byte buffer
+ * L1                              512 byte buffer
+ * L4x2, L4x3                     1024 byte buffer
+ *
+ * To use this driver, you must:
+ * - If you are using a device with crystal-less USB, set up the clock recovery system (CRS)
+ * - Remap pins to be D+/D- on devices that they are shared (for example: F042Fx)
+ *   - This is different to the normal "alternate function" GPIO interface, needs to go through SYSCFG->CFGRx register
+ * - Enable USB clock; Perhaps use __HAL_RCC_USB_CLK_ENABLE();
+ * - (Optionally configure GPIO HAL to tell it the USB driver is using the USB pins)
+ * - call tusb_init();
+ * - periodically call tusb_task();
+ *
+ * Assumptions of the driver:
+ * - You are not using CAN (it must share the packet buffer)
+ * - APB clock is >= 10 MHz
+ * - On some boards, series resistors are required, but not on others.
+ * - On some boards, D+ pull up resistor (1.5kohm) is required, but not on others.
+ * - You don't have long-running interrupts; some USB packets must be quickly responded to.
+ * - You have the ST CMSIS library linked into the project. HAL is not used.
+ *
+ * Current driver limitations (i.e., a list of features for you to add):
+ * - STALL handled, but not tested.
+ *   - Does it work? No clue.
+ * - All EP BTABLE buffers are created based on max packet size of first EP opened with that address.
+ * - No isochronous endpoints
+ * - Endpoint index is the ID of the endpoint
+ *   - This means that priority is given to endpoints with lower ID numbers
+ *   - Code is mixing up EP IX with EP ID. Everywhere.
+ * - Packet buffer memory is copied in the interrupt.
+ *   - This is better for performance, but means interrupts are disabled for longer
+ *   - DMA may be the best choice, but it could also be pushed to the USBD task.
+ * - No double-buffering
+ * - No DMA
+ * - Minimal error handling
+ *   - Perhaps error interrupts should be reported to the stack, or cause a device reset?
+ * - Assumes a single USB peripheral; I think that no hardware has multiple so this is fine.
+ * - Add a callback for enabling/disabling the D+ PU on devices without an internal PU.
+ * - F3 models use three separate interrupts. I think we could only use the LP interrupt for
+ *     everything?  However, the interrupts are configurable so the DisableInt and EnableInt
+ *     below functions could be adjusting the wrong interrupts (if they had been reconfigured)
+ * - LPM is not used correctly, or at all?
+ *
+ * USB documentation and Reference implementations
+ * - STM32 Reference manuals
+ * - STM32 USB Hardware Guidelines AN4879
+ *
+ * - STM32 HAL (much of this driver is based on this)
+ * - libopencm3/lib/stm32/common/st_usbfs_core.c
+ * - Keil USB Device http://www.keil.com/pack/doc/mw/USB/html/group__usbd.html
+ *
+ * - YouTube OpenTechLab 011; https://www.youtube.com/watch?v=4FOkJLp_PUw
+ *
+ * Advantages over HAL driver:
+ * - Tiny (saves RAM, assumes a single USB peripheral)
+ *
+ * Notes:
+ * - The buffer table is allocated as endpoints are opened. The allocation is only
+ *   cleared when the device is reset. This may be bad if the USB device needs
+ *   to be reconfigured.
+ */
+
+#include "tusb_option.h"
+
+#if defined(STM32F102x6) || defined(STM32F102xB) || \
+    defined(STM32F103x6) || defined(STM32F103xB) || \
+    defined(STM32F103xE) || defined(STM32F103xG)
+#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) || \
+        (TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) \
+      )
+
+// In order to reduce the dependance on HAL, we undefine this.
+// Some definitions are copied to our private include file.
+#undef USE_HAL_DRIVER
+
+#include "device/dcd.h"
+#include "portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h"
+
+
+/*****************************************************
+ * Configuration
+ *****************************************************/
+
+// HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM
+// (8u here would mean 8 IN and 8 OUT)
+#ifndef MAX_EP_COUNT
+#  define MAX_EP_COUNT 8U
+#endif
+
+// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it
+// Both of these MUST be a multiple of 2, and are in byte units.
+#ifndef DCD_STM32_BTABLE_BASE
+#  define DCD_STM32_BTABLE_BASE 0U
+#endif
+
+#ifndef DCD_STM32_BTABLE_LENGTH
+#  define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE)
+#endif
+
+// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
+// We disable SOF for now until needed later on
+#ifndef USE_SOF
+#  define USE_SOF     0
+#endif
+
+/***************************************************
+ * Checks, structs, defines, function definitions, etc.
+ */
+
+TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware");
+
+TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH),
+    "BTABLE does not fit in PMA RAM");
+
+TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes");
+
+// One of these for every EP IN & OUT, uses a bit of RAM....
+typedef struct
+{
+  uint8_t * buffer;
+  // tu_fifo_t * ff;  // TODO support dcd_edpt_xfer_fifo API
+  uint16_t total_len;
+  uint16_t queued_len;
+  uint16_t pma_ptr;
+  uint8_t max_packet_size;
+  uint8_t pma_alloc_size;
+} xfer_ctl_t;
+
+static xfer_ctl_t xfer_status[MAX_EP_COUNT][2];
+
+static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t epnum, uint32_t dir)
+{
+  return &xfer_status[epnum][dir];
+}
+
+static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6];
+
+static uint8_t remoteWakeCountdown; // When wake is requested
+
+// into the stack.
+static void dcd_handle_bus_reset(void);
+static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix);
+static void dcd_ep_ctr_handler(void);
+
+// PMA allocation/access 
+static uint8_t open_ep_count;
+static uint16_t ep_buf_ptr; ///< Points to first free memory location
+static void dcd_pma_alloc_reset(void);
+static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length);
+static void dcd_pma_free(uint8_t ep_addr);
+static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes);
+static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes);
+
+//static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes);
+//static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes);
+
+// Using a function due to better type checks
+// This seems better than having to do type casts everywhere else
+static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) {
+  *reg = (uint16_t)(*reg & ~mask);
+}
+
+// Bits in ISTR are cleared upon writing 0
+static inline void clear_istr_bits(uint16_t mask) {
+  USB->ISTR = ~mask;
+}
+
+void dcd_init (uint8_t rhport)
+{
+  /* Clocks should already be enabled */
+  /* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */
+
+  /* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL.
+   * Here, the RM is followed. */
+
+  for(uint32_t i = 0; i<200; i++) // should be a few us
+  {
+    asm("NOP");
+  }
+	// Perform USB peripheral reset
+  USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
+  for(uint32_t i = 0; i<200; i++) // should be a few us
+  {
+    asm("NOP");
+  }
+  reg16_clear_bits(&USB->CNTR, USB_CNTR_PDWN);// Remove powerdown
+  // Wait startup time, for F042 and F070, this is <= 1 us.
+  for(uint32_t i = 0; i<200; i++) // should be a few us
+  {
+    asm("NOP");
+  }
+  USB->CNTR = 0; // Enable USB
+  
+  USB->BTABLE = DCD_STM32_BTABLE_BASE;
+
+  USB->ISTR = 0; // Clear pending interrupts
+
+  // Reset endpoints to disabled
+  for(uint32_t i=0; i<STFSDEV_EP_COUNT; i++)
+  {
+    // This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED.
+    pcd_set_endpoint(USB,i,0u);
+  }
+
+  USB->CNTR |= USB_CNTR_RESETM | (USE_SOF ? USB_CNTR_SOFM : 0) | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
+  dcd_handle_bus_reset();
+  
+  // Enable pull-up if supported
+  if ( dcd_connect ) dcd_connect(rhport);
+}
+
+// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU.
+#if defined(USB_BCDR_DPPU)
+
+// Disable internal D+ PU
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  USB->BCDR &= ~(USB_BCDR_DPPU);
+}
+
+// Enable internal D+ PU
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  USB->BCDR |= USB_BCDR_DPPU;
+}
+
+#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151
+// Disable internal D+ PU
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU);
+}
+
+// Enable internal D+ PU
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
+}
+#endif
+
+// Enable device interrupt
+void dcd_int_enable (uint8_t rhport)
+{
+  (void)rhport;
+  // Member here forces write to RAM before allowing ISR to execute
+  __DSB();
+  __ISB();
+#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0
+  NVIC_EnableIRQ(USB_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
+  NVIC_EnableIRQ(USB_LP_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
+  // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+  // shared USB/CAN IRQs to separate CAN and USB IRQs.
+  // This dynamically checks if this remap is active to enable the right IRQs.
+  #ifdef SYSCFG_CFGR1_USB_IT_RMP
+  if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP)
+  {
+    NVIC_EnableIRQ(USB_HP_IRQn);
+    NVIC_EnableIRQ(USB_LP_IRQn);
+    NVIC_EnableIRQ(USBWakeUp_RMP_IRQn);
+  }
+  else
+  #endif
+  {
+    NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn);
+    NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn);
+    NVIC_EnableIRQ(USBWakeUp_IRQn);
+  }
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
+  NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
+  NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
+  NVIC_EnableIRQ(USBWakeUp_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+  NVIC_EnableIRQ(USB_HP_IRQn);
+  NVIC_EnableIRQ(USB_LP_IRQn);
+  NVIC_EnableIRQ(USBWakeUp_IRQn);
+
+#else
+  #error Unknown arch in USB driver
+#endif
+}
+
+// Disable device interrupt
+void dcd_int_disable(uint8_t rhport)
+{
+  (void)rhport;
+
+#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0
+  NVIC_DisableIRQ(USB_IRQn);
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
+  NVIC_DisableIRQ(USB_LP_IRQn);
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
+  // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+  // shared USB/CAN IRQs to separate CAN and USB IRQs.
+  // This dynamically checks if this remap is active to disable the right IRQs.
+  #ifdef SYSCFG_CFGR1_USB_IT_RMP
+  if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP)
+  {
+    NVIC_DisableIRQ(USB_HP_IRQn);
+    NVIC_DisableIRQ(USB_LP_IRQn);
+    NVIC_DisableIRQ(USBWakeUp_RMP_IRQn);
+  }
+  else
+  #endif
+  {
+    NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn);
+    NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
+    NVIC_DisableIRQ(USBWakeUp_IRQn);
+  }
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
+  NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
+  NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
+  NVIC_DisableIRQ(USBWakeUp_IRQn);
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+  NVIC_DisableIRQ(USB_HP_IRQn);
+  NVIC_DisableIRQ(USB_LP_IRQn);
+  NVIC_DisableIRQ(USBWakeUp_IRQn);
+
+#else
+  #error Unknown arch in USB driver
+#endif
+
+  // CMSIS has a membar after disabling interrupts
+}
+
+// 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
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+
+  // DCD can only set address after status for this request is complete.
+  // do it at dcd_edpt0_status_complete()
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+
+  USB->CNTR |= (uint16_t) USB_CNTR_RESUME;
+  remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms.
+}
+
+static const tusb_desc_endpoint_t 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 const tusb_desc_endpoint_t 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
+};
+
+static void dcd_handle_bus_reset(void)
+{
+  //__IO uint16_t * const epreg = &(EPREG(0));
+  USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag
+
+  // Clear all EPREG (or maybe this is automatic? I'm not sure)
+  for(uint32_t i=0; i<STFSDEV_EP_COUNT; i++)
+  {
+    pcd_set_endpoint(USB,i,0u);
+  }
+
+  dcd_pma_alloc_reset();
+  dcd_edpt_open (0, &ep0OUT_desc);
+  dcd_edpt_open (0, &ep0IN_desc);
+
+  USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero.
+}
+
+// Handle CTR interrupt for the TX/IN direction
+//
+// Upon call, (wIstr & USB_ISTR_DIR) == 0U
+static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
+{
+  uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
+  uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
+
+  // Verify the CTR_TX bit is set. This was in the ST Micro code,
+  // but I'm not sure it's actually necessary?
+  if((wEPRegVal & USB_EP_CTR_TX) == 0U)
+  {
+    return;
+  }
+
+  /* clear int flag */
+  pcd_clear_tx_ep_ctr(USB, EPindex);
+
+  xfer_ctl_t * xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_IN);
+  if((xfer->total_len != xfer->queued_len)) /* TX not complete */
+  {
+      dcd_transmit_packet(xfer, EPindex);
+  }
+  else /* TX Complete */
+  {
+    dcd_event_xfer_complete(0, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true);
+  }
+}
+
+// Handle CTR interrupt for the RX/OUT direction
+//
+// Upon call, (wIstr & USB_ISTR_DIR) == 0U
+static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
+{
+  uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
+  uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
+  uint32_t count = pcd_get_ep_rx_cnt(USB,EPindex);
+
+  xfer_ctl_t *xfer = xfer_ctl_ptr(EPindex,TUSB_DIR_OUT);
+
+  // Verify the CTR_RX bit is set. This was in the ST Micro code,
+  // but I'm not sure it's actually necessary?
+  if((wEPRegVal & USB_EP_CTR_RX) == 0U)
+  {
+    return;
+  }
+  
+  if((EPindex == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) /* Setup packet */
+  {
+    // The setup_received function uses memcpy, so this must first copy the setup data into
+    // user memory, to allow for the 32-bit access that memcpy performs.
+    uint8_t userMemBuf[8];
+    /* Get SETUP Packet*/
+    if(count == 8) // Setup packet should always be 8 bytes. If not, ignore it, and try again.
+    {
+      // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here)
+      pcd_set_ep_rx_status(USB,0u,USB_EP_RX_NAK);
+      pcd_set_ep_tx_status(USB,0u,USB_EP_TX_NAK);
+      dcd_read_packet_memory(userMemBuf, *pcd_ep_rx_address_ptr(USB,EPindex), 8);
+      dcd_event_setup_received(0, (uint8_t*)userMemBuf, true);
+    }
+  }
+  else
+  {
+    // Clear RX CTR interrupt flag
+    if(EPindex != 0u)
+    {
+      pcd_clear_rx_ep_ctr(USB, EPindex);
+    }
+
+    if (count != 0U)
+    {
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+      if (xfer->ff)
+      {
+        dcd_read_packet_memory_ff(xfer->ff, *pcd_ep_rx_address_ptr(USB,EPindex), count);
+      }
+      else
+#endif
+      {
+        dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), *pcd_ep_rx_address_ptr(USB,EPindex), count);
+      }
+
+      xfer->queued_len = (uint16_t)(xfer->queued_len + count);
+    }
+
+    if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
+    {
+      /* RX COMPLETE */
+      dcd_event_xfer_complete(0, EPindex, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+      // Though the host could still send, we don't know.
+      // Does the bulk pipe need to be reset to valid to allow for a ZLP?
+    }
+    else
+    {
+      uint32_t remaining = (uint32_t)xfer->total_len - (uint32_t)xfer->queued_len;
+      if(remaining >= xfer->max_packet_size) {
+        pcd_set_ep_rx_cnt(USB, EPindex,xfer->max_packet_size);
+      } else {
+        pcd_set_ep_rx_cnt(USB, EPindex,remaining);
+      }
+      pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID);
+    }
+  }
+
+  // For EP0, prepare to receive another SETUP packet.
+  // Clear CTR last so that a new packet does not overwrite the packing being read.
+  // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared)
+  if(EPindex == 0u)
+  {
+      // Always be prepared for a status packet...
+    pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
+    pcd_clear_rx_ep_ctr(USB, EPindex);
+  }
+}
+
+static void dcd_ep_ctr_handler(void)
+{
+  uint32_t wIstr;
+
+  /* stay in loop while pending interrupts */
+  while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U)
+  {
+
+    if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */
+    {
+      dcd_ep_ctr_tx_handler(wIstr);
+    }
+    else /* RX/OUT*/
+    {
+      dcd_ep_ctr_rx_handler(wIstr);
+    }
+  }
+}
+
+void dcd_int_handler(uint8_t rhport) {
+
+  (void) rhport;
+
+  uint32_t int_status = USB->ISTR;
+  //const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP
+  //    | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF;
+  // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ )
+
+  // The ST driver loops here on the CTR bit, but that loop has been moved into the
+  // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't
+  // be triggered repeatedly.
+
+  if(int_status & USB_ISTR_RESET) {
+    // USBRST is start of reset.
+    clear_istr_bits(USB_ISTR_RESET);
+    dcd_handle_bus_reset();
+    dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+    return; // Don't do the rest of the things here; perhaps they've been cleared?
+  }
+
+  if (int_status & USB_ISTR_CTR)
+  {
+    /* servicing of the endpoint correct transfer interrupt */
+    /* clear of the CTR flag into the sub */
+    dcd_ep_ctr_handler();
+  }
+
+  if (int_status & USB_ISTR_WKUP)
+  {
+    reg16_clear_bits(&USB->CNTR, USB_CNTR_LPMODE);
+    reg16_clear_bits(&USB->CNTR, USB_CNTR_FSUSP);
+    clear_istr_bits(USB_ISTR_WKUP);
+    dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+  }
+
+  if (int_status & USB_ISTR_SUSP)
+  {
+    /* Suspend is asserted for both suspend and unplug events. without Vbus monitoring,
+     * these events cannot be differentiated, so we only trigger suspend. */
+
+    /* Force low-power mode in the macrocell */
+    USB->CNTR |= USB_CNTR_FSUSP;
+    USB->CNTR |= USB_CNTR_LPMODE;
+
+    /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
+    clear_istr_bits(USB_ISTR_SUSP);
+    dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+  }
+
+#if USE_SOF
+  if(int_status & USB_ISTR_SOF) {
+    clear_istr_bits(USB_ISTR_SOF);
+    dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+  }
+#endif 
+
+  if(int_status & USB_ISTR_ESOF) {
+    if(remoteWakeCountdown == 1u)
+    {
+      USB->CNTR &= (uint16_t)(~USB_CNTR_RESUME);
+    }
+    if(remoteWakeCountdown > 0u)
+    {
+      remoteWakeCountdown--;
+    }
+    clear_istr_bits(USB_ISTR_ESOF);
+  }
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+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 &&
+      request->bRequest == TUSB_REQ_SET_ADDRESS )
+  {
+    uint8_t const dev_addr = (uint8_t) request->wValue;
+
+    // Setting new address after the whole request is complete
+    reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD);
+    USB->DADDR = (uint16_t)(USB->DADDR | dev_addr); // leave the enable bit set
+  }
+}
+
+static void dcd_pma_alloc_reset(void)
+{
+  ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each)
+  //TU_LOG2("dcd_pma_alloc_reset()\r\n");
+  for(uint32_t i=0; i<MAX_EP_COUNT; i++)
+  {
+    xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_alloc_size = 0U;
+    xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U;
+    xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U;
+    xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U;
+  }
+}
+
+/***
+ * Allocate a section of PMA
+ * 
+ * If the EP number has already been allocated, and the new allocation
+ * is larger than the old allocation, then this will fail with a TU_ASSERT.
+ * (This is done to simplify the code. More complicated algorithms could be used)
+ * 
+ * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually.
+ */
+static uint16_t dcd_pma_alloc(uint8_t ep_addr, size_t length)
+{
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+  xfer_ctl_t* epXferCtl = xfer_ctl_ptr(epnum,dir);
+
+  if(epXferCtl->pma_alloc_size != 0U)
+  {
+    //TU_LOG2("dcd_pma_alloc(%x,%x)=%x (cached)\r\n",ep_addr,length,epXferCtl->pma_ptr);
+    // Previously allocated
+    TU_ASSERT(length <= epXferCtl->pma_alloc_size, 0xFFFF);  // Verify no larger than previous alloc
+    return epXferCtl->pma_ptr;
+  }
+  
+  uint16_t addr = ep_buf_ptr; 
+  ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer
+  
+  // Verify no overflow
+  TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF);
+  
+  epXferCtl->pma_ptr = addr;
+  epXferCtl->pma_alloc_size = length;
+  //TU_LOG2("dcd_pma_alloc(%x,%x)=%x\r\n",ep_addr,length,addr);
+
+  return addr;
+}
+
+/***
+ * Free a block of PMA space
+ */
+static void dcd_pma_free(uint8_t ep_addr)
+{
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  // Presently, this should never be called for EP0 IN/OUT
+  TU_ASSERT(open_ep_count > 2, /**/);
+  TU_ASSERT(xfer_ctl_ptr(epnum,dir)->max_packet_size != 0, /**/);
+  open_ep_count--;
+
+  // If count is 2, only EP0 should be open, so allocations can be mostly reset.
+
+  if(open_ep_count == 2)
+  {
+    ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT + 2*CFG_TUD_ENDPOINT0_SIZE; // 8 bytes per endpoint (two TX and two RX words, each), and EP0
+
+    // Skip EP0
+    for(uint32_t i=1; i<MAX_EP_COUNT; i++)
+    {
+      xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_alloc_size = 0U;
+      xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_alloc_size = 0U;
+      xfer_ctl_ptr(i,TUSB_DIR_OUT)->pma_ptr = 0U;
+      xfer_ctl_ptr(i,TUSB_DIR_IN)->pma_ptr = 0U;
+    }
+  }
+}
+
+// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers,
+// so I'm using the #define from HAL here, instead.
+
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+  (void)rhport;
+  uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+  uint8_t const dir   = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+  const uint16_t epMaxPktSize = tu_edpt_packet_size(p_endpoint_desc);
+  uint16_t pma_addr;
+  uint32_t wType;
+  
+  // Isochronous not supported (yet), and some other driver assumptions.
+  TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
+  TU_ASSERT(epnum < MAX_EP_COUNT);
+
+  // Set type
+  switch(p_endpoint_desc->bmAttributes.xfer) {
+  case TUSB_XFER_CONTROL:
+    wType = USB_EP_CONTROL;
+    break;
+#if (0)
+  case TUSB_XFER_ISOCHRONOUS: // FIXME: Not yet supported
+    wType = USB_EP_ISOCHRONOUS;
+    break;
+#endif
+
+  case TUSB_XFER_BULK:
+    wType = USB_EP_CONTROL;
+    break;
+
+  case TUSB_XFER_INTERRUPT:
+    wType = USB_EP_INTERRUPT;
+    break;
+
+  default:
+    TU_ASSERT(false);
+  }
+
+  pcd_set_eptype(USB, epnum, wType);
+  pcd_set_ep_address(USB, epnum, epnum);
+  // Be normal, for now, instead of only accepting zero-byte packets (on control endpoint)
+  // or being double-buffered (bulk endpoints)
+  pcd_clear_ep_kind(USB,0);
+
+  pma_addr = dcd_pma_alloc(p_endpoint_desc->bEndpointAddress, epMaxPktSize);
+
+  if(dir == TUSB_DIR_IN)
+  {
+    *pcd_ep_tx_address_ptr(USB, epnum) = pma_addr;
+    pcd_set_ep_tx_cnt(USB, epnum, epMaxPktSize);
+    pcd_clear_tx_dtog(USB, epnum);
+    pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_NAK);
+  }
+  else
+  {
+    *pcd_ep_rx_address_ptr(USB, epnum) = pma_addr;
+    pcd_set_ep_rx_cnt(USB, epnum, epMaxPktSize);
+    pcd_clear_rx_dtog(USB, epnum);
+    pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_NAK);
+  }
+
+  xfer_ctl_ptr(epnum, dir)->max_packet_size = epMaxPktSize;
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+/**
+ * Close an endpoint.
+ * 
+ * This function may be called with interrupts enabled or disabled.
+ * 
+ * This also clears transfers in progress, should there be any.
+ */
+void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
+{
+  (void)rhport;
+  uint32_t const epnum = tu_edpt_number(ep_addr);
+  uint32_t const dir   = tu_edpt_dir(ep_addr);
+  
+  if(dir == TUSB_DIR_IN)
+  {
+    pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_DIS);
+  }
+  else
+  {
+    pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_DIS);
+  }
+
+  dcd_pma_free(ep_addr);
+}
+
+// Currently, single-buffered, and only 64 bytes at a time (max)
+
+static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix)
+{
+  uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len);
+
+  if(len > xfer->max_packet_size) // max packet size for FS transfer
+  {
+    len = xfer->max_packet_size;
+  }
+  uint16_t oldAddr = *pcd_ep_tx_address_ptr(USB,ep_ix);
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+  if (xfer->ff)
+  {
+    dcd_write_packet_memory_ff(xfer->ff, oldAddr, len);
+  }
+  else
+#endif
+  {
+    dcd_write_packet_memory(oldAddr, &(xfer->buffer[xfer->queued_len]), len);
+  }
+  xfer->queued_len = (uint16_t)(xfer->queued_len + len);
+
+  pcd_set_ep_tx_cnt(USB,ep_ix,len);
+  pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID);
+}
+
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir);
+
+  xfer->buffer = buffer;
+  // xfer->ff     = NULL; // TODO support dcd_edpt_xfer_fifo API
+  xfer->total_len = total_bytes;
+  xfer->queued_len = 0;
+
+  if ( dir == TUSB_DIR_OUT )
+  {
+    // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid
+    // buffer for the control endpoint.
+    if (epnum == 0 && buffer == NULL)
+    {
+        xfer->buffer = (uint8_t*)_setup_packet;
+    }
+    if(total_bytes > xfer->max_packet_size)
+    {
+      pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size);
+    } else {
+      pcd_set_ep_rx_cnt(USB,epnum,total_bytes);
+    }
+    pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID);
+  }
+  else // IN
+  {
+    dcd_transmit_packet(xfer,epnum);
+  }
+  return true;
+}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  xfer_ctl_t * xfer = xfer_ctl_ptr(epnum,dir);
+
+  xfer->buffer = NULL;
+  // xfer->ff     = ff; // TODO support dcd_edpt_xfer_fifo API
+  xfer->total_len = total_bytes;
+  xfer->queued_len = 0;
+
+  if ( dir == TUSB_DIR_OUT )
+  {
+    if(total_bytes > xfer->max_packet_size)
+    {
+      pcd_set_ep_rx_cnt(USB,epnum,xfer->max_packet_size);
+    } else {
+      pcd_set_ep_rx_cnt(USB,epnum,total_bytes);
+    }
+    pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_VALID);
+  }
+  else // IN
+  {
+    dcd_transmit_packet(xfer,epnum);
+  }
+  return true;
+}
+#endif
+
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+{
+  (void)rhport;
+
+  if (ep_addr & 0x80)
+  { // IN
+    pcd_set_ep_tx_status(USB, ep_addr & 0x7F, USB_EP_TX_STALL);
+  }
+  else
+  { // OUT
+    pcd_set_ep_rx_status(USB, ep_addr, USB_EP_RX_STALL);
+  }
+}
+
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+  (void)rhport;
+
+  if (ep_addr & 0x80)
+  { // IN
+    ep_addr &= 0x7F;
+
+    pcd_set_ep_tx_status(USB,ep_addr, USB_EP_TX_NAK);
+
+    /* Reset to DATA0 if clearing stall condition. */
+    pcd_clear_tx_dtog(USB,ep_addr);
+  }
+  else
+  { // OUT
+    /* Reset to DATA0 if clearing stall condition. */
+    pcd_clear_rx_dtog(USB,ep_addr);
+
+    pcd_set_ep_rx_status(USB,ep_addr, USB_EP_RX_NAK);
+  }
+}
+
+// Packet buffer access can only be 8- or 16-bit.
+/**
+  * @brief Copy a buffer from user memory area to packet memory area (PMA).
+  *        This uses byte-access for user memory (so support non-aligned buffers)
+  *        and 16-bit access for packet memory.
+  * @param   dst, byte address in PMA; must be 16-bit aligned
+  * @param   src pointer to user memory area.
+  * @param   wPMABufAddr address into PMA.
+  * @param   wNBytes no. of bytes to be copied.
+  * @retval None
+  */
+static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, size_t wNBytes)
+{
+  uint32_t n =  ((uint32_t)wNBytes + 1U) >> 1U;
+  uint32_t i;
+  uint16_t temp1, temp2;
+  const uint8_t * srcVal;
+
+  // The GCC optimizer will combine access to 32-bit sizes if we let it. Force
+  // it volatile so that it won't do that.
+  __IO uint16_t *pdwVal;
+
+  srcVal = src;
+  pdwVal = &pma[PMA_STRIDE*(dst>>1)];
+
+  for (i = n; i != 0; i--)
+  {
+    temp1 = (uint16_t) *srcVal;
+    srcVal++;
+    temp2 = temp1 | ((uint16_t)((uint16_t) ((*srcVal) << 8U))) ;
+    *pdwVal = temp2;
+    pdwVal += PMA_STRIDE;
+    srcVal++;
+  }
+  return true;
+}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+/**
+  * @brief Copy from FIFO to packet memory area (PMA).
+  *        Uses byte-access of system memory and 16-bit access of packet memory
+  * @param   wNBytes no. of bytes to be copied.
+  * @retval None
+  */
+
+// THIS FUNCTION IS UNTESTED
+
+static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wNBytes)
+{
+  // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
+  // Check for first linear part
+  void * src;
+  uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes);  // We want to read from the FIFO        - THIS FUNCTION CHANGED!!!
+  TU_VERIFY(len && dcd_write_packet_memory(dst, src, len));           // and write it into the PMA
+  tu_fifo_advance_read_pointer(ff, len);
+
+  // Check for wrapped part
+  if (len < wNBytes)
+  {
+    // Get remaining wrapped length
+    uint16_t len2 = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes - len);
+    TU_VERIFY(len2);
+
+    // Update destination pointer
+    dst += len;
+
+    // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split
+    if (len % 2)    // If len is uneven there is a byte left to copy
+    {
+      // Since PMA can accessed only 16 bit-wise we copy the last byte again
+      tu_fifo_backward_read_pointer(ff, 1);                 // Move one byte back and copy two bytes for the PMA
+      tu_fifo_read_n(ff, (void *) &pma[PMA_STRIDE*(dst>>1)], 2);     // Since EP FIFOs must be of item size 1 this is safe to do
+      dst++;
+      len2--;
+    }
+
+    TU_VERIFY(dcd_write_packet_memory(dst, src, len2));
+    tu_fifo_advance_write_pointer(ff, len2);
+  }
+
+  return true;
+}
+#endif
+
+/**
+  * @brief Copy a buffer from packet memory area (PMA) to user memory area.
+  *        Uses byte-access of system memory and 16-bit access of packet memory
+  * @param   wNBytes no. of bytes to be copied.
+  * @retval None
+  */
+static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, size_t wNBytes)
+{
+  uint32_t n = (uint32_t)wNBytes >> 1U;
+  uint32_t i;
+  // The GCC optimizer will combine access to 32-bit sizes if we let it. Force
+  // it volatile so that it won't do that.
+  __IO const uint16_t *pdwVal;
+  uint32_t temp;
+
+  pdwVal = &pma[PMA_STRIDE*(src>>1)];
+  uint8_t *dstVal = (uint8_t*)dst;
+
+  for (i = n; i != 0U; i--)
+  {
+    temp = *pdwVal;
+    pdwVal += PMA_STRIDE;
+    *dstVal++ = ((temp >> 0) & 0xFF);
+    *dstVal++ = ((temp >> 8) & 0xFF);
+  }
+
+  if (wNBytes % 2)
+  {
+    temp = *pdwVal;
+    pdwVal += PMA_STRIDE;
+    *dstVal++ = ((temp >> 0) & 0xFF);
+  }
+  return true;
+}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+/**
+  * @brief Copy a buffer from user packet memory area (PMA) to FIFO.
+  *        Uses byte-access of system memory and 16-bit access of packet memory
+  * @param   wNBytes no. of bytes to be copied.
+  * @retval None
+  */
+
+// THIS FUNCTION IS UNTESTED
+
+static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNBytes)
+{
+  // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
+  // Check for first linear part
+  void * dst;
+  uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes);           // THIS FUNCTION CHANGED!!!!
+  TU_VERIFY(len && dcd_read_packet_memory(dst, src, len));
+  tu_fifo_advance_write_pointer(ff, len);
+
+  // Check for wrapped part
+  if (len < wNBytes)
+  {
+    // Get remaining wrapped length
+    uint16_t len2 = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes - len);
+    TU_VERIFY(len2);
+
+    // Update source pointer
+    src += len;
+
+    // Since PMA is accessed 16-bit wise we need to handle the case when a 16 bit value was split
+    if (len % 2)    // If len is uneven there is a byte left to copy
+    {
+      uint32_t temp = pma[PMA_STRIDE*(src>>1)];
+      *((uint8_t *)dst++) = ((temp >> 8) & 0xFF);
+      src++;
+      len2--;
+    }
+
+    TU_VERIFY(dcd_read_packet_memory(dst, src, len2));
+    tu_fifo_advance_write_pointer(ff, len2);
+  }
+
+  return true;
+}
+
+#endif
+
+#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
new file mode 100644
index 0000000..596f7be
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
@@ -0,0 +1,415 @@
+/**
+  ******************************************************************************
+  * @file    dcd_stm32f0_pvt_st.h
+  * @brief   DCD utilities from ST code
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+  * <h2><center>&copy; parts COPYRIGHT(c) N Conrad</center></h2>
+  *
+  * Redistribution and use in source and binary forms, with or without modification,
+  * are permitted provided that the following conditions are met:
+  *   1. Redistributions of source code must retain the above copyright notice,
+  *      this list of conditions and the following disclaimer.
+  *   2. Redistributions in binary form must reproduce the above copyright notice,
+  *      this list of conditions and the following disclaimer in the documentation
+  *      and/or other materials provided with the distribution.
+  *   3. Neither the name of STMicroelectronics nor the names of its contributors
+  *      may be used to endorse or promote products derived from this software
+  *      without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  **********/
+
+// This file contains source copied from ST's HAL, and thus should have their copyright statement.
+
+// PMA_LENGTH is PMA buffer size in bytes.
+// On 512-byte devices, access with a stride of two words (use every other 16-bit address)
+// On 1024-byte devices, access with a stride of one word (use every 16-bit address)
+
+#ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
+#define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
+
+#if defined(STM32F042x6) || \
+    defined(STM32F070x6) || defined(STM32F070xB) || \
+    defined(STM32F072xB) || \
+    defined(STM32F078xx)
+  #include "stm32f0xx.h"
+  #define PMA_LENGTH (1024u)
+  // F0x2 models are crystal-less
+  // All have internal D+ pull-up
+  // 070RB:    2 x 16 bits/word memory     LPM Support, BCD Support
+  // PMA dedicated to USB (no sharing with CAN)
+
+#elif defined(STM32F1_FSDEV)
+  #include "stm32f1xx.h"
+  #define PMA_LENGTH (512u)
+  // NO internal Pull-ups
+  //         *B, and *C:    2 x 16 bits/word
+
+  // F1 names this differently from the rest
+  #define USB_CNTR_LPMODE   USB_CNTR_LP_MODE
+
+#elif defined(STM32F302xB) || defined(STM32F302xC) || \
+      defined(STM32F303xB) || defined(STM32F303xC) || \
+      defined(STM32F373xC)
+  #include "stm32f3xx.h"
+  #define PMA_LENGTH (512u)
+  // NO internal Pull-ups
+  //         *B, and *C:    1 x 16 bits/word
+  // PMA dedicated to USB (no sharing with CAN)
+
+#elif defined(STM32F302x6) || defined(STM32F302x8) || \
+      defined(STM32F302xD) || defined(STM32F302xE) || \
+      defined(STM32F303xD) || defined(STM32F303xE)
+  #include "stm32f3xx.h"
+  #define PMA_LENGTH (1024u)
+  // NO internal Pull-ups
+  // *6, *8, *D, and *E:    2 x 16 bits/word     LPM Support
+  // When CAN clock is enabled, USB can use first 768 bytes ONLY.
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
+  #include "stm32l0xx.h"
+  #define PMA_LENGTH (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
+  #include "stm32l1xx.h"
+  #define PMA_LENGTH (512u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+  #include "stm32g4xx.h"
+  #define PMA_LENGTH (1024u)
+
+#else
+  #error You are using an untested or unimplemented STM32 variant. Please update the driver.
+  // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4
+#endif
+
+// For purposes of accessing the packet
+#if ((PMA_LENGTH) == 512u)
+  #define PMA_STRIDE  (2u)
+#elif ((PMA_LENGTH) == 1024u)
+  #define PMA_STRIDE  (1u)
+#endif
+
+// And for type-safety create a new macro for the volatile address of PMAADDR
+// The compiler should warn us if we cast it to a non-volatile type?
+// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden)
+static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR;
+
+// prototypes
+static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum);
+static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum);
+static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue);
+
+
+/* SetENDPOINT */
+static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wRegValue)
+{
+  __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpNum*2u);
+  *reg = (uint16_t)wRegValue;
+}
+
+/* GetENDPOINT */
+static inline uint16_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpNum) {
+  __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpNum*2u);
+  return *reg;
+}
+
+static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpNum, uint32_t wType)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= (uint32_t)USB_EP_T_MASK;
+  regVal |= wType;
+  regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high
+  pcd_set_endpoint(USBx, bEpNum, regVal);
+}
+
+static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= USB_EP_T_FIELD;
+  return regVal;
+}
+/**
+  * @brief  Clears bit CTR_RX / CTR_TX in the endpoint register.
+  * @param  USBx USB peripheral instance register address.
+  * @param  bEpNum Endpoint Number.
+  * @retval None
+  */
+static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= USB_EPREG_MASK;
+  regVal &= ~USB_EP_CTR_RX;
+  regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0)
+  pcd_set_endpoint(USBx, bEpNum, regVal);
+}
+static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= USB_EPREG_MASK;
+  regVal &= ~USB_EP_CTR_TX;
+  regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0)
+  pcd_set_endpoint(USBx, bEpNum,regVal);
+}
+/**
+  * @brief  gets counter of the tx buffer.
+  * @param  USBx USB peripheral instance register address.
+  * @param  bEpNum Endpoint Number.
+  * @retval Counter value
+  */
+static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpNum);
+  return *regPtr & 0x3ffU;
+}
+
+static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpNum);
+  return *regPtr & 0x3ffU;
+}
+
+/**
+  * @brief  Sets counter of rx buffer with no. of blocks.
+  * @param  dwReg Register
+  * @param  wCount Counter.
+  * @param  wNBlocks no. of Blocks.
+  * @retval None
+  */
+
+static inline void pcd_set_ep_cnt_rx_reg(__O uint16_t * pdwReg, size_t wCount)  {
+  uint32_t wNBlocks;
+  if(wCount > 62u)
+  {
+    wNBlocks = wCount >> 5u;
+    if((wCount & 0x1fU) == 0u)
+    {
+      wNBlocks--;
+    }
+    wNBlocks = wNBlocks << 10u;
+    wNBlocks |= 0x8000u; // Mark block size as 32byte
+    *pdwReg = (uint16_t)wNBlocks;
+  }
+  else
+  {
+    wNBlocks = wCount >> 1u;
+    if((wCount & 0x1U) != 0u)
+    {
+      wNBlocks++;
+    }
+    *pdwReg = (uint16_t)((wNBlocks) << 10u);
+  }
+}
+
+
+/**
+  * @brief  Sets address in an endpoint register.
+  * @param  USBx USB peripheral instance register address.
+  * @param  bEpNum Endpoint Number.
+  * @param  bAddr Address.
+  * @retval None
+  */
+static inline void pcd_set_ep_address(USB_TypeDef * USBx,  uint32_t bEpNum, uint32_t bAddr)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= USB_EPREG_MASK;
+  regVal |= bAddr;
+  regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+  pcd_set_endpoint(USBx, bEpNum,regVal);
+}
+
+static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x)
+{
+  size_t total_word_offset = (((USBx)->BTABLE)>>1) + x;
+  total_word_offset *= PMA_STRIDE;
+  return &(pma[total_word_offset]);
+}
+
+// Pointers to the PMA table entries (using the ARM address space)
+static inline __IO uint16_t* pcd_ep_tx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 0u);
+}
+static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 1u);
+}
+
+static inline __IO uint16_t* pcd_ep_rx_address_ptr(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  return  pcd_btable_word_ptr(USBx,(bEpNum)*4u + 2u);
+}
+
+static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  return pcd_btable_word_ptr(USBx,(bEpNum)*4u + 3u);
+}
+
+static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx,  uint32_t bEpNum, uint32_t wCount)
+{
+  *pcd_ep_tx_cnt_ptr(USBx, bEpNum) = (uint16_t)wCount;
+}
+
+static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx,  uint32_t bEpNum, uint32_t wCount)
+{
+  __IO uint16_t *pdwReg = pcd_ep_rx_cnt_ptr((USBx),(bEpNum));
+  pcd_set_ep_cnt_rx_reg(pdwReg, wCount);
+}
+
+/**
+  * @brief  sets the status for tx transfer (bits STAT_TX[1:0]).
+  * @param  USBx USB peripheral instance register address.
+  * @param  bEpNum Endpoint Number.
+  * @param  wState new state
+  * @retval None
+  */
+static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx,  uint32_t bEpNum, uint32_t wState)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= USB_EPTX_DTOGMASK;
+
+  /* toggle first bit ? */
+  if((USB_EPTX_DTOG1 & (wState))!= 0U)
+  {
+    regVal ^= USB_EPTX_DTOG1;
+  }
+  /* toggle second bit ?  */
+  if((USB_EPTX_DTOG2 & ((uint32_t)(wState)))!= 0U)
+  {
+    regVal ^= USB_EPTX_DTOG2;
+  }
+  regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+  pcd_set_endpoint(USBx, bEpNum, regVal);
+} /* pcd_set_ep_tx_status */
+
+/**
+  * @brief  sets the status for rx transfer (bits STAT_TX[1:0])
+  * @param  USBx USB peripheral instance register address.
+  * @param  bEpNum Endpoint Number.
+  * @param  wState new state
+  * @retval None
+  */
+
+static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx,  uint32_t bEpNum, uint32_t wState)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= USB_EPRX_DTOGMASK;
+
+  /* toggle first bit ? */
+  if((USB_EPRX_DTOG1 & wState)!= 0U)
+  {
+    regVal ^= USB_EPRX_DTOG1;
+  }
+  /* toggle second bit ? */
+  if((USB_EPRX_DTOG2 & wState)!= 0U)
+  {
+    regVal ^= USB_EPRX_DTOG2;
+  }
+  regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+  pcd_set_endpoint(USBx, bEpNum, regVal);
+} /* pcd_set_ep_rx_status */
+
+static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx,  uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  return (regVal & USB_EPRX_STAT) >> (12u);
+} /* pcd_get_ep_rx_status */
+
+
+/**
+  * @brief  Toggles DTOG_RX / DTOG_TX bit in the endpoint register.
+  * @param  USBx USB peripheral instance register address.
+  * @param  bEpNum Endpoint Number.
+  * @retval None
+  */
+static inline void pcd_rx_dtog(USB_TypeDef * USBx,  uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= USB_EPREG_MASK;
+  regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX;
+  pcd_set_endpoint(USBx, bEpNum, regVal);
+}
+
+static inline void pcd_tx_dtog(USB_TypeDef * USBx,  uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= USB_EPREG_MASK;
+  regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX;
+  pcd_set_endpoint(USBx, bEpNum, regVal);
+}
+
+/**
+  * @brief  Clears DTOG_RX / DTOG_TX bit in the endpoint register.
+  * @param  USBx USB peripheral instance register address.
+  * @param  bEpNum Endpoint Number.
+  * @retval None
+  */
+
+static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx,  uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  if((regVal & USB_EP_DTOG_RX) != 0)
+  {
+    pcd_rx_dtog(USBx,bEpNum);
+  }
+}
+
+static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx,  uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  if((regVal & USB_EP_DTOG_TX) != 0)
+  {
+    pcd_tx_dtog(USBx,bEpNum);
+  }
+}
+
+/**
+  * @brief  set & clear EP_KIND bit.
+  * @param  USBx USB peripheral instance register address.
+  * @param  bEpNum Endpoint Number.
+  * @retval None
+  */
+
+static inline void pcd_set_ep_kind(USB_TypeDef * USBx,  uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal |= USB_EP_KIND;
+  regVal &= USB_EPREG_MASK;
+  regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+  pcd_set_endpoint(USBx, bEpNum, regVal);
+}
+static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpNum)
+{
+  uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
+  regVal &= USB_EPKIND_MASK;
+  regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
+  pcd_set_endpoint(USBx, bEpNum, regVal);
+}
+
+// This checks if the device has "LPM"
+#if defined(USB_ISTR_L1REQ)
+#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ)
+#else
+#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U)
+#endif
+
+#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \
+     USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED )
+
+// Number of endpoints in hardware
+#define STFSDEV_EP_COUNT (8u)
+
+#endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */
diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c
new file mode 100644
index 0000000..4782ead
--- /dev/null
+++ b/src/portable/st/synopsys/dcd_synopsys.c
@@ -0,0 +1,1233 @@
+/*
+ * 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"
+
+// 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
+
+#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
+    defined (STM32F107xB) || defined (STM32F107xC)
+#define STM32F1_SYNOPSYS
+#endif
+
+#if defined (STM32L475xx) || defined (STM32L476xx) ||                          \
+    defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
+    defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
+    defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
+#define STM32L4_SYNOPSYS
+#endif
+
+#if TUSB_OPT_DEVICE_ENABLED &&                                          \
+    ( (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \
+       CFG_TUSB_MCU == OPT_MCU_STM32F2                               || \
+       CFG_TUSB_MCU == OPT_MCU_STM32F4                               || \
+       CFG_TUSB_MCU == OPT_MCU_STM32F7                               || \
+       CFG_TUSB_MCU == OPT_MCU_STM32H7                               || \
+      (CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)  || \
+       CFG_TUSB_MCU == OPT_MCU_GD32VF103 )                           \
+    )
+
+// EP_MAX       : Max number of bi-directional endpoints including EP0
+// EP_FIFO_SIZE : Size of dedicated USB SRAM
+#if CFG_TUSB_MCU == OPT_MCU_STM32F1
+#include "stm32f1xx.h"
+#define EP_MAX_FS       4
+#define EP_FIFO_SIZE_FS 1280
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F2
+#include "stm32f2xx.h"
+#define EP_MAX_FS       USB_OTG_FS_MAX_IN_ENDPOINTS
+#define EP_FIFO_SIZE_FS USB_OTG_FS_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
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H7
+#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
+
+#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
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
+#include "stm32l4xx.h"
+#define EP_MAX_FS       6
+#define EP_FIFO_SIZE_FS 1280
+
+#elif CFG_TUSB_MCU == OPT_MCU_GD32VF103
+#include "synopsys_common.h"
+
+// for remote wakeup delay
+#define __NOP()   __asm volatile ("nop")
+
+// These numbers are the same for the whole GD32VF103 family.
+#define OTG_FS_IRQn     86
+#define EP_MAX_FS       4
+#define EP_FIFO_SIZE_FS 1280
+
+// The GD32VF103 is a RISC-V MCU, which implements the ECLIC Core-Local
+// Interrupt Controller by Nuclei. It is nearly API compatible to the
+// NVIC used by ARM MCUs.
+#define ECLIC_INTERRUPT_ENABLE_BASE 0xD2001001UL
+
+#define NVIC_EnableIRQ __eclic_enable_interrupt
+#define NVIC_DisableIRQ __eclic_disable_interrupt
+
+static inline void __eclic_enable_interrupt (uint32_t irq) {
+  *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 1;
+}
+
+static inline void __eclic_disable_interrupt (uint32_t irq){
+  *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 0;
+}
+
+#else
+#error "Unsupported MCUs"
+#endif
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+
+// On STM32 we associate Port0 to OTG_FS, and Port1 to OTG_HS
+#if TUD_OPT_RHPORT == 0
+#define EP_MAX            EP_MAX_FS
+#define EP_FIFO_SIZE      EP_FIFO_SIZE_FS
+#define RHPORT_REGS_BASE  USB_OTG_FS_PERIPH_BASE
+#define RHPORT_IRQn       OTG_FS_IRQn
+
+#else
+#define EP_MAX            EP_MAX_HS
+#define EP_FIFO_SIZE      EP_FIFO_SIZE_HS
+#define RHPORT_REGS_BASE  USB_OTG_HS_PERIPH_BASE
+#define RHPORT_IRQn       OTG_HS_IRQn
+
+#endif
+
+#define GLOBAL_BASE(_port)     ((USB_OTG_GlobalTypeDef*) RHPORT_REGS_BASE)
+#define DEVICE_BASE(_port)     (USB_OTG_DeviceTypeDef *) (RHPORT_REGS_BASE + 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.
+
+  usb_otg->GRXFSIZ = calc_rx_ff_size(TUD_OPT_HIGH_SPEED ? 512 : 64);
+
+  _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 defined(USB_HS_PHYC)
+static bool USB_HS_PHYCInit(void)
+{
+  USB_HS_PHYC_GlobalTypeDef *usb_hs_phyc = (USB_HS_PHYC_GlobalTypeDef*) USB_HS_PHYC_CONTROLLER_BASE;
+
+  // Enable LDO: Note STM32F72/3xx Reference Manual rev 3 June 2018 incorrectly defined this bit as Disabled !!
+  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
+ *------------------------------------------------------------------*/
+void dcd_init (uint8_t rhport)
+{
+  // Programming model begins in the last section of the chapter on the USB
+  // peripheral in each Reference Manual.
+
+  USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport);
+
+  // No HNP/SRP (no OTG support), program timeout later.
+  if ( rhport == 1 )
+  {
+    // On selected MCUs HS port1 can be used with external PHY via ULPI interface
+#if CFG_TUSB_RHPORT1_MODE & OPT_MODE_HIGH_SPEED
+    // 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);
+#else
+    usb_otg->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL;
+#endif
+
+#if defined(USB_HS_PHYC)
+    // Highspeed with embedded UTMI PHYC
+
+    // Select UTMI Interface
+    usb_otg->GUSBCFG &= ~USB_OTG_GUSBCFG_ULPI_UTMI_SEL;
+    usb_otg->GCCFG |= USB_OTG_GCCFG_PHYHSEN;
+
+    // Enables control of a High Speed USB PHY
+    USB_HS_PHYCInit();
+#endif
+  } else
+  {
+    // Enable internal PHY
+    usb_otg->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL;
+  }
+
+  // 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) {}
+
+  // Restart PHY clock
+  *((volatile uint32_t *)(RHPORT_REGS_BASE + USB_OTG_PCGCCTL_BASE)) = 0;
+
+  // 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, TUD_OPT_HIGH_SPEED ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL);
+
+  // Enable internal USB transceiver, unless using HS core (port 1) with external PHY.
+  if (!(rhport == 1 && (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HIGH_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;
+  NVIC_EnableIRQ(RHPORT_IRQn);
+}
+
+void dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(RHPORT_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/st/synopsys/synopsys_common.h b/src/portable/st/synopsys/synopsys_common.h
new file mode 100644
index 0000000..6f0602f
--- /dev/null
+++ b/src/portable/st/synopsys/synopsys_common.h
@@ -0,0 +1,1465 @@
+/**
+  ******************************************************************************
+  * @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                           Address offset: 03Ch */
+  uint32_t  Reserved40[48];           /*!< Reserved 040h-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/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
new file mode 100644
index 0000000..bb21b3d
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -0,0 +1,1311 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 William D. Jones
+ * 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"
+#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) )
+
+#include "device/dcd.h"
+#include "dwc2_type.h"
+
+#if defined(DCD_ATTR_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)
+  #include "dwc2_bcm.h"
+#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
+  #include "dwc2_efm32.h"
+#elif TU_CHECK_MCU(OPT_MCU_XMC4000)
+  #include "dwc2_xmc.h"
+#else
+  #error "Unsupported MCUs"
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+
+// DWC2 registers
+#define DWC2_REG(_port)       ((dwc2_regs_t*) DWC2_REG_BASE)
+
+// Debug level for DWC2
+#define DWC2_DEBUG    2
+
+#ifndef dcache_clean
+#define dcache_clean(_addr, _size)
+#endif
+
+#ifndef dcache_invalidate
+#define dcache_invalidate(_addr, _size)
+#endif
+
+#ifndef dcache_clean_invalidate
+#define dcache_clean_invalidate(_addr, _size)
+#endif
+
+
+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;
+
+static xfer_ctl_t xfer_status[DWC2_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 dwc2->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*DWC2_EP_MAX;
+}
+
+static void update_grxfsiz(uint8_t rhport)
+{
+  (void) rhport;
+
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+
+  // Determine largest EP size for RX FIFO
+  uint16_t max_epsize = 0;
+  for (uint8_t epnum = 0; epnum < DWC2_EP_MAX; 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);
+}
+
+// Setup the control endpoint 0.
+static void bus_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+
+  tu_memclr(xfer_status, sizeof(xfer_status));
+  _out_ep_closed = 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++ )
+  {
+    dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
+  }
+
+  // 2. Set up interrupt mask
+  dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos);
+  dwc2->doepmsk  = DOEPMSK_STUPM | DOEPMSK_XFRCM;
+  dwc2->diepmsk  = DIEPMSK_TOM   | 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 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
+  //
+  //   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
+  //
+  //   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);
+
+  _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);
+
+  // Fixed control EP0 size to 64 bytes
+  dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
+  xfer_status[0][TUSB_DIR_OUT].max_size = 64;
+  xfer_status[0][TUSB_DIR_IN ].max_size = 64;
+
+  dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
+
+  dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT;
+}
+
+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;
+
+  dwc2_regs_t * dwc2 = DWC2_REG(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 )
+  {
+    dwc2_epin_t* epin = dwc2->epin;
+
+    // A full IN transfer (multiple packets, possibly) triggers XFRC.
+    epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) |
+                           ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk);
+
+    epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK;
+
+    // For ISO endpoint set correct odd/even bit for next frame.
+    if ( (epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1 )
+    {
+      // Take odd/even bit from frame counter.
+      uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos));
+      epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk);
+    }
+    // Enable fifo empty interrupt only if there are something to put in the fifo.
+    if ( total_bytes != 0 )
+    {
+      dwc2->diepempmsk |= (1 << epnum);
+    }
+  }
+  else
+  {
+    dwc2_epout_t* epout = dwc2->epout;
+
+    // A full OUT transfer (multiple packets, possibly) triggers XFRC.
+    epout[epnum].doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ);
+    epout[epnum].doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) |
+                             ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk);
+
+    epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK;
+    if ( (epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 &&
+         XFER_CTL_BASE(epnum, dir)->interval == 1 )
+    {
+      // Take odd/even bit from frame counter.
+      uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos));
+      epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk);
+    }
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+#if CFG_TUSB_DEBUG >= DWC2_DEBUG
+void print_dwc2_info(dwc2_regs_t * dwc2)
+{
+  dwc2_ghwcfg2_t const * hw_cfg2 = &dwc2->ghwcfg2_bm;
+  dwc2_ghwcfg3_t const * hw_cfg3 = &dwc2->ghwcfg3_bm;
+  dwc2_ghwcfg4_t const * hw_cfg4 = &dwc2->ghwcfg4_bm;
+
+//  TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl);
+//  TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg);
+//  TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg);
+  TU_LOG_HEX(DWC2_DEBUG, dwc2->guid);
+  TU_LOG_HEX(DWC2_DEBUG, dwc2->gsnpsid);
+  TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg1);
+
+  // HW configure 2
+  TU_LOG(DWC2_DEBUG, "\r\n");
+  TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg2);
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->op_mode                );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->arch                   );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->point2point            );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->hs_phy_type            );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->fs_phy_type            );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_dev_ep             );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_host_ch            );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->period_channel_support );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->enable_dynamic_fifo    );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->mul_cpu_int            );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->nperiod_tx_q_depth     );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->host_period_tx_q_depth );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->dev_token_q_depth      );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg2->otg_enable_ic_usb      );
+
+  // HW configure 3
+  TU_LOG(DWC2_DEBUG, "\r\n");
+  TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg3);
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->xfer_size_width          );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->packet_size_width        );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable               );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->i2c_enable               );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->vendor_ctrl_itf          );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->optional_feature_removed );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->synch_reset              );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_adp_support          );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable_hsic          );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->battery_charger_support  );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->lpm_mode                 );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg3->total_fifo_size          );
+
+  // HW configure 4
+  TU_LOG(DWC2_DEBUG, "\r\n");
+  TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg4);
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_period_in_ep      );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->power_optimized           );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ahb_freq_min              );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->hibernation               );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->service_interval_mode     );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ipg_isoc_en               );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->acg_enable                );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->utmi_phy_data_width       );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dev_ctrl_ep_num           );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->iddg_filter_enabled       );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->vbus_valid_filter_enabled );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->a_valid_filter_enabled    );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->b_valid_filter_enabled    );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dedicated_fifos           );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_in_eps            );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_desc_enable           );
+  TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_dynamic               );
+}
+#endif
+
+static void reset_core(dwc2_regs_t * dwc2)
+{
+  // reset core
+  dwc2->grstctl |= GRSTCTL_CSRST;
+
+  // wait for reset bit is cleared
+  // TODO version 4.20a should wait for RESET DONE mask
+  while (dwc2->grstctl & GRSTCTL_CSRST) { }
+
+  // wait for AHB master IDLE
+  while ( !(dwc2->grstctl & GRSTCTL_AHBIDL) ) { }
+
+  // wait for device mode ?
+}
+
+static bool phy_hs_supported(dwc2_regs_t * dwc2)
+{
+  // note: esp32 incorrect report its hs_phy_type as utmi
+  return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE;
+}
+
+static void phy_fs_init(dwc2_regs_t * dwc2)
+{
+  TU_LOG(DWC2_DEBUG, "Fullspeed PHY init\r\n");
+
+  // Select FS PHY
+  dwc2->gusbcfg |= GUSBCFG_PHYSEL;
+
+  // MCU specific PHY init before reset
+  dwc2_phy_init(dwc2, HS_PHY_TYPE_NONE);
+
+  // Reset core after selecting PHY
+  reset_core(dwc2);
+
+  // USB turnaround time is critical for certification where long cables and 5-Hubs are used.
+  // So if you need the AHB to run at less than 30 MHz, and if USB turnaround time is not critical,
+  // these bits can be programmed to a larger value. Default is 5
+  dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos);
+
+  // MCU specific PHY update post reset
+  dwc2_phy_update(dwc2, HS_PHY_TYPE_NONE);
+
+  // set max speed
+  dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos);
+}
+
+static void phy_hs_init(dwc2_regs_t * dwc2)
+{
+  uint32_t gusbcfg = dwc2->gusbcfg;
+
+  // De-select FS PHY
+  gusbcfg &= ~GUSBCFG_PHYSEL;
+
+  if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI)
+  {
+    TU_LOG(DWC2_DEBUG, "Highspeed ULPI PHY init\r\n");
+
+    // Select ULPI
+    gusbcfg |= GUSBCFG_ULPI_UTMI_SEL;
+
+    // ULPI 8-bit interface, single data rate
+    gusbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
+
+    // default internal VBUS Indicator and Drive
+    gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI);
+
+    // Disable FS/LS ULPI
+    gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM);
+  }else
+  {
+    TU_LOG(DWC2_DEBUG, "Highspeed UTMI+ PHY init\r\n");
+
+    // Select UTMI+ with 8-bit interface
+    gusbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
+
+    // Set 16-bit interface if supported
+    if (dwc2->ghwcfg4_bm.utmi_phy_data_width) gusbcfg |= GUSBCFG_PHYIF16;
+  }
+
+  // Apply config
+  dwc2->gusbcfg = gusbcfg;
+
+  // mcu specific phy init
+  dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type);
+
+  // Reset core after selecting PHY
+  reset_core(dwc2);
+
+  // Set turn-around, must after core reset otherwise it will be clear
+  // - 9 if using 8-bit PHY interface
+  // - 5 if using 16-bit PHY interface
+  gusbcfg &= ~GUSBCFG_TRDT_Msk;
+  gusbcfg |= (dwc2->ghwcfg4_bm.utmi_phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
+  dwc2->gusbcfg = gusbcfg;
+
+  // MCU specific PHY update post reset
+  dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type);
+
+  // Set max speed
+  uint32_t dcfg = dwc2->dcfg;
+  dcfg &= ~DCFG_DSPD_Msk;
+  dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos;
+
+  // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required
+  // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347)
+  if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) dcfg |= DCFG_XCVRDLY;
+
+  dwc2->dcfg = dcfg;
+}
+
+static bool check_dwc2(dwc2_regs_t * dwc2)
+{
+#if CFG_TUSB_DEBUG >= DWC2_DEBUG
+  print_dwc2_info(dwc2);
+#endif
+
+  // For some reasons: GD32VF103 snpsid and all hwcfg register are always zero (skip it)
+#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);
+#endif
+
+  return true;
+}
+
+void dcd_init (uint8_t rhport)
+{
+  // Programming model begins in the last section of the chapter on the USB
+  // peripheral in each Reference Manual.
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+
+  // Check Synopsys ID register, failed if controller clock/power is not enabled
+  TU_VERIFY(check_dwc2(dwc2), );
+
+  dcd_disconnect(rhport);
+
+  // max number of endpoints & total_fifo_size are:
+  // hw_cfg2->num_dev_ep, hw_cfg2->total_fifo_size
+
+  if( phy_hs_supported(dwc2) )
+  {
+    // Highspeed
+    phy_hs_init(dwc2);
+  }else
+  {
+    // core does not support highspeed or hs-phy is not present
+    phy_fs_init(dwc2);
+  }
+
+  // Restart PHY clock
+  dwc2->pcgctl &= ~(PCGCTL_STOPPCLK | PCGCTL_GATEHCLK | PCGCTL_PWRCLMP | PCGCTL_RSTPDWNMODULE);
+
+	/* Set HS/FS Timeout Calibration to 7 (max available value).
+	 * The number of PHY clocks that the application programs in
+	 * this field is added to the high/full speed interpacket timeout
+	 * duration in the core to account for any additional delays
+	 * introduced by the PHY. This can be required, because the delay
+	 * introduced by the PHY in generating the linestate condition
+	 * can vary from one PHY to another.
+	 */
+  dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos);
+
+  // Force device mode
+  dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD;
+
+  // Clear A override, force B Valid
+  dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL;
+
+  // If USB host misbehaves during status portion of control xfer
+  // (non zero-length packet), send STALL back and discard.
+  dwc2->dcfg |= DCFG_NZLSOHSK;
+
+  // Clear all interrupts
+  dwc2->gintsts |= dwc2->gintsts;
+  dwc2->gotgint |= dwc2->gotgint;
+
+  // Required as part of core initialization.
+  // TODO: How should mode mismatch be handled? It will cause
+  // the core to stop working/require reset.
+  dwc2->gintmsk = GINTMSK_OTGINT   | GINTMSK_MMISM  | GINTMSK_RXFLVLM  |
+                  GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
+
+  // Enable global interrupt
+  dwc2->gahbcfg |= GAHBCFG_GINT;
+
+  // make sure we are in device mode
+//  TU_ASSERT(!(dwc2->gintsts & GINTSTS_CMOD), );
+
+//  TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl);
+//  TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg);
+//  TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg);
+//  TU_LOG_HEX(DWC2_DEBUG, dwc2->gahbcfg);
+
+  dcd_connect(rhport);
+}
+
+void dcd_int_enable (uint8_t rhport)
+{
+  dwc2_dcd_int_enable(rhport);
+}
+
+void dcd_int_disable (uint8_t rhport)
+{
+  dwc2_dcd_int_disable(rhport);
+}
+
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+  dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos);
+
+  // Response with status after changing device address
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+
+  // set remote wakeup
+  dwc2->dctl |= DCTL_RWUSIG;
+
+  // enable SOF to detect bus resume
+  dwc2->gintsts = GINTSTS_SOF;
+  dwc2->gintmsk |= GINTMSK_SOFM;
+
+  // Per specs: remote wakeup signal bit must be clear within 1-15ms
+  dwc2_remote_wakeup_delay();
+
+  dwc2->dctl &= ~DCTL_RWUSIG;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+  dwc2->dctl &= ~DCTL_SDIS;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+  dwc2->dctl |= DCTL_SDIS;
+}
+
+
+/*------------------------------------------------------------------*/
+/* DCD Endpoint port
+ *------------------------------------------------------------------*/
+
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
+{
+  (void) rhport;
+
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+
+  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);
+
+  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 = tu_div_ceil(xfer->max_size, 4);
+
+  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 (dwc2->grxfsiz < sz)
+    {
+      TU_ASSERT(sz + _allocated_fifo_words_tx <= DWC2_EP_FIFO_SIZE/4);
+
+      // Enlarge RX FIFO
+      dwc2->grxfsiz = sz;
+    }
+
+    dwc2->epout[epnum].doepctl |= (1 << DOEPCTL_USBAEP_Pos) |
+                                  (desc_edpt->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) |
+                                  (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
+                                  (xfer->max_size << DOEPCTL_MPSIZ_Pos);
+
+    dwc2->daintmsk |= TU_BIT(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 + dwc2->grxfsiz <= DWC2_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);
+
+    // 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->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) |
+                                 (epnum << DIEPCTL_TXFNUM_Pos) |
+                                 (desc_edpt->bmAttributes.xfer << DIEPCTL_EPTYP_Pos) |
+                                 (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DIEPCTL_SD0PID_SEVNFRM : 0) |
+                                 (xfer->max_size << DIEPCTL_MPSIZ_Pos);
+
+    dwc2->daintmsk |= (1 << (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;
+
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+
+  // Disable non-control interrupt
+  dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos);
+
+  for(uint8_t n = 1; n < DWC2_EP_MAX; n++)
+  {
+    // disable OUT endpoint
+    dwc2->epout[n].doepctl = 0;
+    xfer_status[n][TUSB_DIR_OUT].max_size = 0;
+
+    // disable IN endpoint
+    dwc2->epin[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]);
+  }
+  else
+  {
+    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;
+
+  dwc2_regs_t *dwc2 = DWC2_REG(rhport);
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  if ( dir == TUSB_DIR_IN )
+  {
+    dwc2_epin_t* epin = dwc2->epin;
+
+    // Only disable currently enabled non-control endpoint
+    if ( (epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA) )
+    {
+      epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0);
+    }
+    else
+    {
+      // Stop transmitting packets and NAK IN xfers.
+      epin[epnum].diepctl |= DIEPCTL_SNAK;
+      while ( (epin[epnum].diepint & DIEPINT_INEPNE) == 0 ) {}
+
+      // Disable the endpoint.
+      epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0);
+      while ( (epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0 ) {}
+
+      epin[epnum].diepint = DIEPINT_EPDISD;
+    }
+
+    // Flush the FIFO, and wait until we have confirmed it cleared.
+    dwc2->grstctl |= (epnum << GRSTCTL_TXFNUM_Pos);
+    dwc2->grstctl |= GRSTCTL_TXFFLSH;
+    while ( (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0 ) {}
+  }
+  else
+  {
+    dwc2_epout_t* epout = dwc2->epout;
+
+    // Only disable currently enabled non-control endpoint
+    if ( (epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA) )
+    {
+      epout[epnum].doepctl |= stall ? 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.
+      dwc2->dctl |= DCTL_SGONAK;
+      while ( (dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0 ) {}
+
+      // Ditto here- disable the endpoint.
+      epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0);
+      while ( (epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0 ) {}
+
+      epout[epnum].doepint = DOEPINT_EPDISD;
+
+      // Allow other OUT endpoints to keep receiving.
+      dwc2->dctl |= DCTL_CGONAK;
+    }
+  }
+}
+
+/**
+ * Close an endpoint.
+ */
+void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
+{
+  dwc2_regs_t * dwc2 = DWC2_REG(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 = (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,);
+    _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;
+
+  dwc2_regs_t * dwc2 = DWC2_REG(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 )
+  {
+    dwc2->epin[epnum].diepctl &= ~DIEPCTL_STALL;
+    dwc2->epin[epnum].diepctl |= DIEPCTL_SD0PID_SEVNFRM;
+  }
+  else
+  {
+    dwc2->epout[epnum].doepctl &= ~DOEPCTL_STALL;
+    dwc2->epout[epnum].doepctl |= 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;
+
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+  volatile const uint32_t * rx_fifo = dwc2->fifo[0];
+
+  // Reading full available 32 bit words from fifo
+  uint16_t full_words = len >> 2;
+  while(full_words--)
+  {
+    tu_unaligned_write32(dst, *rx_fifo);
+    dst += 4;
+  }
+
+  // Read the remaining 1-3 bytes from fifo
+  uint8_t const bytes_rem = len & 0x03;
+  if ( bytes_rem != 0 )
+  {
+    uint32_t const tmp = *rx_fifo;
+    dst[0] = tu_u32_byte0(tmp);
+    if ( bytes_rem > 1 ) dst[1] = tu_u32_byte1(tmp);
+    if ( bytes_rem > 2 ) dst[2] = tu_u32_byte2(tmp);
+  }
+}
+
+// Write a single data packet to EPIN FIFO
+static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const * src, uint16_t len)
+{
+  (void) rhport;
+
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+  volatile uint32_t * tx_fifo = dwc2->fifo[fifo_num];
+
+  // Pushing full available 32 bit words to fifo
+  uint16_t full_words = len >> 2;
+  while(full_words--)
+  {
+    *tx_fifo = tu_unaligned_read32(src);
+    src += 4;
+  }
+
+  // Write the remaining 1-3 bytes into fifo
+  uint8_t const bytes_rem = len & 0x03;
+  if ( bytes_rem )
+  {
+    uint32_t 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_irq(uint8_t rhport)
+{
+  dwc2_regs_t * dwc2 = DWC2_REG(rhport);
+  volatile uint32_t const * rx_fifo = dwc2->fifo[0];
+
+  // Pop control word off FIFO
+  uint32_t const ctl_word = dwc2->grxstsp;
+  uint8_t  const pktsts   = (ctl_word & GRXSTSP_PKTSTS_Msk ) >> GRXSTSP_PKTSTS_Pos;
+  uint8_t  const epnum    = (ctl_word & GRXSTSP_EPNUM_Msk  ) >> GRXSTSP_EPNUM_Pos;
+  uint16_t const bcnt     = (ctl_word & GRXSTSP_BCNT_Msk   ) >> GRXSTSP_BCNT_Pos;
+
+  dwc2_epout_t* epout = &dwc2->epout[epnum];
+
+//#if CFG_TUSB_DEBUG >= DWC2_DEBUG
+//  const char * pktsts_str[] =
+//  {
+//    "ASSERT", "Global NAK (ISR)", "Out Data Received", "Out Transfer Complete (ISR)",
+//    "Setup Complete (ISR)", "ASSERT", "Setup Data Received"
+//  };
+//  TU_LOG_LOCATION();
+//  TU_LOG(DWC2_DEBUG, "  EP %02X, Byte Count %u, %s\r\n", epnum, bcnt, pktsts_str[pktsts]);
+//  TU_LOG(DWC2_DEBUG, "  daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint);
+//#endif
+
+  switch ( pktsts )
+  {
+    // Global OUT NAK: do nothign
+    case GRXSTS_PKTSTS_GLOBALOUTNAK: break;
+
+    case GRXSTS_PKTSTS_SETUPRX:
+      // Setup packet received
+
+      // 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;
+
+    case GRXSTS_PKTSTS_SETUPDONE:
+      // Setup packet done (Interrupt)
+      epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
+    break;
+
+    case GRXSTS_PKTSTS_OUTRX:
+    {
+      // Out packet received
+      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 -= (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos;
+        if ( epnum == 0 )
+        {
+          xfer->total_len -= ep0_pending[TUSB_DIR_OUT];
+          ep0_pending[TUSB_DIR_OUT] = 0;
+        }
+      }
+    }
+    break;
+
+    // Out packet done (Interrupt)
+    case GRXSTS_PKTSTS_OUTDONE:
+        // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a
+        // May (or not) be 3.10a specific feature/bug or depending on MCU configuration
+        // XFRC complete is additionally generated when
+        // - setup packet is received
+        // - complete the data stage of control write is complete
+        if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a))
+        {
+          uint32_t doepint = epout->doepint;
+
+          if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR))
+          {
+            // skip this "no-data" transfer complete event
+            // Note: STPKTRX will be clear later by setup received handler
+            uint32_t clear_flags = DOEPINT_XFRC;
+
+            if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR;
+
+            epout->doepint = clear_flags;
+
+            // TU_LOG(DWC2_DEBUG, "  FIX extra transfer complete on setup/data compete\r\n");
+          }
+        }
+    break;
+
+    default:    // Invalid
+      TU_BREAKPOINT();
+    break;
+  }
+}
+
+static void handle_epout_irq (uint8_t rhport)
+{
+  dwc2_regs_t *dwc2 = DWC2_REG(rhport);
+
+  // 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++ )
+  {
+    if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) )
+    {
+      dwc2_epout_t* epout = &dwc2->epout[n];
+
+      uint32_t const doepint = epout->doepint;
+
+      // SETUP packet Setup Phase done.
+      if ( doepint & DOEPINT_STUP )
+      {
+        uint32_t clear_flag = DOEPINT_STUP;
+
+        // STPKTRX is only available for version from 3_00a
+        if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a))
+        {
+          clear_flag |= DOEPINT_STPKTRX;
+        }
+
+        epout->doepint = clear_flag;
+        dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true);
+      }
+
+      // OUT XFER complete
+      if ( epout->doepint & DOEPINT_XFRC )
+      {
+        epout->doepint = DOEPINT_XFRC;
+
+        xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
+
+        // 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_irq (uint8_t rhport)
+{
+  dwc2_regs_t *dwc2 = DWC2_REG(rhport);
+  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++ )
+  {
+    if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) )
+    {
+      // IN XFER complete (entire xfer).
+      xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
+
+      if ( epin[n].diepint & DIEPINT_XFRC )
+      {
+        epin[n].diepint = 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 ( (epin[n].diepint & DIEPINT_TXFE) && (dwc2->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 = (epin[n].dieptsiz & DIEPTSIZ_PKTCNT_Msk) >> 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 = (epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> 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 > ((epin[n].dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2) ) break;
+
+          // Push packet to Tx-FIFO
+          if ( xfer->ff )
+          {
+            volatile uint32_t *tx_fifo = dwc2->fifo[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 ( ((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0 )
+        {
+          dwc2->diepempmsk &= ~(1 << n);
+        }
+      }
+    }
+  }
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+  dwc2_regs_t *dwc2 = DWC2_REG(rhport);
+
+  uint32_t const int_status = dwc2->gintsts & dwc2->gintmsk;
+
+  if(int_status & GINTSTS_USBRST)
+  {
+    // USBRST is start of reset.
+    dwc2->gintsts = GINTSTS_USBRST;
+    bus_reset(rhport);
+  }
+
+  if(int_status & GINTSTS_ENUMDNE)
+  {
+    // ENUMDNE is the end of reset where speed of the link is detected
+
+    dwc2->gintsts = GINTSTS_ENUMDNE;
+
+    tusb_speed_t speed;
+    switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos)
+    {
+      case DSTS_ENUMSPD_HS:
+        speed = TUSB_SPEED_HIGH;
+      break;
+
+      case DSTS_ENUMSPD_LS:
+        speed = TUSB_SPEED_LOW;
+      break;
+
+      case DSTS_ENUMSPD_FS_HSPHY:
+      case DSTS_ENUMSPD_FS:
+      default:
+        speed = TUSB_SPEED_FULL;
+      break;
+    }
+
+    dcd_event_bus_reset(rhport, speed, true);
+  }
+
+  if(int_status & GINTSTS_USBSUSP)
+  {
+    dwc2->gintsts = GINTSTS_USBSUSP;
+    dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+  }
+
+  if(int_status & GINTSTS_WKUINT)
+  {
+    dwc2->gintsts = GINTSTS_WKUINT;
+    dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+  }
+
+  // TODO check GINTSTS_DISCINT for disconnect detection
+  // if(int_status & GINTSTS_DISCINT)
+
+  if(int_status & GINTSTS_OTGINT)
+  {
+    // OTG INT bit is read-only
+    uint32_t const otg_int = dwc2->gotgint;
+
+    if (otg_int & GOTGINT_SEDET)
+    {
+      dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+    }
+
+    dwc2->gotgint = otg_int;
+  }
+
+  if(int_status & GINTSTS_SOF)
+  {
+    dwc2->gotgint = GINTSTS_SOF;
+
+    // Disable SOF interrupt since currently only used for remote wakeup detection
+    dwc2->gintmsk &= ~GINTMSK_SOFM;
+
+    dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+  }
+
+  // RxFIFO non-empty interrupt handling.
+  if(int_status & GINTSTS_RXFLVL)
+  {
+    // RXFLVL bit is read-only
+
+    // Mask out RXFLVL while reading data from FIFO
+    dwc2->gintmsk &= ~GINTMSK_RXFLVLM;
+
+    // Loop until all available packets were handled
+    do
+    {
+      handle_rxflvl_irq(rhport);
+    } while(dwc2->gotgint & GINTSTS_RXFLVL);
+
+    // Manage RX FIFO size
+    if (_out_ep_closed)
+    {
+      update_grxfsiz(rhport);
+
+      // Disable flag
+      _out_ep_closed = false;
+    }
+
+    dwc2->gintmsk |= GINTMSK_RXFLVLM;
+  }
+
+  // OUT endpoint interrupt handling.
+  if(int_status & GINTSTS_OEPINT)
+  {
+    // OEPINT is read-only, clear using DOEPINTn
+    handle_epout_irq(rhport);
+  }
+
+  // IN endpoint interrupt handling.
+  if(int_status & GINTSTS_IEPINT)
+  {
+    // IEPINT bit read-only, clear using DIEPINTn
+    handle_epin_irq(rhport);
+  }
+
+  //  // Check for Incomplete isochronous IN transfer
+  //  if(int_status & GINTSTS_IISOIXFR) {
+  //    printf("      IISOIXFR!\r\n");
+  ////    TU_LOG(DWC2_DEBUG, "      IISOIXFR!\r\n");
+  //  }
+}
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_bcm.h b/src/portable/synopsys/dwc2/dwc2_bcm.h
new file mode 100644
index 0000000..353bc21
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_bcm.h
@@ -0,0 +1,89 @@
+/*
+ * 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_DWC2_BCM_H_
+#define _TUSB_DWC2_BCM_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#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
+
+#define dcache_clean(_addr, _size)              data_clean(_addr, _size)
+#define dcache_invalidate(_addr, _size)         data_invalidate(_addr, _size)
+#define dcache_clean_invalidate(_addr, _size)   data_clean_and_invalidate(_addr, _size)
+
+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 !?
+}
+
+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 !?
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+  // try to delay for 1 ms
+  // TODO implement later
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // nothing to do
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // nothing to do
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_efm32.h b/src/portable/synopsys/dwc2/dwc2_efm32.h
new file mode 100644
index 0000000..ee4c3c7
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_efm32.h
@@ -0,0 +1,87 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Rafael Silva (@perigoso)
+ * 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 _DWC2_EFM32_H_
+#define _DWC2_EFM32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "em_device.h"
+
+// 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
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USB_IRQn);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB_IRQn);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+  // try to delay for 1 ms
+//  uint32_t count = SystemCoreClock / 1000;
+//  while ( count-- ) __NOP();
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // Enable PHY
+  USB->ROUTE = USB_ROUTE_PHYPEN;
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // EFM32 Manual: turn around must be 5 (reset & default value)
+  // dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
new file mode 100644
index 0000000..78da277
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -0,0 +1,94 @@
+/*
+ * 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 _DWC2_ESP32_H_
+#define _DWC2_ESP32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "esp_intr_alloc.h"
+#include "soc/periph_defs.h"
+//#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 EP_FIFO_NUM 5
+
+static intr_handle_t usb_ih;
+
+static void dcd_int_handler_wrap(void* arg)
+{
+  (void) arg;
+  dcd_int_handler(0);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable (uint8_t rhport)
+{
+  (void) rhport;
+  esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, dcd_int_handler_wrap, NULL, &usb_ih);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  esp_intr_free(usb_ih);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+  vTaskDelay(pdMS_TO_TICKS(1));
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // nothing to do
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // nothing to do
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC2_ESP32_H_ */
diff --git a/src/portable/synopsys/dwc2/dwc2_gd32.h b/src/portable/synopsys/dwc2/dwc2_gd32.h
new file mode 100644
index 0000000..f8fa01e
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_gd32.h
@@ -0,0 +1,100 @@
+/*
+ * 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 DWC2_GD32_H_
+#define DWC2_GD32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define DWC2_REG_BASE       0x50000000UL
+#define DWC2_EP_MAX         4
+#define DWC2_EP_FIFO_SIZE   1280
+#define RHPORT_IRQn         86
+
+extern uint32_t SystemCoreClock;
+
+// The GD32VF103 is a RISC-V MCU, which implements the ECLIC Core-Local
+// Interrupt Controller by Nuclei. It is nearly API compatible to the
+// NVIC used by ARM MCUs.
+#define ECLIC_INTERRUPT_ENABLE_BASE 0xD2001001UL
+
+TU_ATTR_ALWAYS_INLINE
+static inline void __eclic_enable_interrupt (uint32_t irq) {
+  *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 1;
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void __eclic_disable_interrupt (uint32_t irq){
+  *(volatile uint8_t*)(ECLIC_INTERRUPT_ENABLE_BASE + (irq * 4)) = 0;
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  __eclic_enable_interrupt(RHPORT_IRQn);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  __eclic_disable_interrupt(RHPORT_IRQn);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+  // try to delay for 1 ms
+  uint32_t count = SystemCoreClock / 1000;
+  while ( count-- ) __asm volatile ("nop");
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // nothing to do
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // nothing to do
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DWC2_GD32_H_ */
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
new file mode 100644
index 0000000..469045a
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -0,0 +1,205 @@
+/*
+ * 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 _DWC2_STM32_H_
+#define _DWC2_STM32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// EP_MAX       : Max number of bi-directional endpoints including EP0
+// EP_FIFO_SIZE : Size of dedicated USB SRAM
+#if CFG_TUSB_MCU == OPT_MCU_STM32F1
+  #include "stm32f1xx.h"
+  #define EP_MAX_FS       4
+  #define EP_FIFO_SIZE_FS 1280
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F2
+  #include "stm32f2xx.h"
+  #define EP_MAX_FS       USB_OTG_FS_MAX_IN_ENDPOINTS
+  #define EP_FIFO_SIZE_FS USB_OTG_FS_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
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H7
+  #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
+
+#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
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
+  #include "stm32l4xx.h"
+  #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
+
+#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
+
+#endif
+
+extern uint32_t SystemCoreClock;
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(RHPORT_IRQn);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(RHPORT_IRQn);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_remote_wakeup_delay(void)
+{
+  // try to delay for 1 ms
+  uint32_t count = SystemCoreClock / 1000;
+  while ( count-- ) __NOP();
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  if ( hs_phy_type == HS_PHY_TYPE_NONE )
+  {
+    // Enable on-chip FS PHY
+    dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN;
+  }else
+  {
+    // Disable FS PHY
+    dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN;
+
+    // Enable on-chip HS PHY
+    if (hs_phy_type == HS_PHY_TYPE_UTMI || hs_phy_type == HS_PHY_TYPE_UTMI_ULPI)
+    {
+#ifdef USB_HS_PHYC
+      // Enable UTMI HS PHY
+      dwc2->stm32_gccfg |= STM32_GCCFG_PHYHSEN;
+
+      // 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(false, );
+      }
+      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 for F7
+      USB_HS_PHYC->USB_HS_PHYC_TUNE |= 0x00000F13U;
+
+      // Enable PLL internal PHY
+      USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
+#endif
+    }
+  }
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  // used to set turnaround time for fullspeed, nothing to do in highspeed mode
+  if ( hs_phy_type == HS_PHY_TYPE_NONE )
+  {
+    // Turnaround timeout depends on the AHB clock dictated by STM32 Reference Manual
+    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;
+
+    dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (turnaround << GUSBCFG_TRDT_Pos);
+  }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DWC2_STM32_H_ */
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
new file mode 100644
index 0000000..dbef203
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -0,0 +1,1730 @@
+/**
+  * @author  MCD Application Team
+  *          Ha Thach (tinyusb.org)
+  *
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2019 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
+  *
+  */
+
+#ifndef _TUSB_DWC2_TYPES_H_
+#define _TUSB_DWC2_TYPES_H_
+
+#include "stdint.h"
+
+/* DWC OTG HW Release versions */
+#define DWC2_CORE_REV_2_71a   0x4f54271a
+#define DWC2_CORE_REV_2_72a   0x4f54272a
+#define DWC2_CORE_REV_2_80a   0x4f54280a
+#define DWC2_CORE_REV_2_90a   0x4f54290a
+#define DWC2_CORE_REV_2_91a   0x4f54291a
+#define DWC2_CORE_REV_2_92a   0x4f54292a
+#define DWC2_CORE_REV_2_94a   0x4f54294a
+#define DWC2_CORE_REV_3_00a   0x4f54300a
+#define DWC2_CORE_REV_3_10a   0x4f54310a
+#define DWC2_CORE_REV_4_00a   0x4f54400a
+#define DWC2_CORE_REV_4_20a   0x4f54420a
+#define DWC2_FS_IOT_REV_1_00a 0x5531100a
+#define DWC2_HS_IOT_REV_1_00a 0x5532100a
+#define DWC2_CORE_REV_MASK    0x0000ffff
+
+/* DWC OTG HW Core ID */
+#define DWC2_OTG_ID           0x4f540000
+#define DWC2_FS_IOT_ID        0x55310000
+#define DWC2_HS_IOT_ID        0x55320000
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#if 0
+// HS PHY
+typedef struct
+{
+  volatile uint32_t HS_PHYC_PLL;         // This register is used to control the PLL of the HS PHY.                       000h */
+  volatile uint32_t Reserved04;          // Reserved                                                                      004h */
+  volatile uint32_t Reserved08;          // Reserved                                                                      008h */
+  volatile uint32_t HS_PHYC_TUNE;        // This register is used to control the tuning interface of the High Speed PHY.  00Ch */
+  volatile uint32_t Reserved10;          // Reserved                                                                      010h */
+  volatile uint32_t Reserved14;          // Reserved                                                                      014h */
+  volatile uint32_t HS_PHYC_LDO;         // This register is used to control the regulator (LDO).                         018h */
+} HS_PHYC_GlobalTypeDef;
+#endif
+
+enum {
+  HS_PHY_TYPE_NONE = 0  , // not supported
+  HS_PHY_TYPE_UTMI      , // internal PHY (mostly)
+  HS_PHY_TYPE_ULPI      , // external PHY
+  HS_PHY_TYPE_UTMI_ULPI ,
+};
+
+enum {
+  FS_PHY_TYPE_NONE = 0,  // not supported
+  FS_PHY_TYPE_DEDICATED,
+  FS_PHY_TYPE_UTMI,
+  FS_PHY_TYPE_ULPI,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+  uint32_t op_mode                  : 3; // 0: HNP and SRP | 1: SRP | 2: non-HNP, non-SRP
+  uint32_t arch                     : 2; // 0: slave-only | 1: External DMA | 2: Internal DMA | 3: others
+  uint32_t point2point              : 1; // 0: support hub and split | 1: no hub, no split
+  uint32_t hs_phy_type              : 2; // 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI
+  uint32_t fs_phy_type              : 2; // 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI
+  uint32_t num_dev_ep               : 4; // Number of device endpoints (not including EP0)
+  uint32_t num_host_ch              : 4; // Number of host channel
+  uint32_t period_channel_support   : 1; // Support Periodic OUT Host Channel
+  uint32_t enable_dynamic_fifo      : 1; // Dynamic FIFO Sizing Enabled
+  uint32_t mul_cpu_int              : 1; // Multi-Processor Interrupt Enabled
+  uint32_t reserved21               : 1;
+  uint32_t nperiod_tx_q_depth       : 2; // Non-periodic request queue depth: 0 = 2.  1 = 4, 2 = 8
+  uint32_t host_period_tx_q_depth   : 2; // Host periodic request queue depth: 0 = 2.  1 = 4, 2 = 8
+  uint32_t dev_token_q_depth        : 5; // Device IN token sequence learning queue depth: 0-30
+  uint32_t otg_enable_ic_usb        : 1; // IC_USB mode specified for mode of operation
+} dwc2_ghwcfg2_t;
+
+TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg2_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED
+{
+  uint32_t xfer_size_width          : 4;  // Transfer size counter in bits = 11 + n (max 19 bits)
+  uint32_t packet_size_width        : 3;  // Packet size counter in bits = 4 + n (max 10 bits)
+  uint32_t otg_enable               : 1;  // 1 is OTG capable
+  uint32_t i2c_enable               : 1;  // I2C interface is available
+  uint32_t vendor_ctrl_itf          : 1;  // Vendor control interface is available
+  uint32_t optional_feature_removed : 1;  // remove User ID, GPIO, SOF toggle & counter
+  uint32_t synch_reset              : 1;  // 0: async reset | 1: synch reset
+  uint32_t otg_adp_support          : 1;  // ADP logic is present along with HSOTG controller
+  uint32_t otg_enable_hsic          : 1;  // 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC
+  uint32_t battery_charger_support  : 1;  // support battery charger
+  uint32_t lpm_mode                 : 1;  // LPC mode
+  uint32_t total_fifo_size          : 16; // DFIFO depth value in terms of 32-bit words
+}dwc2_ghwcfg3_t;
+
+TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg3_t) == 4, "incorrect size");
+
+typedef struct TU_ATTR_PACKED
+{
+  uint32_t num_dev_period_in_ep       : 4; // Number of Device Periodic IN Endpoints
+  uint32_t power_optimized            : 1; // Partial Power Down Enabled
+  uint32_t ahb_freq_min               : 1; // 1: minimum of AHB frequency is less than 60 MHz
+  uint32_t hibernation                : 1; // Hibernation feature is enabled
+  uint32_t reserved7                  : 3;
+  uint32_t service_interval_mode      : 1; // Service Interval supported
+  uint32_t ipg_isoc_en                : 1; // IPG ISOC supported
+  uint32_t acg_enable                 : 1; // ACG enabled
+  uint32_t reserved13                 : 1;
+  uint32_t utmi_phy_data_width        : 2; // 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable
+  uint32_t dev_ctrl_ep_num            : 4; // Number of Device control endpoints in addition to EP0
+  uint32_t iddg_filter_enabled        : 1;
+  uint32_t vbus_valid_filter_enabled  : 1;
+  uint32_t a_valid_filter_enabled     : 1;
+  uint32_t b_valid_filter_enabled     : 1;
+  uint32_t dedicated_fifos            : 1; // Dedicated tx fifo for device IN Endpoint is enabled
+  uint32_t num_dev_in_eps             : 4; // Number of Device IN Endpoints including EP0
+  uint32_t dma_desc_enable            : 1; // scatter/gather DMA configuration
+  uint32_t dma_dynamic                : 1; // Dynamic scatter/gather DMA
+}dwc2_ghwcfg4_t;
+
+TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size");
+
+// Host Channel
+typedef struct
+{
+  volatile uint32_t hcchar;           // 500 + 20*ch Host Channel Characteristics
+  volatile uint32_t hcsplt;           // 504 + 20*ch Host Channel Split Control
+  volatile uint32_t hcint;            // 508 + 20*ch Host Channel Interrupt
+  volatile uint32_t hcintmsk;         // 50C + 20*ch Host Channel Interrupt Mask
+  volatile uint32_t hctsiz;           // 510 + 20*ch Host Channel Transfer Size
+  volatile uint32_t hcdma;            // 514 + 20*ch Host Channel DMA Address
+           uint32_t reserved518;      // 518 + 20*ch
+  volatile uint32_t hcdmab;           // 51C + 20*ch Host Channel DMA Address
+} dwc2_channel_t;
+
+// Endpoint IN
+typedef struct
+{
+  volatile uint32_t diepctl;          // 900 + 20*ep Device IN Endpoint Control
+           uint32_t reserved04;       // 904
+  volatile uint32_t diepint;          // 908 + 20*ep Device IN Endpoint Interrupt
+           uint32_t reserved0c;       // 90C
+  volatile uint32_t dieptsiz;         // 910 + 20*ep Device IN Endpoint Transfer Size
+  volatile uint32_t diepdma;          // 914 + 20*ep Device IN Endpoint DMA Address
+  volatile uint32_t dtxfsts;          // 918 + 20*ep Device IN Endpoint Tx FIFO Status
+           uint32_t reserved1c;       // 91C
+} dwc2_epin_t;
+
+// Endpoint OUT
+typedef struct
+{
+  volatile uint32_t doepctl;          // B00 + 20*ep Device OUT Endpoint Control
+           uint32_t reserved04;       // B04
+  volatile uint32_t doepint;          // B08 + 20*ep Device OUT Endpoint Interrupt
+           uint32_t reserved0c;       // B0C
+  volatile uint32_t doeptsiz;         // B10 + 20*ep Device OUT Endpoint Transfer Size
+  volatile uint32_t doepdma;          // B14 + 20*ep Device OUT Endpoint DMA Address
+           uint32_t reserved18[2];    // B18..B1C
+} dwc2_epout_t;
+
+typedef struct
+{
+  //------------- Core Global -------------//
+  volatile uint32_t gotgctl;          // 000 OTG Control and Status
+  volatile uint32_t gotgint;          // 004 OTG Interrupt
+  volatile uint32_t gahbcfg;          // 008 AHB Configuration
+  volatile uint32_t gusbcfg;          // 00c USB Configuration
+  volatile uint32_t grstctl;          // 010 Reset
+  volatile uint32_t gintsts;          // 014 Interrupt
+  volatile uint32_t gintmsk;          // 018 Interrupt Mask
+  volatile uint32_t grxstsr;          // 01c Receive Status Debug Read
+  volatile uint32_t grxstsp;          // 020 Receive Status Read/Pop
+  volatile uint32_t grxfsiz;          // 024 Receive FIFO Size
+union {
+  volatile uint32_t dieptxf0;         // 028 EP0 Tx FIFO Size
+  volatile uint32_t gnptxfsiz;        // 028 Non-periodic Transmit FIFO Size
+};
+  volatile uint32_t gnptxsts;         // 02c Non-periodic Transmit FIFO/Queue Status
+  volatile uint32_t gi2cctl;          // 030 I2C Address
+  volatile uint32_t gpvndctl;         // 034 PHY Vendor Control
+union {
+  volatile uint32_t ggpio;            // 038 General Purpose IO
+  volatile uint32_t stm32_gccfg;      // 038 STM32 General Core Configuration
+};
+  volatile uint32_t guid;             // 03C User (Application programmable) ID
+  volatile uint32_t gsnpsid;          // 040 Synopsys ID + Release version
+  volatile uint32_t ghwcfg1;          // 044 User Hardware Configuration1: endpoint dir (2 bit per ep)
+union {
+  volatile uint32_t ghwcfg2;          // 048 User Hardware Configuration2
+  dwc2_ghwcfg2_t    ghwcfg2_bm;
+};
+union {
+  volatile uint32_t ghwcfg3;          // 04C User Hardware Configuration3
+  dwc2_ghwcfg3_t    ghwcfg3_bm;
+};
+union {
+  volatile uint32_t ghwcfg4;          // 050 User Hardware Configuration4
+  dwc2_ghwcfg4_t    ghwcfg4_bm;
+};
+  volatile uint32_t glpmcfg;          // 054 Core LPM Configuration
+  volatile uint32_t gpwrdn;           // 058 Power Down
+  volatile uint32_t gdfifocfg;        // 05C DFIFO Software Configuration
+  volatile uint32_t gadpctl;          // 060 ADP Timer, Control and Status
+           uint32_t reserved64[39];   // 064..0FF
+  volatile uint32_t hptxfsiz;         // 100 Host Periodic Tx FIFO Size
+  volatile uint32_t dieptxf[15];      // 104..13C Device Periodic Transmit FIFO Size
+           uint32_t reserved140[176]; // 140..3FF
+
+  //------------- Host -------------//
+  volatile uint32_t hcfg;             // 400 Host Configuration
+  volatile uint32_t hfir;             // 404 Host Frame Interval
+  volatile uint32_t hfnum;            // 408 Host Frame Number / Frame Remaining
+           uint32_t reserved40c;      // 40C
+  volatile uint32_t hptxsts;          // 410 Host Periodic TX FIFO / Queue Status
+  volatile uint32_t haint;            // 414 Host All Channels Interrupt
+  volatile uint32_t haintmsk;         // 418 Host All Channels Interrupt Mask
+  volatile uint32_t hflbaddr;         // 41C Host Frame List Base Address
+           uint32_t reserved420[8];   // 420..43F
+  volatile uint32_t hprt;             // 440 Host Port Control and Status
+           uint32_t reserved444[47];  // 444..4FF
+
+  //------------- Host Channel -------------//
+  dwc2_channel_t    channel[16];      // 500..6FF Host Channels 0-15
+           uint32_t reserved700[64];  // 700..7FF
+
+ //------------- Device -------------//
+  volatile uint32_t dcfg;             // 800 Device Configuration
+  volatile uint32_t dctl;             // 804 Device Control
+  volatile uint32_t dsts;             // 808 Device Status (RO)
+           uint32_t reserved80c;      // 80C
+  volatile uint32_t diepmsk;          // 810 Device IN Endpoint Interrupt Mask
+  volatile uint32_t doepmsk;          // 814 Device OUT Endpoint Interrupt Mask
+  volatile uint32_t daint;            // 818 Device All Endpoints Interrupt
+  volatile uint32_t daintmsk;         // 81C Device All Endpoints Interrupt Mask
+  volatile uint32_t dtknqr1;          // 820 Device IN token sequence learning queue read1
+  volatile uint32_t dtknqr2;          // 824 Device IN token sequence learning queue read2
+  volatile uint32_t dvbusdis;         // 828 Device VBUS Discharge Time
+  volatile uint32_t dvbuspulse;       // 82C Device VBUS Pulsing Time
+  volatile uint32_t dthrctl;          // 830 Device threshold Control
+  volatile uint32_t diepempmsk;       // 834 Device IN Endpoint FIFO Empty Interrupt Mask
+  volatile uint32_t deachint;         // 838 Device Each Endpoint Interrupt
+  volatile uint32_t deachmsk;         // 83C Device Each Endpoint Interrupt msk
+  volatile uint32_t diepeachmsk[16];  // 840..87C Device Each IN Endpoint mask
+  volatile uint32_t doepeachmsk[16];  // 880..8BF Device Each OUT Endpoint mask
+           uint32_t reserved8c0[16];  // 8C0..8FF
+
+  //------------- Device Endpoint -------------//
+  dwc2_epin_t       epin[16];         // 900..AFF  IN Endpoints
+  dwc2_epout_t      epout[16];        // B00..CFF  OUT Endpoints
+           uint32_t reservedd00[64];  // D00..DFF
+
+  //------------- Power Clock -------------//
+  volatile uint32_t pcgctl;           // E00 Power and Clock Gating Control
+  volatile uint32_t pcgctl1;          // E04
+           uint32_t reservede08[126]; // E08..FFF
+
+  //------------- FIFOs -------------//
+  // Word-accessed only using first pointer since it auto shift
+  volatile uint32_t fifo[16][0x400];  // 1000..FFFF Endpoint FIFO
+} dwc2_regs_t;
+
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, hcfg   ) == 0x0400, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, channel) == 0x0500, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, dcfg   ) == 0x0800, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epin   ) == 0x0900, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epout  ) == 0x0B00, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, pcgctl ) == 0x0E00, "incorrect size");
+TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo   ) == 0x1000, "incorrect size");
+
+//--------------------------------------------------------------------+
+// Register Bit Definitions
+//--------------------------------------------------------------------+
+
+/********************  Bit definition for GOTGCTL register  ********************/
+#define GOTGCTL_SRQSCS_Pos               (0U)
+#define GOTGCTL_SRQSCS_Msk               (0x1UL << GOTGCTL_SRQSCS_Pos)            // 0x00000001 */
+#define GOTGCTL_SRQSCS                   GOTGCTL_SRQSCS_Msk                       // Session request success */
+#define GOTGCTL_SRQ_Pos                  (1U)
+#define GOTGCTL_SRQ_Msk                  (0x1UL << GOTGCTL_SRQ_Pos)               // 0x00000002 */
+#define GOTGCTL_SRQ                      GOTGCTL_SRQ_Msk                          // Session request */
+#define GOTGCTL_VBVALOEN_Pos             (2U)
+#define GOTGCTL_VBVALOEN_Msk             (0x1UL << GOTGCTL_VBVALOEN_Pos)          // 0x00000004 */
+#define GOTGCTL_VBVALOEN                 GOTGCTL_VBVALOEN_Msk                     // VBUS valid override enable */
+#define GOTGCTL_VBVALOVAL_Pos            (3U)
+#define GOTGCTL_VBVALOVAL_Msk            (0x1UL << GOTGCTL_VBVALOVAL_Pos)         // 0x00000008 */
+#define GOTGCTL_VBVALOVAL                GOTGCTL_VBVALOVAL_Msk                    // VBUS valid override value */
+#define GOTGCTL_AVALOEN_Pos              (4U)
+#define GOTGCTL_AVALOEN_Msk              (0x1UL << GOTGCTL_AVALOEN_Pos)           // 0x00000010 */
+#define GOTGCTL_AVALOEN                  GOTGCTL_AVALOEN_Msk                      // A-peripheral session valid override enable */
+#define GOTGCTL_AVALOVAL_Pos             (5U)
+#define GOTGCTL_AVALOVAL_Msk             (0x1UL << GOTGCTL_AVALOVAL_Pos)          // 0x00000020 */
+#define GOTGCTL_AVALOVAL                 GOTGCTL_AVALOVAL_Msk                     // A-peripheral session valid override value */
+#define GOTGCTL_BVALOEN_Pos              (6U)
+#define GOTGCTL_BVALOEN_Msk              (0x1UL << GOTGCTL_BVALOEN_Pos)           // 0x00000040 */
+#define GOTGCTL_BVALOEN                  GOTGCTL_BVALOEN_Msk                      // B-peripheral session valid override enable */
+#define GOTGCTL_BVALOVAL_Pos             (7U)
+#define GOTGCTL_BVALOVAL_Msk             (0x1UL << GOTGCTL_BVALOVAL_Pos)          // 0x00000080 */
+#define GOTGCTL_BVALOVAL                 GOTGCTL_BVALOVAL_Msk                     // B-peripheral session valid override value  */
+#define GOTGCTL_HNGSCS_Pos               (8U)
+#define GOTGCTL_HNGSCS_Msk               (0x1UL << GOTGCTL_HNGSCS_Pos)            // 0x00000100 */
+#define GOTGCTL_HNGSCS                   GOTGCTL_HNGSCS_Msk                       // Host set HNP enable */
+#define GOTGCTL_HNPRQ_Pos                (9U)
+#define GOTGCTL_HNPRQ_Msk                (0x1UL << GOTGCTL_HNPRQ_Pos)             // 0x00000200 */
+#define GOTGCTL_HNPRQ                    GOTGCTL_HNPRQ_Msk                        // HNP request */
+#define GOTGCTL_HSHNPEN_Pos              (10U)
+#define GOTGCTL_HSHNPEN_Msk              (0x1UL << GOTGCTL_HSHNPEN_Pos)           // 0x00000400 */
+#define GOTGCTL_HSHNPEN                  GOTGCTL_HSHNPEN_Msk                      // Host set HNP enable */
+#define GOTGCTL_DHNPEN_Pos               (11U)
+#define GOTGCTL_DHNPEN_Msk               (0x1UL << GOTGCTL_DHNPEN_Pos)            // 0x00000800 */
+#define GOTGCTL_DHNPEN                   GOTGCTL_DHNPEN_Msk                       // Device HNP enabled */
+#define GOTGCTL_EHEN_Pos                 (12U)
+#define GOTGCTL_EHEN_Msk                 (0x1UL << GOTGCTL_EHEN_Pos)              // 0x00001000 */
+#define GOTGCTL_EHEN                     GOTGCTL_EHEN_Msk                         // Embedded host enable */
+#define GOTGCTL_CIDSTS_Pos               (16U)
+#define GOTGCTL_CIDSTS_Msk               (0x1UL << GOTGCTL_CIDSTS_Pos)            // 0x00010000 */
+#define GOTGCTL_CIDSTS                   GOTGCTL_CIDSTS_Msk                       // Connector ID status */
+#define GOTGCTL_DBCT_Pos                 (17U)
+#define GOTGCTL_DBCT_Msk                 (0x1UL << GOTGCTL_DBCT_Pos)              // 0x00020000 */
+#define GOTGCTL_DBCT                     GOTGCTL_DBCT_Msk                         // Long/short debounce time */
+#define GOTGCTL_ASVLD_Pos                (18U)
+#define GOTGCTL_ASVLD_Msk                (0x1UL << GOTGCTL_ASVLD_Pos)             // 0x00040000 */
+#define GOTGCTL_ASVLD                    GOTGCTL_ASVLD_Msk                        // A-session valid  */
+#define GOTGCTL_BSESVLD_Pos              (19U)
+#define GOTGCTL_BSESVLD_Msk              (0x1UL << GOTGCTL_BSESVLD_Pos)           // 0x00080000 */
+#define GOTGCTL_BSESVLD                  GOTGCTL_BSESVLD_Msk                      // B-session valid */
+#define GOTGCTL_OTGVER_Pos               (20U)
+#define GOTGCTL_OTGVER_Msk               (0x1UL << GOTGCTL_OTGVER_Pos)            // 0x00100000 */
+#define GOTGCTL_OTGVER                   GOTGCTL_OTGVER_Msk                       // OTG version  */
+
+/********************  Bit definition for HCFG register  ********************/
+#define HCFG_FSLSPCS_Pos                 (0U)
+#define HCFG_FSLSPCS_Msk                 (0x3UL << HCFG_FSLSPCS_Pos)              // 0x00000003 */
+#define HCFG_FSLSPCS                     HCFG_FSLSPCS_Msk                         // FS/LS PHY clock select  */
+#define HCFG_FSLSPCS_0                   (0x1UL << HCFG_FSLSPCS_Pos)              // 0x00000001 */
+#define HCFG_FSLSPCS_1                   (0x2UL << HCFG_FSLSPCS_Pos)              // 0x00000002 */
+#define HCFG_FSLSS_Pos                   (2U)
+#define HCFG_FSLSS_Msk                   (0x1UL << HCFG_FSLSS_Pos)                // 0x00000004 */
+#define HCFG_FSLSS                       HCFG_FSLSS_Msk                           // FS- and LS-only support */
+
+/********************  Bit definition for PCGCR register  ********************/
+#define PCGCR_STPPCLK_Pos                (0U)
+#define PCGCR_STPPCLK_Msk                (0x1UL << PCGCR_STPPCLK_Pos)             // 0x00000001 */
+#define PCGCR_STPPCLK                    PCGCR_STPPCLK_Msk                        // Stop PHY clock */
+#define PCGCR_GATEHCLK_Pos               (1U)
+#define PCGCR_GATEHCLK_Msk               (0x1UL << PCGCR_GATEHCLK_Pos)            // 0x00000002 */
+#define PCGCR_GATEHCLK                   PCGCR_GATEHCLK_Msk                       // Gate HCLK */
+#define PCGCR_PHYSUSP_Pos                (4U)
+#define PCGCR_PHYSUSP_Msk                (0x1UL << PCGCR_PHYSUSP_Pos)             // 0x00000010 */
+#define PCGCR_PHYSUSP                    PCGCR_PHYSUSP_Msk                        // PHY suspended */
+
+/********************  Bit definition for GOTGINT register  ********************/
+#define GOTGINT_SEDET_Pos                (2U)
+#define GOTGINT_SEDET_Msk                (0x1UL << GOTGINT_SEDET_Pos)             // 0x00000004 */
+#define GOTGINT_SEDET                    GOTGINT_SEDET_Msk                        // Session end detected                   */
+#define GOTGINT_SRSSCHG_Pos              (8U)
+#define GOTGINT_SRSSCHG_Msk              (0x1UL << GOTGINT_SRSSCHG_Pos)           // 0x00000100 */
+#define GOTGINT_SRSSCHG                  GOTGINT_SRSSCHG_Msk                      // Session request success status change  */
+#define GOTGINT_HNSSCHG_Pos              (9U)
+#define GOTGINT_HNSSCHG_Msk              (0x1UL << GOTGINT_HNSSCHG_Pos)           // 0x00000200 */
+#define GOTGINT_HNSSCHG                  GOTGINT_HNSSCHG_Msk                      // Host negotiation success status change */
+#define GOTGINT_HNGDET_Pos               (17U)
+#define GOTGINT_HNGDET_Msk               (0x1UL << GOTGINT_HNGDET_Pos)            // 0x00020000 */
+#define GOTGINT_HNGDET                   GOTGINT_HNGDET_Msk                       // Host negotiation detected              */
+#define GOTGINT_ADTOCHG_Pos              (18U)
+#define GOTGINT_ADTOCHG_Msk              (0x1UL << GOTGINT_ADTOCHG_Pos)           // 0x00040000 */
+#define GOTGINT_ADTOCHG                  GOTGINT_ADTOCHG_Msk                      // A-device timeout change                */
+#define GOTGINT_DBCDNE_Pos               (19U)
+#define GOTGINT_DBCDNE_Msk               (0x1UL << GOTGINT_DBCDNE_Pos)            // 0x00080000 */
+#define GOTGINT_DBCDNE                   GOTGINT_DBCDNE_Msk                       // Debounce done                          */
+#define GOTGINT_IDCHNG_Pos               (20U)
+#define GOTGINT_IDCHNG_Msk               (0x1UL << GOTGINT_IDCHNG_Pos)            // 0x00100000 */
+#define GOTGINT_IDCHNG                   GOTGINT_IDCHNG_Msk                       // Change in ID pin input value           */
+
+/********************  Bit definition for DCFG register  ********************/
+#define DCFG_DSPD_Pos                    (0U)
+#define DCFG_DSPD_Msk                    (0x3UL << DCFG_DSPD_Pos)                 // 0x00000003
+#define DCFG_DSPD_HS                     0    // Highspeed
+#define DCFG_DSPD_FS_HSPHY               1    // Fullspeed on HS PHY
+#define DCFG_DSPD_LS                     2    // Lowspeed
+#define DCFG_DSPD_FS                     3    // Fullspeed on FS PHY
+
+#define DCFG_NZLSOHSK_Pos                (2U)
+#define DCFG_NZLSOHSK_Msk                (0x1UL << DCFG_NZLSOHSK_Pos)             // 0x00000004 */
+#define DCFG_NZLSOHSK                    DCFG_NZLSOHSK_Msk                        // Nonzero-length status OUT handshake */
+
+#define DCFG_DAD_Pos                     (4U)
+#define DCFG_DAD_Msk                     (0x7FUL << DCFG_DAD_Pos)                 // 0x000007F0 */
+#define DCFG_DAD                         DCFG_DAD_Msk                             // Device address */
+#define DCFG_DAD_0                       (0x01UL << DCFG_DAD_Pos)                 // 0x00000010 */
+#define DCFG_DAD_1                       (0x02UL << DCFG_DAD_Pos)                 // 0x00000020 */
+#define DCFG_DAD_2                       (0x04UL << DCFG_DAD_Pos)                 // 0x00000040 */
+#define DCFG_DAD_3                       (0x08UL << DCFG_DAD_Pos)                 // 0x00000080 */
+#define DCFG_DAD_4                       (0x10UL << DCFG_DAD_Pos)                 // 0x00000100 */
+#define DCFG_DAD_5                       (0x20UL << DCFG_DAD_Pos)                 // 0x00000200 */
+#define DCFG_DAD_6                       (0x40UL << DCFG_DAD_Pos)                 // 0x00000400 */
+
+#define DCFG_PFIVL_Pos                   (11U)
+#define DCFG_PFIVL_Msk                   (0x3UL << DCFG_PFIVL_Pos)                // 0x00001800 */
+#define DCFG_PFIVL                       DCFG_PFIVL_Msk                           // Periodic (micro)frame interval */
+#define DCFG_PFIVL_0                     (0x1UL << DCFG_PFIVL_Pos)                // 0x00000800 */
+#define DCFG_PFIVL_1                     (0x2UL << DCFG_PFIVL_Pos)                // 0x00001000 */
+
+#define DCFG_XCVRDLY_Pos                 (14U)
+#define DCFG_XCVRDLY_Msk                 (0x1UL << DCFG_XCVRDLY_Pos)             /*!< 0x00004000 */
+#define DCFG_XCVRDLY                     DCFG_XCVRDLY_Msk                        // Enables delay between xcvr_sel and txvalid during device chirp
+
+#define DCFG_PERSCHIVL_Pos               (24U)
+#define DCFG_PERSCHIVL_Msk               (0x3UL << DCFG_PERSCHIVL_Pos)            // 0x03000000 */
+#define DCFG_PERSCHIVL                   DCFG_PERSCHIVL_Msk                       // Periodic scheduling interval */
+#define DCFG_PERSCHIVL_0                 (0x1UL << DCFG_PERSCHIVL_Pos)            // 0x01000000 */
+#define DCFG_PERSCHIVL_1                 (0x2UL << DCFG_PERSCHIVL_Pos)            // 0x02000000 */
+
+/********************  Bit definition for DCTL register  ********************/
+#define DCTL_RWUSIG_Pos                  (0U)
+#define DCTL_RWUSIG_Msk                  (0x1UL << DCTL_RWUSIG_Pos)               // 0x00000001 */
+#define DCTL_RWUSIG                      DCTL_RWUSIG_Msk                          // Remote wakeup signaling */
+#define DCTL_SDIS_Pos                    (1U)
+#define DCTL_SDIS_Msk                    (0x1UL << DCTL_SDIS_Pos)                 // 0x00000002 */
+#define DCTL_SDIS                        DCTL_SDIS_Msk                            // Soft disconnect         */
+#define DCTL_GINSTS_Pos                  (2U)
+#define DCTL_GINSTS_Msk                  (0x1UL << DCTL_GINSTS_Pos)               // 0x00000004 */
+#define DCTL_GINSTS                      DCTL_GINSTS_Msk                          // Global IN NAK status    */
+#define DCTL_GONSTS_Pos                  (3U)
+#define DCTL_GONSTS_Msk                  (0x1UL << DCTL_GONSTS_Pos)               // 0x00000008 */
+#define DCTL_GONSTS                      DCTL_GONSTS_Msk                          // Global OUT NAK status   */
+
+#define DCTL_TCTL_Pos                    (4U)
+#define DCTL_TCTL_Msk                    (0x7UL << DCTL_TCTL_Pos)                 // 0x00000070 */
+#define DCTL_TCTL                        DCTL_TCTL_Msk                            // Test control */
+#define DCTL_TCTL_0                      (0x1UL << DCTL_TCTL_Pos)                 // 0x00000010 */
+#define DCTL_TCTL_1                      (0x2UL << DCTL_TCTL_Pos)                 // 0x00000020 */
+#define DCTL_TCTL_2                      (0x4UL << DCTL_TCTL_Pos)                 // 0x00000040 */
+#define DCTL_SGINAK_Pos                  (7U)
+#define DCTL_SGINAK_Msk                  (0x1UL << DCTL_SGINAK_Pos)               // 0x00000080 */
+#define DCTL_SGINAK                      DCTL_SGINAK_Msk                          // Set global IN NAK         */
+#define DCTL_CGINAK_Pos                  (8U)
+#define DCTL_CGINAK_Msk                  (0x1UL << DCTL_CGINAK_Pos)               // 0x00000100 */
+#define DCTL_CGINAK                      DCTL_CGINAK_Msk                          // Clear global IN NAK       */
+#define DCTL_SGONAK_Pos                  (9U)
+#define DCTL_SGONAK_Msk                  (0x1UL << DCTL_SGONAK_Pos)               // 0x00000200 */
+#define DCTL_SGONAK                      DCTL_SGONAK_Msk                          // Set global OUT NAK        */
+#define DCTL_CGONAK_Pos                  (10U)
+#define DCTL_CGONAK_Msk                  (0x1UL << DCTL_CGONAK_Pos)               // 0x00000400 */
+#define DCTL_CGONAK                      DCTL_CGONAK_Msk                          // Clear global OUT NAK      */
+#define DCTL_POPRGDNE_Pos                (11U)
+#define DCTL_POPRGDNE_Msk                (0x1UL << DCTL_POPRGDNE_Pos)             // 0x00000800 */
+#define DCTL_POPRGDNE                    DCTL_POPRGDNE_Msk                        // Power-on programming done */
+
+/********************  Bit definition for HFIR register  ********************/
+#define HFIR_FRIVL_Pos                   (0U)
+#define HFIR_FRIVL_Msk                   (0xFFFFUL << HFIR_FRIVL_Pos)             // 0x0000FFFF */
+#define HFIR_FRIVL                       HFIR_FRIVL_Msk                           // Frame interval */
+
+/********************  Bit definition for HFNUM register  ********************/
+#define HFNUM_FRNUM_Pos                  (0U)
+#define HFNUM_FRNUM_Msk                  (0xFFFFUL << HFNUM_FRNUM_Pos)            // 0x0000FFFF */
+#define HFNUM_FRNUM                      HFNUM_FRNUM_Msk                          // Frame number         */
+#define HFNUM_FTREM_Pos                  (16U)
+#define HFNUM_FTREM_Msk                  (0xFFFFUL << HFNUM_FTREM_Pos)            // 0xFFFF0000 */
+#define HFNUM_FTREM                      HFNUM_FTREM_Msk                          // Frame time remaining */
+
+/********************  Bit definition for DSTS register  ********************/
+#define DSTS_SUSPSTS_Pos                 (0U)
+#define DSTS_SUSPSTS_Msk                 (0x1UL << DSTS_SUSPSTS_Pos)              // 0x00000001 */
+#define DSTS_SUSPSTS                     DSTS_SUSPSTS_Msk                         // Suspend status   */
+#define DSTS_ENUMSPD_Pos                 (1U)
+#define DSTS_ENUMSPD_Msk                 (0x3UL << DSTS_ENUMSPD_Pos)              // 0x00000006 */
+#define DSTS_ENUMSPD                     DSTS_ENUMSPD_Msk                         // Enumerated speed */
+#define DSTS_ENUMSPD_HS                  0    // Highspeed
+#define DSTS_ENUMSPD_FS_HSPHY            1    // Fullspeed on HS PHY
+#define DSTS_ENUMSPD_LS                  2    // Lowspeed
+#define DSTS_ENUMSPD_FS                  3    // Fullspeed on FS PHY
+
+
+#define DSTS_EERR_Pos                    (3U)
+#define DSTS_EERR_Msk                    (0x1UL << DSTS_EERR_Pos)                 // 0x00000008 */
+#define DSTS_EERR                        DSTS_EERR_Msk                            // Erratic error     */
+#define DSTS_FNSOF_Pos                   (8U)
+#define DSTS_FNSOF_Msk                   (0x3FFFUL << DSTS_FNSOF_Pos)             // 0x003FFF00 */
+#define DSTS_FNSOF                       DSTS_FNSOF_Msk                           // Frame number of the received SOF */
+
+/********************  Bit definition for GAHBCFG register  ********************/
+#define GAHBCFG_GINT_Pos                 (0U)
+#define GAHBCFG_GINT_Msk                 (0x1UL << GAHBCFG_GINT_Pos)              // 0x00000001 */
+#define GAHBCFG_GINT                     GAHBCFG_GINT_Msk                         // Global interrupt mask */
+#define GAHBCFG_HBSTLEN_Pos              (1U)
+#define GAHBCFG_HBSTLEN_Msk              (0xFUL << GAHBCFG_HBSTLEN_Pos)           // 0x0000001E */
+#define GAHBCFG_HBSTLEN                  GAHBCFG_HBSTLEN_Msk                      // Burst length/type */
+#define GAHBCFG_HBSTLEN_0                (0x0UL << GAHBCFG_HBSTLEN_Pos)           // Single */
+#define GAHBCFG_HBSTLEN_1                (0x1UL << GAHBCFG_HBSTLEN_Pos)           // INCR */
+#define GAHBCFG_HBSTLEN_2                (0x3UL << GAHBCFG_HBSTLEN_Pos)           // INCR4 */
+#define GAHBCFG_HBSTLEN_3                (0x5UL << GAHBCFG_HBSTLEN_Pos)           // INCR8 */
+#define GAHBCFG_HBSTLEN_4                (0x7UL << GAHBCFG_HBSTLEN_Pos)           // INCR16 */
+#define GAHBCFG_DMAEN_Pos                (5U)
+#define GAHBCFG_DMAEN_Msk                (0x1UL << GAHBCFG_DMAEN_Pos)             // 0x00000020 */
+#define GAHBCFG_DMAEN                    GAHBCFG_DMAEN_Msk                        // DMA enable */
+#define GAHBCFG_TXFELVL_Pos              (7U)
+#define GAHBCFG_TXFELVL_Msk              (0x1UL << GAHBCFG_TXFELVL_Pos)           // 0x00000080 */
+#define GAHBCFG_TXFELVL                  GAHBCFG_TXFELVL_Msk                      // TxFIFO empty level */
+#define GAHBCFG_PTXFELVL_Pos             (8U)
+#define GAHBCFG_PTXFELVL_Msk             (0x1UL << GAHBCFG_PTXFELVL_Pos)          // 0x00000100 */
+#define GAHBCFG_PTXFELVL                 GAHBCFG_PTXFELVL_Msk                     // Periodic TxFIFO empty level */
+
+#define GSNPSID_ID_MASK                 TU_GENMASK(31, 16)
+
+/********************  Bit definition for GUSBCFG register  ********************/
+#define GUSBCFG_TOCAL_Pos                (0U)
+#define GUSBCFG_TOCAL_Msk                (0x7UL << GUSBCFG_TOCAL_Pos)             // 0x00000007 */
+#define GUSBCFG_TOCAL                    GUSBCFG_TOCAL_Msk                        // FS timeout calibration */
+#define GUSBCFG_PHYIF16_Pos              (3U)
+#define GUSBCFG_PHYIF16_Msk              (0x1UL << GUSBCFG_PHYIF16_Pos)             // 0x00000008 */
+#define GUSBCFG_PHYIF16                  GUSBCFG_PHYIF16_Msk                        // PHY Interface (PHYIf) */
+#define GUSBCFG_ULPI_UTMI_SEL_Pos        (4U)
+#define GUSBCFG_ULPI_UTMI_SEL_Msk        (0x1UL << GUSBCFG_ULPI_UTMI_SEL_Pos)     // 0x00000010 */
+#define GUSBCFG_ULPI_UTMI_SEL            GUSBCFG_ULPI_UTMI_SEL_Msk                // ULPI or UTMI+ Select (ULPI_UTMI_Sel) */
+#define GUSBCFG_PHYSEL_Pos               (6U)
+#define GUSBCFG_PHYSEL_Msk               (0x1UL << GUSBCFG_PHYSEL_Pos)            // 0x00000040 */
+#define GUSBCFG_PHYSEL                   GUSBCFG_PHYSEL_Msk                       // USB 2.0 high-speed ULPI PHY or USB 1.1 full-speed serial transceiver select */
+#define GUSBCFG_DDRSEL                   TU_BIT(7)                                // Single Data Rate (SDR) or Double Data Rate (DDR) or ULPI interface.
+#define GUSBCFG_SRPCAP_Pos               (8U)
+#define GUSBCFG_SRPCAP_Msk               (0x1UL << GUSBCFG_SRPCAP_Pos)            // 0x00000100 */
+#define GUSBCFG_SRPCAP                   GUSBCFG_SRPCAP_Msk                       // SRP-capable */
+#define GUSBCFG_HNPCAP_Pos               (9U)
+#define GUSBCFG_HNPCAP_Msk               (0x1UL << GUSBCFG_HNPCAP_Pos)            // 0x00000200 */
+#define GUSBCFG_HNPCAP                   GUSBCFG_HNPCAP_Msk                       // HNP-capable */
+#define GUSBCFG_TRDT_Pos                 (10U)
+#define GUSBCFG_TRDT_Msk                 (0xFUL << GUSBCFG_TRDT_Pos)              // 0x00003C00 */
+#define GUSBCFG_TRDT                     GUSBCFG_TRDT_Msk                         // USB turnaround time */
+#define GUSBCFG_PHYLPCS_Pos              (15U)
+#define GUSBCFG_PHYLPCS_Msk              (0x1UL << GUSBCFG_PHYLPCS_Pos)           // 0x00008000 */
+#define GUSBCFG_PHYLPCS                  GUSBCFG_PHYLPCS_Msk                      // PHY Low-power clock select */
+#define GUSBCFG_ULPIFSLS_Pos             (17U)
+#define GUSBCFG_ULPIFSLS_Msk             (0x1UL << GUSBCFG_ULPIFSLS_Pos)          // 0x00020000 */
+#define GUSBCFG_ULPIFSLS                 GUSBCFG_ULPIFSLS_Msk                     // ULPI FS/LS select               */
+#define GUSBCFG_ULPIAR_Pos               (18U)
+#define GUSBCFG_ULPIAR_Msk               (0x1UL << GUSBCFG_ULPIAR_Pos)            // 0x00040000 */
+#define GUSBCFG_ULPIAR                   GUSBCFG_ULPIAR_Msk                       // ULPI Auto-resume                */
+#define GUSBCFG_ULPICSM_Pos              (19U)
+#define GUSBCFG_ULPICSM_Msk              (0x1UL << GUSBCFG_ULPICSM_Pos)           // 0x00080000 */
+#define GUSBCFG_ULPICSM                  GUSBCFG_ULPICSM_Msk                      // ULPI Clock SuspendM             */
+#define GUSBCFG_ULPIEVBUSD_Pos           (20U)
+#define GUSBCFG_ULPIEVBUSD_Msk           (0x1UL << GUSBCFG_ULPIEVBUSD_Pos)        // 0x00100000 */
+#define GUSBCFG_ULPIEVBUSD               GUSBCFG_ULPIEVBUSD_Msk                   // ULPI External VBUS Drive        */
+#define GUSBCFG_ULPIEVBUSI_Pos           (21U)
+#define GUSBCFG_ULPIEVBUSI_Msk           (0x1UL << GUSBCFG_ULPIEVBUSI_Pos)        // 0x00200000 */
+#define GUSBCFG_ULPIEVBUSI               GUSBCFG_ULPIEVBUSI_Msk                   // ULPI external VBUS indicator    */
+#define GUSBCFG_TSDPS_Pos                (22U)
+#define GUSBCFG_TSDPS_Msk                (0x1UL << GUSBCFG_TSDPS_Pos)             // 0x00400000 */
+#define GUSBCFG_TSDPS                    GUSBCFG_TSDPS_Msk                        // TermSel DLine pulsing selection */
+#define GUSBCFG_PCCI_Pos                 (23U)
+#define GUSBCFG_PCCI_Msk                 (0x1UL << GUSBCFG_PCCI_Pos)              // 0x00800000 */
+#define GUSBCFG_PCCI                     GUSBCFG_PCCI_Msk                         // Indicator complement            */
+#define GUSBCFG_PTCI_Pos                 (24U)
+#define GUSBCFG_PTCI_Msk                 (0x1UL << GUSBCFG_PTCI_Pos)              // 0x01000000 */
+#define GUSBCFG_PTCI                     GUSBCFG_PTCI_Msk                         // Indicator pass through          */
+#define GUSBCFG_ULPIIPD_Pos              (25U)
+#define GUSBCFG_ULPIIPD_Msk              (0x1UL << GUSBCFG_ULPIIPD_Pos)           // 0x02000000 */
+#define GUSBCFG_ULPIIPD                  GUSBCFG_ULPIIPD_Msk                      // ULPI interface protect disable  */
+#define GUSBCFG_FHMOD_Pos                (29U)
+#define GUSBCFG_FHMOD_Msk                (0x1UL << GUSBCFG_FHMOD_Pos)             // 0x20000000 */
+#define GUSBCFG_FHMOD                    GUSBCFG_FHMOD_Msk                        // Forced host mode                */
+#define GUSBCFG_FDMOD_Pos                (30U)
+#define GUSBCFG_FDMOD_Msk                (0x1UL << GUSBCFG_FDMOD_Pos)             // 0x40000000 */
+#define GUSBCFG_FDMOD                    GUSBCFG_FDMOD_Msk                        // Forced peripheral mode          */
+#define GUSBCFG_CTXPKT_Pos               (31U)
+#define GUSBCFG_CTXPKT_Msk               (0x1UL << GUSBCFG_CTXPKT_Pos)            // 0x80000000 */
+#define GUSBCFG_CTXPKT                   GUSBCFG_CTXPKT_Msk                       // Corrupt Tx packet               */
+
+/********************  Bit definition for GRSTCTL register  ********************/
+#define GRSTCTL_CSRST_Pos                (0U)
+#define GRSTCTL_CSRST_Msk                (0x1UL << GRSTCTL_CSRST_Pos)             // 0x00000001 */
+#define GRSTCTL_CSRST                    GRSTCTL_CSRST_Msk                        // Core soft reset          */
+#define GRSTCTL_HSRST_Pos                (1U)
+#define GRSTCTL_HSRST_Msk                (0x1UL << GRSTCTL_HSRST_Pos)             // 0x00000002 */
+#define GRSTCTL_HSRST                    GRSTCTL_HSRST_Msk                        // HCLK soft reset          */
+#define GRSTCTL_FCRST_Pos                (2U)
+#define GRSTCTL_FCRST_Msk                (0x1UL << GRSTCTL_FCRST_Pos)             // 0x00000004 */
+#define GRSTCTL_FCRST                    GRSTCTL_FCRST_Msk                        // Host frame counter reset */
+#define GRSTCTL_RXFFLSH_Pos              (4U)
+#define GRSTCTL_RXFFLSH_Msk              (0x1UL << GRSTCTL_RXFFLSH_Pos)           // 0x00000010 */
+#define GRSTCTL_RXFFLSH                  GRSTCTL_RXFFLSH_Msk                      // RxFIFO flush             */
+#define GRSTCTL_TXFFLSH_Pos              (5U)
+#define GRSTCTL_TXFFLSH_Msk              (0x1UL << GRSTCTL_TXFFLSH_Pos)           // 0x00000020 */
+#define GRSTCTL_TXFFLSH                  GRSTCTL_TXFFLSH_Msk                      // TxFIFO flush             */
+#define GRSTCTL_TXFNUM_Pos               (6U)
+#define GRSTCTL_TXFNUM_Msk               (0x1FUL << GRSTCTL_TXFNUM_Pos)           // 0x000007C0 */
+#define GRSTCTL_TXFNUM                   GRSTCTL_TXFNUM_Msk                       // TxFIFO number */
+#define GRSTCTL_TXFNUM_0                 (0x01UL << GRSTCTL_TXFNUM_Pos)           // 0x00000040 */
+#define GRSTCTL_TXFNUM_1                 (0x02UL << GRSTCTL_TXFNUM_Pos)           // 0x00000080 */
+#define GRSTCTL_TXFNUM_2                 (0x04UL << GRSTCTL_TXFNUM_Pos)           // 0x00000100 */
+#define GRSTCTL_TXFNUM_3                 (0x08UL << GRSTCTL_TXFNUM_Pos)           // 0x00000200 */
+#define GRSTCTL_TXFNUM_4                 (0x10UL << GRSTCTL_TXFNUM_Pos)           // 0x00000400 */
+#define GRSTCTL_CSFTRST_DONE_Pos       (29)
+#define GRSTCTL_CSFTRST_DONE           (1u << GRSTCTL_CSFTRST_DONE_Pos)         // Reset Done, only available from v4.20a
+#define GRSTCTL_DMAREQ_Pos               (30U)
+#define GRSTCTL_DMAREQ_Msk               (0x1UL << GRSTCTL_DMAREQ_Pos)            // 0x40000000 */
+#define GRSTCTL_DMAREQ                   GRSTCTL_DMAREQ_Msk                       // DMA request signal */
+#define GRSTCTL_AHBIDL_Pos               (31U)
+#define GRSTCTL_AHBIDL_Msk               (0x1UL << GRSTCTL_AHBIDL_Pos)            // 0x80000000 */
+#define GRSTCTL_AHBIDL                   GRSTCTL_AHBIDL_Msk                       // AHB master idle */
+
+/********************  Bit definition for DIEPMSK register  ********************/
+#define DIEPMSK_XFRCM_Pos                (0U)
+#define DIEPMSK_XFRCM_Msk                (0x1UL << DIEPMSK_XFRCM_Pos)             // 0x00000001 */
+#define DIEPMSK_XFRCM                    DIEPMSK_XFRCM_Msk                        // Transfer completed interrupt mask                 */
+#define DIEPMSK_EPDM_Pos                 (1U)
+#define DIEPMSK_EPDM_Msk                 (0x1UL << DIEPMSK_EPDM_Pos)              // 0x00000002 */
+#define DIEPMSK_EPDM                     DIEPMSK_EPDM_Msk                         // Endpoint disabled interrupt mask                  */
+#define DIEPMSK_TOM_Pos                  (3U)
+#define DIEPMSK_TOM_Msk                  (0x1UL << DIEPMSK_TOM_Pos)               // 0x00000008 */
+#define DIEPMSK_TOM                      DIEPMSK_TOM_Msk                          // Timeout condition mask (nonisochronous endpoints) */
+#define DIEPMSK_ITTXFEMSK_Pos            (4U)
+#define DIEPMSK_ITTXFEMSK_Msk            (0x1UL << DIEPMSK_ITTXFEMSK_Pos)         // 0x00000010 */
+#define DIEPMSK_ITTXFEMSK                DIEPMSK_ITTXFEMSK_Msk                    // IN token received when TxFIFO empty mask          */
+#define DIEPMSK_INEPNMM_Pos              (5U)
+#define DIEPMSK_INEPNMM_Msk              (0x1UL << DIEPMSK_INEPNMM_Pos)           // 0x00000020 */
+#define DIEPMSK_INEPNMM                  DIEPMSK_INEPNMM_Msk                      // IN token received with EP mismatch mask           */
+#define DIEPMSK_INEPNEM_Pos              (6U)
+#define DIEPMSK_INEPNEM_Msk              (0x1UL << DIEPMSK_INEPNEM_Pos)           // 0x00000040 */
+#define DIEPMSK_INEPNEM                  DIEPMSK_INEPNEM_Msk                      // IN endpoint NAK effective mask                    */
+#define DIEPMSK_TXFURM_Pos               (8U)
+#define DIEPMSK_TXFURM_Msk               (0x1UL << DIEPMSK_TXFURM_Pos)            // 0x00000100 */
+#define DIEPMSK_TXFURM                   DIEPMSK_TXFURM_Msk                       // FIFO underrun mask                                */
+#define DIEPMSK_BIM_Pos                  (9U)
+#define DIEPMSK_BIM_Msk                  (0x1UL << DIEPMSK_BIM_Pos)               // 0x00000200 */
+#define DIEPMSK_BIM                      DIEPMSK_BIM_Msk                          // BNA interrupt mask                                */
+
+/********************  Bit definition for HPTXSTS register  ********************/
+#define HPTXSTS_PTXFSAVL_Pos             (0U)
+#define HPTXSTS_PTXFSAVL_Msk             (0xFFFFUL << HPTXSTS_PTXFSAVL_Pos)       // 0x0000FFFF */
+#define HPTXSTS_PTXFSAVL                 HPTXSTS_PTXFSAVL_Msk                     // Periodic transmit data FIFO space available     */
+#define HPTXSTS_PTXQSAV_Pos              (16U)
+#define HPTXSTS_PTXQSAV_Msk              (0xFFUL << HPTXSTS_PTXQSAV_Pos)          // 0x00FF0000 */
+#define HPTXSTS_PTXQSAV                  HPTXSTS_PTXQSAV_Msk                      // Periodic transmit request queue space available */
+#define HPTXSTS_PTXQSAV_0                (0x01UL << HPTXSTS_PTXQSAV_Pos)          // 0x00010000 */
+#define HPTXSTS_PTXQSAV_1                (0x02UL << HPTXSTS_PTXQSAV_Pos)          // 0x00020000 */
+#define HPTXSTS_PTXQSAV_2                (0x04UL << HPTXSTS_PTXQSAV_Pos)          // 0x00040000 */
+#define HPTXSTS_PTXQSAV_3                (0x08UL << HPTXSTS_PTXQSAV_Pos)          // 0x00080000 */
+#define HPTXSTS_PTXQSAV_4                (0x10UL << HPTXSTS_PTXQSAV_Pos)          // 0x00100000 */
+#define HPTXSTS_PTXQSAV_5                (0x20UL << HPTXSTS_PTXQSAV_Pos)          // 0x00200000 */
+#define HPTXSTS_PTXQSAV_6                (0x40UL << HPTXSTS_PTXQSAV_Pos)          // 0x00400000 */
+#define HPTXSTS_PTXQSAV_7                (0x80UL << HPTXSTS_PTXQSAV_Pos)          // 0x00800000 */
+
+#define HPTXSTS_PTXQTOP_Pos              (24U)
+#define HPTXSTS_PTXQTOP_Msk              (0xFFUL << HPTXSTS_PTXQTOP_Pos)          // 0xFF000000 */
+#define HPTXSTS_PTXQTOP                  HPTXSTS_PTXQTOP_Msk                      // Top of the periodic transmit request queue */
+#define HPTXSTS_PTXQTOP_0                (0x01UL << HPTXSTS_PTXQTOP_Pos)          // 0x01000000 */
+#define HPTXSTS_PTXQTOP_1                (0x02UL << HPTXSTS_PTXQTOP_Pos)          // 0x02000000 */
+#define HPTXSTS_PTXQTOP_2                (0x04UL << HPTXSTS_PTXQTOP_Pos)          // 0x04000000 */
+#define HPTXSTS_PTXQTOP_3                (0x08UL << HPTXSTS_PTXQTOP_Pos)          // 0x08000000 */
+#define HPTXSTS_PTXQTOP_4                (0x10UL << HPTXSTS_PTXQTOP_Pos)          // 0x10000000 */
+#define HPTXSTS_PTXQTOP_5                (0x20UL << HPTXSTS_PTXQTOP_Pos)          // 0x20000000 */
+#define HPTXSTS_PTXQTOP_6                (0x40UL << HPTXSTS_PTXQTOP_Pos)          // 0x40000000 */
+#define HPTXSTS_PTXQTOP_7                (0x80UL << HPTXSTS_PTXQTOP_Pos)          // 0x80000000 */
+
+/********************  Bit definition for HAINT register  ********************/
+#define HAINT_HAINT_Pos                  (0U)
+#define HAINT_HAINT_Msk                  (0xFFFFUL << HAINT_HAINT_Pos)            // 0x0000FFFF */
+#define HAINT_HAINT                      HAINT_HAINT_Msk                          // Channel interrupts */
+
+/********************  Bit definition for DOEPMSK register  ********************/
+#define DOEPMSK_XFRCM_Pos                (0U)
+#define DOEPMSK_XFRCM_Msk                (0x1UL << DOEPMSK_XFRCM_Pos)             // 0x00000001 */
+#define DOEPMSK_XFRCM                    DOEPMSK_XFRCM_Msk                        // Transfer completed interrupt mask */
+#define DOEPMSK_EPDM_Pos                 (1U)
+#define DOEPMSK_EPDM_Msk                 (0x1UL << DOEPMSK_EPDM_Pos)              // 0x00000002 */
+#define DOEPMSK_EPDM                     DOEPMSK_EPDM_Msk                         // Endpoint disabled interrupt mask               */
+#define DOEPMSK_AHBERRM_Pos              (2U)
+#define DOEPMSK_AHBERRM_Msk              (0x1UL << DOEPMSK_AHBERRM_Pos)           // 0x00000004 */
+#define DOEPMSK_AHBERRM                  DOEPMSK_AHBERRM_Msk                      // OUT transaction AHB Error interrupt mask    */
+#define DOEPMSK_STUPM_Pos                (3U)
+#define DOEPMSK_STUPM_Msk                (0x1UL << DOEPMSK_STUPM_Pos)             // 0x00000008 */
+#define DOEPMSK_STUPM                    DOEPMSK_STUPM_Msk                        // SETUP phase done mask                          */
+#define DOEPMSK_OTEPDM_Pos               (4U)
+#define DOEPMSK_OTEPDM_Msk               (0x1UL << DOEPMSK_OTEPDM_Pos)            // 0x00000010 */
+#define DOEPMSK_OTEPDM                   DOEPMSK_OTEPDM_Msk                       // OUT token received when endpoint disabled mask */
+#define DOEPMSK_OTEPSPRM_Pos             (5U)
+#define DOEPMSK_OTEPSPRM_Msk             (0x1UL << DOEPMSK_OTEPSPRM_Pos)          // 0x00000020 */
+#define DOEPMSK_OTEPSPRM                 DOEPMSK_OTEPSPRM_Msk                     // Status Phase Received mask                     */
+#define DOEPMSK_B2BSTUP_Pos              (6U)
+#define DOEPMSK_B2BSTUP_Msk              (0x1UL << DOEPMSK_B2BSTUP_Pos)           // 0x00000040 */
+#define DOEPMSK_B2BSTUP                  DOEPMSK_B2BSTUP_Msk                      // Back-to-back SETUP packets received mask       */
+#define DOEPMSK_OPEM_Pos                 (8U)
+#define DOEPMSK_OPEM_Msk                 (0x1UL << DOEPMSK_OPEM_Pos)              // 0x00000100 */
+#define DOEPMSK_OPEM                     DOEPMSK_OPEM_Msk                         // OUT packet error mask                          */
+#define DOEPMSK_BOIM_Pos                 (9U)
+#define DOEPMSK_BOIM_Msk                 (0x1UL << DOEPMSK_BOIM_Pos)              // 0x00000200 */
+#define DOEPMSK_BOIM                     DOEPMSK_BOIM_Msk                         // BNA interrupt mask                             */
+#define DOEPMSK_BERRM_Pos                (12U)
+#define DOEPMSK_BERRM_Msk                (0x1UL << DOEPMSK_BERRM_Pos)             // 0x00001000 */
+#define DOEPMSK_BERRM                    DOEPMSK_BERRM_Msk                        // Babble error interrupt mask                   */
+#define DOEPMSK_NAKM_Pos                 (13U)
+#define DOEPMSK_NAKM_Msk                 (0x1UL << DOEPMSK_NAKM_Pos)              // 0x00002000 */
+#define DOEPMSK_NAKM                     DOEPMSK_NAKM_Msk                         // OUT Packet NAK interrupt mask                  */
+#define DOEPMSK_NYETM_Pos                (14U)
+#define DOEPMSK_NYETM_Msk                (0x1UL << DOEPMSK_NYETM_Pos)             // 0x00004000 */
+#define DOEPMSK_NYETM                    DOEPMSK_NYETM_Msk                        // NYET interrupt mask                           */
+
+/********************  Bit definition for GINTSTS register  ********************/
+#define GINTSTS_CMOD_Pos                 (0U)
+#define GINTSTS_CMOD_Msk                 (0x1UL << GINTSTS_CMOD_Pos)              // 0x00000001 */
+#define GINTSTS_CMOD                     GINTSTS_CMOD_Msk                         // Current mode of operation                      */
+#define GINTSTS_MMIS_Pos                 (1U)
+#define GINTSTS_MMIS_Msk                 (0x1UL << GINTSTS_MMIS_Pos)              // 0x00000002 */
+#define GINTSTS_MMIS                     GINTSTS_MMIS_Msk                         // Mode mismatch interrupt                        */
+#define GINTSTS_OTGINT_Pos               (2U)
+#define GINTSTS_OTGINT_Msk               (0x1UL << GINTSTS_OTGINT_Pos)            // 0x00000004 */
+#define GINTSTS_OTGINT                   GINTSTS_OTGINT_Msk                       // OTG interrupt                                  */
+#define GINTSTS_SOF_Pos                  (3U)
+#define GINTSTS_SOF_Msk                  (0x1UL << GINTSTS_SOF_Pos)               // 0x00000008 */
+#define GINTSTS_SOF                      GINTSTS_SOF_Msk                          // Start of frame                                 */
+#define GINTSTS_RXFLVL_Pos               (4U)
+#define GINTSTS_RXFLVL_Msk               (0x1UL << GINTSTS_RXFLVL_Pos)            // 0x00000010 */
+#define GINTSTS_RXFLVL                   GINTSTS_RXFLVL_Msk                       // RxFIFO nonempty                                */
+#define GINTSTS_NPTXFE_Pos               (5U)
+#define GINTSTS_NPTXFE_Msk               (0x1UL << GINTSTS_NPTXFE_Pos)            // 0x00000020 */
+#define GINTSTS_NPTXFE                   GINTSTS_NPTXFE_Msk                       // Nonperiodic TxFIFO empty                       */
+#define GINTSTS_GINAKEFF_Pos             (6U)
+#define GINTSTS_GINAKEFF_Msk             (0x1UL << GINTSTS_GINAKEFF_Pos)          // 0x00000040 */
+#define GINTSTS_GINAKEFF                 GINTSTS_GINAKEFF_Msk                     // Global IN nonperiodic NAK effective            */
+#define GINTSTS_BOUTNAKEFF_Pos           (7U)
+#define GINTSTS_BOUTNAKEFF_Msk           (0x1UL << GINTSTS_BOUTNAKEFF_Pos)        // 0x00000080 */
+#define GINTSTS_BOUTNAKEFF               GINTSTS_BOUTNAKEFF_Msk                   // Global OUT NAK effective                       */
+#define GINTSTS_ESUSP_Pos                (10U)
+#define GINTSTS_ESUSP_Msk                (0x1UL << GINTSTS_ESUSP_Pos)             // 0x00000400 */
+#define GINTSTS_ESUSP                    GINTSTS_ESUSP_Msk                        // Early suspend                                  */
+#define GINTSTS_USBSUSP_Pos              (11U)
+#define GINTSTS_USBSUSP_Msk              (0x1UL << GINTSTS_USBSUSP_Pos)           // 0x00000800 */
+#define GINTSTS_USBSUSP                  GINTSTS_USBSUSP_Msk                      // USB suspend                                    */
+#define GINTSTS_USBRST_Pos               (12U)
+#define GINTSTS_USBRST_Msk               (0x1UL << GINTSTS_USBRST_Pos)            // 0x00001000 */
+#define GINTSTS_USBRST                   GINTSTS_USBRST_Msk                       // USB reset                                      */
+#define GINTSTS_ENUMDNE_Pos              (13U)
+#define GINTSTS_ENUMDNE_Msk              (0x1UL << GINTSTS_ENUMDNE_Pos)           // 0x00002000 */
+#define GINTSTS_ENUMDNE                  GINTSTS_ENUMDNE_Msk                      // Enumeration done                               */
+#define GINTSTS_ISOODRP_Pos              (14U)
+#define GINTSTS_ISOODRP_Msk              (0x1UL << GINTSTS_ISOODRP_Pos)           // 0x00004000 */
+#define GINTSTS_ISOODRP                  GINTSTS_ISOODRP_Msk                      // Isochronous OUT packet dropped interrupt       */
+#define GINTSTS_EOPF_Pos                 (15U)
+#define GINTSTS_EOPF_Msk                 (0x1UL << GINTSTS_EOPF_Pos)              // 0x00008000 */
+#define GINTSTS_EOPF                     GINTSTS_EOPF_Msk                         // End of periodic frame interrupt                */
+#define GINTSTS_IEPINT_Pos               (18U)
+#define GINTSTS_IEPINT_Msk               (0x1UL << GINTSTS_IEPINT_Pos)            // 0x00040000 */
+#define GINTSTS_IEPINT                   GINTSTS_IEPINT_Msk                       // IN endpoint interrupt                          */
+#define GINTSTS_OEPINT_Pos               (19U)
+#define GINTSTS_OEPINT_Msk               (0x1UL << GINTSTS_OEPINT_Pos)            // 0x00080000 */
+#define GINTSTS_OEPINT                   GINTSTS_OEPINT_Msk                       // OUT endpoint interrupt                         */
+#define GINTSTS_IISOIXFR_Pos             (20U)
+#define GINTSTS_IISOIXFR_Msk             (0x1UL << GINTSTS_IISOIXFR_Pos)          // 0x00100000 */
+#define GINTSTS_IISOIXFR                 GINTSTS_IISOIXFR_Msk                     // Incomplete isochronous IN transfer             */
+#define GINTSTS_PXFR_INCOMPISOOUT_Pos    (21U)
+#define GINTSTS_PXFR_INCOMPISOOUT_Msk    (0x1UL << GINTSTS_PXFR_INCOMPISOOUT_Pos) // 0x00200000 */
+#define GINTSTS_PXFR_INCOMPISOOUT        GINTSTS_PXFR_INCOMPISOOUT_Msk            // Incomplete periodic transfer                   */
+#define GINTSTS_DATAFSUSP_Pos            (22U)
+#define GINTSTS_DATAFSUSP_Msk            (0x1UL << GINTSTS_DATAFSUSP_Pos)         // 0x00400000 */
+#define GINTSTS_DATAFSUSP                GINTSTS_DATAFSUSP_Msk                    // Data fetch suspended                           */
+#define GINTSTS_RSTDET_Pos               (23U)
+#define GINTSTS_RSTDET_Msk               (0x1UL << GINTSTS_RSTDET_Pos)            // 0x00800000 */
+#define GINTSTS_RSTDET                   GINTSTS_RSTDET_Msk                       // Reset detected interrupt                       */
+#define GINTSTS_HPRTINT_Pos              (24U)
+#define GINTSTS_HPRTINT_Msk              (0x1UL << GINTSTS_HPRTINT_Pos)           // 0x01000000 */
+#define GINTSTS_HPRTINT                  GINTSTS_HPRTINT_Msk                      // Host port interrupt                            */
+#define GINTSTS_HCINT_Pos                (25U)
+#define GINTSTS_HCINT_Msk                (0x1UL << GINTSTS_HCINT_Pos)             // 0x02000000 */
+#define GINTSTS_HCINT                    GINTSTS_HCINT_Msk                        // Host channels interrupt                        */
+#define GINTSTS_PTXFE_Pos                (26U)
+#define GINTSTS_PTXFE_Msk                (0x1UL << GINTSTS_PTXFE_Pos)             // 0x04000000 */
+#define GINTSTS_PTXFE                    GINTSTS_PTXFE_Msk                        // Periodic TxFIFO empty                          */
+#define GINTSTS_LPMINT_Pos               (27U)
+#define GINTSTS_LPMINT_Msk               (0x1UL << GINTSTS_LPMINT_Pos)            // 0x08000000 */
+#define GINTSTS_LPMINT                   GINTSTS_LPMINT_Msk                       // LPM interrupt                                  */
+#define GINTSTS_CIDSCHG_Pos              (28U)
+#define GINTSTS_CIDSCHG_Msk              (0x1UL << GINTSTS_CIDSCHG_Pos)           // 0x10000000 */
+#define GINTSTS_CIDSCHG                  GINTSTS_CIDSCHG_Msk                      // Connector ID status change                     */
+#define GINTSTS_DISCINT_Pos              (29U)
+#define GINTSTS_DISCINT_Msk              (0x1UL << GINTSTS_DISCINT_Pos)           // 0x20000000 */
+#define GINTSTS_DISCINT                  GINTSTS_DISCINT_Msk                      // Disconnect detected interrupt                  */
+#define GINTSTS_SRQINT_Pos               (30U)
+#define GINTSTS_SRQINT_Msk               (0x1UL << GINTSTS_SRQINT_Pos)            // 0x40000000 */
+#define GINTSTS_SRQINT                   GINTSTS_SRQINT_Msk                       // Session request/new session detected interrupt */
+#define GINTSTS_WKUINT_Pos               (31U)
+#define GINTSTS_WKUINT_Msk               (0x1UL << GINTSTS_WKUINT_Pos)            // 0x80000000 */
+#define GINTSTS_WKUINT                   GINTSTS_WKUINT_Msk                       // Resume/remote wakeup detected interrupt        */
+
+/********************  Bit definition for GINTMSK register  ********************/
+#define GINTMSK_MMISM_Pos                (1U)
+#define GINTMSK_MMISM_Msk                (0x1UL << GINTMSK_MMISM_Pos)             // 0x00000002 */
+#define GINTMSK_MMISM                    GINTMSK_MMISM_Msk                        // Mode mismatch interrupt mask                        */
+#define GINTMSK_OTGINT_Pos               (2U)
+#define GINTMSK_OTGINT_Msk               (0x1UL << GINTMSK_OTGINT_Pos)            // 0x00000004 */
+#define GINTMSK_OTGINT                   GINTMSK_OTGINT_Msk                       // OTG interrupt mask                                  */
+#define GINTMSK_SOFM_Pos                 (3U)
+#define GINTMSK_SOFM_Msk                 (0x1UL << GINTMSK_SOFM_Pos)              // 0x00000008 */
+#define GINTMSK_SOFM                     GINTMSK_SOFM_Msk                         // Start of frame mask                                 */
+#define GINTMSK_RXFLVLM_Pos              (4U)
+#define GINTMSK_RXFLVLM_Msk              (0x1UL << GINTMSK_RXFLVLM_Pos)           // 0x00000010 */
+#define GINTMSK_RXFLVLM                  GINTMSK_RXFLVLM_Msk                      // Receive FIFO nonempty mask                          */
+#define GINTMSK_NPTXFEM_Pos              (5U)
+#define GINTMSK_NPTXFEM_Msk              (0x1UL << GINTMSK_NPTXFEM_Pos)           // 0x00000020 */
+#define GINTMSK_NPTXFEM                  GINTMSK_NPTXFEM_Msk                      // Nonperiodic TxFIFO empty mask                       */
+#define GINTMSK_GINAKEFFM_Pos            (6U)
+#define GINTMSK_GINAKEFFM_Msk            (0x1UL << GINTMSK_GINAKEFFM_Pos)         // 0x00000040 */
+#define GINTMSK_GINAKEFFM                GINTMSK_GINAKEFFM_Msk                    // Global nonperiodic IN NAK effective mask            */
+#define GINTMSK_GONAKEFFM_Pos            (7U)
+#define GINTMSK_GONAKEFFM_Msk            (0x1UL << GINTMSK_GONAKEFFM_Pos)         // 0x00000080 */
+#define GINTMSK_GONAKEFFM                GINTMSK_GONAKEFFM_Msk                    // Global OUT NAK effective mask                       */
+#define GINTMSK_ESUSPM_Pos               (10U)
+#define GINTMSK_ESUSPM_Msk               (0x1UL << GINTMSK_ESUSPM_Pos)            // 0x00000400 */
+#define GINTMSK_ESUSPM                   GINTMSK_ESUSPM_Msk                       // Early suspend mask                                  */
+#define GINTMSK_USBSUSPM_Pos             (11U)
+#define GINTMSK_USBSUSPM_Msk             (0x1UL << GINTMSK_USBSUSPM_Pos)          // 0x00000800 */
+#define GINTMSK_USBSUSPM                 GINTMSK_USBSUSPM_Msk                     // USB suspend mask                                    */
+#define GINTMSK_USBRST_Pos               (12U)
+#define GINTMSK_USBRST_Msk               (0x1UL << GINTMSK_USBRST_Pos)            // 0x00001000 */
+#define GINTMSK_USBRST                   GINTMSK_USBRST_Msk                       // USB reset mask                                      */
+#define GINTMSK_ENUMDNEM_Pos             (13U)
+#define GINTMSK_ENUMDNEM_Msk             (0x1UL << GINTMSK_ENUMDNEM_Pos)          // 0x00002000 */
+#define GINTMSK_ENUMDNEM                 GINTMSK_ENUMDNEM_Msk                     // Enumeration done mask                               */
+#define GINTMSK_ISOODRPM_Pos             (14U)
+#define GINTMSK_ISOODRPM_Msk             (0x1UL << GINTMSK_ISOODRPM_Pos)          // 0x00004000 */
+#define GINTMSK_ISOODRPM                 GINTMSK_ISOODRPM_Msk                     // Isochronous OUT packet dropped interrupt mask       */
+#define GINTMSK_EOPFM_Pos                (15U)
+#define GINTMSK_EOPFM_Msk                (0x1UL << GINTMSK_EOPFM_Pos)             // 0x00008000 */
+#define GINTMSK_EOPFM                    GINTMSK_EOPFM_Msk                        // End of periodic frame interrupt mask                */
+#define GINTMSK_EPMISM_Pos               (17U)
+#define GINTMSK_EPMISM_Msk               (0x1UL << GINTMSK_EPMISM_Pos)            // 0x00020000 */
+#define GINTMSK_EPMISM                   GINTMSK_EPMISM_Msk                       // Endpoint mismatch interrupt mask                    */
+#define GINTMSK_IEPINT_Pos               (18U)
+#define GINTMSK_IEPINT_Msk               (0x1UL << GINTMSK_IEPINT_Pos)            // 0x00040000 */
+#define GINTMSK_IEPINT                   GINTMSK_IEPINT_Msk                       // IN endpoints interrupt mask                         */
+#define GINTMSK_OEPINT_Pos               (19U)
+#define GINTMSK_OEPINT_Msk               (0x1UL << GINTMSK_OEPINT_Pos)            // 0x00080000 */
+#define GINTMSK_OEPINT                   GINTMSK_OEPINT_Msk                       // OUT endpoints interrupt mask                        */
+#define GINTMSK_IISOIXFRM_Pos            (20U)
+#define GINTMSK_IISOIXFRM_Msk            (0x1UL << GINTMSK_IISOIXFRM_Pos)         // 0x00100000 */
+#define GINTMSK_IISOIXFRM                GINTMSK_IISOIXFRM_Msk                    // Incomplete isochronous IN transfer mask             */
+#define GINTMSK_PXFRM_IISOOXFRM_Pos      (21U)
+#define GINTMSK_PXFRM_IISOOXFRM_Msk      (0x1UL << GINTMSK_PXFRM_IISOOXFRM_Pos)   // 0x00200000 */
+#define GINTMSK_PXFRM_IISOOXFRM          GINTMSK_PXFRM_IISOOXFRM_Msk              // Incomplete periodic transfer mask                   */
+#define GINTMSK_FSUSPM_Pos               (22U)
+#define GINTMSK_FSUSPM_Msk               (0x1UL << GINTMSK_FSUSPM_Pos)            // 0x00400000 */
+#define GINTMSK_FSUSPM                   GINTMSK_FSUSPM_Msk                       // Data fetch suspended mask                           */
+#define GINTMSK_RSTDEM_Pos               (23U)
+#define GINTMSK_RSTDEM_Msk               (0x1UL << GINTMSK_RSTDEM_Pos)            // 0x00800000 */
+#define GINTMSK_RSTDEM                   GINTMSK_RSTDEM_Msk                       // Reset detected interrupt mask                       */
+#define GINTMSK_PRTIM_Pos                (24U)
+#define GINTMSK_PRTIM_Msk                (0x1UL << GINTMSK_PRTIM_Pos)             // 0x01000000 */
+#define GINTMSK_PRTIM                    GINTMSK_PRTIM_Msk                        // Host port interrupt mask                            */
+#define GINTMSK_HCIM_Pos                 (25U)
+#define GINTMSK_HCIM_Msk                 (0x1UL << GINTMSK_HCIM_Pos)              // 0x02000000 */
+#define GINTMSK_HCIM                     GINTMSK_HCIM_Msk                         // Host channels interrupt mask                        */
+#define GINTMSK_PTXFEM_Pos               (26U)
+#define GINTMSK_PTXFEM_Msk               (0x1UL << GINTMSK_PTXFEM_Pos)            // 0x04000000 */
+#define GINTMSK_PTXFEM                   GINTMSK_PTXFEM_Msk                       // Periodic TxFIFO empty mask                          */
+#define GINTMSK_LPMINTM_Pos              (27U)
+#define GINTMSK_LPMINTM_Msk              (0x1UL << GINTMSK_LPMINTM_Pos)           // 0x08000000 */
+#define GINTMSK_LPMINTM                  GINTMSK_LPMINTM_Msk                      // LPM interrupt Mask                                  */
+#define GINTMSK_CIDSCHGM_Pos             (28U)
+#define GINTMSK_CIDSCHGM_Msk             (0x1UL << GINTMSK_CIDSCHGM_Pos)          // 0x10000000 */
+#define GINTMSK_CIDSCHGM                 GINTMSK_CIDSCHGM_Msk                     // Connector ID status change mask                     */
+#define GINTMSK_DISCINT_Pos              (29U)
+#define GINTMSK_DISCINT_Msk              (0x1UL << GINTMSK_DISCINT_Pos)           // 0x20000000 */
+#define GINTMSK_DISCINT                  GINTMSK_DISCINT_Msk                      // Disconnect detected interrupt mask                  */
+#define GINTMSK_SRQIM_Pos                (30U)
+#define GINTMSK_SRQIM_Msk                (0x1UL << GINTMSK_SRQIM_Pos)             // 0x40000000 */
+#define GINTMSK_SRQIM                    GINTMSK_SRQIM_Msk                        // Session request/new session detected interrupt mask */
+#define GINTMSK_WUIM_Pos                 (31U)
+#define GINTMSK_WUIM_Msk                 (0x1UL << GINTMSK_WUIM_Pos)              // 0x80000000 */
+#define GINTMSK_WUIM                     GINTMSK_WUIM_Msk                         // Resume/remote wakeup detected interrupt mask        */
+
+/********************  Bit definition for DAINT register  ********************/
+#define DAINT_IEPINT_Pos                 (0U)
+#define DAINT_IEPINT_Msk                 (0xFFFFUL << DAINT_IEPINT_Pos)           // 0x0000FFFF */
+#define DAINT_IEPINT                     DAINT_IEPINT_Msk                         // IN endpoint interrupt bits  */
+#define DAINT_OEPINT_Pos                 (16U)
+#define DAINT_OEPINT_Msk                 (0xFFFFUL << DAINT_OEPINT_Pos)           // 0xFFFF0000 */
+#define DAINT_OEPINT                     DAINT_OEPINT_Msk                         // OUT endpoint interrupt bits */
+
+/********************  Bit definition for HAINTMSK register  ********************/
+#define HAINTMSK_HAINTM_Pos              (0U)
+#define HAINTMSK_HAINTM_Msk              (0xFFFFUL << HAINTMSK_HAINTM_Pos)        // 0x0000FFFF */
+#define HAINTMSK_HAINTM                  HAINTMSK_HAINTM_Msk                      // Channel interrupt mask */
+
+/********************  Bit definition for GRXSTSP register  ********************/
+#define GRXSTSP_EPNUM_Pos                (0U)
+#define GRXSTSP_EPNUM_Msk                (0xFUL << GRXSTSP_EPNUM_Pos)             // 0x0000000F */
+#define GRXSTSP_EPNUM                    GRXSTSP_EPNUM_Msk                        // IN EP interrupt mask bits  */
+#define GRXSTSP_BCNT_Pos                 (4U)
+#define GRXSTSP_BCNT_Msk                 (0x7FFUL << GRXSTSP_BCNT_Pos)            // 0x00007FF0 */
+#define GRXSTSP_BCNT                     GRXSTSP_BCNT_Msk                         // OUT EP interrupt mask bits */
+#define GRXSTSP_DPID_Pos                 (15U)
+#define GRXSTSP_DPID_Msk                 (0x3UL << GRXSTSP_DPID_Pos)              // 0x00018000 */
+#define GRXSTSP_DPID                     GRXSTSP_DPID_Msk                         // OUT EP interrupt mask bits */
+#define GRXSTSP_PKTSTS_Pos               (17U)
+#define GRXSTSP_PKTSTS_Msk               (0xFUL << GRXSTSP_PKTSTS_Pos)            // 0x001E0000 */
+#define GRXSTSP_PKTSTS                   GRXSTSP_PKTSTS_Msk                       // OUT EP interrupt mask bits */
+
+#define GRXSTS_PKTSTS_GLOBALOUTNAK       1
+#define GRXSTS_PKTSTS_OUTRX              2
+#define GRXSTS_PKTSTS_HCHIN              2
+#define GRXSTS_PKTSTS_OUTDONE            3
+#define GRXSTS_PKTSTS_HCHIN_XFER_COMP    3
+#define GRXSTS_PKTSTS_SETUPDONE          4
+#define GRXSTS_PKTSTS_DATATOGGLEERR      5
+#define GRXSTS_PKTSTS_SETUPRX            6
+#define GRXSTS_PKTSTS_HCHHALTED          7
+
+
+/********************  Bit definition for DAINTMSK register  ********************/
+#define DAINTMSK_IEPM_Pos                (0U)
+#define DAINTMSK_IEPM_Msk                (0xFFFFUL << DAINTMSK_IEPM_Pos)          // 0x0000FFFF */
+#define DAINTMSK_IEPM                    DAINTMSK_IEPM_Msk                        // IN EP interrupt mask bits */
+#define DAINTMSK_OEPM_Pos                (16U)
+#define DAINTMSK_OEPM_Msk                (0xFFFFUL << DAINTMSK_OEPM_Pos)          // 0xFFFF0000 */
+#define DAINTMSK_OEPM                    DAINTMSK_OEPM_Msk                        // OUT EP interrupt mask bits */
+
+#if 0
+/********************  Bit definition for OTG register  ********************/
+#define CHNUM_Pos                        (0U)
+#define CHNUM_Msk                        (0xFUL << CHNUM_Pos)                     // 0x0000000F */
+#define CHNUM                            CHNUM_Msk                                // Channel number */
+#define CHNUM_0                          (0x1UL << CHNUM_Pos)                     // 0x00000001 */
+#define CHNUM_1                          (0x2UL << CHNUM_Pos)                     // 0x00000002 */
+#define CHNUM_2                          (0x4UL << CHNUM_Pos)                     // 0x00000004 */
+#define CHNUM_3                          (0x8UL << CHNUM_Pos)                     // 0x00000008 */
+#define BCNT_Pos                         (4U)
+#define BCNT_Msk                         (0x7FFUL << BCNT_Pos)                    // 0x00007FF0 */
+#define BCNT                             BCNT_Msk                                 // Byte count */
+
+#define DPID_Pos                         (15U)
+#define DPID_Msk                         (0x3UL << DPID_Pos)                      // 0x00018000 */
+#define DPID                             DPID_Msk                                 // Data PID */
+#define DPID_0                           (0x1UL << DPID_Pos)                      // 0x00008000 */
+#define DPID_1                           (0x2UL << DPID_Pos)                      // 0x00010000 */
+
+#define PKTSTS_Pos                       (17U)
+#define PKTSTS_Msk                       (0xFUL << PKTSTS_Pos)                    // 0x001E0000 */
+#define PKTSTS                           PKTSTS_Msk                               // Packet status */
+#define PKTSTS_0                         (0x1UL << PKTSTS_Pos)                    // 0x00020000 */
+#define PKTSTS_1                         (0x2UL << PKTSTS_Pos)                    // 0x00040000 */
+#define PKTSTS_2                         (0x4UL << PKTSTS_Pos)                    // 0x00080000 */
+#define PKTSTS_3                         (0x8UL << PKTSTS_Pos)                    // 0x00100000 */
+
+#define EPNUM_Pos                        (0U)
+#define EPNUM_Msk                        (0xFUL << EPNUM_Pos)                     // 0x0000000F */
+#define EPNUM                            EPNUM_Msk                                // Endpoint number */
+#define EPNUM_0                          (0x1UL << EPNUM_Pos)                     // 0x00000001 */
+#define EPNUM_1                          (0x2UL << EPNUM_Pos)                     // 0x00000002 */
+#define EPNUM_2                          (0x4UL << EPNUM_Pos)                     // 0x00000004 */
+#define EPNUM_3                          (0x8UL << EPNUM_Pos)                     // 0x00000008 */
+
+#define FRMNUM_Pos                       (21U)
+#define FRMNUM_Msk                       (0xFUL << FRMNUM_Pos)                    // 0x01E00000 */
+#define FRMNUM                           FRMNUM_Msk                               // Frame number */
+#define FRMNUM_0                         (0x1UL << FRMNUM_Pos)                    // 0x00200000 */
+#define FRMNUM_1                         (0x2UL << FRMNUM_Pos)                    // 0x00400000 */
+#define FRMNUM_2                         (0x4UL << FRMNUM_Pos)                    // 0x00800000 */
+#define FRMNUM_3                         (0x8UL << FRMNUM_Pos)                    // 0x01000000 */
+#endif
+
+/********************  Bit definition for GRXFSIZ register  ********************/
+#define GRXFSIZ_RXFD_Pos                 (0U)
+#define GRXFSIZ_RXFD_Msk                 (0xFFFFUL << GRXFSIZ_RXFD_Pos)           // 0x0000FFFF */
+#define GRXFSIZ_RXFD                     GRXFSIZ_RXFD_Msk                         // RxFIFO depth */
+
+/********************  Bit definition for DVBUSDIS register  ********************/
+#define DVBUSDIS_VBUSDT_Pos              (0U)
+#define DVBUSDIS_VBUSDT_Msk              (0xFFFFUL << DVBUSDIS_VBUSDT_Pos)        // 0x0000FFFF */
+#define DVBUSDIS_VBUSDT                  DVBUSDIS_VBUSDT_Msk                      // Device VBUS discharge time */
+
+/********************  Bit definition for OTG register  ********************/
+#define GNPTXFSIZ_NPTXFSA_Pos            (0U)
+#define GNPTXFSIZ_NPTXFSA_Msk            (0xFFFFUL << 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                 GNPTXFSIZ_NPTXFD_Msk                     // Nonperiodic TxFIFO depth               */
+#define DIEPTXF0_TX0FSA_Pos              (0U)
+#define DIEPTXF0_TX0FSA_Msk              (0xFFFFUL << 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                   DIEPTXF0_TX0FD_Msk                       // Endpoint 0 TxFIFO depth                */
+
+/********************  Bit definition for DVBUSPULSE register  ********************/
+#define DVBUSPULSE_DVBUSP_Pos            (0U)
+#define DVBUSPULSE_DVBUSP_Msk            (0xFFFUL << DVBUSPULSE_DVBUSP_Pos)       // 0x00000FFF */
+#define DVBUSPULSE_DVBUSP                DVBUSPULSE_DVBUSP_Msk                    // Device VBUS pulsing time */
+
+/********************  Bit definition for GNPTXSTS register  ********************/
+#define GNPTXSTS_NPTXFSAV_Pos            (0U)
+#define GNPTXSTS_NPTXFSAV_Msk            (0xFFFFUL << GNPTXSTS_NPTXFSAV_Pos)      // 0x0000FFFF */
+#define GNPTXSTS_NPTXFSAV                GNPTXSTS_NPTXFSAV_Msk                    // Nonperiodic TxFIFO space available */
+
+#define GNPTXSTS_NPTQXSAV_Pos            (16U)
+#define GNPTXSTS_NPTQXSAV_Msk            (0xFFUL << GNPTXSTS_NPTQXSAV_Pos)        // 0x00FF0000 */
+#define GNPTXSTS_NPTQXSAV                GNPTXSTS_NPTQXSAV_Msk                    // Nonperiodic transmit request queue space available */
+#define GNPTXSTS_NPTQXSAV_0              (0x01UL << GNPTXSTS_NPTQXSAV_Pos)        // 0x00010000 */
+#define GNPTXSTS_NPTQXSAV_1              (0x02UL << GNPTXSTS_NPTQXSAV_Pos)        // 0x00020000 */
+#define GNPTXSTS_NPTQXSAV_2              (0x04UL << GNPTXSTS_NPTQXSAV_Pos)        // 0x00040000 */
+#define GNPTXSTS_NPTQXSAV_3              (0x08UL << GNPTXSTS_NPTQXSAV_Pos)        // 0x00080000 */
+#define GNPTXSTS_NPTQXSAV_4              (0x10UL << GNPTXSTS_NPTQXSAV_Pos)        // 0x00100000 */
+#define GNPTXSTS_NPTQXSAV_5              (0x20UL << GNPTXSTS_NPTQXSAV_Pos)        // 0x00200000 */
+#define GNPTXSTS_NPTQXSAV_6              (0x40UL << GNPTXSTS_NPTQXSAV_Pos)        // 0x00400000 */
+#define GNPTXSTS_NPTQXSAV_7              (0x80UL << GNPTXSTS_NPTQXSAV_Pos)        // 0x00800000 */
+
+#define GNPTXSTS_NPTXQTOP_Pos            (24U)
+#define GNPTXSTS_NPTXQTOP_Msk            (0x7FUL << GNPTXSTS_NPTXQTOP_Pos)        // 0x7F000000 */
+#define GNPTXSTS_NPTXQTOP                GNPTXSTS_NPTXQTOP_Msk                    // Top of the nonperiodic transmit request queue */
+#define GNPTXSTS_NPTXQTOP_0              (0x01UL << GNPTXSTS_NPTXQTOP_Pos)        // 0x01000000 */
+#define GNPTXSTS_NPTXQTOP_1              (0x02UL << GNPTXSTS_NPTXQTOP_Pos)        // 0x02000000 */
+#define GNPTXSTS_NPTXQTOP_2              (0x04UL << GNPTXSTS_NPTXQTOP_Pos)        // 0x04000000 */
+#define GNPTXSTS_NPTXQTOP_3              (0x08UL << GNPTXSTS_NPTXQTOP_Pos)        // 0x08000000 */
+#define GNPTXSTS_NPTXQTOP_4              (0x10UL << GNPTXSTS_NPTXQTOP_Pos)        // 0x10000000 */
+#define GNPTXSTS_NPTXQTOP_5              (0x20UL << GNPTXSTS_NPTXQTOP_Pos)        // 0x20000000 */
+#define GNPTXSTS_NPTXQTOP_6              (0x40UL << GNPTXSTS_NPTXQTOP_Pos)        // 0x40000000 */
+
+/********************  Bit definition for DTHRCTL register  ********************/
+#define DTHRCTL_NONISOTHREN_Pos          (0U)
+#define DTHRCTL_NONISOTHREN_Msk          (0x1UL << DTHRCTL_NONISOTHREN_Pos)       // 0x00000001 */
+#define DTHRCTL_NONISOTHREN              DTHRCTL_NONISOTHREN_Msk                  // Nonisochronous IN endpoints threshold enable */
+#define DTHRCTL_ISOTHREN_Pos             (1U)
+#define DTHRCTL_ISOTHREN_Msk             (0x1UL << DTHRCTL_ISOTHREN_Pos)          // 0x00000002 */
+#define DTHRCTL_ISOTHREN                 DTHRCTL_ISOTHREN_Msk                     // ISO IN endpoint threshold enable */
+
+#define DTHRCTL_TXTHRLEN_Pos             (2U)
+#define DTHRCTL_TXTHRLEN_Msk             (0x1FFUL << DTHRCTL_TXTHRLEN_Pos)        // 0x000007FC */
+#define DTHRCTL_TXTHRLEN                 DTHRCTL_TXTHRLEN_Msk                     // Transmit threshold length */
+#define DTHRCTL_TXTHRLEN_0               (0x001UL << DTHRCTL_TXTHRLEN_Pos)        // 0x00000004 */
+#define DTHRCTL_TXTHRLEN_1               (0x002UL << DTHRCTL_TXTHRLEN_Pos)        // 0x00000008 */
+#define DTHRCTL_TXTHRLEN_2               (0x004UL << DTHRCTL_TXTHRLEN_Pos)        // 0x00000010 */
+#define DTHRCTL_TXTHRLEN_3               (0x008UL << DTHRCTL_TXTHRLEN_Pos)        // 0x00000020 */
+#define DTHRCTL_TXTHRLEN_4               (0x010UL << DTHRCTL_TXTHRLEN_Pos)        // 0x00000040 */
+#define DTHRCTL_TXTHRLEN_5               (0x020UL << DTHRCTL_TXTHRLEN_Pos)        // 0x00000080 */
+#define DTHRCTL_TXTHRLEN_6               (0x040UL << DTHRCTL_TXTHRLEN_Pos)        // 0x00000100 */
+#define DTHRCTL_TXTHRLEN_7               (0x080UL << DTHRCTL_TXTHRLEN_Pos)        // 0x00000200 */
+#define DTHRCTL_TXTHRLEN_8               (0x100UL << DTHRCTL_TXTHRLEN_Pos)        // 0x00000400 */
+#define DTHRCTL_RXTHREN_Pos              (16U)
+#define DTHRCTL_RXTHREN_Msk              (0x1UL << DTHRCTL_RXTHREN_Pos)           // 0x00010000 */
+#define DTHRCTL_RXTHREN                  DTHRCTL_RXTHREN_Msk                      // Receive threshold enable */
+
+#define DTHRCTL_RXTHRLEN_Pos             (17U)
+#define DTHRCTL_RXTHRLEN_Msk             (0x1FFUL << DTHRCTL_RXTHRLEN_Pos)        // 0x03FE0000 */
+#define DTHRCTL_RXTHRLEN                 DTHRCTL_RXTHRLEN_Msk                     // Receive threshold length */
+#define DTHRCTL_RXTHRLEN_0               (0x001UL << DTHRCTL_RXTHRLEN_Pos)        // 0x00020000 */
+#define DTHRCTL_RXTHRLEN_1               (0x002UL << DTHRCTL_RXTHRLEN_Pos)        // 0x00040000 */
+#define DTHRCTL_RXTHRLEN_2               (0x004UL << DTHRCTL_RXTHRLEN_Pos)        // 0x00080000 */
+#define DTHRCTL_RXTHRLEN_3               (0x008UL << DTHRCTL_RXTHRLEN_Pos)        // 0x00100000 */
+#define DTHRCTL_RXTHRLEN_4               (0x010UL << DTHRCTL_RXTHRLEN_Pos)        // 0x00200000 */
+#define DTHRCTL_RXTHRLEN_5               (0x020UL << DTHRCTL_RXTHRLEN_Pos)        // 0x00400000 */
+#define DTHRCTL_RXTHRLEN_6               (0x040UL << DTHRCTL_RXTHRLEN_Pos)        // 0x00800000 */
+#define DTHRCTL_RXTHRLEN_7               (0x080UL << DTHRCTL_RXTHRLEN_Pos)        // 0x01000000 */
+#define DTHRCTL_RXTHRLEN_8               (0x100UL << DTHRCTL_RXTHRLEN_Pos)        // 0x02000000 */
+#define DTHRCTL_ARPEN_Pos                (27U)
+#define DTHRCTL_ARPEN_Msk                (0x1UL << DTHRCTL_ARPEN_Pos)             // 0x08000000 */
+#define DTHRCTL_ARPEN                    DTHRCTL_ARPEN_Msk                        // Arbiter parking enable */
+
+/********************  Bit definition for DIEPEMPMSK register  ********************/
+#define DIEPEMPMSK_INEPTXFEM_Pos         (0U)
+#define DIEPEMPMSK_INEPTXFEM_Msk         (0xFFFFUL << DIEPEMPMSK_INEPTXFEM_Pos)   // 0x0000FFFF */
+#define DIEPEMPMSK_INEPTXFEM             DIEPEMPMSK_INEPTXFEM_Msk                 // IN EP Tx FIFO empty interrupt mask bits */
+
+/********************  Bit definition for DEACHINT register  ********************/
+#define DEACHINT_IEP1INT_Pos             (1U)
+#define DEACHINT_IEP1INT_Msk             (0x1UL << DEACHINT_IEP1INT_Pos)          // 0x00000002 */
+#define DEACHINT_IEP1INT                 DEACHINT_IEP1INT_Msk                     // IN endpoint 1interrupt bit   */
+#define DEACHINT_OEP1INT_Pos             (17U)
+#define DEACHINT_OEP1INT_Msk             (0x1UL << DEACHINT_OEP1INT_Pos)          // 0x00020000 */
+#define DEACHINT_OEP1INT                 DEACHINT_OEP1INT_Msk                     // OUT endpoint 1 interrupt bit */
+
+/********************  Bit definition for GCCFG register  ********************/
+#define STM32_GCCFG_DCDET_Pos            (0U)
+#define STM32_GCCFG_DCDET_Msk            (0x1UL << STM32_GCCFG_DCDET_Pos)         // 0x00000001 */
+#define STM32_GCCFG_DCDET                STM32_GCCFG_DCDET_Msk                    // Data contact detection (DCD) status */
+#define STM32_GCCFG_PDET_Pos             (1U)
+#define STM32_GCCFG_PDET_Msk             (0x1UL << STM32_GCCFG_PDET_Pos)          // 0x00000002 */
+#define STM32_GCCFG_PDET                 STM32_GCCFG_PDET_Msk                     // Primary detection (PD) status */
+#define STM32_GCCFG_SDET_Pos             (2U)
+#define STM32_GCCFG_SDET_Msk             (0x1UL << STM32_GCCFG_SDET_Pos)          // 0x00000004 */
+#define STM32_GCCFG_SDET                 STM32_GCCFG_SDET_Msk                     // Secondary detection (SD) status */
+#define STM32_GCCFG_PS2DET_Pos           (3U)
+#define STM32_GCCFG_PS2DET_Msk           (0x1UL << STM32_GCCFG_PS2DET_Pos)        // 0x00000008 */
+#define STM32_GCCFG_PS2DET               STM32_GCCFG_PS2DET_Msk                   // DM pull-up detection status */
+#define STM32_GCCFG_PWRDWN_Pos           (16U)
+#define STM32_GCCFG_PWRDWN_Msk           (0x1UL << STM32_GCCFG_PWRDWN_Pos)        // 0x00010000 */
+#define STM32_GCCFG_PWRDWN               STM32_GCCFG_PWRDWN_Msk                   // Power down */
+#define STM32_GCCFG_BCDEN_Pos            (17U)
+#define STM32_GCCFG_BCDEN_Msk            (0x1UL << STM32_GCCFG_BCDEN_Pos)         // 0x00020000 */
+#define STM32_GCCFG_BCDEN                STM32_GCCFG_BCDEN_Msk                    // Battery charging detector (BCD) enable */
+#define STM32_GCCFG_DCDEN_Pos            (18U)
+#define STM32_GCCFG_DCDEN_Msk            (0x1UL << STM32_GCCFG_DCDEN_Pos)         // 0x00040000 */
+#define STM32_GCCFG_DCDEN                STM32_GCCFG_DCDEN_Msk                    // Data contact detection (DCD) mode enable*/
+#define STM32_GCCFG_PDEN_Pos             (19U)
+#define STM32_GCCFG_PDEN_Msk             (0x1UL << STM32_GCCFG_PDEN_Pos)          // 0x00080000 */
+#define STM32_GCCFG_PDEN                 STM32_GCCFG_PDEN_Msk                     // Primary detection (PD) mode enable*/
+#define STM32_GCCFG_SDEN_Pos             (20U)
+#define STM32_GCCFG_SDEN_Msk             (0x1UL << STM32_GCCFG_SDEN_Pos)          // 0x00100000 */
+#define STM32_GCCFG_SDEN                 STM32_GCCFG_SDEN_Msk                     // Secondary detection (SD) mode enable */
+#define STM32_GCCFG_VBDEN_Pos            (21U)
+#define STM32_GCCFG_VBDEN_Msk            (0x1UL << STM32_GCCFG_VBDEN_Pos)         // 0x00200000 */
+#define STM32_GCCFG_VBDEN                STM32_GCCFG_VBDEN_Msk                    // VBUS mode enable */
+#define STM32_GCCFG_OTGIDEN_Pos          (22U)
+#define STM32_GCCFG_OTGIDEN_Msk          (0x1UL << STM32_GCCFG_OTGIDEN_Pos)       // 0x00400000 */
+#define STM32_GCCFG_OTGIDEN              STM32_GCCFG_OTGIDEN_Msk                  // OTG Id enable */
+#define STM32_GCCFG_PHYHSEN_Pos          (23U)
+#define STM32_GCCFG_PHYHSEN_Msk          (0x1UL << STM32_GCCFG_PHYHSEN_Pos)       // 0x00800000 */
+#define STM32_GCCFG_PHYHSEN              STM32_GCCFG_PHYHSEN_Msk                  // HS PHY enable */
+
+/********************  Bit definition for DEACHINTMSK register  ********************/
+#define DEACHINTMSK_IEP1INTM_Pos         (1U)
+#define DEACHINTMSK_IEP1INTM_Msk         (0x1UL << DEACHINTMSK_IEP1INTM_Pos)      // 0x00000002 */
+#define DEACHINTMSK_IEP1INTM             DEACHINTMSK_IEP1INTM_Msk                 // IN Endpoint 1 interrupt mask bit  */
+#define DEACHINTMSK_OEP1INTM_Pos         (17U)
+#define DEACHINTMSK_OEP1INTM_Msk         (0x1UL << DEACHINTMSK_OEP1INTM_Pos)      // 0x00020000 */
+#define DEACHINTMSK_OEP1INTM             DEACHINTMSK_OEP1INTM_Msk                 // OUT Endpoint 1 interrupt mask bit */
+
+/********************  Bit definition for CID register  ********************/
+#define CID_PRODUCT_ID_Pos               (0U)
+#define CID_PRODUCT_ID_Msk               (0xFFFFFFFFUL << CID_PRODUCT_ID_Pos)     // 0xFFFFFFFF */
+#define CID_PRODUCT_ID                   CID_PRODUCT_ID_Msk                       // Product ID field */
+
+/********************  Bit definition for GLPMCFG register  ********************/
+#define GLPMCFG_LPMEN_Pos                (0U)
+#define GLPMCFG_LPMEN_Msk                (0x1UL << GLPMCFG_LPMEN_Pos)             // 0x00000001 */
+#define GLPMCFG_LPMEN                    GLPMCFG_LPMEN_Msk                        // LPM support enable                                     */
+#define GLPMCFG_LPMACK_Pos               (1U)
+#define GLPMCFG_LPMACK_Msk               (0x1UL << GLPMCFG_LPMACK_Pos)            // 0x00000002 */
+#define GLPMCFG_LPMACK                   GLPMCFG_LPMACK_Msk                       // LPM Token acknowledge enable                           */
+#define GLPMCFG_BESL_Pos                 (2U)
+#define GLPMCFG_BESL_Msk                 (0xFUL << GLPMCFG_BESL_Pos)              // 0x0000003C */
+#define GLPMCFG_BESL                     GLPMCFG_BESL_Msk                         // BESL value received with last ACKed LPM Token          */
+#define GLPMCFG_REMWAKE_Pos              (6U)
+#define GLPMCFG_REMWAKE_Msk              (0x1UL << GLPMCFG_REMWAKE_Pos)           // 0x00000040 */
+#define GLPMCFG_REMWAKE                  GLPMCFG_REMWAKE_Msk                      // bRemoteWake value received with last ACKed LPM Token   */
+#define GLPMCFG_L1SSEN_Pos               (7U)
+#define GLPMCFG_L1SSEN_Msk               (0x1UL << GLPMCFG_L1SSEN_Pos)            // 0x00000080 */
+#define GLPMCFG_L1SSEN                   GLPMCFG_L1SSEN_Msk                       // L1 shallow sleep enable                                */
+#define GLPMCFG_BESLTHRS_Pos             (8U)
+#define GLPMCFG_BESLTHRS_Msk             (0xFUL << GLPMCFG_BESLTHRS_Pos)          // 0x00000F00 */
+#define GLPMCFG_BESLTHRS                 GLPMCFG_BESLTHRS_Msk                     // BESL threshold                                         */
+#define GLPMCFG_L1DSEN_Pos               (12U)
+#define GLPMCFG_L1DSEN_Msk               (0x1UL << GLPMCFG_L1DSEN_Pos)            // 0x00001000 */
+#define GLPMCFG_L1DSEN                   GLPMCFG_L1DSEN_Msk                       // L1 deep sleep enable                                   */
+#define GLPMCFG_LPMRSP_Pos               (13U)
+#define GLPMCFG_LPMRSP_Msk               (0x3UL << GLPMCFG_LPMRSP_Pos)            // 0x00006000 */
+#define GLPMCFG_LPMRSP                   GLPMCFG_LPMRSP_Msk                       // LPM response                                           */
+#define GLPMCFG_SLPSTS_Pos               (15U)
+#define GLPMCFG_SLPSTS_Msk               (0x1UL << GLPMCFG_SLPSTS_Pos)            // 0x00008000 */
+#define GLPMCFG_SLPSTS                   GLPMCFG_SLPSTS_Msk                       // Port sleep status                                      */
+#define GLPMCFG_L1RSMOK_Pos              (16U)
+#define GLPMCFG_L1RSMOK_Msk              (0x1UL << GLPMCFG_L1RSMOK_Pos)           // 0x00010000 */
+#define GLPMCFG_L1RSMOK                  GLPMCFG_L1RSMOK_Msk                      // Sleep State Resume OK                                  */
+#define GLPMCFG_LPMCHIDX_Pos             (17U)
+#define GLPMCFG_LPMCHIDX_Msk             (0xFUL << GLPMCFG_LPMCHIDX_Pos)          // 0x001E0000 */
+#define GLPMCFG_LPMCHIDX                 GLPMCFG_LPMCHIDX_Msk                     // LPM Channel Index                                      */
+#define GLPMCFG_LPMRCNT_Pos              (21U)
+#define GLPMCFG_LPMRCNT_Msk              (0x7UL << GLPMCFG_LPMRCNT_Pos)           // 0x00E00000 */
+#define GLPMCFG_LPMRCNT                  GLPMCFG_LPMRCNT_Msk                      // LPM retry count                                        */
+#define GLPMCFG_SNDLPM_Pos               (24U)
+#define GLPMCFG_SNDLPM_Msk               (0x1UL << GLPMCFG_SNDLPM_Pos)            // 0x01000000 */
+#define GLPMCFG_SNDLPM                   GLPMCFG_SNDLPM_Msk                       // Send LPM transaction                                   */
+#define GLPMCFG_LPMRCNTSTS_Pos           (25U)
+#define GLPMCFG_LPMRCNTSTS_Msk           (0x7UL << GLPMCFG_LPMRCNTSTS_Pos)        // 0x0E000000 */
+#define GLPMCFG_LPMRCNTSTS               GLPMCFG_LPMRCNTSTS_Msk                   // LPM retry count status                                 */
+#define GLPMCFG_ENBESL_Pos               (28U)
+#define GLPMCFG_ENBESL_Msk               (0x1UL << GLPMCFG_ENBESL_Pos)            // 0x10000000 */
+#define GLPMCFG_ENBESL                   GLPMCFG_ENBESL_Msk                       // Enable best effort service latency                     */
+
+/********************  Bit definition for DIEPEACHMSK1 register  ********************/
+#define DIEPEACHMSK1_XFRCM_Pos           (0U)
+#define DIEPEACHMSK1_XFRCM_Msk           (0x1UL << DIEPEACHMSK1_XFRCM_Pos)        // 0x00000001 */
+#define DIEPEACHMSK1_XFRCM               DIEPEACHMSK1_XFRCM_Msk                   // Transfer completed interrupt mask                 */
+#define DIEPEACHMSK1_EPDM_Pos            (1U)
+#define DIEPEACHMSK1_EPDM_Msk            (0x1UL << DIEPEACHMSK1_EPDM_Pos)         // 0x00000002 */
+#define DIEPEACHMSK1_EPDM                DIEPEACHMSK1_EPDM_Msk                    // Endpoint disabled interrupt mask                  */
+#define DIEPEACHMSK1_TOM_Pos             (3U)
+#define DIEPEACHMSK1_TOM_Msk             (0x1UL << DIEPEACHMSK1_TOM_Pos)          // 0x00000008 */
+#define DIEPEACHMSK1_TOM                 DIEPEACHMSK1_TOM_Msk                     // Timeout condition mask (nonisochronous endpoints) */
+#define DIEPEACHMSK1_ITTXFEMSK_Pos       (4U)
+#define DIEPEACHMSK1_ITTXFEMSK_Msk       (0x1UL << DIEPEACHMSK1_ITTXFEMSK_Pos)    // 0x00000010 */
+#define DIEPEACHMSK1_ITTXFEMSK           DIEPEACHMSK1_ITTXFEMSK_Msk               // IN token received when TxFIFO empty mask          */
+#define DIEPEACHMSK1_INEPNMM_Pos         (5U)
+#define DIEPEACHMSK1_INEPNMM_Msk         (0x1UL << DIEPEACHMSK1_INEPNMM_Pos)      // 0x00000020 */
+#define DIEPEACHMSK1_INEPNMM             DIEPEACHMSK1_INEPNMM_Msk                 // IN token received with EP mismatch mask           */
+#define DIEPEACHMSK1_INEPNEM_Pos         (6U)
+#define DIEPEACHMSK1_INEPNEM_Msk         (0x1UL << DIEPEACHMSK1_INEPNEM_Pos)      // 0x00000040 */
+#define DIEPEACHMSK1_INEPNEM             DIEPEACHMSK1_INEPNEM_Msk                 // IN endpoint NAK effective mask                    */
+#define DIEPEACHMSK1_TXFURM_Pos          (8U)
+#define DIEPEACHMSK1_TXFURM_Msk          (0x1UL << DIEPEACHMSK1_TXFURM_Pos)       // 0x00000100 */
+#define DIEPEACHMSK1_TXFURM              DIEPEACHMSK1_TXFURM_Msk                  // FIFO underrun mask                                */
+#define DIEPEACHMSK1_BIM_Pos             (9U)
+#define DIEPEACHMSK1_BIM_Msk             (0x1UL << DIEPEACHMSK1_BIM_Pos)          // 0x00000200 */
+#define DIEPEACHMSK1_BIM                 DIEPEACHMSK1_BIM_Msk                     // BNA interrupt mask                                */
+#define DIEPEACHMSK1_NAKM_Pos            (13U)
+#define DIEPEACHMSK1_NAKM_Msk            (0x1UL << DIEPEACHMSK1_NAKM_Pos)         // 0x00002000 */
+#define DIEPEACHMSK1_NAKM                DIEPEACHMSK1_NAKM_Msk                    // NAK interrupt mask                                */
+
+/********************  Bit definition for HPRT register  ********************/
+#define HPRT_PCSTS_Pos                   (0U)
+#define HPRT_PCSTS_Msk                   (0x1UL << HPRT_PCSTS_Pos)                // 0x00000001 */
+#define HPRT_PCSTS                       HPRT_PCSTS_Msk                           // Port connect status        */
+#define HPRT_PCDET_Pos                   (1U)
+#define HPRT_PCDET_Msk                   (0x1UL << HPRT_PCDET_Pos)                // 0x00000002 */
+#define HPRT_PCDET                       HPRT_PCDET_Msk                           // Port connect detected      */
+#define HPRT_PENA_Pos                    (2U)
+#define HPRT_PENA_Msk                    (0x1UL << HPRT_PENA_Pos)                 // 0x00000004 */
+#define HPRT_PENA                        HPRT_PENA_Msk                            // Port enable                */
+#define HPRT_PENCHNG_Pos                 (3U)
+#define HPRT_PENCHNG_Msk                 (0x1UL << HPRT_PENCHNG_Pos)              // 0x00000008 */
+#define HPRT_PENCHNG                     HPRT_PENCHNG_Msk                         // Port enable/disable change */
+#define HPRT_POCA_Pos                    (4U)
+#define HPRT_POCA_Msk                    (0x1UL << HPRT_POCA_Pos)                 // 0x00000010 */
+#define HPRT_POCA                        HPRT_POCA_Msk                            // Port overcurrent active    */
+#define HPRT_POCCHNG_Pos                 (5U)
+#define HPRT_POCCHNG_Msk                 (0x1UL << HPRT_POCCHNG_Pos)              // 0x00000020 */
+#define HPRT_POCCHNG                     HPRT_POCCHNG_Msk                         // Port overcurrent change    */
+#define HPRT_PRES_Pos                    (6U)
+#define HPRT_PRES_Msk                    (0x1UL << HPRT_PRES_Pos)                 // 0x00000040 */
+#define HPRT_PRES                        HPRT_PRES_Msk                            // Port resume                */
+#define HPRT_PSUSP_Pos                   (7U)
+#define HPRT_PSUSP_Msk                   (0x1UL << HPRT_PSUSP_Pos)                // 0x00000080 */
+#define HPRT_PSUSP                       HPRT_PSUSP_Msk                           // Port suspend               */
+#define HPRT_PRST_Pos                    (8U)
+#define HPRT_PRST_Msk                    (0x1UL << HPRT_PRST_Pos)                 // 0x00000100 */
+#define HPRT_PRST                        HPRT_PRST_Msk                            // Port reset                 */
+
+#define HPRT_PLSTS_Pos                   (10U)
+#define HPRT_PLSTS_Msk                   (0x3UL << HPRT_PLSTS_Pos)                // 0x00000C00 */
+#define HPRT_PLSTS                       HPRT_PLSTS_Msk                           // Port line status           */
+#define HPRT_PLSTS_0                     (0x1UL << HPRT_PLSTS_Pos)                // 0x00000400 */
+#define HPRT_PLSTS_1                     (0x2UL << HPRT_PLSTS_Pos)                // 0x00000800 */
+#define HPRT_PPWR_Pos                    (12U)
+#define HPRT_PPWR_Msk                    (0x1UL << HPRT_PPWR_Pos)                 // 0x00001000 */
+#define HPRT_PPWR                        HPRT_PPWR_Msk                            // Port power                 */
+
+#define HPRT_PTCTL_Pos                   (13U)
+#define HPRT_PTCTL_Msk                   (0xFUL << HPRT_PTCTL_Pos)                // 0x0001E000 */
+#define HPRT_PTCTL                       HPRT_PTCTL_Msk                           // Port test control          */
+#define HPRT_PTCTL_0                     (0x1UL << HPRT_PTCTL_Pos)                // 0x00002000 */
+#define HPRT_PTCTL_1                     (0x2UL << HPRT_PTCTL_Pos)                // 0x00004000 */
+#define HPRT_PTCTL_2                     (0x4UL << HPRT_PTCTL_Pos)                // 0x00008000 */
+#define HPRT_PTCTL_3                     (0x8UL << HPRT_PTCTL_Pos)                // 0x00010000 */
+
+#define HPRT_PSPD_Pos                    (17U)
+#define HPRT_PSPD_Msk                    (0x3UL << HPRT_PSPD_Pos)                 // 0x00060000 */
+#define HPRT_PSPD                        HPRT_PSPD_Msk                            // Port speed                 */
+#define HPRT_PSPD_0                      (0x1UL << HPRT_PSPD_Pos)                 // 0x00020000 */
+#define HPRT_PSPD_1                      (0x2UL << HPRT_PSPD_Pos)                 // 0x00040000 */
+
+/********************  Bit definition for DOEPEACHMSK1 register  ********************/
+#define DOEPEACHMSK1_XFRCM_Pos           (0U)
+#define DOEPEACHMSK1_XFRCM_Msk           (0x1UL << DOEPEACHMSK1_XFRCM_Pos)        // 0x00000001 */
+#define DOEPEACHMSK1_XFRCM               DOEPEACHMSK1_XFRCM_Msk                   // Transfer completed interrupt mask         */
+#define DOEPEACHMSK1_EPDM_Pos            (1U)
+#define DOEPEACHMSK1_EPDM_Msk            (0x1UL << DOEPEACHMSK1_EPDM_Pos)         // 0x00000002 */
+#define DOEPEACHMSK1_EPDM                DOEPEACHMSK1_EPDM_Msk                    // Endpoint disabled interrupt mask          */
+#define DOEPEACHMSK1_TOM_Pos             (3U)
+#define DOEPEACHMSK1_TOM_Msk             (0x1UL << DOEPEACHMSK1_TOM_Pos)          // 0x00000008 */
+#define DOEPEACHMSK1_TOM                 DOEPEACHMSK1_TOM_Msk                     // Timeout condition mask                    */
+#define DOEPEACHMSK1_ITTXFEMSK_Pos       (4U)
+#define DOEPEACHMSK1_ITTXFEMSK_Msk       (0x1UL << DOEPEACHMSK1_ITTXFEMSK_Pos)    // 0x00000010 */
+#define DOEPEACHMSK1_ITTXFEMSK           DOEPEACHMSK1_ITTXFEMSK_Msk               // IN token received when TxFIFO empty mask  */
+#define DOEPEACHMSK1_INEPNMM_Pos         (5U)
+#define DOEPEACHMSK1_INEPNMM_Msk         (0x1UL << DOEPEACHMSK1_INEPNMM_Pos)      // 0x00000020 */
+#define DOEPEACHMSK1_INEPNMM             DOEPEACHMSK1_INEPNMM_Msk                 // IN token received with EP mismatch mask   */
+#define DOEPEACHMSK1_INEPNEM_Pos         (6U)
+#define DOEPEACHMSK1_INEPNEM_Msk         (0x1UL << DOEPEACHMSK1_INEPNEM_Pos)      // 0x00000040 */
+#define DOEPEACHMSK1_INEPNEM             DOEPEACHMSK1_INEPNEM_Msk                 // IN endpoint NAK effective mask            */
+#define DOEPEACHMSK1_TXFURM_Pos          (8U)
+#define DOEPEACHMSK1_TXFURM_Msk          (0x1UL << DOEPEACHMSK1_TXFURM_Pos)       // 0x00000100 */
+#define DOEPEACHMSK1_TXFURM              DOEPEACHMSK1_TXFURM_Msk                  // OUT packet error mask                     */
+#define DOEPEACHMSK1_BIM_Pos             (9U)
+#define DOEPEACHMSK1_BIM_Msk             (0x1UL << DOEPEACHMSK1_BIM_Pos)          // 0x00000200 */
+#define DOEPEACHMSK1_BIM                 DOEPEACHMSK1_BIM_Msk                     // BNA interrupt mask                        */
+#define DOEPEACHMSK1_BERRM_Pos           (12U)
+#define DOEPEACHMSK1_BERRM_Msk           (0x1UL << DOEPEACHMSK1_BERRM_Pos)        // 0x00001000 */
+#define DOEPEACHMSK1_BERRM               DOEPEACHMSK1_BERRM_Msk                   // Bubble error interrupt mask               */
+#define DOEPEACHMSK1_NAKM_Pos            (13U)
+#define DOEPEACHMSK1_NAKM_Msk            (0x1UL << DOEPEACHMSK1_NAKM_Pos)         // 0x00002000 */
+#define DOEPEACHMSK1_NAKM                DOEPEACHMSK1_NAKM_Msk                    // NAK interrupt mask                        */
+#define DOEPEACHMSK1_NYETM_Pos           (14U)
+#define DOEPEACHMSK1_NYETM_Msk           (0x1UL << DOEPEACHMSK1_NYETM_Pos)        // 0x00004000 */
+#define DOEPEACHMSK1_NYETM               DOEPEACHMSK1_NYETM_Msk                   // NYET interrupt mask                       */
+
+/********************  Bit definition for HPTXFSIZ register  ********************/
+#define HPTXFSIZ_PTXSA_Pos               (0U)
+#define HPTXFSIZ_PTXSA_Msk               (0xFFFFUL << HPTXFSIZ_PTXSA_Pos)         // 0x0000FFFF */
+#define HPTXFSIZ_PTXSA                   HPTXFSIZ_PTXSA_Msk                       // Host periodic TxFIFO start address            */
+#define HPTXFSIZ_PTXFD_Pos               (16U)
+#define HPTXFSIZ_PTXFD_Msk               (0xFFFFUL << HPTXFSIZ_PTXFD_Pos)         // 0xFFFF0000 */
+#define HPTXFSIZ_PTXFD                   HPTXFSIZ_PTXFD_Msk                       // Host periodic TxFIFO depth                    */
+
+/********************  Bit definition for DIEPCTL register  ********************/
+#define DIEPCTL_MPSIZ_Pos                (0U)
+#define DIEPCTL_MPSIZ_Msk                (0x7FFUL << DIEPCTL_MPSIZ_Pos)           // 0x000007FF */
+#define DIEPCTL_MPSIZ                    DIEPCTL_MPSIZ_Msk                        // Maximum packet size              */
+#define DIEPCTL_USBAEP_Pos               (15U)
+#define DIEPCTL_USBAEP_Msk               (0x1UL << DIEPCTL_USBAEP_Pos)            // 0x00008000 */
+#define DIEPCTL_USBAEP                   DIEPCTL_USBAEP_Msk                       // USB active endpoint              */
+#define DIEPCTL_EONUM_DPID_Pos           (16U)
+#define DIEPCTL_EONUM_DPID_Msk           (0x1UL << DIEPCTL_EONUM_DPID_Pos)        // 0x00010000 */
+#define DIEPCTL_EONUM_DPID               DIEPCTL_EONUM_DPID_Msk                   // Even/odd frame                   */
+#define DIEPCTL_NAKSTS_Pos               (17U)
+#define DIEPCTL_NAKSTS_Msk               (0x1UL << DIEPCTL_NAKSTS_Pos)            // 0x00020000 */
+#define DIEPCTL_NAKSTS                   DIEPCTL_NAKSTS_Msk                       // NAK status                       */
+
+#define DIEPCTL_EPTYP_Pos                (18U)
+#define DIEPCTL_EPTYP_Msk                (0x3UL << DIEPCTL_EPTYP_Pos)             // 0x000C0000 */
+#define DIEPCTL_EPTYP                    DIEPCTL_EPTYP_Msk                        // Endpoint type                    */
+#define DIEPCTL_EPTYP_0                  (0x1UL << DIEPCTL_EPTYP_Pos)             // 0x00040000 */
+#define DIEPCTL_EPTYP_1                  (0x2UL << DIEPCTL_EPTYP_Pos)             // 0x00080000 */
+#define DIEPCTL_STALL_Pos                (21U)
+#define DIEPCTL_STALL_Msk                (0x1UL << DIEPCTL_STALL_Pos)             // 0x00200000 */
+#define DIEPCTL_STALL                    DIEPCTL_STALL_Msk                        // STALL handshake                  */
+
+#define DIEPCTL_TXFNUM_Pos               (22U)
+#define DIEPCTL_TXFNUM_Msk               (0xFUL << DIEPCTL_TXFNUM_Pos)            // 0x03C00000 */
+#define DIEPCTL_TXFNUM                   DIEPCTL_TXFNUM_Msk                       // TxFIFO number                    */
+#define DIEPCTL_TXFNUM_0                 (0x1UL << DIEPCTL_TXFNUM_Pos)            // 0x00400000 */
+#define DIEPCTL_TXFNUM_1                 (0x2UL << DIEPCTL_TXFNUM_Pos)            // 0x00800000 */
+#define DIEPCTL_TXFNUM_2                 (0x4UL << DIEPCTL_TXFNUM_Pos)            // 0x01000000 */
+#define DIEPCTL_TXFNUM_3                 (0x8UL << DIEPCTL_TXFNUM_Pos)            // 0x02000000 */
+#define DIEPCTL_CNAK_Pos                 (26U)
+#define DIEPCTL_CNAK_Msk                 (0x1UL << DIEPCTL_CNAK_Pos)              // 0x04000000 */
+#define DIEPCTL_CNAK                     DIEPCTL_CNAK_Msk                         // Clear NAK                        */
+#define DIEPCTL_SNAK_Pos                 (27U)
+#define DIEPCTL_SNAK_Msk                 (0x1UL << DIEPCTL_SNAK_Pos)              // 0x08000000 */
+#define DIEPCTL_SNAK                     DIEPCTL_SNAK_Msk                         // Set NAK */
+#define DIEPCTL_SD0PID_SEVNFRM_Pos       (28U)
+#define DIEPCTL_SD0PID_SEVNFRM_Msk       (0x1UL << DIEPCTL_SD0PID_SEVNFRM_Pos)    // 0x10000000 */
+#define DIEPCTL_SD0PID_SEVNFRM           DIEPCTL_SD0PID_SEVNFRM_Msk               // Set DATA0 PID                    */
+#define DIEPCTL_SODDFRM_Pos              (29U)
+#define DIEPCTL_SODDFRM_Msk              (0x1UL << DIEPCTL_SODDFRM_Pos)           // 0x20000000 */
+#define DIEPCTL_SODDFRM                  DIEPCTL_SODDFRM_Msk                      // Set odd frame                    */
+#define DIEPCTL_EPDIS_Pos                (30U)
+#define DIEPCTL_EPDIS_Msk                (0x1UL << DIEPCTL_EPDIS_Pos)             // 0x40000000 */
+#define DIEPCTL_EPDIS                    DIEPCTL_EPDIS_Msk                        // Endpoint disable                 */
+#define DIEPCTL_EPENA_Pos                (31U)
+#define DIEPCTL_EPENA_Msk                (0x1UL << DIEPCTL_EPENA_Pos)             // 0x80000000 */
+#define DIEPCTL_EPENA                    DIEPCTL_EPENA_Msk                        // Endpoint enable                  */
+
+/********************  Bit definition for HCCHAR register  ********************/
+#define HCCHAR_MPSIZ_Pos                 (0U)
+#define HCCHAR_MPSIZ_Msk                 (0x7FFUL << HCCHAR_MPSIZ_Pos)            // 0x000007FF */
+#define HCCHAR_MPSIZ                     HCCHAR_MPSIZ_Msk                         // Maximum packet size */
+
+#define HCCHAR_EPNUM_Pos                 (11U)
+#define HCCHAR_EPNUM_Msk                 (0xFUL << HCCHAR_EPNUM_Pos)              // 0x00007800 */
+#define HCCHAR_EPNUM                     HCCHAR_EPNUM_Msk                         // Endpoint number */
+#define HCCHAR_EPNUM_0                   (0x1UL << HCCHAR_EPNUM_Pos)              // 0x00000800 */
+#define HCCHAR_EPNUM_1                   (0x2UL << HCCHAR_EPNUM_Pos)              // 0x00001000 */
+#define HCCHAR_EPNUM_2                   (0x4UL << HCCHAR_EPNUM_Pos)              // 0x00002000 */
+#define HCCHAR_EPNUM_3                   (0x8UL << HCCHAR_EPNUM_Pos)              // 0x00004000 */
+#define HCCHAR_EPDIR_Pos                 (15U)
+#define HCCHAR_EPDIR_Msk                 (0x1UL << HCCHAR_EPDIR_Pos)              // 0x00008000 */
+#define HCCHAR_EPDIR                     HCCHAR_EPDIR_Msk                         // Endpoint direction */
+#define HCCHAR_LSDEV_Pos                 (17U)
+#define HCCHAR_LSDEV_Msk                 (0x1UL << HCCHAR_LSDEV_Pos)              // 0x00020000 */
+#define HCCHAR_LSDEV                     HCCHAR_LSDEV_Msk                         // Low-speed device */
+
+#define HCCHAR_EPTYP_Pos                 (18U)
+#define HCCHAR_EPTYP_Msk                 (0x3UL << HCCHAR_EPTYP_Pos)              // 0x000C0000 */
+#define HCCHAR_EPTYP                     HCCHAR_EPTYP_Msk                         // Endpoint type */
+#define HCCHAR_EPTYP_0                   (0x1UL << HCCHAR_EPTYP_Pos)              // 0x00040000 */
+#define HCCHAR_EPTYP_1                   (0x2UL << HCCHAR_EPTYP_Pos)              // 0x00080000 */
+
+#define HCCHAR_MC_Pos                    (20U)
+#define HCCHAR_MC_Msk                    (0x3UL << HCCHAR_MC_Pos)                 // 0x00300000 */
+#define HCCHAR_MC                        HCCHAR_MC_Msk                            // Multi Count (MC) / Error Count (EC) */
+#define HCCHAR_MC_0                      (0x1UL << HCCHAR_MC_Pos)                 // 0x00100000 */
+#define HCCHAR_MC_1                      (0x2UL << HCCHAR_MC_Pos)                 // 0x00200000 */
+
+#define HCCHAR_DAD_Pos                   (22U)
+#define HCCHAR_DAD_Msk                   (0x7FUL << HCCHAR_DAD_Pos)               // 0x1FC00000 */
+#define HCCHAR_DAD                       HCCHAR_DAD_Msk                           // Device address */
+#define HCCHAR_DAD_0                     (0x01UL << HCCHAR_DAD_Pos)               // 0x00400000 */
+#define HCCHAR_DAD_1                     (0x02UL << HCCHAR_DAD_Pos)               // 0x00800000 */
+#define HCCHAR_DAD_2                     (0x04UL << HCCHAR_DAD_Pos)               // 0x01000000 */
+#define HCCHAR_DAD_3                     (0x08UL << HCCHAR_DAD_Pos)               // 0x02000000 */
+#define HCCHAR_DAD_4                     (0x10UL << HCCHAR_DAD_Pos)               // 0x04000000 */
+#define HCCHAR_DAD_5                     (0x20UL << HCCHAR_DAD_Pos)               // 0x08000000 */
+#define HCCHAR_DAD_6                     (0x40UL << HCCHAR_DAD_Pos)               // 0x10000000 */
+#define HCCHAR_ODDFRM_Pos                (29U)
+#define HCCHAR_ODDFRM_Msk                (0x1UL << HCCHAR_ODDFRM_Pos)             // 0x20000000 */
+#define HCCHAR_ODDFRM                    HCCHAR_ODDFRM_Msk                        // Odd frame */
+#define HCCHAR_CHDIS_Pos                 (30U)
+#define HCCHAR_CHDIS_Msk                 (0x1UL << HCCHAR_CHDIS_Pos)              // 0x40000000 */
+#define HCCHAR_CHDIS                     HCCHAR_CHDIS_Msk                         // Channel disable */
+#define HCCHAR_CHENA_Pos                 (31U)
+#define HCCHAR_CHENA_Msk                 (0x1UL << HCCHAR_CHENA_Pos)              // 0x80000000 */
+#define HCCHAR_CHENA                     HCCHAR_CHENA_Msk                         // Channel enable */
+
+/********************  Bit definition for HCSPLT register  ********************/
+
+#define HCSPLT_PRTADDR_Pos               (0U)
+#define HCSPLT_PRTADDR_Msk               (0x7FUL << HCSPLT_PRTADDR_Pos)           // 0x0000007F */
+#define HCSPLT_PRTADDR                   HCSPLT_PRTADDR_Msk                       // Port address */
+#define HCSPLT_PRTADDR_0                 (0x01UL << HCSPLT_PRTADDR_Pos)           // 0x00000001 */
+#define HCSPLT_PRTADDR_1                 (0x02UL << HCSPLT_PRTADDR_Pos)           // 0x00000002 */
+#define HCSPLT_PRTADDR_2                 (0x04UL << HCSPLT_PRTADDR_Pos)           // 0x00000004 */
+#define HCSPLT_PRTADDR_3                 (0x08UL << HCSPLT_PRTADDR_Pos)           // 0x00000008 */
+#define HCSPLT_PRTADDR_4                 (0x10UL << HCSPLT_PRTADDR_Pos)           // 0x00000010 */
+#define HCSPLT_PRTADDR_5                 (0x20UL << HCSPLT_PRTADDR_Pos)           // 0x00000020 */
+#define HCSPLT_PRTADDR_6                 (0x40UL << HCSPLT_PRTADDR_Pos)           // 0x00000040 */
+
+#define HCSPLT_HUBADDR_Pos               (7U)
+#define HCSPLT_HUBADDR_Msk               (0x7FUL << HCSPLT_HUBADDR_Pos)           // 0x00003F80 */
+#define HCSPLT_HUBADDR                   HCSPLT_HUBADDR_Msk                       // Hub address */
+#define HCSPLT_HUBADDR_0                 (0x01UL << HCSPLT_HUBADDR_Pos)           // 0x00000080 */
+#define HCSPLT_HUBADDR_1                 (0x02UL << HCSPLT_HUBADDR_Pos)           // 0x00000100 */
+#define HCSPLT_HUBADDR_2                 (0x04UL << HCSPLT_HUBADDR_Pos)           // 0x00000200 */
+#define HCSPLT_HUBADDR_3                 (0x08UL << HCSPLT_HUBADDR_Pos)           // 0x00000400 */
+#define HCSPLT_HUBADDR_4                 (0x10UL << HCSPLT_HUBADDR_Pos)           // 0x00000800 */
+#define HCSPLT_HUBADDR_5                 (0x20UL << HCSPLT_HUBADDR_Pos)           // 0x00001000 */
+#define HCSPLT_HUBADDR_6                 (0x40UL << HCSPLT_HUBADDR_Pos)           // 0x00002000 */
+
+#define HCSPLT_XACTPOS_Pos               (14U)
+#define HCSPLT_XACTPOS_Msk               (0x3UL << HCSPLT_XACTPOS_Pos)            // 0x0000C000 */
+#define HCSPLT_XACTPOS                   HCSPLT_XACTPOS_Msk                       // XACTPOS */
+#define HCSPLT_XACTPOS_0                 (0x1UL << HCSPLT_XACTPOS_Pos)            // 0x00004000 */
+#define HCSPLT_XACTPOS_1                 (0x2UL << HCSPLT_XACTPOS_Pos)            // 0x00008000 */
+#define HCSPLT_COMPLSPLT_Pos             (16U)
+#define HCSPLT_COMPLSPLT_Msk             (0x1UL << HCSPLT_COMPLSPLT_Pos)          // 0x00010000 */
+#define HCSPLT_COMPLSPLT                 HCSPLT_COMPLSPLT_Msk                     // Do complete split */
+#define HCSPLT_SPLITEN_Pos               (31U)
+#define HCSPLT_SPLITEN_Msk               (0x1UL << HCSPLT_SPLITEN_Pos)            // 0x80000000 */
+#define HCSPLT_SPLITEN                   HCSPLT_SPLITEN_Msk                       // Split enable */
+
+/********************  Bit definition for HCINT register  ********************/
+#define HCINT_XFRC_Pos                   (0U)
+#define HCINT_XFRC_Msk                   (0x1UL << HCINT_XFRC_Pos)                // 0x00000001 */
+#define HCINT_XFRC                       HCINT_XFRC_Msk                           // Transfer completed */
+#define HCINT_CHH_Pos                    (1U)
+#define HCINT_CHH_Msk                    (0x1UL << HCINT_CHH_Pos)                 // 0x00000002 */
+#define HCINT_CHH                        HCINT_CHH_Msk                            // Channel halted */
+#define HCINT_AHBERR_Pos                 (2U)
+#define HCINT_AHBERR_Msk                 (0x1UL << HCINT_AHBERR_Pos)              // 0x00000004 */
+#define HCINT_AHBERR                     HCINT_AHBERR_Msk                         // AHB error */
+#define HCINT_STALL_Pos                  (3U)
+#define HCINT_STALL_Msk                  (0x1UL << HCINT_STALL_Pos)               // 0x00000008 */
+#define HCINT_STALL                      HCINT_STALL_Msk                          // STALL response received interrupt */
+#define HCINT_NAK_Pos                    (4U)
+#define HCINT_NAK_Msk                    (0x1UL << HCINT_NAK_Pos)                 // 0x00000010 */
+#define HCINT_NAK                        HCINT_NAK_Msk                            // NAK response received interrupt */
+#define HCINT_ACK_Pos                    (5U)
+#define HCINT_ACK_Msk                    (0x1UL << HCINT_ACK_Pos)                 // 0x00000020 */
+#define HCINT_ACK                        HCINT_ACK_Msk                            // ACK response received/transmitted interrupt */
+#define HCINT_NYET_Pos                   (6U)
+#define HCINT_NYET_Msk                   (0x1UL << HCINT_NYET_Pos)                // 0x00000040 */
+#define HCINT_NYET                       HCINT_NYET_Msk                           // Response received interrupt */
+#define HCINT_TXERR_Pos                  (7U)
+#define HCINT_TXERR_Msk                  (0x1UL << HCINT_TXERR_Pos)               // 0x00000080 */
+#define HCINT_TXERR                      HCINT_TXERR_Msk                          // Transaction error */
+#define HCINT_BBERR_Pos                  (8U)
+#define HCINT_BBERR_Msk                  (0x1UL << HCINT_BBERR_Pos)               // 0x00000100 */
+#define HCINT_BBERR                      HCINT_BBERR_Msk                          // Babble error */
+#define HCINT_FRMOR_Pos                  (9U)
+#define HCINT_FRMOR_Msk                  (0x1UL << HCINT_FRMOR_Pos)               // 0x00000200 */
+#define HCINT_FRMOR                      HCINT_FRMOR_Msk                          // Frame overrun */
+#define HCINT_DTERR_Pos                  (10U)
+#define HCINT_DTERR_Msk                  (0x1UL << HCINT_DTERR_Pos)               // 0x00000400 */
+#define HCINT_DTERR                      HCINT_DTERR_Msk                          // Data toggle error */
+
+/********************  Bit definition for DIEPINT register  ********************/
+#define DIEPINT_XFRC_Pos                 (0U)
+#define DIEPINT_XFRC_Msk                 (0x1UL << DIEPINT_XFRC_Pos)              // 0x00000001 */
+#define DIEPINT_XFRC                     DIEPINT_XFRC_Msk                         // Transfer completed interrupt */
+#define DIEPINT_EPDISD_Pos               (1U)
+#define DIEPINT_EPDISD_Msk               (0x1UL << DIEPINT_EPDISD_Pos)            // 0x00000002 */
+#define DIEPINT_EPDISD                   DIEPINT_EPDISD_Msk                       // Endpoint disabled interrupt */
+#define DIEPINT_AHBERR_Pos               (2U)
+#define DIEPINT_AHBERR_Msk               (0x1UL << DIEPINT_AHBERR_Pos)            // 0x00000004 */
+#define DIEPINT_AHBERR                   DIEPINT_AHBERR_Msk                       // AHB Error (AHBErr) during an IN transaction */
+#define DIEPINT_TOC_Pos                  (3U)
+#define DIEPINT_TOC_Msk                  (0x1UL << DIEPINT_TOC_Pos)               // 0x00000008 */
+#define DIEPINT_TOC                      DIEPINT_TOC_Msk                          // Timeout condition */
+#define DIEPINT_ITTXFE_Pos               (4U)
+#define DIEPINT_ITTXFE_Msk               (0x1UL << DIEPINT_ITTXFE_Pos)            // 0x00000010 */
+#define DIEPINT_ITTXFE                   DIEPINT_ITTXFE_Msk                       // IN token received when TxFIFO is empty */
+#define DIEPINT_INEPNM_Pos               (5U)
+#define DIEPINT_INEPNM_Msk               (0x1UL << DIEPINT_INEPNM_Pos)            // 0x00000020 */
+#define DIEPINT_INEPNM                   DIEPINT_INEPNM_Msk                       // IN token received with EP mismatch */
+#define DIEPINT_INEPNE_Pos               (6U)
+#define DIEPINT_INEPNE_Msk               (0x1UL << DIEPINT_INEPNE_Pos)            // 0x00000040 */
+#define DIEPINT_INEPNE                   DIEPINT_INEPNE_Msk                       // IN endpoint NAK effective */
+#define DIEPINT_TXFE_Pos                 (7U)
+#define DIEPINT_TXFE_Msk                 (0x1UL << DIEPINT_TXFE_Pos)              // 0x00000080 */
+#define DIEPINT_TXFE                     DIEPINT_TXFE_Msk                         // Transmit FIFO empty */
+#define DIEPINT_TXFIFOUDRN_Pos           (8U)
+#define DIEPINT_TXFIFOUDRN_Msk           (0x1UL << DIEPINT_TXFIFOUDRN_Pos)        // 0x00000100 */
+#define DIEPINT_TXFIFOUDRN               DIEPINT_TXFIFOUDRN_Msk                   // Transmit Fifo Underrun */
+#define DIEPINT_BNA_Pos                  (9U)
+#define DIEPINT_BNA_Msk                  (0x1UL << DIEPINT_BNA_Pos)               // 0x00000200 */
+#define DIEPINT_BNA                      DIEPINT_BNA_Msk                          // Buffer not available interrupt */
+#define DIEPINT_PKTDRPSTS_Pos            (11U)
+#define DIEPINT_PKTDRPSTS_Msk            (0x1UL << DIEPINT_PKTDRPSTS_Pos)         // 0x00000800 */
+#define DIEPINT_PKTDRPSTS                DIEPINT_PKTDRPSTS_Msk                    // Packet dropped status */
+#define DIEPINT_BERR_Pos                 (12U)
+#define DIEPINT_BERR_Msk                 (0x1UL << DIEPINT_BERR_Pos)              // 0x00001000 */
+#define DIEPINT_BERR                     DIEPINT_BERR_Msk                         // Babble error interrupt */
+#define DIEPINT_NAK_Pos                  (13U)
+#define DIEPINT_NAK_Msk                  (0x1UL << DIEPINT_NAK_Pos)               // 0x00002000 */
+#define DIEPINT_NAK                      DIEPINT_NAK_Msk                          // NAK interrupt */
+
+/********************  Bit definition for HCINTMSK register  ********************/
+#define HCINTMSK_XFRCM_Pos               (0U)
+#define HCINTMSK_XFRCM_Msk               (0x1UL << HCINTMSK_XFRCM_Pos)            // 0x00000001 */
+#define HCINTMSK_XFRCM                   HCINTMSK_XFRCM_Msk                       // Transfer completed mask */
+#define HCINTMSK_CHHM_Pos                (1U)
+#define HCINTMSK_CHHM_Msk                (0x1UL << HCINTMSK_CHHM_Pos)             // 0x00000002 */
+#define HCINTMSK_CHHM                    HCINTMSK_CHHM_Msk                        // Channel halted mask */
+#define HCINTMSK_AHBERR_Pos              (2U)
+#define HCINTMSK_AHBERR_Msk              (0x1UL << HCINTMSK_AHBERR_Pos)           // 0x00000004 */
+#define HCINTMSK_AHBERR                  HCINTMSK_AHBERR_Msk                      // AHB error */
+#define HCINTMSK_STALLM_Pos              (3U)
+#define HCINTMSK_STALLM_Msk              (0x1UL << HCINTMSK_STALLM_Pos)           // 0x00000008 */
+#define HCINTMSK_STALLM                  HCINTMSK_STALLM_Msk                      // STALL response received interrupt mask */
+#define HCINTMSK_NAKM_Pos                (4U)
+#define HCINTMSK_NAKM_Msk                (0x1UL << HCINTMSK_NAKM_Pos)             // 0x00000010 */
+#define HCINTMSK_NAKM                    HCINTMSK_NAKM_Msk                        // NAK response received interrupt mask */
+#define HCINTMSK_ACKM_Pos                (5U)
+#define HCINTMSK_ACKM_Msk                (0x1UL << HCINTMSK_ACKM_Pos)             // 0x00000020 */
+#define HCINTMSK_ACKM                    HCINTMSK_ACKM_Msk                        // ACK response received/transmitted interrupt mask */
+#define HCINTMSK_NYET_Pos                (6U)
+#define HCINTMSK_NYET_Msk                (0x1UL << HCINTMSK_NYET_Pos)             // 0x00000040 */
+#define HCINTMSK_NYET                    HCINTMSK_NYET_Msk                        // response received interrupt mask */
+#define HCINTMSK_TXERRM_Pos              (7U)
+#define HCINTMSK_TXERRM_Msk              (0x1UL << HCINTMSK_TXERRM_Pos)           // 0x00000080 */
+#define HCINTMSK_TXERRM                  HCINTMSK_TXERRM_Msk                      // Transaction error mask */
+#define HCINTMSK_BBERRM_Pos              (8U)
+#define HCINTMSK_BBERRM_Msk              (0x1UL << HCINTMSK_BBERRM_Pos)           // 0x00000100 */
+#define HCINTMSK_BBERRM                  HCINTMSK_BBERRM_Msk                      // Babble error mask */
+#define HCINTMSK_FRMORM_Pos              (9U)
+#define HCINTMSK_FRMORM_Msk              (0x1UL << HCINTMSK_FRMORM_Pos)           // 0x00000200 */
+#define HCINTMSK_FRMORM                  HCINTMSK_FRMORM_Msk                      // Frame overrun mask */
+#define HCINTMSK_DTERRM_Pos              (10U)
+#define HCINTMSK_DTERRM_Msk              (0x1UL << HCINTMSK_DTERRM_Pos)           // 0x00000400 */
+#define HCINTMSK_DTERRM                  HCINTMSK_DTERRM_Msk                      // Data toggle error mask */
+
+/********************  Bit definition for DIEPTSIZ register  ********************/
+
+#define DIEPTSIZ_XFRSIZ_Pos              (0U)
+#define DIEPTSIZ_XFRSIZ_Msk              (0x7FFFFUL << DIEPTSIZ_XFRSIZ_Pos)       // 0x0007FFFF */
+#define DIEPTSIZ_XFRSIZ                  DIEPTSIZ_XFRSIZ_Msk                      // Transfer size */
+#define DIEPTSIZ_PKTCNT_Pos              (19U)
+#define DIEPTSIZ_PKTCNT_Msk              (0x3FFUL << DIEPTSIZ_PKTCNT_Pos)         // 0x1FF80000 */
+#define DIEPTSIZ_PKTCNT                  DIEPTSIZ_PKTCNT_Msk                      // Packet count */
+#define DIEPTSIZ_MULCNT_Pos              (29U)
+#define DIEPTSIZ_MULCNT_Msk              (0x3UL << DIEPTSIZ_MULCNT_Pos)           // 0x60000000 */
+#define DIEPTSIZ_MULCNT                  DIEPTSIZ_MULCNT_Msk                      // Packet count */
+                                                                                  /********************  Bit definition for HCTSIZ register  ********************/
+#define HCTSIZ_XFRSIZ_Pos                (0U)
+#define HCTSIZ_XFRSIZ_Msk                (0x7FFFFUL << HCTSIZ_XFRSIZ_Pos)         // 0x0007FFFF */
+#define HCTSIZ_XFRSIZ                    HCTSIZ_XFRSIZ_Msk                        // Transfer size */
+#define HCTSIZ_PKTCNT_Pos                (19U)
+#define HCTSIZ_PKTCNT_Msk                (0x3FFUL << HCTSIZ_PKTCNT_Pos)           // 0x1FF80000 */
+#define HCTSIZ_PKTCNT                    HCTSIZ_PKTCNT_Msk                        // Packet count */
+#define HCTSIZ_DOPING_Pos                (31U)
+#define HCTSIZ_DOPING_Msk                (0x1UL << HCTSIZ_DOPING_Pos)             // 0x80000000 */
+#define HCTSIZ_DOPING                    HCTSIZ_DOPING_Msk                        // Do PING */
+#define HCTSIZ_DPID_Pos                  (29U)
+#define HCTSIZ_DPID_Msk                  (0x3UL << HCTSIZ_DPID_Pos)               // 0x60000000 */
+#define HCTSIZ_DPID                      HCTSIZ_DPID_Msk                          // Data PID */
+#define HCTSIZ_DPID_0                    (0x1UL << HCTSIZ_DPID_Pos)               // 0x20000000 */
+#define HCTSIZ_DPID_1                    (0x2UL << HCTSIZ_DPID_Pos)               // 0x40000000 */
+
+/********************  Bit definition for DIEPDMA register  ********************/
+#define DIEPDMA_DMAADDR_Pos              (0U)
+#define DIEPDMA_DMAADDR_Msk              (0xFFFFFFFFUL << DIEPDMA_DMAADDR_Pos)    // 0xFFFFFFFF */
+#define DIEPDMA_DMAADDR                  DIEPDMA_DMAADDR_Msk                      // DMA address */
+
+/********************  Bit definition for HCDMA register  ********************/
+#define HCDMA_DMAADDR_Pos                (0U)
+#define HCDMA_DMAADDR_Msk                (0xFFFFFFFFUL << HCDMA_DMAADDR_Pos)      // 0xFFFFFFFF */
+#define HCDMA_DMAADDR                    HCDMA_DMAADDR_Msk                        // DMA address */
+
+                                                                                  /********************  Bit definition for DTXFSTS register  ********************/
+#define DTXFSTS_INEPTFSAV_Pos            (0U)
+#define DTXFSTS_INEPTFSAV_Msk            (0xFFFFUL << DTXFSTS_INEPTFSAV_Pos)      // 0x0000FFFF */
+#define DTXFSTS_INEPTFSAV                DTXFSTS_INEPTFSAV_Msk                    // IN endpoint TxFIFO space available */
+
+                                                                                  /********************  Bit definition for DIEPTXF register  ********************/
+#define DIEPTXF_INEPTXSA_Pos             (0U)
+#define DIEPTXF_INEPTXSA_Msk             (0xFFFFUL << DIEPTXF_INEPTXSA_Pos)       // 0x0000FFFF */
+#define DIEPTXF_INEPTXSA                 DIEPTXF_INEPTXSA_Msk                     // IN endpoint FIFOx transmit RAM start address */
+#define DIEPTXF_INEPTXFD_Pos             (16U)
+#define DIEPTXF_INEPTXFD_Msk             (0xFFFFUL << DIEPTXF_INEPTXFD_Pos)       // 0xFFFF0000 */
+#define DIEPTXF_INEPTXFD                 DIEPTXF_INEPTXFD_Msk                     // IN endpoint TxFIFO depth */
+
+/********************  Bit definition for DOEPCTL register  ********************/
+#define DOEPCTL_MPSIZ_Pos                (0U)
+#define DOEPCTL_MPSIZ_Msk                (0x7FFUL << DOEPCTL_MPSIZ_Pos)           // 0x000007FF */
+#define DOEPCTL_MPSIZ                    DOEPCTL_MPSIZ_Msk                        // Maximum packet size */          //Bit 1 */
+#define DOEPCTL_USBAEP_Pos               (15U)
+#define DOEPCTL_USBAEP_Msk               (0x1UL << DOEPCTL_USBAEP_Pos)            // 0x00008000 */
+#define DOEPCTL_USBAEP                   DOEPCTL_USBAEP_Msk                       // USB active endpoint */
+#define DOEPCTL_NAKSTS_Pos               (17U)
+#define DOEPCTL_NAKSTS_Msk               (0x1UL << DOEPCTL_NAKSTS_Pos)            // 0x00020000 */
+#define DOEPCTL_NAKSTS                   DOEPCTL_NAKSTS_Msk                       // NAK status */
+#define DOEPCTL_SD0PID_SEVNFRM_Pos       (28U)
+#define DOEPCTL_SD0PID_SEVNFRM_Msk       (0x1UL << DOEPCTL_SD0PID_SEVNFRM_Pos)    // 0x10000000 */
+#define DOEPCTL_SD0PID_SEVNFRM           DOEPCTL_SD0PID_SEVNFRM_Msk               // Set DATA0 PID */
+#define DOEPCTL_SODDFRM_Pos              (29U)
+#define DOEPCTL_SODDFRM_Msk              (0x1UL << DOEPCTL_SODDFRM_Pos)           // 0x20000000 */
+#define DOEPCTL_SODDFRM                  DOEPCTL_SODDFRM_Msk                      // Set odd frame */
+#define DOEPCTL_EPTYP_Pos                (18U)
+#define DOEPCTL_EPTYP_Msk                (0x3UL << DOEPCTL_EPTYP_Pos)             // 0x000C0000 */
+#define DOEPCTL_EPTYP                    DOEPCTL_EPTYP_Msk                        // Endpoint type */
+#define DOEPCTL_EPTYP_0                  (0x1UL << DOEPCTL_EPTYP_Pos)             // 0x00040000 */
+#define DOEPCTL_EPTYP_1                  (0x2UL << DOEPCTL_EPTYP_Pos)             // 0x00080000 */
+#define DOEPCTL_SNPM_Pos                 (20U)
+#define DOEPCTL_SNPM_Msk                 (0x1UL << DOEPCTL_SNPM_Pos)              // 0x00100000 */
+#define DOEPCTL_SNPM                     DOEPCTL_SNPM_Msk                         // Snoop mode */
+#define DOEPCTL_STALL_Pos                (21U)
+#define DOEPCTL_STALL_Msk                (0x1UL << DOEPCTL_STALL_Pos)             // 0x00200000 */
+#define DOEPCTL_STALL                    DOEPCTL_STALL_Msk                        // STALL handshake */
+#define DOEPCTL_CNAK_Pos                 (26U)
+#define DOEPCTL_CNAK_Msk                 (0x1UL << DOEPCTL_CNAK_Pos)              // 0x04000000 */
+#define DOEPCTL_CNAK                     DOEPCTL_CNAK_Msk                         // Clear NAK */
+#define DOEPCTL_SNAK_Pos                 (27U)
+#define DOEPCTL_SNAK_Msk                 (0x1UL << DOEPCTL_SNAK_Pos)              // 0x08000000 */
+#define DOEPCTL_SNAK                     DOEPCTL_SNAK_Msk                         // Set NAK */
+#define DOEPCTL_EPDIS_Pos                (30U)
+#define DOEPCTL_EPDIS_Msk                (0x1UL << DOEPCTL_EPDIS_Pos)             // 0x40000000 */
+#define DOEPCTL_EPDIS                    DOEPCTL_EPDIS_Msk                        // Endpoint disable */
+#define DOEPCTL_EPENA_Pos                (31U)
+#define DOEPCTL_EPENA_Msk                (0x1UL << DOEPCTL_EPENA_Pos)             // 0x80000000 */
+#define DOEPCTL_EPENA                    DOEPCTL_EPENA_Msk                        // Endpoint enable */
+
+/********************  Bit definition for DOEPINT register  ********************/
+#define DOEPINT_XFRC_Pos                 (0U)
+#define DOEPINT_XFRC_Msk                 (0x1UL << DOEPINT_XFRC_Pos)              // 0x00000001 */
+#define DOEPINT_XFRC                     DOEPINT_XFRC_Msk                         // Transfer completed interrupt */
+#define DOEPINT_EPDISD_Pos               (1U)
+#define DOEPINT_EPDISD_Msk               (0x1UL << DOEPINT_EPDISD_Pos)            // 0x00000002 */
+#define DOEPINT_EPDISD                   DOEPINT_EPDISD_Msk                       // Endpoint disabled interrupt */
+#define DOEPINT_AHBERR_Pos               (2U)
+#define DOEPINT_AHBERR_Msk               (0x1UL << DOEPINT_AHBERR_Pos)            // 0x00000004 */
+#define DOEPINT_AHBERR                   DOEPINT_AHBERR_Msk                       // AHB Error (AHBErr) during an OUT transaction */
+#define DOEPINT_STUP_Pos                 (3U)
+#define DOEPINT_STUP_Msk                 (0x1UL << DOEPINT_STUP_Pos)              // 0x00000008 */
+#define DOEPINT_STUP                     DOEPINT_STUP_Msk                         // SETUP phase done */
+#define DOEPINT_OTEPDIS_Pos              (4U)
+#define DOEPINT_OTEPDIS_Msk              (0x1UL << DOEPINT_OTEPDIS_Pos)           // 0x00000010 */
+#define DOEPINT_OTEPDIS                  DOEPINT_OTEPDIS_Msk                      // OUT token received when endpoint disabled */
+#define DOEPINT_OTEPSPR_Pos              (5U)
+#define DOEPINT_OTEPSPR_Msk              (0x1UL << DOEPINT_OTEPSPR_Pos)           // 0x00000020 */
+#define DOEPINT_OTEPSPR                  DOEPINT_OTEPSPR_Msk                      // Status Phase Received For Control Write */
+#define DOEPINT_B2BSTUP_Pos              (6U)
+#define DOEPINT_B2BSTUP_Msk              (0x1UL << DOEPINT_B2BSTUP_Pos)           // 0x00000040 */
+#define DOEPINT_B2BSTUP                  DOEPINT_B2BSTUP_Msk                      // Back-to-back SETUP packets received */
+#define DOEPINT_OUTPKTERR_Pos            (8U)
+#define DOEPINT_OUTPKTERR_Msk            (0x1UL << DOEPINT_OUTPKTERR_Pos)         // 0x00000100 */
+#define DOEPINT_OUTPKTERR                DOEPINT_OUTPKTERR_Msk                    // OUT packet error */
+#define DOEPINT_NAK_Pos                  (13U)
+#define DOEPINT_NAK_Msk                  (0x1UL << DOEPINT_NAK_Pos)               // 0x00002000 */
+#define DOEPINT_NAK                      DOEPINT_NAK_Msk                          // NAK Packet is transmitted by the device */
+#define DOEPINT_NYET_Pos                 (14U)
+#define DOEPINT_NYET_Msk                 (0x1UL << DOEPINT_NYET_Pos)              // 0x00004000 */
+#define DOEPINT_NYET                     DOEPINT_NYET_Msk                         // NYET interrupt */
+#define DOEPINT_STPKTRX_Pos              (15U)
+#define DOEPINT_STPKTRX_Msk              (0x1UL << DOEPINT_STPKTRX_Pos)           // 0x00008000 */
+#define DOEPINT_STPKTRX                  DOEPINT_STPKTRX_Msk                      // Setup Packet Received */
+
+/********************  Bit definition for DOEPTSIZ register  ********************/
+#define DOEPTSIZ_XFRSIZ_Pos              (0U)
+#define DOEPTSIZ_XFRSIZ_Msk              (0x7FFFFUL << DOEPTSIZ_XFRSIZ_Pos)       // 0x0007FFFF */
+#define DOEPTSIZ_XFRSIZ                  DOEPTSIZ_XFRSIZ_Msk                      // Transfer size */
+#define DOEPTSIZ_PKTCNT_Pos              (19U)
+#define DOEPTSIZ_PKTCNT_Msk              (0x3FFUL << DOEPTSIZ_PKTCNT_Pos)         // 0x1FF80000 */
+#define DOEPTSIZ_PKTCNT                  DOEPTSIZ_PKTCNT_Msk                      // Packet count */
+
+#define DOEPTSIZ_STUPCNT_Pos             (29U)
+#define DOEPTSIZ_STUPCNT_Msk             (0x3UL << DOEPTSIZ_STUPCNT_Pos)          // 0x60000000 */
+#define DOEPTSIZ_STUPCNT                 DOEPTSIZ_STUPCNT_Msk                     // SETUP packet count */
+#define DOEPTSIZ_STUPCNT_0               (0x1UL << DOEPTSIZ_STUPCNT_Pos)          // 0x20000000 */
+#define DOEPTSIZ_STUPCNT_1               (0x2UL << DOEPTSIZ_STUPCNT_Pos)          // 0x40000000 */
+
+/********************  Bit definition for PCGCTL register  ********************/
+#define PCGCTL_IF_DEV_MODE              TU_BIT(31)
+#define PCGCTL_P2HD_PRT_SPD_MASK        (0x3ul << 29)
+#define PCGCTL_P2HD_PRT_SPD_SHIFT       29
+#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK   (0x3ul << 27)
+#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT  27
+#define PCGCTL_MAC_DEV_ADDR_MASK        (0x7ful << 20)
+#define PCGCTL_MAC_DEV_ADDR_SHIFT       20
+#define PCGCTL_MAX_TERMSEL              TU_BIT(19)
+#define PCGCTL_MAX_XCVRSELECT_MASK      (0x3ul << 17)
+#define PCGCTL_MAX_XCVRSELECT_SHIFT     17
+#define PCGCTL_PORT_POWER               TU_BIT(16)
+#define PCGCTL_PRT_CLK_SEL_MASK         (0x3ul << 14)
+#define PCGCTL_PRT_CLK_SEL_SHIFT        14
+#define PCGCTL_ESS_REG_RESTORED         TU_BIT(13)
+#define PCGCTL_EXTND_HIBER_SWITCH       TU_BIT(12)
+#define PCGCTL_EXTND_HIBER_PWRCLMP      TU_BIT(11)
+#define PCGCTL_ENBL_EXTND_HIBER         TU_BIT(10)
+#define PCGCTL_RESTOREMODE              TU_BIT(9)
+#define PCGCTL_RESETAFTSUSP             TU_BIT(8)
+#define PCGCTL_DEEP_SLEEP               TU_BIT(7)
+#define PCGCTL_PHY_IN_SLEEP             TU_BIT(6)
+#define PCGCTL_ENBL_SLEEP_GATING        TU_BIT(5)
+#define PCGCTL_RSTPDWNMODULE            TU_BIT(3)
+#define PCGCTL_PWRCLMP                  TU_BIT(2)
+#define PCGCTL_GATEHCLK                 TU_BIT(1)
+#define PCGCTL_STOPPCLK                 TU_BIT(0)
+
+#define PCGCTL1_TIMER                   (0x3ul << 1)
+#define PCGCTL1_GATEEN                  TU_BIT(0)
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_xmc.h b/src/portable/synopsys/dwc2/dwc2_xmc.h
new file mode 100644
index 0000000..4e6bebb
--- /dev/null
+++ b/src/portable/synopsys/dwc2/dwc2_xmc.h
@@ -0,0 +1,87 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Rafael Silva (@perigoso)
+ * 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 _DWC2_XMC_H_
+#define _DWC2_XMC_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#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
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_EnableIRQ(USB0_0_IRQn);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void dwc2_dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB0_0_IRQn);
+}
+
+static inline void dwc2_remote_wakeup_delay(void)
+{
+  // try to delay for 1 ms
+//  uint32_t count = SystemCoreClock / 1000;
+//  while ( count-- ) __NOP();
+}
+
+// MCU specific PHY init, called BEFORE core reset
+static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // Enable PHY
+  //USB->ROUTE = USB_ROUTE_PHYPEN;
+}
+
+// MCU specific PHY update, it is called AFTER init() and core reset
+static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type)
+{
+  (void) dwc2;
+  (void) hs_phy_type;
+
+  // XMC Manual: turn around must be 5 (reset & default value)
+  // dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/portable/synopsys/dwc2/hwcfg_list.md b/src/portable/synopsys/dwc2/hwcfg_list.md
new file mode 100644
index 0000000..b5590da
--- /dev/null
+++ b/src/portable/synopsys/dwc2/hwcfg_list.md
@@ -0,0 +1,777 @@
+# DWC2 Hardware Configuration Registers
+
+## Broadcom BCM2711 (Pi4)
+
+dwc2->guid = 2708A000
+dwc2->gsnpsid = 4F54280A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 228DDD50
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 2
+hw_cfg2->point2point = 0
+hw_cfg2->hs_phy_type = 1
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 7
+hw_cfg2->num_host_ch = 7
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 0
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = FF000E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 0
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 0
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 0
+hw_cfg3->lpm_mode = 0
+hw_cfg3->total_fifo_size = 4080
+
+dwc2->ghwcfg4 = 1FF00020
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 0
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 0
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 15
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+## EFM32GG FS
+
+dwc2->guid = 0
+dwc2->gsnpsid = 4F54330A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 228F5910
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 2
+hw_cfg2->point2point = 0
+hw_cfg2->hs_phy_type = 0
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 6
+hw_cfg2->num_host_ch = 13
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 0
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 1F204E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 0
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 1
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 0
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 0
+hw_cfg3->lpm_mode = 0
+hw_cfg3->total_fifo_size = 498
+
+dwc2->ghwcfg4 = 1BF08030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 2
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 13
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+## ESP32-S2 Fullspeed
+
+dwc2->guid = 0
+dwc2->gsnpsid = 4F54400A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 224DD930
+hw_cfg2->op_mode = 2
+hw_cfg2->arch = 3
+hw_cfg2->point2point = 0
+hw_cfg2->hs_phy_type = 1
+hw_cfg2->fs_phy_type = 2
+hw_cfg2->num_dev_ep = 6
+hw_cfg2->num_host_ch = 9
+hw_cfg2->period_channel_support = 0
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 1
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 22
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = C804B5
+hw_cfg3->xfer_size_width = 10
+hw_cfg3->packet_size_width = 5
+hw_cfg3->otg_enable = 0
+hw_cfg3->i2c_enable = 0
+hw_cfg3->vendor_ctrl_itf = 1
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 1
+hw_cfg3->otg_adp_support = 1
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 1
+hw_cfg3->lpm_mode = 0
+hw_cfg3->total_fifo_size = 23130
+
+dwc2->ghwcfg4 = D3F0A030
+hw_cfg4->num_dev_period_in_ep = 10
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 0
+hw_cfg4->hibernation = 1
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 1
+hw_cfg4->acg_enable = 1
+hw_cfg4->utmi_phy_data_width = 1
+hw_cfg4->dev_ctrl_ep_num = 10
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 0
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 0
+hw_cfg4->dedicated_fifos = 0
+hw_cfg4->num_dev_in_eps = 13
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 1
+
+## STM32F407 and STM32F207
+
+STM32F407 and STM32F207 are exactly the same
+
+### STM32F407 Fullspeed
+
+dwc2->guid = 1200
+dwc2->gsnpsid = 4F54281A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 229DCD20
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 0
+hw_cfg2->point2point = 1
+hw_cfg2->hs_phy_type = 0
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 3
+hw_cfg2->num_host_ch = 7
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 20001E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 1
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 0
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 0
+hw_cfg3->lpm_mode = 0
+hw_cfg3->total_fifo_size = 512
+
+dwc2->ghwcfg4 = FF08030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 2
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 7
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+### STM32F407 Highspeed
+
+dwc2->guid = 1100
+dwc2->gsnpsid = 4F54281A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 229ED590
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 2
+hw_cfg2->point2point = 0
+hw_cfg2->hs_phy_type = 2
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 5
+hw_cfg2->num_host_ch = 11
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 3F403E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 1
+hw_cfg3->vendor_ctrl_itf = 1
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 0
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 0
+hw_cfg3->lpm_mode = 0
+hw_cfg3->total_fifo_size = 1012
+
+dwc2->ghwcfg4 = 17F00030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 0
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 11
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+## STM32F411 Fullspeed
+
+dwc2->guid = 1200
+dwc2->gsnpsid = 4F54281A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 229DCD20
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 0
+hw_cfg2->point2point = 1
+hw_cfg2->hs_phy_type = 0
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 3
+hw_cfg2->num_host_ch = 7
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 20001E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 1
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 0
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 0
+hw_cfg3->lpm_mode = 0
+hw_cfg3->total_fifo_size = 512
+
+dwc2->ghwcfg4 = FF08030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 2
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 7
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+## STM32F412 FS
+
+dwc2->guid = 2000
+dwc2->gsnpsid = 4F54320A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 229ED520
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 0
+hw_cfg2->point2point = 1
+hw_cfg2->hs_phy_type = 0
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 5
+hw_cfg2->num_host_ch = 11
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 200D1E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 1
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 1
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 1
+hw_cfg3->lpm_mode = 1
+hw_cfg3->total_fifo_size = 512
+
+dwc2->ghwcfg4 = 17F08030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 2
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 11
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+## STM32F723
+
+### STM32F723 HighSpeed
+
+dwc2->guid = 3100
+dwc2->gsnpsid = 4F54330A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 229FE1D0
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 2
+hw_cfg2->point2point = 0
+hw_cfg2->hs_phy_type = 3
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 8
+hw_cfg2->num_host_ch = 15
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 3EED2E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 0
+hw_cfg3->vendor_ctrl_itf = 1
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 1
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 1
+hw_cfg3->lpm_mode = 1
+hw_cfg3->total_fifo_size = 1006
+
+dwc2->ghwcfg4 = 23F00030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 0
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 1
+hw_cfg4->dma_desc_enable = 1
+hw_cfg4->dma_dynamic = 0
+
+### STM32F723 Fullspeed
+
+dwc2->guid = 3000
+dwc2->gsnpsid = 4F54330A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 229ED520
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 0
+hw_cfg2->point2point = 1
+hw_cfg2->hs_phy_type = 0
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 5
+hw_cfg2->num_host_ch = 11
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 200D1E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 1
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 1
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 1
+hw_cfg3->lpm_mode = 1
+hw_cfg3->total_fifo_size = 512
+
+dwc2->ghwcfg4 = 17F08030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 2
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 11
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+## STM32F767 FS
+
+dwc2->guid = 2000
+dwc2->gsnpsid = 4F54320A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 229ED520
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 0
+hw_cfg2->point2point = 1
+hw_cfg2->hs_phy_type = 0
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 5
+hw_cfg2->num_host_ch = 11
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 200D1E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 1
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 1
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 1
+hw_cfg3->lpm_mode = 1
+hw_cfg3->total_fifo_size = 512
+
+dwc2->ghwcfg4 = 17F08030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 2
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 11
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+## STM32H743 (both cores HS)
+
+dwc2->guid = 2300
+dwc2->gsnpsid = 4F54330A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 229FE190
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 2
+hw_cfg2->point2point = 0
+hw_cfg2->hs_phy_type = 2
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 8
+hw_cfg2->num_host_ch = 15
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 3B8D2E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 0
+hw_cfg3->vendor_ctrl_itf = 1
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 1
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 1
+hw_cfg3->lpm_mode = 1
+hw_cfg3->total_fifo_size = 952
+
+dwc2->ghwcfg4 = E3F00030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 0
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 1
+hw_cfg4->dma_desc_enable = 1
+hw_cfg4->dma_dynamic = 1
+
+## STM32L476 FS
+
+dwc2->guid = 2000
+dwc2->gsnpsid = 4F54310A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 229ED520
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 0
+hw_cfg2->point2point = 1
+hw_cfg2->hs_phy_type = 0
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 5
+hw_cfg2->num_host_ch = 11
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 1
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 200D1E8
+hw_cfg3->xfer_size_width = 8
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 1
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 1
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 1
+hw_cfg3->lpm_mode = 1
+hw_cfg3->total_fifo_size = 512
+
+dwc2->ghwcfg4 = 17F08030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 2
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 11
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+## GD32VF103 Fullspeed
+
+dwc2->guid = 1000
+dwc2->gsnpsid = 0
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 0
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 0
+hw_cfg2->point2point = 0
+hw_cfg2->hs_phy_type = 0
+hw_cfg2->fs_phy_type = 0
+hw_cfg2->num_dev_ep = 0
+hw_cfg2->num_host_ch = 0
+hw_cfg2->period_channel_support = 0
+hw_cfg2->enable_dynamic_fifo = 0
+hw_cfg2->mul_cpu_int = 0
+hw_cfg2->nperiod_tx_q_depth = 0
+hw_cfg2->host_period_tx_q_depth = 0
+hw_cfg2->dev_token_q_depth = 0
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 0
+hw_cfg3->xfer_size_width = 0
+hw_cfg3->packet_size_width = 0
+hw_cfg3->otg_enable = 0
+hw_cfg3->i2c_enable = 0
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 0
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 0
+hw_cfg3->lpm_mode = 0
+hw_cfg3->total_fifo_size = 0
+
+dwc2->ghwcfg4 = 0
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 0
+hw_cfg4->ahb_freq_min = 0
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 0
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 0
+hw_cfg4->vbus_valid_filter_enabled = 0
+hw_cfg4->a_valid_filter_enabled = 0
+hw_cfg4->b_valid_filter_enabled = 0
+hw_cfg4->dedicated_fifos = 0
+hw_cfg4->num_dev_in_eps = 0
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 0
+
+## XMC4500
+
+dwc2->guid = AEC000
+dwc2->gsnpsid = 4F54292A
+dwc2->ghwcfg1 = 0
+
+dwc2->ghwcfg2 = 228F5930
+hw_cfg2->op_mode = 0
+hw_cfg2->arch = 2
+hw_cfg2->point2point = 1
+hw_cfg2->hs_phy_type = 0
+hw_cfg2->fs_phy_type = 1
+hw_cfg2->num_dev_ep = 6
+hw_cfg2->num_host_ch = 13
+hw_cfg2->period_channel_support = 1
+hw_cfg2->enable_dynamic_fifo = 1
+hw_cfg2->mul_cpu_int = 0
+hw_cfg2->nperiod_tx_q_depth = 2
+hw_cfg2->host_period_tx_q_depth = 2
+hw_cfg2->dev_token_q_depth = 8
+hw_cfg2->otg_enable_ic_usb = 0
+
+dwc2->ghwcfg3 = 27A01E5
+hw_cfg3->xfer_size_width = 5
+hw_cfg3->packet_size_width = 6
+hw_cfg3->otg_enable = 1
+hw_cfg3->i2c_enable = 1
+hw_cfg3->vendor_ctrl_itf = 0
+hw_cfg3->optional_feature_removed = 0
+hw_cfg3->synch_reset = 0
+hw_cfg3->otg_adp_support = 0
+hw_cfg3->otg_enable_hsic = 0
+hw_cfg3->battery_charger_support = 0
+hw_cfg3->lpm_mode = 0
+hw_cfg3->total_fifo_size = 634
+
+dwc2->ghwcfg4 = DBF08030
+hw_cfg4->num_dev_period_in_ep = 0
+hw_cfg4->power_optimized = 1
+hw_cfg4->ahb_freq_min = 1
+hw_cfg4->hibernation = 0
+hw_cfg4->service_interval_mode = 0
+hw_cfg4->ipg_isoc_en = 0
+hw_cfg4->acg_enable = 0
+hw_cfg4->utmi_phy_data_width = 2
+hw_cfg4->dev_ctrl_ep_num = 0
+hw_cfg4->iddg_filter_enabled = 1
+hw_cfg4->vbus_valid_filter_enabled = 1
+hw_cfg4->a_valid_filter_enabled = 1
+hw_cfg4->b_valid_filter_enabled = 1
+hw_cfg4->dedicated_fifos = 1
+hw_cfg4->num_dev_in_eps = 13
+hw_cfg4->dma_desc_enable = 0
+hw_cfg4->dma_dynamic = 1
diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c
new file mode 100644
index 0000000..9773693
--- /dev/null
+++ b/src/portable/template/dcd_template.c
@@ -0,0 +1,136 @@
+/* 
+ * 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_TUSB_MCU == OPT_MCU_NONE
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+// Initialize controller to device mode
+void dcd_init (uint8_t rhport)
+{
+  (void) rhport;
+}
+
+// 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)
+{
+  (void) rhport;
+  (void) dev_addr;
+}
+
+// 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 * ep_desc)
+{
+  (void) rhport;
+  (void) ep_desc;
+  return false;
+}
+
+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;
+  (void) ep_addr;
+  (void) buffer;
+  (void) total_bytes;
+  return false;
+}
+
+// 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;
+  (void) ep_addr;
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  (void) ep_addr;
+}
+
+#endif
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
new file mode 100644
index 0000000..3b91f27
--- /dev/null
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -0,0 +1,699 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019-2020 William D. Jones
+ * Copyright (c) 2019-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_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MSP430x5xx )
+
+#include "msp430.h"
+#include "device/dcd.h"
+
+/*------------------------------------------------------------------*/
+/* MACRO TYPEDEF CONSTANT ENUM
+ *------------------------------------------------------------------*/
+// usbpllir_mirror and usbmaintl_mirror can be added later if needed.
+static volatile uint16_t usbiepie_mirror = 0;
+static volatile uint16_t usboepie_mirror = 0;
+static volatile uint8_t usbie_mirror = 0;
+static volatile uint16_t usbpwrctl_mirror = 0;
+static bool in_isr = false;
+
+uint8_t _setup_packet[8];
+
+// Xfer control
+typedef struct
+{
+  uint8_t * buffer;
+  // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
+  uint16_t total_len;
+  uint16_t queued_len;
+  uint16_t max_size;
+  bool short_packet;
+} xfer_ctl_t;
+
+xfer_ctl_t xfer_status[8][2];
+#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
+
+// Accessing endpoint regs
+typedef volatile uint8_t * ep_regs_t;
+
+typedef enum
+{
+  CNF = 0,
+  BBAX = 1,
+  BCTX = 2,
+  BBAY = 5,
+  BCTY = 6,
+  SIZXY = 7
+} ep_regs_index_t;
+
+#define EP_REGS(epnum, dir) ((ep_regs_t) ((uintptr_t)&USBOEPCNF_1 + 64*dir + 8*(epnum - 1)))
+
+static void bus_reset(void)
+{
+  // Hardcoded into the USB core.
+  xfer_status[0][TUSB_DIR_OUT].max_size = 8;
+  xfer_status[0][TUSB_DIR_IN].max_size = 8;
+
+  USBKEYPID = USBKEY;
+
+  // Enable the control EP 0. Also enable Indication Enable- a guard flag
+  // separate from the Interrupt Enable mask.
+  USBOEPCNF_0 |= (UBME | USBIIE);
+  USBIEPCNF_0 |= (UBME | USBIIE);
+
+  // Enable interrupts for this endpoint.
+  USBOEPIE |= BIT0;
+  USBIEPIE |= BIT0;
+
+  // Clear NAK until a setup packet is received.
+  USBOEPCNT_0 &= ~NAK;
+  USBIEPCNT_0 &= ~NAK;
+
+  USBCTL |= FEN; // Enable responding to packets.
+
+  // Dedicated buffers in hardware for SETUP and EP0, no setup needed.
+  // Now safe to respond to SETUP packets.
+  USBIE |= SETUPIE;
+
+  USBKEYPID = 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/* Controller API
+ *------------------------------------------------------------------*/
+void dcd_init (uint8_t rhport)
+{
+  (void) rhport;
+
+  USBKEYPID = USBKEY;
+
+  // Enable the module (required to write config regs)!
+  USBCNF |= USB_EN;
+
+  // Reset used interrupts
+  USBOEPIE = 0;
+  USBIEPIE = 0;
+  USBIE = 0;
+  USBOEPIFG = 0;
+  USBIEPIFG = 0;
+  USBIFG = 0;
+  USBPWRCTL &= ~(VUOVLIE | VBONIE | VBOFFIE | VUOVLIFG | VBONIFG | VBOFFIFG);
+  usboepie_mirror = 0;
+  usbiepie_mirror = 0;
+  usbie_mirror = 0;
+  usbpwrctl_mirror = 0;
+
+  USBVECINT = 0;
+
+  // Enable reset and wait for it before continuing.
+  USBIE |= RSTRIE;
+
+  // Enable pullup.
+  USBCNF |= PUR_EN;
+
+  USBKEYPID = 0;
+}
+
+// There is no "USB peripheral interrupt disable" bit on MSP430, so we have
+// to save the relevant registers individually.
+// WARNING: Unlike the ARM/NVIC routines, these functions are _not_ idempotent
+// if you modified the registers saved in between calls so they don't match
+// the mirrors; mirrors will be updated to reflect most recent register
+// contents.
+void dcd_int_enable (uint8_t rhport)
+{
+  (void) rhport;
+
+  __bic_SR_register(GIE); // Unlikely to be called in ISR, but let's be safe.
+                          // Also, this cleanly disables all USB interrupts
+                          // atomically from application's POV.
+
+  // This guard is required because tinyusb can enable interrupts without
+  // having disabled them first.
+  if(in_isr)
+  {
+    USBOEPIE = usboepie_mirror;
+    USBIEPIE = usbiepie_mirror;
+    USBIE = usbie_mirror;
+    USBPWRCTL |= usbpwrctl_mirror;
+  }
+
+  in_isr = false;
+  __bis_SR_register(GIE);
+}
+
+void dcd_int_disable (uint8_t rhport)
+{
+  (void) rhport;
+
+  __bic_SR_register(GIE);
+  usboepie_mirror = USBOEPIE;
+  usbiepie_mirror = USBIEPIE;
+  usbie_mirror = USBIE;
+  usbpwrctl_mirror = (USBPWRCTL & (VUOVLIE | VBONIE | VBOFFIE));
+  USBOEPIE = 0;
+  USBIEPIE = 0;
+  USBIE = 0;
+  USBPWRCTL &= ~(VUOVLIE | VBONIE | VBOFFIE);
+  in_isr = true;
+  __bis_SR_register(GIE);
+}
+
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+  (void) rhport;
+
+  USBFUNADR = dev_addr;
+
+  // Response with status after changing device address
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  dcd_int_disable(rhport);
+
+  USBKEYPID = USBKEY;
+  USBCNF |= PUR_EN; // Enable pullup.
+  USBKEYPID = 0;
+
+  dcd_int_enable(rhport);
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  dcd_int_disable(rhport);
+
+  USBKEYPID = USBKEY;
+  USBCNF &= ~PUR_EN; // Disable pullup.
+  USBKEYPID = 0;
+
+  dcd_int_enable(rhport);
+}
+
+/*------------------------------------------------------------------*/
+/* 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);
+
+  // Unsupported endpoint numbers or type (Iso not supported. Control
+  // not supported on nonzero endpoints).
+  if( (epnum > 7) || \
+      (desc_edpt->bmAttributes.xfer == 0) || \
+      (desc_edpt->bmAttributes.xfer == 1)) {
+    return false;
+  }
+
+  xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+  xfer->max_size = tu_edpt_packet_size(desc_edpt);
+
+  // Buffer allocation scheme:
+  // For simplicity, only single buffer for now, since tinyusb currently waits
+  // for an xfer to complete before scheduling another one. This means only
+  // the X buffer is used.
+  //
+  // 1904 bytes are available, the max endpoint size supported on msp430 is
+  // 64 bytes. This is enough RAM for all 14 endpoints enabled _with_ double
+  // bufferring (64*14*2 = 1792 bytes). Extra RAM exists for triple and higher
+  // order bufferring, which must be maintained in software.
+  //
+  // For simplicity, each endpoint gets a hardcoded 64 byte chunk (regardless
+  // of actual wMaxPacketSize) whose start address is the following:
+  // addr = 128 * (epnum - 1) + 64 * dir.
+  //
+  // Double buffering equation:
+  // x_addr = 256 * (epnum - 1) + 128 * dir
+  // y_addr = x_addr + 64
+  // Address is right-shifted by 3 to fit into 8 bits.
+
+  uint8_t buf_base = (128 * (epnum - 1) + 64 * dir) >> 3;
+
+  // IN and OUT EP registers have the same structure.
+  ep_regs_t ep_regs = EP_REGS(epnum, dir);
+
+  // FIXME: I was able to get into a situation where OUT EP 3 would stall
+  // while debugging, despite stall code never being called. It appears
+  // these registers don't get cleared on reset, being part of RAM.
+  // Investigate and see if I can duplicate.
+  // Also, DBUF got set on OUT EP 2 while debugging. Only OUT EPs seem to be
+  // affected at this time. USB RAM directly precedes main RAM; perhaps I'm
+  // overwriting registers via buffer overflow w/ my debugging code?
+  ep_regs[SIZXY] = tu_edpt_packet_size(desc_edpt);
+  ep_regs[BCTX] |= NAK;
+  ep_regs[BBAX] = buf_base;
+  ep_regs[CNF] &= ~(TOGGLE | STALL | DBUF); // ISO xfers not supported on
+                           // MSP430, so no need to gate DATA0/1 and frame
+                           // behavior. Clear stall and double buffer bit as
+                           // well- see above comment.
+  ep_regs[CNF] |= (UBME | USBIIE);
+
+  USBKEYPID = USBKEY;
+  if(dir == TUSB_DIR_OUT)
+  {
+    USBOEPIE |= (1 << epnum);
+  }
+  else
+  {
+    USBIEPIE |= (1 << epnum);
+  }
+  USBKEYPID = 0;
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  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; // TODO support dcd_edpt_xfer_fifo API
+  xfer->total_len = total_bytes;
+  xfer->queued_len = 0;
+  xfer->short_packet = false;
+
+  if(epnum == 0)
+  {
+    if(dir == TUSB_DIR_OUT)
+    {
+      // Interrupt will notify us when data was received.
+      USBCTL &= ~DIR;
+      USBOEPCNT_0 &= ~NAK;
+    }
+    else
+    {
+      // Kickstart the IN packet handler by queuing initial data and calling
+      // the ISR to transmit the first packet.
+      // Interrupt only fires on completed xfer.
+      USBCTL |= DIR;
+      USBIEPIFG |= BIT0;
+    }
+  }
+  else
+  {
+    ep_regs_t ep_regs = EP_REGS(epnum, dir);
+
+    if(dir == TUSB_DIR_OUT)
+    {
+      ep_regs[BCTX] &= ~NAK;
+    }
+    else
+    {
+      USBIEPIFG |= (1 << epnum);
+    }
+  }
+
+  return true;
+}
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+  (void) rhport;
+
+  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;
+  xfer->queued_len = 0;
+  xfer->short_packet = false;
+
+  ep_regs_t ep_regs = EP_REGS(epnum, dir);
+
+  if(dir == TUSB_DIR_OUT)
+  {
+    ep_regs[BCTX] &= ~NAK;
+  }
+  else
+  {
+    USBIEPIFG |= (1 << epnum);
+  }
+
+  return true;
+}
+#endif
+
+void dcd_edpt_stall (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(epnum == 0)
+  {
+    if(dir == TUSB_DIR_OUT)
+    {
+      USBOEPCNT_0 |= NAK;
+      USBOEPCNF_0 |= STALL;
+    }
+    else
+    {
+      USBIEPCNT_0 |= NAK;
+      USBIEPCNF_0 |= STALL;
+    }
+  }
+  else
+  {
+    ep_regs_t ep_regs = EP_REGS(epnum, dir);
+    ep_regs[CNF] |= STALL;
+  }
+}
+
+void dcd_edpt_clear_stall (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(epnum == 0)
+  {
+    if(dir == TUSB_DIR_OUT)
+    {
+      USBOEPCNF_0 &= ~STALL;
+    }
+    else
+    {
+      USBIEPCNF_0 &= ~STALL;
+    }
+  }
+  else
+  {
+    ep_regs_t ep_regs = EP_REGS(epnum, dir);
+    // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt
+    // and bulk endpoints.
+    ep_regs[CNF] &= ~(STALL + TOGGLE);
+  }
+}
+
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
+{
+  (void) rhport;
+  (void) request;
+
+  // FIXME: Per manual, we should be clearing the NAK bits of EP0 after the
+  // Status Phase of a control xfer is done, in preparation of another possible
+  // SETUP packet. However, from my own testing, SETUP packets _are_ correctly
+  // handled by the USB core without clearing the NAKs.
+  //
+  // Right now, clearing NAKs in this callbacks causes a direction mismatch
+  // between host and device on EP0. Figure out why and come back to this.
+  // USBOEPCNT_0 &= ~NAK;
+  // USBIEPCNT_0 &= ~NAK;
+}
+
+/*------------------------------------------------------------------*/
+
+static void receive_packet(uint8_t ep_num)
+{
+  xfer_ctl_t * xfer = XFER_CTL_BASE(ep_num, TUSB_DIR_OUT);
+  ep_regs_t ep_regs = EP_REGS(ep_num, TUSB_DIR_OUT);
+  uint8_t xfer_size;
+
+  if(ep_num == 0)
+  {
+    xfer_size = USBOEPCNT_0 & 0x0F;
+  }
+  else
+  {
+    xfer_size = ep_regs[BCTX] & 0x7F;
+  }
+
+  uint16_t remaining = xfer->total_len - xfer->queued_len;
+  uint16_t to_recv_size;
+
+  if(remaining <= xfer->max_size) {
+    // Avoid buffer overflow.
+    to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
+  } else {
+    // Room for full packet, choose recv_size based on what the microcontroller
+    // claims.
+    to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
+  }
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+  if (xfer->ff)
+  {
+    volatile uint8_t * ep_buf = (ep_num == 0) ? &USBOEP0BUF : (&USBSTABUFF + (ep_regs[BBAX] << 3));
+    tu_fifo_write_n(xfer->ff, (const void *) ep_buf, to_recv_size);
+  }
+  else
+#endif
+  {
+    uint8_t * base = (xfer->buffer + xfer->queued_len);
+
+    if(ep_num == 0)
+    {
+      volatile uint8_t * ep0out_buf = &USBOEP0BUF;
+      for(uint16_t i = 0; i < to_recv_size; i++)
+      {
+        base[i] = ep0out_buf[i];
+      }
+    }
+    else
+    {
+      volatile uint8_t * ep_buf = &USBSTABUFF + (ep_regs[BBAX] << 3);
+      for(uint16_t i = 0; i < to_recv_size ; i++)
+      {
+        base[i] = ep_buf[i];
+      }
+    }
+  }
+
+  xfer->queued_len += xfer_size;
+
+  xfer->short_packet = (xfer_size < xfer->max_size);
+  if((xfer->total_len == xfer->queued_len) || xfer->short_packet)
+  {
+    dcd_event_xfer_complete(0, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+  }
+  else
+  {
+    // Schedule to receive another packet.
+    if(ep_num == 0)
+    {
+      USBOEPCNT_0 &= ~NAK;
+    }
+    else
+    {
+      ep_regs[BCTX] &= ~NAK;
+    }
+  }
+}
+
+static void transmit_packet(uint8_t ep_num)
+{
+  xfer_ctl_t * xfer = XFER_CTL_BASE(ep_num, TUSB_DIR_IN);
+
+  // First, determine whether we should even send a packet or finish
+  // up the xfer.
+  bool zlp = (xfer->total_len == 0); // By necessity, xfer->total_len will
+                                     // equal xfer->queued_len for ZLPs.
+                                     // Of course a ZLP is a short packet.
+  if((!zlp && (xfer->total_len == xfer->queued_len)) || xfer->short_packet)
+  {
+    dcd_event_xfer_complete(0, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+    return;
+  }
+
+  // Then actually commit to transmit a packet.
+  uint8_t * base = (xfer->buffer + xfer->queued_len);
+  uint16_t remaining = xfer->total_len - xfer->queued_len;
+  uint8_t xfer_size = (xfer->max_size < xfer->total_len) ? xfer->max_size : remaining;
+
+  xfer->queued_len += xfer_size;
+  if(xfer_size < xfer->max_size)
+  {
+    // Next "xfer complete interrupt", the transfer will end.
+    xfer->short_packet = true;
+  }
+
+  if(ep_num == 0)
+  {
+    volatile uint8_t * ep0in_buf = &USBIEP0BUF;
+    for(uint16_t i = 0; i < xfer_size; i++)
+    {
+      ep0in_buf[i] = base[i];
+    }
+
+    USBIEPCNT_0 = (USBIEPCNT_0 & 0xF0) + xfer_size;
+    USBIEPCNT_0 &= ~NAK;
+  }
+  else
+  {
+    ep_regs_t ep_regs = EP_REGS(ep_num, TUSB_DIR_IN);
+    volatile uint8_t * ep_buf = &USBSTABUFF + (ep_regs[BBAX] << 3);
+
+#if 0 // TODO support dcd_edpt_xfer_fifo API
+    if (xfer->ff)
+    {
+      tu_fifo_read_n(xfer->ff, (void *) ep_buf, xfer_size);
+    }
+    else
+#endif
+    {
+      for(int i = 0; i < xfer_size; i++)
+      {
+        ep_buf[i] = base[i];
+      }
+    }
+
+    ep_regs[BCTX] = (ep_regs[BCTX] & 0x80) + (xfer_size & 0x7F);
+    ep_regs[BCTX] &= ~NAK;
+  }
+}
+
+static void handle_setup_packet(void)
+{
+  volatile uint8_t * setup_buf = &USBSUBLK;
+
+  for(int i = 0; i < 8; i++)
+  {
+    _setup_packet[i] = setup_buf[i];
+  }
+
+  // Clearing SETUPIFG by reading USBVECINT does not set NAK, so now that we
+  // have a SETUP packet, force NAKs until tinyusb can handle the SETUP
+  // packet and prepare for a new xfer.
+  USBIEPCNT_0 |= NAK;
+  USBOEPCNT_0 |= NAK;
+  dcd_event_setup_received(0, (uint8_t*) &_setup_packet[0], true);
+}
+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void) rhport;
+
+  // Setup is special- reading USBVECINT to handle setup packets is done to
+  // stop hardware-generated NAKs on EP0.
+  uint8_t setup_status = USBIFG & SETUPIFG;
+
+  if(setup_status)
+  {
+    handle_setup_packet();
+  }
+
+  uint16_t curr_vector = USBVECINT;
+
+  switch(curr_vector)
+  {
+    case USBVECINT_RSTR:
+      bus_reset();
+      dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+      break;
+
+    // Clear the (hardware-enforced) NAK on EP 0 after a SETUP packet
+    // is received. At this point, even though the hardware is no longer
+    // forcing NAKs, the EP0 NAK bits should still be set to avoid
+    // sending/receiving data before tinyusb is ready.
+    //
+    // Furthermore, it's possible for the hardware to STALL in the middle of
+    // a control xfer if the EP0 NAK bits aren't set properly.
+    // See: https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/845259
+    // From my testing, if all of the following hold:
+    // * OUT EP0 NAK is cleared.
+    // * IN EP0 NAK is set.
+    // * DIR bit in USBCTL is clear.
+    // and an IN packet is received on EP0, the USB core will STALL. Setting
+    // both EP0 NAKs manually when a SETUP packet is received, as is done
+    // in handle_setup_packet(), avoids meeting STALL conditions.
+    //
+    // TODO: Figure out/explain why the STALL condition can be reached in the
+    // first place. When I first noticed the STALL, the only two places I
+    // touched the NAK bits were in dcd_edpt_xfer() and to _set_ (sic) them in
+    // bus_reset(). SETUP packet handling should've been unaffected.
+    case USBVECINT_SETUP_PACKET_RECEIVED:
+      break;
+
+    case USBVECINT_INPUT_ENDPOINT0:
+      transmit_packet(0);
+      break;
+
+    case USBVECINT_OUTPUT_ENDPOINT0:
+      receive_packet(0);
+      break;
+
+    case USBVECINT_INPUT_ENDPOINT1:
+    case USBVECINT_INPUT_ENDPOINT2:
+    case USBVECINT_INPUT_ENDPOINT3:
+    case USBVECINT_INPUT_ENDPOINT4:
+    case USBVECINT_INPUT_ENDPOINT5:
+    case USBVECINT_INPUT_ENDPOINT6:
+    case USBVECINT_INPUT_ENDPOINT7:
+    {
+      uint8_t ep = ((curr_vector - USBVECINT_INPUT_ENDPOINT1) >> 1) + 1;
+      transmit_packet(ep);
+    }
+    break;
+
+    case USBVECINT_OUTPUT_ENDPOINT1:
+    case USBVECINT_OUTPUT_ENDPOINT2:
+    case USBVECINT_OUTPUT_ENDPOINT3:
+    case USBVECINT_OUTPUT_ENDPOINT4:
+    case USBVECINT_OUTPUT_ENDPOINT5:
+    case USBVECINT_OUTPUT_ENDPOINT6:
+    case USBVECINT_OUTPUT_ENDPOINT7:
+    {
+      uint8_t ep = ((curr_vector - USBVECINT_OUTPUT_ENDPOINT1) >> 1) + 1;
+      receive_packet(ep);
+    }
+    break;
+
+    default:
+      while(true);
+      break;
+  }
+
+}
+
+#endif
diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c
new file mode 100644
index 0000000..51fb8b4
--- /dev/null
+++ b/src/portable/valentyusb/eptri/dcd_eptri.c
@@ -0,0 +1,649 @@
+/* 
+ * 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 TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+#ifndef LOG_USB
+#define LOG_USB 0
+#endif
+
+#include "device/dcd.h"
+#include "dcd_eptri.h"
+#include "csr.h"
+#include "irq.h"
+void fomu_error(uint32_t line);
+
+#if LOG_USB
+struct usb_log {
+  uint8_t ep_num;
+  uint8_t size;
+  uint8_t data[66];
+};
+__attribute__((used))
+struct usb_log usb_log[128];
+__attribute__((used))
+uint8_t usb_log_offset;
+
+struct xfer_log {
+  uint8_t ep_num;
+  uint16_t size;
+};
+__attribute__((used))
+struct xfer_log xfer_log[64];
+__attribute__((used))
+uint8_t xfer_log_offset;
+
+__attribute__((used))
+struct xfer_log queue_log[64];
+__attribute__((used))
+uint8_t queue_log_offset;
+#endif
+
+//--------------------------------------------------------------------+
+// SIE Command
+//--------------------------------------------------------------------+
+
+#define EP_SIZE 64
+
+uint16_t volatile rx_buffer_offset[16];
+uint8_t* volatile rx_buffer[16];
+uint16_t volatile rx_buffer_max[16];
+
+volatile uint8_t tx_ep;
+volatile bool tx_active;
+volatile uint16_t tx_buffer_offset[16];
+uint8_t* volatile tx_buffer[16];
+volatile uint16_t tx_buffer_max[16];
+volatile uint8_t reset_count;
+
+#if DEBUG
+__attribute__((used)) uint8_t volatile * last_tx_buffer;
+__attribute__((used)) volatile uint8_t last_tx_ep;
+uint8_t setup_packet_bfr[10];
+#endif
+
+//--------------------------------------------------------------------+
+// PIPE HELPER
+//--------------------------------------------------------------------+
+
+static bool advance_tx_ep(void) {
+  // Move on to the next transmit buffer in a round-robin manner
+  uint8_t prev_tx_ep = tx_ep;
+  for (tx_ep = (tx_ep + 1) & 0xf; tx_ep != prev_tx_ep; tx_ep = ((tx_ep + 1) & 0xf)) {
+    if (tx_buffer[tx_ep])
+      return true;
+  }
+  if (!tx_buffer[tx_ep])
+    return false;
+  return true;
+}
+
+#if LOG_USB
+void xfer_log_append(uint8_t ep_num, uint16_t sz) {
+  xfer_log[xfer_log_offset].ep_num = ep_num;
+  xfer_log[xfer_log_offset].size = sz;
+  xfer_log_offset++;
+  if (xfer_log_offset >= sizeof(xfer_log)/sizeof(*xfer_log))
+    xfer_log_offset = 0;
+}
+
+void queue_log_append(uint8_t ep_num, uint16_t sz) {
+  queue_log[queue_log_offset].ep_num = ep_num;
+  queue_log[queue_log_offset].size = sz;
+  queue_log_offset++;
+  if (queue_log_offset >= sizeof(queue_log)/sizeof(*queue_log))
+    queue_log_offset = 0;
+}
+#endif
+
+static void tx_more_data(void) {
+  // Send more data
+  uint8_t added_bytes;
+  for (added_bytes = 0; (added_bytes < EP_SIZE) && (tx_buffer_offset[tx_ep] < tx_buffer_max[tx_ep]); added_bytes++) {
+#if LOG_USB
+    usb_log[usb_log_offset].data[added_bytes] = tx_buffer[tx_ep][tx_buffer_offset[tx_ep]];
+#endif
+    usb_in_data_write(tx_buffer[tx_ep][tx_buffer_offset[tx_ep]++]);
+  }
+
+#if LOG_USB
+  usb_log[usb_log_offset].ep_num = tu_edpt_addr(tx_ep, TUSB_DIR_IN);
+  usb_log[usb_log_offset].size = added_bytes;
+  usb_log_offset++;
+  if (usb_log_offset >= sizeof(usb_log)/sizeof(*usb_log))
+    usb_log_offset = 0;
+#endif
+
+  // Updating the epno queues the data
+  usb_in_ctrl_write(tx_ep & 0xf);
+}
+
+static void process_tx(void) {
+#if DEBUG
+  // If the system isn't idle, then something is very wrong.
+  uint8_t in_status = usb_in_status_read();
+  if (!(in_status & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET)))
+    fomu_error(__LINE__);
+#endif
+
+  // If the buffer is now empty, search for the next buffer to fill.
+  if (!tx_buffer[tx_ep]) {
+    if (advance_tx_ep())
+      tx_more_data();
+    else
+      tx_active = false;
+    return;
+  }
+
+  if (tx_buffer_offset[tx_ep] >= tx_buffer_max[tx_ep]) {
+#if DEBUG
+    last_tx_buffer = tx_buffer[tx_ep];
+    last_tx_ep = tx_ep;
+#endif
+    tx_buffer[tx_ep] = NULL;
+    uint16_t xferred_bytes = tx_buffer_max[tx_ep];
+    uint8_t xferred_ep = tx_ep;
+
+    if (!advance_tx_ep())
+      tx_active = false;
+#if LOG_USB
+    xfer_log_append(tu_edpt_addr(xferred_ep, TUSB_DIR_IN), xferred_bytes);
+#endif
+    dcd_event_xfer_complete(0, tu_edpt_addr(xferred_ep, TUSB_DIR_IN), xferred_bytes, XFER_RESULT_SUCCESS, true);
+    if (!tx_active)
+      return;
+  }
+
+  tx_more_data();
+  return;
+}
+
+static void process_rx(void) {
+  uint8_t out_status = usb_out_status_read();
+#if DEBUG
+  // If the OUT handler is still waiting to send, don't do anything.
+  if (!(out_status & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)))
+    fomu_error(__LINE__);
+    // return;
+#endif
+  uint8_t rx_ep = (out_status >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf;
+
+  // If the destination buffer doesn't exist, don't drain the hardware
+  // fifo.  Note that this can cause deadlocks if the host is waiting
+  // on some other endpoint's data!
+#if DEBUG
+  if (rx_buffer[rx_ep] == NULL) {
+    fomu_error(__LINE__);
+    return;
+  }
+#endif
+
+  // Drain the FIFO into the destination buffer
+  uint32_t total_read = 0;
+  uint32_t current_offset = rx_buffer_offset[rx_ep];
+#if DEBUG
+  uint8_t test_buffer[256];
+  memset(test_buffer, 0, sizeof(test_buffer));
+  if (current_offset > rx_buffer_max[rx_ep])
+    fomu_error(__LINE__);
+#endif
+#if LOG_USB
+  usb_log[usb_log_offset].ep_num = tu_edpt_addr(rx_ep, TUSB_DIR_OUT);
+  usb_log[usb_log_offset].size = 0;
+#endif
+  while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) {
+    uint8_t c = usb_out_data_read();
+#if DEBUG
+    test_buffer[total_read] = c;
+#endif
+    total_read++;
+    if (current_offset < rx_buffer_max[rx_ep]) {
+#if LOG_USB
+      usb_log[usb_log_offset].data[usb_log[usb_log_offset].size++] = c;
+#endif
+      if (rx_buffer[rx_ep] != (volatile uint8_t *)0xffffffff)
+        rx_buffer[rx_ep][current_offset++] = c;
+    }
+  }
+#if LOG_USB
+  usb_log_offset++;
+  if (usb_log_offset >= sizeof(usb_log)/sizeof(*usb_log))
+    usb_log_offset = 0;
+#endif
+#if DEBUG
+  if (total_read > 66)
+    fomu_error(__LINE__);
+  if (total_read < 2)
+    total_read = 2;
+    // fomu_error(__LINE__);
+#endif
+
+  // Strip off the CRC16
+  rx_buffer_offset[rx_ep] += (total_read - 2);
+  if (rx_buffer_offset[rx_ep] > rx_buffer_max[rx_ep])
+    rx_buffer_offset[rx_ep] = rx_buffer_max[rx_ep];
+
+  // If there's no more data, complete the transfer to tinyusb
+  if ((rx_buffer_max[rx_ep] == rx_buffer_offset[rx_ep])
+  // ZLP with less than the total amount of data
+  || ((total_read == 2) && ((rx_buffer_offset[rx_ep] & 63) == 0))
+  // Short read, but not a full packet
+  || (((rx_buffer_offset[rx_ep] & 63) != 0) && (total_read < 66))) {
+#if DEBUG
+    if (rx_buffer[rx_ep] == NULL)
+      fomu_error(__LINE__);
+#endif
+
+    // Free up this buffer.
+    rx_buffer[rx_ep] = NULL;
+    uint16_t len = rx_buffer_offset[rx_ep];
+
+#if DEBUG
+    // Validate that all enabled endpoints have buffers,
+    // and no disabled endpoints have buffers.
+    uint16_t ep_en_mask = usb_out_enable_status_read();
+    int i;
+    for (i = 0; i < 16; i++) {
+      if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) {
+        uint8_t new_status = usb_out_status_read();
+        // Another IRQ came in while we were processing, so ignore this endpoint.
+        if ((new_status & 0x20) && ((new_status & 0xf) == i))
+          continue;
+        fomu_error(__LINE__);
+      }
+    }
+#endif
+#if LOG_USB
+    xfer_log_append(tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len);
+#endif
+    dcd_event_xfer_complete(0, tu_edpt_addr(rx_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, true);
+  }
+  else {
+    // If there's more data, re-enable data reception on this endpoint
+    usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | rx_ep);
+  }
+
+  // Now that the buffer is drained, clear the pending IRQ.
+  usb_out_ev_pending_write(usb_out_ev_pending_read());
+}
+
+//--------------------------------------------------------------------+
+// CONTROLLER API
+//--------------------------------------------------------------------+
+
+static void dcd_reset(void)
+{
+  reset_count++;
+  usb_setup_ev_enable_write(0);
+  usb_in_ev_enable_write(0);
+  usb_out_ev_enable_write(0);
+
+  usb_address_write(0);
+
+  // Reset all three FIFO handlers
+  usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET);
+  usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET);
+  usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET);
+
+  memset((void *)(uintptr_t) rx_buffer, 0, sizeof(rx_buffer));
+  memset((void *)(uintptr_t) rx_buffer_max, 0, sizeof(rx_buffer_max));
+  memset((void *)(uintptr_t) rx_buffer_offset, 0, sizeof(rx_buffer_offset));
+
+  memset((void *)(uintptr_t) tx_buffer, 0, sizeof(tx_buffer));
+  memset((void *)(uintptr_t) tx_buffer_max, 0, sizeof(tx_buffer_max));
+  memset((void *)(uintptr_t) tx_buffer_offset, 0, sizeof(tx_buffer_offset));
+  tx_ep = 0;
+  tx_active = false;
+
+  // Enable all event handlers and clear their contents
+  usb_setup_ev_pending_write(0xff);
+  usb_in_ev_pending_write(0xff);
+  usb_out_ev_pending_write(0xff);
+  usb_in_ev_enable_write(1);
+  usb_out_ev_enable_write(1);
+  usb_setup_ev_enable_write(3);
+
+  dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+}
+
+// Initializes the USB peripheral for device mode and enables it.
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  usb_pullup_out_write(0);
+
+  // Enable all event handlers and clear their contents
+  usb_setup_ev_pending_write(usb_setup_ev_pending_read());
+  usb_in_ev_pending_write(usb_in_ev_pending_read());
+  usb_out_ev_pending_write(usb_out_ev_pending_read());
+  usb_in_ev_enable_write(1);
+  usb_out_ev_enable_write(1);
+  usb_setup_ev_enable_write(3);
+
+  // Turn on the external pullup
+  usb_pullup_out_write(1);
+}
+
+// Enables or disables the USB device interrupt(s). May be used to
+// prevent concurrency issues when mutating data structures shared
+// between main code and the interrupt handler.
+void dcd_int_enable(uint8_t rhport)
+{
+  (void) rhport;
+	irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
+}
+
+// Called when the device is given a new bus address.
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  // Respond with ACK status first before changing device address
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+
+  // Wait for the response packet to get sent
+  while (tx_active)
+    ;
+
+  // Activate the new address
+  usb_address_write(dev_addr);
+}
+
+// Called to remote wake up host when suspended (e.g hid keyboard)
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  usb_pullup_out_write(1);
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  usb_pullup_out_write(0);
+}
+
+
+//--------------------------------------------------------------------+
+// DCD Endpoint Port
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
+{
+  (void) rhport;
+  uint8_t ep_num = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+  uint8_t ep_dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+
+  if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
+    return false; // Not supported
+
+  if (ep_dir == TUSB_DIR_OUT) {
+    rx_buffer_offset[ep_num] = 0;
+    rx_buffer_max[ep_num] = 0;
+    rx_buffer[ep_num] = NULL;
+  }
+
+  else if (ep_dir == TUSB_DIR_IN) {
+    tx_buffer_offset[ep_num] = 0;
+    tx_buffer_max[ep_num] = 0;
+    tx_buffer[ep_num] = NULL;
+  }
+
+  return true;
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+  (void) rhport;
+  // TODO implement dcd_edpt_close_all()
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) {
+    uint8_t enable = 0;
+    if (rx_buffer[ep_addr])
+      enable = 1;
+    usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_STALL_OFFSET) | (enable << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | tu_edpt_number(ep_addr));
+  }
+  else
+    usb_in_ctrl_write((1 << CSR_USB_IN_CTRL_STALL_OFFSET) | tu_edpt_number(ep_addr));
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) {
+    uint8_t enable = 0;
+    if (rx_buffer[ep_addr])
+      enable = 1;
+    usb_out_ctrl_write((0 << CSR_USB_OUT_CTRL_STALL_OFFSET) | (enable << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | tu_edpt_number(ep_addr));
+  }
+  // IN endpoints will get unstalled when more data is written.
+}
+
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+  (void)rhport;
+  uint8_t ep_num = tu_edpt_number(ep_addr);
+  uint8_t ep_dir = tu_edpt_dir(ep_addr);
+  TU_ASSERT(ep_num < 16);
+
+  // Give a nonzero buffer when we transmit 0 bytes, so that the
+  // system doesn't think the endpoint is idle.
+  if ((buffer == NULL) && (total_bytes == 0)) {
+    buffer = (uint8_t *)0xffffffff;
+  }
+
+  TU_ASSERT(buffer != NULL);
+
+  if (ep_dir == TUSB_DIR_IN) {
+    // Wait for the tx pipe to free up
+    uint8_t previous_reset_count = reset_count;
+    // Continue until the buffer is empty, the system is idle, and the fifo is empty.
+    while (tx_buffer[ep_num] != NULL)
+      ;
+
+    dcd_int_disable(0);
+#if LOG_USB
+    queue_log_append(ep_addr, total_bytes);
+#endif
+    // If a reset happens while we're waiting, abort the transfer
+    if (previous_reset_count != reset_count)
+      return true;
+
+    TU_ASSERT(tx_buffer[ep_num] == NULL);
+    tx_buffer_offset[ep_num] = 0;
+    tx_buffer_max[ep_num] = total_bytes;
+    tx_buffer[ep_num] = buffer;
+
+    // If the current buffer is NULL, then that means the tx logic is idle.
+    // Update the tx_ep to point to our endpoint number and queue the data.
+    // Otherwise, let it be and it'll get picked up after the next transfer
+    // finishes.
+    if (!tx_active) {
+      tx_ep = ep_num;
+      tx_active = true;
+      tx_more_data();
+    }
+    dcd_int_enable(0);
+  }
+
+  else if (ep_dir == TUSB_DIR_OUT) {
+    while (rx_buffer[ep_num] != NULL)
+      ;
+
+    TU_ASSERT(rx_buffer[ep_num] == NULL);
+    dcd_int_disable(0);
+#if LOG_USB
+    queue_log_append(ep_addr, total_bytes);
+#endif
+    rx_buffer[ep_num] = buffer;
+    rx_buffer_offset[ep_num] = 0;
+    rx_buffer_max[ep_num] = total_bytes;
+
+    // Enable receiving on this particular endpoint
+    usb_out_ctrl_write((1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET) | ep_num);
+#if DEBUG
+    uint16_t ep_en_mask = usb_out_enable_status_read();
+    int i;
+    for (i = 0; i < 16; i++) {
+      if ((!!(ep_en_mask & (1 << i))) ^ (!!(rx_buffer[i]))) {
+        if (rx_buffer[i] && usb_out_ev_pending_read() && (usb_out_status_read() & 0xf) == i)
+          continue;
+        fomu_error(__LINE__);
+      }
+    }
+#endif
+    dcd_int_enable(0);
+  }
+  return true;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+
+static void handle_out(void)
+{
+  // An "OUT" transaction just completed so we have new data.
+  // (But only if we can accept the data)
+#if DEBUG
+  if (!usb_out_ev_pending_read())
+    fomu_error(__LINE__);
+  if (!usb_out_ev_enable_read())
+    fomu_error(__LINE__);
+#endif
+  process_rx();
+}
+
+static void handle_in(void)
+{
+#if DEBUG
+  if (!usb_in_ev_pending_read())
+    fomu_error(__LINE__);
+  if (!usb_in_ev_enable_read())
+    fomu_error(__LINE__);
+#endif
+  usb_in_ev_pending_write(usb_in_ev_pending_read());
+  process_tx();
+}
+
+static void handle_reset(void)
+{
+#if DEBUG
+  uint8_t setup_pending   = usb_setup_ev_pending_read() & usb_setup_ev_enable_read();
+  if (!(setup_pending & 2))
+    fomu_error(__LINE__);
+#endif
+  usb_setup_ev_pending_write(2);
+
+  // This event means a bus reset occurred.  Reset everything, and
+  // abandon any further processing.
+  dcd_reset();
+}
+
+static void handle_setup(void)
+{
+#if !DEBUG
+  uint8_t setup_packet_bfr[10];
+#endif
+
+#if DEBUG
+  uint8_t setup_pending   = usb_setup_ev_pending_read() & usb_setup_ev_enable_read();
+  if (!(setup_pending & 1))
+    fomu_error(__LINE__);
+#endif
+
+  // We got a SETUP packet.  Copy it to the setup buffer and clear
+  // the "pending" bit.
+  // Setup packets are always 8 bytes, plus two bytes of crc16.
+  uint32_t setup_length = 0;
+
+#if DEBUG
+  if (!(usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET)))
+    fomu_error(__LINE__);
+#endif
+
+  while (usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET)) {
+    uint8_t c = usb_setup_data_read();
+    if (setup_length < sizeof(setup_packet_bfr))
+      setup_packet_bfr[setup_length] = c;
+    setup_length++;
+  }
+
+  // If we have 10 bytes, that's a full SETUP packet plus CRC16.
+  // Otherwise, it was an RX error.
+  if (setup_length == 10) {
+    dcd_event_setup_received(0, setup_packet_bfr, true);
+  }
+#if DEBUG
+  else {
+    fomu_error(__LINE__);
+  }
+#endif
+
+  usb_setup_ev_pending_write(1);
+}
+void dcd_int_handler(uint8_t rhport)
+{
+  (void)rhport;
+  uint8_t next_ev;
+  while ((next_ev = usb_next_ev_read())) {
+    switch (next_ev) {
+    case 1 << CSR_USB_NEXT_EV_IN_OFFSET:
+      handle_in();
+      break;
+    case 1 << CSR_USB_NEXT_EV_OUT_OFFSET:
+      handle_out();
+      break;
+    case 1 << CSR_USB_NEXT_EV_SETUP_OFFSET:
+      handle_setup();
+      break;
+    case 1 << CSR_USB_NEXT_EV_RESET_OFFSET:
+      handle_reset();
+      break;
+    }
+  }
+}
+
+#endif
diff --git a/src/portable/valentyusb/eptri/dcd_eptri.h b/src/portable/valentyusb/eptri/dcd_eptri.h
new file mode 100644
index 0000000..0fa6ecc
--- /dev/null
+++ b/src/portable/valentyusb/eptri/dcd_eptri.h
@@ -0,0 +1,39 @@
+/* 
+ * 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.
+ */
+
+#ifndef _TUSB_DCD_VALENTYUSB_EPTRI_H_
+#define _TUSB_DCD_VALENTYUSB_EPTRI_H_
+
+#include "common/tusb_common.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_DCD_VALENTYUSB_EPTRI_H_ */
diff --git a/src/tusb.c b/src/tusb.c
new file mode 100644
index 0000000..9583f50
--- /dev/null
+++ b/src/tusb.c
@@ -0,0 +1,245 @@
+/*
+ * 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 TUSB_OPT_HOST_ENABLED || TUSB_OPT_DEVICE_ENABLED
+
+#include "tusb.h"
+
+// TODO clean up
+#if TUSB_OPT_DEVICE_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
+#endif
+
+#if TUSB_OPT_HOST_ENABLED
+  TU_ASSERT( tuh_init(TUH_OPT_RHPORT) ); // init host stack
+#endif
+
+  return true;
+}
+
+bool tusb_inited(void)
+{
+  bool ret = false;
+
+#if TUSB_OPT_DEVICE_ENABLED
+  ret = ret || tud_inited();
+#endif
+
+#if TUSB_OPT_HOST_ENABLED
+  ret = ret || tuh_inited();
+#endif
+
+  return ret;
+}
+
+//--------------------------------------------------------------------+
+// Internal Helper for both Host and Device stack
+//--------------------------------------------------------------------+
+
+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);
+  TU_LOG2("  Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size);
+
+  switch (desc_ep->bmAttributes.xfer)
+  {
+    case TUSB_XFER_ISOCHRONOUS:
+    {
+      uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 1023);
+      TU_ASSERT(max_packet_size <= spec_size);
+    }
+    break;
+
+    case TUSB_XFER_BULK:
+      if (speed == TUSB_SPEED_HIGH)
+      {
+        // Bulk highspeed must be EXACTLY 512
+        TU_ASSERT(max_packet_size == 512);
+      }else
+      {
+        // TODO Bulk fullspeed can only be 8, 16, 32, 64
+        TU_ASSERT(max_packet_size <= 64);
+      }
+    break;
+
+    case TUSB_XFER_INTERRUPT:
+    {
+      uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 64);
+      TU_ASSERT(max_packet_size <= spec_size);
+    }
+    break;
+
+    default: return false;
+  }
+
+  return true;
+}
+
+void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, uint8_t driver_id)
+{
+  uint8_t const* p_desc = (uint8_t const*) desc_itf;
+  uint8_t const* desc_end = p_desc + desc_len;
+
+  while( p_desc < desc_end )
+  {
+    if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
+    {
+      uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress;
+
+      TU_LOG(2, "  Bind EP %02x to driver id %u\r\n", ep_addr, driver_id);
+      ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id;
+    }
+
+    p_desc = tu_desc_next(p_desc);
+  }
+}
+
+uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len)
+{
+  uint8_t const* p_desc = (uint8_t const*) desc_itf;
+  uint16_t len = 0;
+
+  while (itf_count--)
+  {
+    // Next on interface desc
+    len += tu_desc_len(desc_itf);
+    p_desc = tu_desc_next(p_desc);
+
+    while (len < max_len)
+    {
+      // return on IAD regardless of itf count
+      if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len;
+
+      if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) &&
+           ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 )
+      {
+        break;
+      }
+
+      len += tu_desc_len(p_desc);
+      p_desc = tu_desc_next(p_desc);
+    }
+  }
+
+  return len;
+}
+
+/*------------------------------------------------------------------*/
+/* Debug
+ *------------------------------------------------------------------*/
+#if CFG_TUSB_DEBUG
+#include <ctype.h>
+
+char const* const tusb_strerr[TUSB_ERROR_COUNT] = { ERROR_TABLE(ERROR_STRING) };
+
+static void dump_str_line(uint8_t const* buf, uint16_t count)
+{
+  tu_printf("  |");
+
+  // each line is 16 bytes
+  for(uint16_t i=0; i<count; i++)
+  {
+    const char ch = buf[i];
+    tu_printf("%c", isprint(ch) ? ch : '.');
+  }
+
+  tu_printf("|\r\n");
+}
+
+/* Print out memory contents
+ *  - buf   : buffer
+ *  - count : number of item
+ *  - indent: prefix spaces on every line
+ */
+void tu_print_mem(void const *buf, uint32_t count, uint8_t indent)
+{
+  uint8_t const size = 1; // fixed 1 byte for now
+
+  if ( !buf || !count )
+  {
+    tu_printf("NULL\r\n");
+    return;
+  }
+
+  uint8_t const *buf8 = (uint8_t const *) buf;
+
+  char format[] = "%00X";
+  format[2] += 2*size;
+
+  const uint8_t item_per_line  = 16 / size;
+
+  for(unsigned int i=0; i<count; i++)
+  {
+    unsigned int value=0;
+
+    if ( i%item_per_line == 0 )
+    {
+      // Print Ascii
+      if ( i != 0 )
+      {
+        dump_str_line(buf8-16, 16);
+      }
+
+      for(uint8_t s=0; s < indent; s++) tu_printf(" ");
+
+      // print offset or absolute address
+      tu_printf("%04X: ", 16*i/item_per_line);
+    }
+
+    memcpy(&value, buf8, size);
+    buf8 += size;
+
+    tu_printf(" ");
+    tu_printf(format, value);
+  }
+
+  // fill up last row to 16 for printing ascii
+  const uint32_t remain = count%16;
+  uint8_t nback = (remain ? remain : 16);
+
+  if ( remain )
+  {
+    for(uint32_t i=0; i< 16-remain; i++)
+    {
+      tu_printf(" ");
+      for(int j=0; j<2*size; j++) tu_printf(" ");
+    }
+  }
+
+  dump_str_line(buf8-nback, nback);
+}
+
+#endif
+
+#endif // host or device enabled
diff --git a/src/tusb.h b/src/tusb.h
new file mode 100644
index 0000000..0d29e10
--- /dev/null
+++ b/src/tusb.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+#ifndef _TUSB_H_
+#define _TUSB_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "common/tusb_common.h"
+#include "osal/osal.h"
+#include "common/tusb_fifo.h"
+
+//------------- HOST -------------//
+#if TUSB_OPT_HOST_ENABLED
+  #include "host/usbh.h"
+
+  #if CFG_TUH_HID
+    #include "class/hid/hid_host.h"
+  #endif
+
+  #if CFG_TUH_MSC
+    #include "class/msc/msc_host.h"
+  #endif
+
+  #if CFG_TUH_CDC
+    #include "class/cdc/cdc_host.h"
+  #endif
+
+  #if CFG_TUH_VENDOR
+    #include "class/vendor/vendor_host.h"
+  #endif
+
+#endif
+
+//------------- DEVICE -------------//
+#if TUSB_OPT_DEVICE_ENABLED
+  #include "device/usbd.h"
+
+  #if CFG_TUD_HID
+    #include "class/hid/hid_device.h"
+  #endif
+
+  #if CFG_TUD_CDC
+    #include "class/cdc/cdc_device.h"
+  #endif
+
+  #if CFG_TUD_MSC
+    #include "class/msc/msc_device.h"
+  #endif
+
+  #if CFG_TUD_AUDIO
+    #include "class/audio/audio_device.h"
+  #endif
+
+  #if CFG_TUD_VIDEO
+    #include "class/video/video_device.h"
+  #endif
+
+  #if CFG_TUD_MIDI
+    #include "class/midi/midi_device.h"
+  #endif
+
+  #if CFG_TUD_VENDOR
+    #include "class/vendor/vendor_device.h"
+  #endif
+
+  #if CFG_TUD_USBTMC
+    #include "class/usbtmc/usbtmc_device.h"
+  #endif
+
+  #if CFG_TUD_DFU_RUNTIME
+    #include "class/dfu/dfu_rt_device.h"
+  #endif
+
+  #if CFG_TUD_DFU
+    #include "class/dfu/dfu_device.h"
+  #endif
+
+  #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM
+    #include "class/net/net_device.h"
+  #endif
+
+  #if CFG_TUD_BTH
+    #include "class/bth/bth_device.h"
+  #endif
+#endif
+
+
+//--------------------------------------------------------------------+
+// APPLICATION API
+//--------------------------------------------------------------------+
+/** \ingroup group_application_api
+ *  @{ */
+
+// Initialize device/host stack
+// Note: when using with RTOS, this should be called after scheduler/kernel is started.
+// Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API.
+bool tusb_init(void);
+
+// Check if stack is initialized
+bool tusb_inited(void);
+
+// TODO
+// bool tusb_teardown(void);
+
+/** @} */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_H_ */
diff --git a/src/tusb_option.h b/src/tusb_option.h
new file mode 100644
index 0000000..2edd310
--- /dev/null
+++ b/src/tusb_option.h
@@ -0,0 +1,373 @@
+/*
+ * 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.
+ */
+
+#ifndef _TUSB_OPTION_H_
+#define _TUSB_OPTION_H_
+
+#include "common/tusb_compiler.h"
+
+#define TUSB_VERSION_MAJOR     0
+#define TUSB_VERSION_MINOR     12
+#define TUSB_VERSION_REVISION  0
+#define TUSB_VERSION_STRING    TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
+
+//--------------------------------------------------------------------+
+// Supported MCUs
+// CFG_TUSB_MCU must be defined to one of following value
+//--------------------------------------------------------------------+
+
+#define OPT_MCU_NONE                0
+
+// LPC
+#define OPT_MCU_LPC11UXX            1 ///< NXP LPC11Uxx
+#define OPT_MCU_LPC13XX             2 ///< NXP LPC13xx
+#define OPT_MCU_LPC15XX             3 ///< NXP LPC15xx
+#define OPT_MCU_LPC175X_6X          4 ///< NXP LPC175x, LPC176x
+#define OPT_MCU_LPC177X_8X          5 ///< NXP LPC177x, LPC178x
+#define OPT_MCU_LPC18XX             6 ///< NXP LPC18xx
+#define OPT_MCU_LPC40XX             7 ///< NXP LPC40xx
+#define OPT_MCU_LPC43XX             8 ///< NXP LPC43xx
+#define OPT_MCU_LPC51UXX            9 ///< NXP LPC51U6x
+#define OPT_MCU_LPC54XXX           10 ///< NXP LPC54xxx
+#define OPT_MCU_LPC55XX            11 ///< NXP LPC55xx
+
+// NRF
+#define OPT_MCU_NRF5X             100 ///< Nordic nRF5x series
+
+// SAM
+#define OPT_MCU_SAMD21            200 ///< MicroChip SAMD21
+#define OPT_MCU_SAMD51            201 ///< MicroChip SAMD51
+#define OPT_MCU_SAMG              202 ///< MicroChip SAMDG series
+#define OPT_MCU_SAME5X            203 ///< MicroChip SAM E5x
+#define OPT_MCU_SAMD11            204 ///< MicroChip SAMD11
+#define OPT_MCU_SAML22            205 ///< MicroChip SAML22
+#define OPT_MCU_SAML21            206 ///< MicroChip SAML21
+#define OPT_MCU_SAMX7X            207 ///< MicroChip SAME70, S70, V70, V71 family
+
+// STM32
+#define OPT_MCU_STM32F0           300 ///< ST F0
+#define OPT_MCU_STM32F1           301 ///< ST F1
+#define OPT_MCU_STM32F2           302 ///< ST F2
+#define OPT_MCU_STM32F3           303 ///< ST F3
+#define OPT_MCU_STM32F4           304 ///< ST F4
+#define OPT_MCU_STM32F7           305 ///< ST F7
+#define OPT_MCU_STM32H7           306 ///< ST H7
+#define OPT_MCU_STM32L1           308 ///< ST L1
+#define OPT_MCU_STM32L0           307 ///< ST L0
+#define OPT_MCU_STM32L4           309 ///< ST L4
+#define OPT_MCU_STM32G0           310 ///< ST G0
+#define OPT_MCU_STM32G4           311 ///< ST G4
+
+// Sony
+#define OPT_MCU_CXD56             400 ///< SONY CXD56
+
+// TI
+#define OPT_MCU_MSP430x5xx        500 ///< TI MSP430x5xx
+#define OPT_MCU_MSP432E4          510 ///< TI MSP432E4xx
+#define OPT_MCU_TM4C123           511 ///< TI Tiva-C 123x
+#define OPT_MCU_TM4C129           512 ///< TI Tiva-C 129x
+
+// ValentyUSB eptri
+#define OPT_MCU_VALENTYUSB_EPTRI  600 ///< Fomu eptri config
+
+// NXP iMX RT
+#define OPT_MCU_MIMXRT10XX        700 ///< NXP iMX RT10xx
+
+// Nuvoton
+#define OPT_MCU_NUC121            800
+#define OPT_MCU_NUC126            801
+#define OPT_MCU_NUC120            802
+#define OPT_MCU_NUC505            803
+
+// Espressif
+#define OPT_MCU_ESP32S2           900 ///< Espressif ESP32-S2
+#define OPT_MCU_ESP32S3           901 ///< Espressif ESP32-S3
+
+// Dialog
+#define OPT_MCU_DA1469X          1000 ///< Dialog Semiconductor DA1469x
+
+// Raspberry Pi
+#define OPT_MCU_RP2040           1100 ///< Raspberry Pi RP2040
+
+// NXP Kinetis
+#define OPT_MCU_MKL25ZXX         1200 ///< NXP MKL25Zxx
+#define OPT_MCU_K32L2BXX         1201 ///< NXP K32L2Bxx
+
+// Silabs
+#define OPT_MCU_EFM32GG          1300 ///< Silabs EFM32GG
+
+// Renesas RX
+#define OPT_MCU_RX63X            1400 ///< Renesas RX63N/631
+#define OPT_MCU_RX65X            1401 ///< Renesas RX65N/RX651
+#define OPT_MCU_RX72N            1402 ///< Renesas RX72N
+
+// Mind Motion
+#define OPT_MCU_MM32F327X        1500 ///< Mind Motion MM32F327
+
+// GigaDevice
+#define OPT_MCU_GD32VF103        1600 ///< GigaDevice GD32VF103
+
+// Broadcom
+#define OPT_MCU_BCM2711          1700 ///< Broadcom BCM2711
+
+// Infineon
+#define OPT_MCU_XMC4000          1800 ///< Infineon XMC4000
+
+// 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)
+#define TU_CHECK_MCU(...)   (TU_ARGS_APPLY(_TU_CHECK_MCU, ||, __VA_ARGS__))
+
+//--------------------------------------------------------------------+
+// Supported OS
+//--------------------------------------------------------------------+
+
+#define OPT_OS_NONE       1  ///< No RTOS
+#define OPT_OS_FREERTOS   2  ///< FreeRTOS
+#define OPT_OS_MYNEWT     3  ///< Mynewt OS
+#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
+
+// Allow to use command line to change the config name/location
+#ifdef CFG_TUSB_CONFIG_FILE
+  #include CFG_TUSB_CONFIG_FILE
+#else
+  #include "tusb_config.h"
+#endif
+
+//--------------------------------------------------------------------
+// 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
+
+// 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
+
+
+#ifndef CFG_TUSB_RHPORT0_MODE
+  #define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE
+#endif
+
+
+#ifndef CFG_TUSB_RHPORT1_MODE
+  #define CFG_TUSB_RHPORT1_MODE OPT_MODE_NONE
+#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"
+#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 )
+
+// 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) )
+
+#if TUD_OPT_RHPORT == 0
+#define TUD_OPT_HIGH_SPEED      ( (CFG_TUSB_RHPORT0_MODE) & OPT_MODE_HIGH_SPEED )
+#else
+#define TUD_OPT_HIGH_SPEED      ( (CFG_TUSB_RHPORT1_MODE) & OPT_MODE_HIGH_SPEED )
+#endif
+
+#define TUSB_OPT_DEVICE_ENABLED ( TUD_OPT_RHPORT >= 0 )
+
+//--------------------------------------------------------------------+
+// COMMON OPTIONS
+//--------------------------------------------------------------------+
+
+// Debug enable to print out error message
+#ifndef CFG_TUSB_DEBUG
+  #define CFG_TUSB_DEBUG 0
+#endif
+
+// place data in accessible RAM for usb controller
+#ifndef CFG_TUSB_MEM_SECTION
+  #define CFG_TUSB_MEM_SECTION
+#endif
+
+// alignment requirement of buffer used for endpoint transferring
+#ifndef CFG_TUSB_MEM_ALIGN
+  #define CFG_TUSB_MEM_ALIGN      TU_ATTR_ALIGNED(4)
+#endif
+
+// OS selection
+#ifndef CFG_TUSB_OS
+  #define CFG_TUSB_OS             OPT_OS_NONE
+#endif
+
+#ifndef CFG_TUSB_OS_INC_PATH
+  #define CFG_TUSB_OS_INC_PATH
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE OPTIONS
+//--------------------------------------------------------------------
+
+#ifndef CFG_TUD_ENDPOINT0_SIZE
+  #define CFG_TUD_ENDPOINT0_SIZE  64
+#endif
+
+#ifndef CFG_TUD_CDC
+  #define CFG_TUD_CDC             0
+#endif
+
+#ifndef CFG_TUD_MSC
+  #define CFG_TUD_MSC             0
+#endif
+
+#ifndef CFG_TUD_HID
+  #define CFG_TUD_HID             0
+#endif
+
+#ifndef CFG_TUD_AUDIO
+  #define CFG_TUD_AUDIO           0
+#endif
+
+#ifndef CFG_TUD_VIDEO
+  #define CFG_TUD_VIDEO           0
+#endif
+
+#ifndef CFG_TUD_MIDI
+  #define CFG_TUD_MIDI            0
+#endif
+
+#ifndef CFG_TUD_VENDOR
+  #define CFG_TUD_VENDOR          0
+#endif
+
+#ifndef CFG_TUD_USBTMC
+  #define CFG_TUD_USBTMC          0
+#endif
+
+#ifndef CFG_TUD_DFU_RUNTIME
+  #define CFG_TUD_DFU_RUNTIME     0
+#endif
+
+#ifndef CFG_TUD_DFU
+  #define CFG_TUD_DFU             0
+#endif
+
+#ifndef CFG_TUD_BTH
+  #define CFG_TUD_BTH             0
+#endif
+
+#ifndef CFG_TUD_ECM_RNDIS
+  #ifdef CFG_TUD_NET
+    #warning "CFG_TUD_NET is renamed to CFG_TUD_ECM_RNDIS"
+    #define CFG_TUD_ECM_RNDIS   CFG_TUD_NET
+  #else
+    #define CFG_TUD_ECM_RNDIS   0
+  #endif
+#endif
+
+#ifndef CFG_TUD_NCM
+  #define CFG_TUD_NCM         0
+#endif
+
+//--------------------------------------------------------------------
+// HOST OPTIONS
+//--------------------------------------------------------------------
+#if TUSB_OPT_HOST_ENABLED
+  #ifndef CFG_TUH_DEVICE_MAX
+    #define CFG_TUH_DEVICE_MAX 1
+  #endif
+
+  #ifndef CFG_TUH_ENUMERATION_BUFSIZE
+    #define CFG_TUH_ENUMERATION_BUFSIZE 256
+  #endif
+#endif // TUSB_OPT_HOST_ENABLED
+
+//------------- CLASS -------------//
+
+#ifndef CFG_TUH_HUB
+#define CFG_TUH_HUB    0
+#endif
+
+#ifndef CFG_TUH_CDC
+#define CFG_TUH_CDC    0
+#endif
+
+#ifndef CFG_TUH_HID
+#define CFG_TUH_HID    0
+#endif
+
+#ifndef CFG_TUH_MIDI
+#define CFG_TUH_MIDI   0
+#endif
+
+#ifndef CFG_TUH_MSC
+#define CFG_TUH_MSC    0
+#endif
+
+#ifndef CFG_TUH_VENDOR
+#define CFG_TUH_VENDOR 0
+#endif
+
+//--------------------------------------------------------------------+
+// Port Specific
+// TUP stand for TinyUSB Port (can be renamed)
+//--------------------------------------------------------------------+
+
+//------------- Unaligned Memory -------------//
+
+// 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
+
+// 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
+#endif
+
+
+//------------------------------------------------------------------
+// Configuration Validation
+//------------------------------------------------------------------
+#if CFG_TUD_ENDPOINT0_SIZE > 64
+  #error Control Endpoint Max Packet Size cannot be larger than 64
+#endif
+
+#endif /* _TUSB_OPTION_H_ */
+
+/** @} */