Переглянути джерело

Merge remote-tracking branch 'origin/master'

tfx2001 4 роки тому
батько
коміт
98bdfcc34a

+ 6 - 0
CONTRIBUTORS.rst

@@ -153,6 +153,12 @@ Notable contributors
 -  Add new class driver for DFU Runtime
 
 
+`Tian Yunhao <https://github.com/t123yh>`__
+-------------------------------------------
+
+-  Add new DCD port for Allwinner F1C100S/F1C200S
+-  Add support for osal_rtx4
+
 `Timon Skerutsch <https://github.com/PTS93>`__
 ----------------------------------------------
 

+ 3 - 2
README.rst

@@ -32,6 +32,7 @@ Supported MCUs
 
 The stack supports the following MCUs:
 
+- **Allwinner:** F1C100s/F1C200s
 - **Broadcom:** BCM2837, BCM2711
 - **Dialog:** DA1469x
 - **Espressif:** ESP32-S2, ESP32-S3
@@ -64,7 +65,7 @@ Supports multiple device configurations by dynamically changing USB descriptors,
 -  Audio Class 2.0 (UAC2)
 -  Bluetooth Host Controller Interface (BTH HCI)
 -  Communication Device Class (CDC)
--  Device Firmware Update (DFU): DFU mode (WIP) and Runtinme
+-  Device Firmware Update (DFU): DFU mode (WIP) and Runtime
 -  Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
 -  Mass Storage Class (MSC): with multiple LUNs
 -  Musical Instrument Digital Interface (MIDI)
@@ -90,7 +91,7 @@ TinyUSB is completely thread-safe by pushing all Interrupt Service Request (ISR)
 
 - **No OS**
 - **FreeRTOS**
-- `RT-Thread <https://github.com/RT-Thread/rt-thread>`_
+- `RT-Thread <https://github.com/RT-Thread/rt-thread>`_: `repo <https://github.com/RT-Thread-packages/tinyusb>`_
 - **Mynewt** Due to the newt package build system, Mynewt examples are better to be on its `own repo <https://github.com/hathach/mynewt-tinyusb-example>`_
 
 Local Docs

+ 1 - 1
docs/reference/getting_started.rst

@@ -37,7 +37,7 @@ It is relatively simple to incorporate tinyusb to your (existing) project
 Examples
 --------
 
-For your convenience, TinyUSB contains a handful of examples for both host and device with/without RTOS to quickly test the functionality as well as demonstrate how API() should be used. Most examples will work on most of `the supported Boards <boards.md>`_. Firstly we need to ``git clone`` if not already
+For your convenience, TinyUSB contains a handful of examples for both host and device with/without RTOS to quickly test the functionality as well as demonstrate how API() should be used. Most examples will work on most of `the supported boards <supported.rst>`_. Firstly we need to ``git clone`` if not already
 
 .. code-block::
 

+ 1 - 1
docs/reference/supported.rst

@@ -42,7 +42,7 @@ Supported MCUs
 +--------------+---------+-------------+--------+------+-----------+-------------------+--------------+
 | NXP          | iMXRT   | RT10xx      | ✔      | ✔    | ✔         | ci_hs             |              |
 |              +---------+-------------+--------+------+-----------+-------------------+--------------+
-|              | Kinetis | KL25        | ✔      |      | ✖         |                   |              |
+|              | Kinetis | KL25        | ✔      |      | ✖         |                   |              |
 |              |         +-------------+--------+------+-----------+-------------------+--------------+
 |              |         | K32L2       | ✔      |      | ✖         |                   |              |
 |              +---------+-------------+--------+------+-----------+-------------------+--------------+

+ 0 - 5
examples/device/cdc_msc/src/msc_disk.c

@@ -243,11 +243,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
 
   switch (scsi_cmd[0])
   {
-    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
-      // Host is about to read/write etc ... better not to disconnect disk
-      resplen = 0;
-    break;
-
     default:
       // Set Sense = Invalid Command Operation
       tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);

+ 0 - 0
examples/device/cdc_msc_freertos/.skip.MCU_F1C100S


+ 0 - 5
examples/device/cdc_msc_freertos/src/msc_disk.c

@@ -221,11 +221,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
 
   switch (scsi_cmd[0])
   {
-    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
-      // Host is about to read/write etc ... better not to disconnect disk
-      resplen = 0;
-    break;
-
     default:
       // Set Sense = Invalid Command Operation
       tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);

+ 0 - 5
examples/device/dynamic_configuration/src/msc_disk.c

@@ -221,11 +221,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
 
   switch (scsi_cmd[0])
   {
-    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
-      // Host is about to read/write etc ... better not to disconnect disk
-      resplen = 0;
-    break;
-
     default:
       // Set Sense = Invalid Command Operation
       tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);

+ 0 - 0
examples/device/hid_composite_freertos/.skip.MCU_F1C100S


+ 4 - 18
examples/device/msc_dual_lun/src/msc_disk_dual.c

@@ -28,6 +28,9 @@
 
 #if CFG_TUD_MSC
 
+// When button is pressed, LUN1 will be set to not ready to simulate
+// medium not present (e.g SD card removed)
+
 // Some MCU doesn't have enough 8KB SRAM to store the whole disk
 // We will use Flash as read-only disk with board that has
 // CFG_EXAMPLE_MSC_READONLY defined
@@ -227,7 +230,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16
 // return true allowing host to read/write this LUN e.g SD card inserted
 bool tud_msc_test_unit_ready_cb(uint8_t lun)
 {
-  (void) lun;
+  if ( lun == 1 && board_button_read() ) return false;
 
   return true; // RAM disk is always ready
 }
@@ -320,23 +323,6 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
 
   switch (scsi_cmd[0])
   {
-    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
-      // Host is about to read/write etc ... better not to disconnect disk
-      resplen = 0;
-    break;
-
-    case SCSI_CMD_START_STOP_UNIT:
-      // Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
-      /* scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
-        // Start bit = 0 : low power mode, if load_eject = 1 : unmount disk storage as well
-        // Start bit = 1 : Ready mode, if load_eject = 1 : mount disk storage
-        start_stop->start;
-        start_stop->load_eject;
-       */
-       resplen = 0;
-    break;
-
-
     default:
       // Set Sense = Invalid Command Operation
       tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);

+ 7 - 0
examples/rules.mk

@@ -188,6 +188,13 @@ flash-jlink: $(BUILD)/$(PROJECT).hex
 flash-stlink: $(BUILD)/$(PROJECT).elf
 	STM32_Programmer_CLI --connect port=swd --write $< --go
 
+$(BUILD)/$(PROJECT)-sunxi.bin: $(BUILD)/$(PROJECT).bin
+	$(PYTHON) $(TOP)/tools/mksunxi.py $< $@
+
+flash-xfel: $(BUILD)/$(PROJECT)-sunxi.bin
+	xfel spinor write 0 $<
+	xfel reset
+
 # Flash using pyocd
 PYOCD_OPTION ?=
 flash-pyocd: $(BUILD)/$(PROJECT).hex

+ 20 - 0
hw/bsp/f1c100s/README.md

@@ -0,0 +1,20 @@
+# BSP support for F1Cx00s boards
+
+This folder contains necessary file and scripts to run TinyUSB examples on F1Cx00s boards.
+
+Currently tested on:
+
+- Lichee Pi Nano (F1C100s)
+- [Widora Tiny200 v2 (also called MangoPi-R3c)](https://mangopi.org/tiny200)
+
+## Flashing
+
+There are two options to put your code into the MCU: `flash` and `exec`. Both modes require you to install [xfel](https://github.com/xboot/xfel) tool to your PATH. You must enter FEL mode before any operation can be done. To enter FEL mode, press BOOT button, then press RESET once, and release BOOT button. You will find VID/PID=1f3a:efe8 on your PC.
+
+Exec: `make BOARD=f1c100s exec` will just upload the image to the DDR ram and execute it. It will not touch anything in the SPI flash.
+
+Flash: `make BOARD=f1c100s flash` will write the image to SPI flash, and then reset the chip to execute it.
+
+## TODO
+
+* Add F1C100s to `#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX` high speed MCU check in examples (maybe we should extract the logic?)

+ 1 - 0
hw/bsp/f1c100s/board.h

@@ -0,0 +1 @@
+// Nothing valuable here

+ 52 - 0
hw/bsp/f1c100s/board.mk

@@ -0,0 +1,52 @@
+DEPS_SUBMODULES += hw/mcu/allwinner
+
+DEFINES += -D__ARM32_ARCH__=5 -D__ARM926EJS__
+
+CFLAGS += \
+  -ffreestanding \
+  -std=gnu99 \
+  -march=armv5te \
+  -mtune=arm926ej-s \
+  -mfloat-abi=soft \
+  -marm \
+  -mno-thumb-interwork \
+  -Wno-unused-parameter \
+  -Wno-float-equal \
+  -DCFG_TUSB_MCU=OPT_MCU_F1C100S \
+  -Wno-error=cast-align \
+  -Wno-error=address-of-packed-member \
+  $(DEFINES)
+
+LD_FILE = hw/mcu/allwinner/f1c100s/f1c100s.ld
+LDFLAGS += -nostdlib -lgcc
+MCU_DIR = hw/mcu/allwinner/f1c100s
+
+SRC_C += \
+	src/portable/sunxi/dcd_sunxi_musb.c \
+	$(MCU_DIR)/machine/sys-uart.c \
+	$(MCU_DIR)/machine/exception.c \
+	$(MCU_DIR)/machine/sys-clock.c \
+	$(MCU_DIR)/machine/sys-copyself.c \
+	$(MCU_DIR)/machine/sys-dram.c \
+	$(MCU_DIR)/machine/sys-mmu.c \
+	$(MCU_DIR)/machine/sys-spi-flash.c \
+	$(MCU_DIR)/machine/f1c100s-intc.c \
+	$(MCU_DIR)/lib/malloc.c \
+	$(MCU_DIR)/lib/printf.c 
+
+SRC_S += \
+  $(MCU_DIR)/machine/start.S \
+	$(MCU_DIR)/lib/memcpy.S \
+	$(MCU_DIR)/lib/memset.S
+
+INC += \
+	$(TOP)/$(MCU_DIR)/include \
+	$(TOP)/$(BOARD_PATH)
+
+# flash target using xfel
+flash: flash-xfel
+
+exec: $(BUILD)/$(PROJECT).bin
+	xfel ddr 
+	xfel write 0x80000000 $<
+	xfel exec 0x80000000

+ 130 - 0
hw/bsp/f1c100s/f1c100s.c

@@ -0,0 +1,130 @@
+/* 
+ * 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 <stdint.h>
+#include <malloc.h>
+#include <irqflags.h>
+#include <f1c100s-irq.h>
+#include "bsp/board.h"
+#include "board.h"
+
+extern void sys_uart_putc(char c);
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+static void timer_init(void);
+
+void board_init(void)
+{
+  arch_local_irq_disable();
+	do_init_mem_pool();
+  f1c100s_intc_init();
+  timer_init();
+  printf("Timer INIT done\n");
+  arch_local_irq_enable();
+}
+
+// No LED, no button
+void board_led_write(bool state)
+{
+
+}
+
+uint32_t board_button_read(void)
+{
+  return 0;
+}
+
+int board_uart_read(uint8_t* buf, int len)
+{
+  return 0;
+}
+
+int board_uart_write(void const * buf, int len)
+{
+  int txsize = len;
+  while (txsize--) {
+    sys_uart_putc(*(uint8_t const*)buf);
+    buf++;
+  }
+  return len;
+}
+
+#if CFG_TUSB_OS  == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+
+uint32_t board_millis(void)
+{
+  return system_ticks;
+}
+
+static void timer_handler(void)
+{
+  volatile uint32_t *temp_addr = (uint32_t *)(0x01C20C00 + 0x04);
+
+  /* clear timer */
+  *temp_addr |= 0x01;
+
+  system_ticks++;
+}
+
+static void timer_init(void) {
+  uint32_t temp;
+  volatile uint32_t *temp_addr;
+
+  /* reload value */
+  temp = 12000000 / 1000;
+  temp_addr = (uint32_t *)(0x01C20C00 + 0x14);
+  *temp_addr = temp;
+
+  /* continuous | /2 | 24Mhz |  reload*/
+  temp = (0x00 << 7) | (0x01 << 4) | (0x01 << 2) | (0x00 << 1);
+  temp_addr = (uint32_t *)(0x01C20C00 + 0x10);
+  *temp_addr &= 0xffffff00;
+  *temp_addr |= temp;
+
+  /* open timer irq */
+  temp = 0x01 << 0;
+  temp_addr = (uint32_t *)(0x01C20C00);
+  *temp_addr |= temp;
+
+  /* set init value */
+  temp_addr = (uint32_t *)(0x01C20C00 + 0x18);
+  *temp_addr = 0;
+
+  /* begin run timer */
+  temp = 0x01 << 0;
+  temp_addr = (uint32_t *)(0x01C20C00 + 0x10);
+  *temp_addr |= temp;
+
+  f1c100s_intc_set_isr(F1C100S_IRQ_TIMER0, timer_handler);
+  f1c100s_intc_enable_irq(F1C100S_IRQ_TIMER0);
+}
+#else 
+static void timer_init(void) { }
+#endif

+ 1 - 1
hw/bsp/family_support.cmake

@@ -2,7 +2,7 @@ if (NOT TARGET _family_support_marker)
     add_library(_family_support_marker INTERFACE)
 
     if (NOT FAMILY)
-        message(FATAL_ERROR "You must set a FAMILY variable for the build (e.g. rp2040, eps32s2, esp32s3). You can do this via -DFAMILY=xxx on the camke command line")
+        message(FATAL_ERROR "You must set a FAMILY variable for the build (e.g. rp2040, eps32s2, esp32s3). You can do this via -DFAMILY=xxx on the cmake command line")
     endif()
 
     if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/${FAMILY}/family.cmake)

+ 1 - 0
hw/bsp/frdm_kl25z/board.mk

@@ -23,6 +23,7 @@ LD_FILE = $(MCU_DIR)/gcc/MKL25Z128xxx4_flash.ld
 
 SRC_C += \
 	src/portable/nxp/khci/dcd_khci.c \
+	src/portable/nxp/khci/hcd_khci.c \
 	$(MCU_DIR)/system_MKL25Z4.c \
 	$(MCU_DIR)/project_template/clock_config.c \
 	$(MCU_DIR)/drivers/fsl_clock.c \

+ 5 - 0
hw/bsp/frdm_kl25z/frdm_kl25z.c

@@ -39,7 +39,12 @@
 //--------------------------------------------------------------------+
 void USB0_IRQHandler(void)
 {
+#if TUSB_OPT_HOST_ENABLED
+  tuh_int_handler(0);
+#endif
+#if TUSB_OPT_DEVICE_ENABLED
   tud_int_handler(0);
+#endif
 }
 
 //--------------------------------------------------------------------+

+ 1 - 0
hw/mcu/allwinner

@@ -0,0 +1 @@
+Subproject commit 8e5e89e8e132c0fd90e72d5422e5d3d68232b756

+ 1 - 1
src/class/hid/hid.h

@@ -645,7 +645,7 @@ enum {
 #define HID_REPORT_SIZE_N(x, n)   HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_SIZE, RI_TYPE_GLOBAL, n)
 
 #define HID_REPORT_ID(x)          HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, 1),
-#define HID_REPORT_ID_N(x)        HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, n),
+#define HID_REPORT_ID_N(x, n)     HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_ID, RI_TYPE_GLOBAL, n),
 
 #define HID_REPORT_COUNT(x)       HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, 1)
 #define HID_REPORT_COUNT_N(x, n)  HID_REPORT_ITEM(x, RI_GLOBAL_REPORT_COUNT, RI_TYPE_GLOBAL, n)

+ 36 - 25
src/class/msc/msc_device.c

@@ -209,7 +209,7 @@ TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
   { .key = SCSI_CMD_MODE_SELECT_6                , .data = "Mode_Select 6" },
   { .key = SCSI_CMD_MODE_SENSE_6                 , .data = "Mode_Sense 6" },
   { .key = SCSI_CMD_START_STOP_UNIT              , .data = "Start Stop Unit" },
-  { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent Allow Medium Removal" },
+  { .key = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL , .data = "Prevent/Allow Medium Removal" },
   { .key = SCSI_CMD_READ_CAPACITY_10             , .data = "Read Capacity10" },
   { .key = SCSI_CMD_REQUEST_SENSE                , .data = "Request Sense" },
   { .key = SCSI_CMD_READ_FORMAT_CAPACITY         , .data = "Read Format Capacity" },
@@ -239,6 +239,12 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u
   return true;
 }
 
+static inline void set_sense_medium_not_present(uint8_t lun)
+{
+  // default sense is NOT READY, MEDIUM NOT PRESENT
+  tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00);
+}
+
 //--------------------------------------------------------------------+
 // USBD Driver API
 //--------------------------------------------------------------------+
@@ -406,7 +412,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
         return false;
       }
 
-      TU_LOG(MSC_DEBUG, "  SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
+      TU_LOG(MSC_DEBUG, "  SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
       //TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2);
 
       p_csw->signature    = MSC_CSW_SIGNATURE;
@@ -473,7 +479,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
           if ( resplen < 0 )
           {
             // unsupported command
-            TU_LOG(MSC_DEBUG, "  SCSI unsupported command\r\n");
+            TU_LOG(MSC_DEBUG, "  SCSI unsupported or failed command\r\n");
             fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
           }
           else if (resplen == 0)
@@ -508,7 +514,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
     break;
 
     case MSC_STAGE_DATA:
-      TU_LOG(MSC_DEBUG, "  SCSI Data\r\n");
+      TU_LOG(MSC_DEBUG, "  SCSI Data [Lun%u]\r\n", p_cbw->lun);
       //TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2);
 
       if (SCSI_CMD_READ_10 == p_cbw->command[0])
@@ -569,7 +575,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
       // Wait for the Status phase to complete
       if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) )
       {
-        TU_LOG(MSC_DEBUG, "  SCSI Status = %u\r\n", p_csw->status);
+        TU_LOG(MSC_DEBUG, "  SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status);
         // TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2);
 
         // Invoke complete callback if defined
@@ -654,8 +660,8 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
         // Failed status response
         resplen = - 1;
 
-        // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
-        if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+        // set default sense if not set by callback
+        if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun);
       }
     break;
 
@@ -670,8 +676,8 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
           // Failed status response
           resplen = - 1;
 
-          // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
-          if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+          // set default sense if not set by callback
+          if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun);
         }
       }
     break;
@@ -691,13 +697,13 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
       {
         resplen = -1;
 
-        // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
-        if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+        // set default sense if not set by callback
+        if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun);
       }else
       {
         scsi_read_capacity10_resp_t read_capa10;
 
-        read_capa10.last_lba = tu_htonl(block_count-1);
+        read_capa10.last_lba   = tu_htonl(block_count-1);
         read_capa10.block_size = tu_htonl(block_size);
 
         resplen = sizeof(read_capa10);
@@ -727,8 +733,8 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
       {
         resplen = -1;
 
-        // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
-        if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+        // set default sense if not set by callback
+        if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun);
       }else
       {
         read_fmt_capa.block_num = tu_htonl(block_count);
@@ -765,10 +771,10 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
     {
       scsi_mode_sense6_resp_t mode_resp =
       {
-          .data_len = 3,
-          .medium_type = 0,
-          .write_protected = false,
-          .reserved = 0,
+          .data_len             = 3,
+          .medium_type          = 0,
+          .write_protected      = false,
+          .reserved             = 0,
           .block_descriptor_len = 0  // no block descriptor are included
       };
 
@@ -789,12 +795,11 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
     {
       scsi_sense_fixed_resp_t sense_rsp =
       {
-          .response_code = 0x70,
+          .response_code = 0x70, // current, fixed format
           .valid         = 1
       };
 
-      sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8;
-
+      sense_rsp.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;
@@ -802,6 +807,12 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
       resplen = sizeof(sense_rsp);
       memcpy(buffer, &sense_rsp, resplen);
 
+      // request sense callback could overwrite the sense data
+      if (tud_msc_request_sense_cb)
+      {
+        resplen = tud_msc_request_sense_cb(lun, buffer, bufsize);
+      }
+
       // Clear sense data after copy
       tud_msc_set_sense(lun, 0, 0, 0);
     }
@@ -835,8 +846,8 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
     // negative means error -> endpoint is stalled & status in CSW set to failed
     TU_LOG(MSC_DEBUG, "  tud_msc_read10_cb() return -1\r\n");
 
-    // Sense = Flash not ready for access
-    tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_MEDIUM_ERROR, 0x33, 0x00);
+    // set sense
+    set_sense_medium_not_present(p_cbw->lun);
 
     fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
   }
@@ -900,8 +911,8 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3
     // update actual byte before failed
     p_msc->xferred_len += xferred_bytes;
 
-    // Sense = Flash not ready for access
-    tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_MEDIUM_ERROR, 0x33, 0x00);
+    // Set sense
+    set_sense_medium_not_present(p_cbw->lun);
 
     fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
   }else

+ 3 - 0
src/class/msc/msc_device.h

@@ -131,6 +131,9 @@ TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void);
 // - Start = 1 : active mode, if load_eject = 1 : load disk storage
 TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject);
 
+// Invoked when received REQUEST_SENSE
+TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize);
+
 // Invoked when Read10 command is complete
 TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);
 

+ 3 - 1
src/common/tusb_compiler.h

@@ -137,9 +137,11 @@
   #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
   #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
 
+	#ifndef __ARMCC_VERSION
   // List of obsolete callback function that is renamed and should not be defined.
   // Put it here since only gcc support this pragma
-  #pragma GCC poison tud_vendor_control_request_cb
+		#pragma GCC poison tud_vendor_control_request_cb
+	#endif
 
 #elif defined(__TI_COMPILER_VERSION__)
   #define TU_ATTR_ALIGNED(Bytes)        __attribute__ ((aligned(Bytes)))

+ 2 - 2
src/device/dcd.h

@@ -106,12 +106,12 @@ typedef struct TU_ATTR_ALIGNED(4)
 void dcd_init       (uint8_t rhport);
 
 // Interrupt Handler
-#if __GNUC__
+#if __GNUC__ && !defined(__ARMCC_VERSION)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wredundant-decls"
 #endif
 void dcd_int_handler(uint8_t rhport);
-#if __GNUC__
+#if __GNUC__ && !defined(__ARMCC_VERSION)
 #pragma GCC diagnostic pop
 #endif
 

+ 4 - 0
src/device/dcd_attr.h

@@ -208,6 +208,10 @@
 #elif TU_CHECK_MCU(OPT_MCU_FT93X)
   #define DCD_ATTR_ENDPOINT_MAX   16
 
+//------------ Allwinner -------------//
+#elif TU_CHECK_MCU(OPT_MCU_F1C100S)
+  #define DCD_ATTR_ENDPOINT_MAX   4
+
 #else
   #warning "DCD_ATTR_ENDPOINT_MAX is not defined for this MCU, default to 8"
   #define DCD_ATTR_ENDPOINT_MAX   8

+ 5 - 5
src/device/usbd.c

@@ -1008,7 +1008,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
         return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
       }
     }
-    break;
+    // break; // unreachable
 
     case TUSB_DESC_BOS:
     {
@@ -1025,7 +1025,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
 
       return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
     }
-    break;
+    // break; // unreachable
 
     case TUSB_DESC_CONFIGURATION:
     case TUSB_DESC_OTHER_SPEED_CONFIG:
@@ -1051,7 +1051,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
 
       return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
     }
-    break;
+    // break; // unreachable
 
     case TUSB_DESC_STRING:
     {
@@ -1064,7 +1064,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
       // first byte of descriptor is its size
       return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str));
     }
-    break;
+    // break; // unreachable
 
     case TUSB_DESC_DEVICE_QUALIFIER:
     {
@@ -1078,7 +1078,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
       // first byte of descriptor is its size
       return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier));
     }
-    break;
+    // break; // unreachable
 
     default: return false;
   }

+ 4 - 2
src/osal/osal.h

@@ -57,6 +57,8 @@ typedef void (*osal_task_func_t)( void * );
   #include "osal_pico.h"
 #elif CFG_TUSB_OS == OPT_OS_RTTHREAD
   #include "osal_rtthread.h"
+#elif CFG_TUSB_OS == OPT_OS_RTX4
+  #include "osal_rtx4.h"
 #elif CFG_TUSB_OS == OPT_OS_CUSTOM
   #include "tusb_os_custom.h" // implemented by application
 #else
@@ -67,7 +69,7 @@ typedef void (*osal_task_func_t)( void * );
 // OSAL Porting API
 //--------------------------------------------------------------------+
 
-#if __GNUC__
+#if __GNUC__ && !defined(__ARMCC_VERSION)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wredundant-decls"
 #endif
@@ -88,7 +90,7 @@ 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__
+#if __GNUC__ && !defined(__ARMCC_VERSION)
 #pragma GCC diagnostic pop
 #endif
 

+ 170 - 0
src/osal/osal_rtx4.h

@@ -0,0 +1,170 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_OSAL_RTX4_H_
+#define _TUSB_OSAL_RTX4_H_
+
+#include <rtl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TASK API
+//--------------------------------------------------------------------+
+static inline void osal_task_delay(uint32_t msec)
+{
+  uint16_t hi = msec >> 16;
+  uint16_t lo = msec;
+  while (hi--) {
+    os_dly_wait(0xFFFE);
+  }
+  os_dly_wait(lo);
+}
+
+static inline uint16_t msec2wait(uint32_t msec) {
+  if (msec == OSAL_TIMEOUT_WAIT_FOREVER)
+    return 0xFFFF;
+  else if (msec >= 0xFFFE)
+    return 0xFFFE;
+  else
+    return msec;
+}
+
+//--------------------------------------------------------------------+
+// Semaphore API
+//--------------------------------------------------------------------+
+typedef OS_SEM osal_semaphore_def_t;
+typedef OS_ID osal_semaphore_t;
+
+static inline OS_ID osal_semaphore_create(osal_semaphore_def_t* semdef) {
+  os_sem_init(semdef, 0);
+  return semdef;
+}
+
+static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
+  if ( !in_isr ) {
+    os_sem_send(sem_hdl);
+  } else {
+    isr_sem_send(sem_hdl);
+  }
+	return true;
+}
+
+static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec) {
+  return os_sem_wait(sem_hdl, msec2wait(msec)) != OS_R_TMO;
+}
+
+static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) {
+  // TODO: implement
+}
+
+//--------------------------------------------------------------------+
+// MUTEX API (priority inheritance)
+//--------------------------------------------------------------------+
+typedef OS_MUT osal_mutex_def_t;
+typedef OS_ID osal_mutex_t;
+
+static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
+{
+  os_mut_init(mdef);
+  return mdef;
+}
+
+static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
+{
+  return os_mut_wait(mutex_hdl, msec2wait(msec)) != OS_R_TMO;
+}
+
+static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
+{
+  return os_mut_release(mutex_hdl) == OS_R_OK;
+}
+
+//--------------------------------------------------------------------+
+// QUEUE API
+//--------------------------------------------------------------------+
+
+// role device/host is used by OS NONE for mutex (disable usb isr) only
+#define OSAL_QUEUE_DEF(_role, _name, _depth, _type)   \
+  os_mbx_declare(_name##__mbox, _depth);              \
+  _declare_box(_name##__pool, sizeof(_type), _depth); \
+  osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .pool = _name##__pool, .mbox = _name##__mbox };
+  
+
+typedef struct
+{
+  uint16_t depth;
+  uint16_t item_sz;
+  U32* pool;
+  U32* mbox;
+}osal_queue_def_t;
+
+typedef osal_queue_def_t* osal_queue_t;
+
+static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
+{
+  os_mbx_init(qdef->mbox, (qdef->depth + 4) * 4);
+  _init_box(qdef->pool, ((qdef->item_sz+3)/4)*(qdef->depth) + 3, qdef->item_sz);
+  return qdef;
+}
+
+static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
+{
+  void* buf;
+  os_mbx_wait(qhdl->mbox, &buf, 0xFFFF);
+  memcpy(data, buf, qhdl->item_sz);
+  _free_box(qhdl->pool, buf);
+  return true;
+}
+
+static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
+{
+  void* buf = _alloc_box(qhdl->pool);
+  memcpy(buf, data, qhdl->item_sz);
+  if ( !in_isr )
+  {
+    os_mbx_send(qhdl->mbox, buf, 0xFFFF);
+  }
+  else
+  {
+    isr_mbx_send(qhdl->mbox, buf);
+  }
+  return true;
+}
+
+static inline bool osal_queue_empty(osal_queue_t qhdl)
+{
+  return os_mbx_check(qhdl->mbox) == qhdl->depth;
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_OSAL_FREERTOS_H_ */

+ 13 - 4
src/portable/dialog/da146xx/dcd_da146xx.c

@@ -733,6 +733,15 @@ static void handle_alt_ev(void)
       set_nfsr(NFSR_NODE_OPERATIONAL);
       USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
                             USB_USB_ALTMSK_REG_USB_M_SD3_Msk;
+      // Re-enable reception of endpoint with pending transfer
+      for (int epnum = 1; epnum <= 3; ++epnum)
+      {
+        xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
+        if (xfer->total_len > xfer->transferred)
+        {
+          start_rx_packet(xfer);
+        }
+      }
       dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
     }
   }
@@ -935,13 +944,13 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
     if (dir == TUSB_DIR_OUT)
     {
       regs->epc_out = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
-      USB->USB_RXMSK_REG |= 0x101 << (epnum - 1);
+      USB->USB_RXMSK_REG |= 0x11 << (epnum - 1);
       REG_SET_BIT(USB_MAMSK_REG, USB_M_RX_EV);
     }
     else
     {
       regs->epc_in = epnum | USB_USB_EPC1_REG_USB_EP_EN_Msk | iso_mask;
-      USB->USB_TXMSK_REG |= 0x101 << (epnum - 1);
+      USB->USB_TXMSK_REG |= 0x11 << (epnum - 1);
       REG_SET_BIT(USB_MAMSK_REG, USB_M_TX_EV);
     }
   }
@@ -982,7 +991,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
     {
       regs->rxc = USB_USB_RXC1_REG_USB_FLUSH_Msk;
       regs->epc_out = 0;
-      USB->USB_RXMSK_REG &= ~(0x101 << (epnum - 1));
+      USB->USB_RXMSK_REG &= ~(0x11 << (epnum - 1));
       // Release DMA if needed
       if (_dcd.dma_ep[TUSB_DIR_OUT] == epnum)
       {
@@ -994,7 +1003,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
     {
       regs->txc = USB_USB_TXC1_REG_USB_FLUSH_Msk;
       regs->epc_in = 0;
-      USB->USB_TXMSK_REG &= ~(0x101 << (epnum - 1));
+      USB->USB_TXMSK_REG &= ~(0x11 << (epnum - 1));
       // Release DMA if needed
       if (_dcd.dma_ep[TUSB_DIR_IN] == epnum)
       {

+ 626 - 0
src/portable/nxp/khci/hcd_khci.c

@@ -0,0 +1,626 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji Kitayama
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_HOST_ENABLED && ( \
+      ( CFG_TUSB_MCU == OPT_MCU_MKL25ZXX ) || ( CFG_TUSB_MCU == OPT_MCU_K32L2BXX ) \
+    )
+
+#include "fsl_device_registers.h"
+#define KHCI        USB0
+
+#include "host/hcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+  TOK_PID_OUT   = 0x1u,
+  TOK_PID_IN    = 0x9u,
+  TOK_PID_SETUP = 0xDu,
+  TOK_PID_DATA0 = 0x3u,
+  TOK_PID_DATA1 = 0xbu,
+  TOK_PID_ACK   = 0x2u,
+  TOK_PID_STALL = 0xeu,
+  TOK_PID_NAK   = 0xau,
+  TOK_PID_BUSTO = 0x0u,
+  TOK_PID_ERR   = 0xfu,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+  union {
+    uint32_t head;
+    struct {
+      union {
+        struct {
+               uint16_t           :  2;
+          __IO uint16_t tok_pid   :  4;
+               uint16_t data      :  1;
+          __IO uint16_t own       :  1;
+               uint16_t           :  8;
+        };
+        struct {
+               uint16_t           :  2;
+               uint16_t bdt_stall :  1;
+               uint16_t dts       :  1;
+               uint16_t ninc      :  1;
+               uint16_t keep      :  1;
+               uint16_t           : 10;
+        };
+      };
+      __IO uint16_t bc : 10;
+           uint16_t    :  6;
+    };
+  };
+  uint8_t *addr;
+}buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+
+typedef struct TU_ATTR_PACKED
+{
+  union {
+    uint32_t state;
+    struct {
+      uint32_t pipenum:16;
+      uint32_t odd    : 1;
+      uint32_t        : 0;
+    };
+  };
+  uint8_t *buffer;
+  uint16_t length;
+  uint16_t remaining;
+} endpoint_state_t;
+
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  dev_addr;
+  uint8_t  ep_addr;
+  uint16_t max_packet_size;
+  union {
+    uint8_t flags;
+    struct {
+      uint8_t data : 1;
+      uint8_t xfer : 2;
+      uint8_t      : 0;
+    };
+  };
+  uint8_t *buffer;
+  uint16_t length;
+  uint16_t remaining;
+} pipe_state_t;
+
+
+typedef struct
+{
+  union {
+    /* [OUT,IN][EVEN,ODD] */
+    buffer_descriptor_t bdt[2][2];
+    uint16_t            bda[2*2];
+  };
+  endpoint_state_t endpoint[2];
+  pipe_state_t pipe[HCD_MAX_XFER * 2];
+  uint32_t     in_progress; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe is in progress */
+  uint32_t     pending;     /* Bitmap. Each bit indicates that a transfer of the corresponding pipe will be resume the next frame */
+  bool         need_reset;  /* The device has not been reset after connection. */
+} hcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static hcd_data_t _hcd;
+//CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _rx_buf[1024];
+
+int find_pipe(uint8_t dev_addr, uint8_t ep_addr)
+{
+  /* Find the target pipe */
+  int num;
+  for (num = 0; num < HCD_MAX_XFER * 2; ++num) {
+    pipe_state_t *p = &_hcd.pipe[num];
+    if ((p->dev_addr == dev_addr) && (p->ep_addr == ep_addr))
+      return num;
+  }
+  return -1;
+}
+
+static int prepare_packets(int pipenum)
+{
+  pipe_state_t *pipe      = &_hcd.pipe[pipenum];
+  unsigned const dir_tx   = tu_edpt_dir(pipe->ep_addr) ? 0 : 1;
+  endpoint_state_t *ep    = &_hcd.endpoint[dir_tx];
+  unsigned const odd      = ep->odd;
+  buffer_descriptor_t *bd = _hcd.bdt[dir_tx];
+  TU_ASSERT(0 == bd[odd].own, -1);
+
+  // TU_LOG1("  %p dir %d odd %d data %d\n", &bd[odd], dir_tx, odd, pipe->data);
+
+  ep->pipenum = pipenum;
+
+  bd[odd    ].data      = pipe->data;
+  bd[odd ^ 1].data      = pipe->data ^ 1;
+  bd[odd ^ 1].own       = 0;
+  /* reset values for a next transfer */
+
+  int num_tokens = 0; /* The number of prepared packets */
+  unsigned const mps = pipe->max_packet_size;
+  unsigned const rem = pipe->remaining;
+  if (rem > mps) {
+    /* When total_bytes is greater than the max packet size,
+     * it prepares to the next transfer to avoid NAK in advance. */
+    bd[odd ^ 1].bc   = rem >= 2 * mps ? mps: rem - mps;
+    bd[odd ^ 1].addr = pipe->buffer + mps;
+    bd[odd ^ 1].own  = 1;
+    if (dir_tx) ++num_tokens;
+  }
+  bd[odd].bc   = rem >= mps ? mps: rem;
+  bd[odd].addr = pipe->buffer;
+  __DSB();
+  bd[odd].own  = 1; /* This bit must be set last */
+  ++num_tokens;
+  return num_tokens;
+}
+
+static int select_next_pipenum(int pipenum)
+{
+  unsigned wip  = _hcd.in_progress & ~_hcd.pending;
+  if (!wip) return -1;
+  unsigned msk  = TU_GENMASK(31, pipenum);
+  int      next = __builtin_ctz(wip & msk);
+  if (next) return next;
+  msk  = TU_GENMASK(pipenum, 0);
+  next = __builtin_ctz(wip & msk);
+  return next;
+}
+
+/* When transfer is completed, return true. */
+static bool continue_transfer(int pipenum, buffer_descriptor_t *bd)
+{
+  pipe_state_t *pipe = &_hcd.pipe[pipenum];
+  unsigned const bc  = bd->bc;
+  unsigned const rem = pipe->remaining - bc;
+
+  pipe->remaining = rem;
+  if (rem && bc == pipe->max_packet_size) {
+    int const next_rem = rem - pipe->max_packet_size;
+    if (next_rem > 0) {
+      /* Prepare to the after next transfer */
+      bd->addr += pipe->max_packet_size * 2;
+      bd->bc    = next_rem > pipe->max_packet_size ? pipe->max_packet_size: next_rem;
+      __DSB();
+      bd->own   = 1; /* This bit must be set last */
+      while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+      KHCI->TOKEN = KHCI->TOKEN; /* Queue the same token as the last */
+    } else if (TUSB_DIR_IN == tu_edpt_dir(pipe->ep_addr)) { /* IN */
+      while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+      KHCI->TOKEN = KHCI->TOKEN;
+    }
+    return true;
+  }
+  pipe->data = bd->data ^ 1;
+  return false;
+}
+
+static bool resume_transfer(int pipenum)
+{
+  int num_tokens = prepare_packets(pipenum);
+  TU_ASSERT(0 <= num_tokens);
+
+  const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  pipe_state_t *pipe = &_hcd.pipe[pipenum];
+
+  unsigned flags = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
+  flags |= USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+  switch (pipe->xfer) {
+  case TUSB_XFER_CONTROL:
+    flags |= USB_ENDPT_EPHSHK_MASK;
+    break;
+  case TUSB_XFER_ISOCHRONOUS:
+    flags |= USB_ENDPT_EPCTLDIS_MASK | USB_ENDPT_RETRYDIS_MASK;
+    break;
+  default:
+    flags |= USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPCTLDIS_MASK | USB_ENDPT_RETRYDIS_MASK;
+    break;
+  }
+  // TU_LOG1("  resume pipenum %d flags %x\n", pipenum, flags);
+
+  KHCI->ENDPOINT[0].ENDPT = flags;
+  KHCI->ADDR  = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | pipe->dev_addr;
+
+  unsigned const token = tu_edpt_number(pipe->ep_addr) |
+    ((tu_edpt_dir(pipe->ep_addr) ? TOK_PID_IN: TOK_PID_OUT) << USB_TOKEN_TOKENPID_SHIFT);
+  do {
+    while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+    KHCI->TOKEN = token;
+  } while (--num_tokens);
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+  return true;
+}
+
+static void suspend_transfer(int pipenum, buffer_descriptor_t *bd)
+{
+  pipe_state_t *pipe = &_hcd.pipe[pipenum];
+  pipe->buffer  = bd->addr;
+  pipe->data    = bd->data ^ 1;
+  if ((TUSB_XFER_INTERRUPT == pipe->xfer) ||
+      (TUSB_XFER_BULK == pipe->xfer)) {
+    _hcd.pending |= TU_BIT(pipenum);
+    KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK;
+  }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+  (void)rhport;
+  const unsigned s = KHCI->STAT;
+  KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+  uint8_t const dir_in = (s & USB_STAT_TX_MASK) ? TUSB_DIR_OUT: TUSB_DIR_IN;
+  unsigned const odd   = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
+  buffer_descriptor_t *bd = (buffer_descriptor_t *)&_hcd.bda[s];
+  endpoint_state_t    *ep = &_hcd.endpoint[s >> 3];
+
+  /* fetch status before discarded by the next steps */
+  const unsigned pid = bd->tok_pid;
+
+  /* reset values for a next transfer */
+  bd->bdt_stall = 0;
+  bd->dts       = 1;
+  bd->ninc      = 0;
+  bd->keep      = 0;
+  /* Update the odd variable to prepare for the next transfer */
+  ep->odd       = odd ^ 1;
+
+  int pipenum = ep->pipenum;
+  int next_pipenum;
+  // TU_LOG1("TOKDNE %x PID %x pipe %d\n", s, pid, pipenum);
+
+  xfer_result_t result;
+  switch (pid) {
+    default:
+      if (continue_transfer(pipenum, bd))
+        return;
+      result = XFER_RESULT_SUCCESS;
+      break;
+    case TOK_PID_NAK:
+      suspend_transfer(pipenum, bd);
+      next_pipenum = select_next_pipenum(pipenum);
+      if (0 <= next_pipenum)
+        resume_transfer(next_pipenum);
+      return;
+    case TOK_PID_STALL:
+      result = XFER_RESULT_STALLED;
+      break;
+    case TOK_PID_ERR: /* mismatch toggle bit */
+    case TOK_PID_BUSTO:
+      result = XFER_RESULT_FAILED;
+      break;
+  }
+  _hcd.in_progress  &= ~TU_BIT(pipenum);
+  pipe_state_t *pipe = &_hcd.pipe[ep->pipenum];
+  hcd_event_xfer_complete(pipe->dev_addr,
+                          tu_edpt_addr(KHCI->TOKEN & USB_TOKEN_TOKENENDPT_MASK, dir_in),
+                          pipe->length - pipe->remaining,
+                          result, true);
+  next_pipenum = select_next_pipenum(pipenum);
+  if (0 <= next_pipenum)
+    resume_transfer(next_pipenum);
+}
+
+static void process_attach(uint8_t rhport)
+{
+  unsigned ctl = KHCI->CTL;
+  if (!(ctl & USB_CTL_JSTATE_MASK)) {
+    /* The attached device is a low speed device. */
+    KHCI->ADDR = USB_ADDR_LSEN_MASK;
+    KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_HOSTWOHUB_MASK;
+  }
+  hcd_event_device_attach(rhport, true);
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+  KHCI->ISTAT    = USB_ISTAT_TOKDNE_MASK;
+  KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+  KHCI->CTL     &= ~USB_CTL_USBENSOFEN_MASK;
+  KHCI->ADDR     = 0;
+  KHCI->ENDPOINT[0].ENDPT = 0;
+
+  hcd_event_device_remove(rhport, true);
+
+  _hcd.in_progress = 0;
+  _hcd.pending     = 0;
+  buffer_descriptor_t *bd = &_hcd.bdt[0][0];
+  for (unsigned i = 0; i < 2; ++i, ++bd) {
+    bd->head = 0;
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* Host API
+ *------------------------------------------------------------------*/
+bool hcd_init(uint8_t rhport)
+{
+  (void)rhport;
+
+  KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+  while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+  tu_memclr(&_hcd, sizeof(_hcd));
+  KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
+  KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_hcd.bdt >>  8);
+  KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_hcd.bdt >> 16);
+  KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_hcd.bdt >> 24);
+
+  KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+  KHCI->CTL     |= USB_CTL_ODDRST_MASK;
+  for (unsigned i = 0; i < 16; ++i) {
+    KHCI->ENDPOINT[i].ENDPT = 0;
+  }
+  KHCI->CTL &= ~USB_CTL_ODDRST_MASK;
+
+  KHCI->SOFTHLD = 74; /* for 64-byte packets */
+  // KHCI->SOFTHLD = 144; /* for low speed 8-byte packets */
+  KHCI->CTL     = USB_CTL_HOSTMODEEN_MASK | USB_CTL_SE0_MASK;
+  KHCI->USBCTRL = USB_USBCTRL_PDE_MASK;
+
+  NVIC_ClearPendingIRQ(USB0_IRQn);
+  KHCI->INTEN = USB_INTEN_ATTACHEN_MASK | USB_INTEN_TOKDNEEN_MASK |
+    USB_INTEN_USBRSTEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
+  KHCI->ERREN = 0xff;
+
+  return true;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+  (void)rhport;
+  NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+  (void)rhport;
+  NVIC_DisableIRQ(USB0_IRQn);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+  (void)rhport;
+  /* The device must be reset at least once after connection 
+   * in order to start the frame counter. */
+  if (_hcd.need_reset) hcd_port_reset(rhport);
+  uint32_t frmnum = KHCI->FRMNUML;
+  frmnum |= KHCI->FRMNUMH << 8u;
+   return frmnum;
+}
+
+/*--------------------------------------------------------------------+
+ * Port API
+ *--------------------------------------------------------------------+ */
+bool hcd_port_connect_status(uint8_t rhport)
+{
+  (void)rhport;
+  if (KHCI->ISTAT & USB_ISTAT_ATTACH_MASK)
+    return true;
+  return false;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+  (void)rhport;
+  KHCI->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+  KHCI->CTL |= USB_CTL_RESET_MASK;
+  unsigned cnt = SystemCoreClock / 100;
+  while (cnt--) __NOP();
+  KHCI->CTL &= ~USB_CTL_RESET_MASK;
+  KHCI->CTL |= USB_CTL_USBENSOFEN_MASK;
+  _hcd.need_reset = false;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+  (void)rhport;
+  tusb_speed_t speed = TUSB_SPEED_FULL;
+  const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  if (KHCI->ADDR & USB_ADDR_LSEN_MASK)
+    speed = TUSB_SPEED_LOW;
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+  return speed;
+}
+
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+  (void)rhport;
+  const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  pipe_state_t *p   = &_hcd.pipe[0];
+  pipe_state_t *end = &_hcd.pipe[HCD_MAX_XFER * 2];
+  for (;p != end; ++p) {
+    if (p->dev_addr == dev_addr)
+      tu_memclr(p, sizeof(*p));
+  }
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+}
+
+//--------------------------------------------------------------------+
+// Endpoints API
+//--------------------------------------------------------------------+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+  (void)rhport;
+  // TU_LOG1("SETUP %u\n", dev_addr);
+  TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(0)));
+
+  int pipenum = find_pipe(dev_addr, 0);
+  if (pipenum < 0) return false;
+
+  pipe_state_t *pipe = &_hcd.pipe[pipenum];
+  pipe[0].data       = 0;
+  pipe[0].buffer     = (uint8_t*)(uintptr_t)setup_packet;
+  pipe[0].length     = 8;
+  pipe[0].remaining  = 8;
+  pipe[1].data       = 1;
+
+  if (1 != prepare_packets(pipenum))
+    return false;
+
+  _hcd.in_progress |= TU_BIT(pipenum);
+
+  unsigned hostwohub = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
+  KHCI->ENDPOINT[0].ENDPT = hostwohub |
+    USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+  KHCI->ADDR  = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | dev_addr;
+  while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
+  KHCI->TOKEN = (TOK_PID_SETUP << USB_TOKEN_TOKENPID_SHIFT);
+  return true;
+}
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+  (void)rhport;
+  uint8_t const ep_addr = ep_desc->bEndpointAddress;
+  // TU_LOG1("O %u %x\n", dev_addr, ep_addr);
+  /* Find a free pipe */
+  pipe_state_t *p = &_hcd.pipe[0];
+  pipe_state_t *end = &_hcd.pipe[HCD_MAX_XFER * 2];
+  if (dev_addr || ep_addr) {
+    p += 2;
+    for (; p < end && (p->dev_addr || p->ep_addr); ++p) ;
+    if (p == end) return false;
+  }
+  p->dev_addr        = dev_addr;
+  p->ep_addr         = ep_addr;
+  p->max_packet_size = ep_desc->wMaxPacketSize;
+  p->xfer            = ep_desc->bmAttributes.xfer;
+  p->data            = 0;
+  if (!ep_addr) {
+    /* Open one more pipe for Control IN transfer */
+    TU_ASSERT(TUSB_XFER_CONTROL == p->xfer);
+    pipe_state_t *q = p + 1;
+    TU_ASSERT(!q->dev_addr && !q->ep_addr);
+    q->dev_addr        = dev_addr;
+    q->ep_addr         = tu_edpt_addr(0, TUSB_DIR_IN);
+    q->max_packet_size = ep_desc->wMaxPacketSize;
+    q->xfer            = ep_desc->bmAttributes.xfer;
+    q->data            = 1;
+  }
+  return true;
+}
+
+/* The address of buffer must be aligned to 4 byte boundary. And it must be at least 4 bytes long.
+ * DMA writes data in 4 byte unit */
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
+{
+  (void)rhport;
+  // TU_LOG1("X %u %x %x %d\n", dev_addr, ep_addr, (uintptr_t)buffer, buflen);
+
+  int pipenum = find_pipe(dev_addr, ep_addr);
+  TU_ASSERT(0 <= pipenum);
+
+  TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(pipenum)));
+  unsigned const ie  = NVIC_GetEnableIRQ(USB0_IRQn);
+  NVIC_DisableIRQ(USB0_IRQn);
+  pipe_state_t *pipe = &_hcd.pipe[pipenum];
+  pipe->buffer       = buffer;
+  pipe->length       = buflen;
+  pipe->remaining    = buflen;
+  _hcd.in_progress  |= TU_BIT(pipenum);
+  _hcd.pending      |= TU_BIT(pipenum); /* Send at the next Frame */
+  KHCI->INTEN |= USB_ISTAT_SOFTOK_MASK;
+  if (ie) NVIC_EnableIRQ(USB0_IRQn);
+  return true;
+}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+  if (!tu_edpt_number(ep_addr)) return true;
+  int num = find_pipe(dev_addr, ep_addr);
+  if (num < 0) return false;
+  pipe_state_t *p = &_hcd.pipe[num];
+  p->data = 0; /* Reset data toggle */
+  return true;
+}
+
+/*--------------------------------------------------------------------+
+ * ISR
+ *--------------------------------------------------------------------+*/
+void hcd_int_handler(uint8_t rhport)
+{
+  uint32_t is  = KHCI->ISTAT;
+  uint32_t msk = KHCI->INTEN;
+
+  // TU_LOG1("S %lx\n", is);
+
+  /* clear disabled interrupts */
+  KHCI->ISTAT = (is & ~msk & ~USB_ISTAT_TOKDNE_MASK) | USB_ISTAT_SOFTOK_MASK;
+  is &= msk;
+
+  if (is & USB_ISTAT_ERROR_MASK) {
+    unsigned err = KHCI->ERRSTAT;
+    if (err) {
+      TU_LOG1(" ERR %x\n", err);
+      KHCI->ERRSTAT = err;
+    } else {
+      KHCI->INTEN &= ~USB_ISTAT_ERROR_MASK;
+    }
+  }
+
+  if (is & USB_ISTAT_USBRST_MASK) {
+    KHCI->INTEN = (msk & ~USB_INTEN_USBRSTEN_MASK) | USB_INTEN_ATTACHEN_MASK;
+    process_bus_reset(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_ATTACH_MASK) {
+    KHCI->INTEN = (msk & ~USB_INTEN_ATTACHEN_MASK) | USB_INTEN_USBRSTEN_MASK;
+    _hcd.need_reset = true;
+    process_attach(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_STALL_MASK) {
+    KHCI->ISTAT = USB_ISTAT_STALL_MASK;
+  }
+  if (is & USB_ISTAT_SOFTOK_MASK) {
+    msk &= ~USB_ISTAT_SOFTOK_MASK;
+    KHCI->INTEN = msk;
+    if (_hcd.pending) {
+      int pipenum = __builtin_ctz(_hcd.pending);
+      _hcd.pending = 0;
+      if (!(is & USB_ISTAT_TOKDNE_MASK))
+        resume_transfer(pipenum);
+    }
+  }
+  if (is & USB_ISTAT_TOKDNE_MASK) {
+    process_tokdne(rhport);
+  }
+}
+
+#endif

+ 1 - 1
src/portable/ohci/ohci.h

@@ -159,7 +159,7 @@ typedef struct TU_ATTR_ALIGNED(256)
   struct {
     ohci_ed_t ed;
     ohci_gtd_t gtd;
-  }control[CFG_TUH_DEVICE_MAX+1];
+  }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
 
   //  ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
   ohci_ed_t ed_pool[HCD_MAX_ENDPOINT];

+ 1211 - 0
src/portable/sunxi/dcd_sunxi_musb.c

@@ -0,0 +1,1211 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include <stdint.h>
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_F1C100S
+
+#include "osal/osal.h"
+#include <f1c100s-irq.h>
+#include <device/dcd.h>
+#include "musb_def.h"
+#include "bsp/board.h"
+
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+
+#define REQUEST_TYPE_INVALID  (0xFFu)
+
+typedef struct {
+  uint_fast16_t beg; /* offset of including first element */
+  uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+typedef struct TU_ATTR_PACKED
+{
+  void      *buf;      /* the start address of a transfer data buffer */
+  uint16_t  length;    /* the number of bytes in the buffer */
+  uint16_t  remaining; /* the number of bytes remaining in the buffer */
+} pipe_state_t;
+
+typedef struct
+{
+  tusb_control_request_t setup_packet;
+  uint16_t     remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
+  int8_t       status_out;
+  pipe_state_t pipe0;
+  pipe_state_t pipe[2][7];   /* pipe[direction][endpoint number - 1] */
+  uint16_t     pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */
+} dcd_data_t;
+
+/*------------------------------------------------------------------
+ * SUNXI FUNCTION
+ *------------------------------------------------------------------*/
+
+static void usb_phy_write(int addr, int data, int len)
+{
+	int j = 0, usbc_bit = 0;
+	void *dest = (void *)USBC_REG_CSR(USBC0_BASE);
+
+	usbc_bit = 1 << (0 * 2);
+	for (j = 0; j < len; j++)
+	{
+		/* set the bit address to be written */
+		USBC_ClrBit_Mask_l(dest, 0xff << 8);
+		USBC_SetBit_Mask_l(dest, (addr + j) << 8);
+
+		USBC_ClrBit_Mask_l(dest, usbc_bit);
+		/* set data bit */
+		if (data & 0x1)
+			USBC_SetBit_Mask_l(dest, 1 << 7);
+		else
+			USBC_ClrBit_Mask_l(dest, 1 << 7);
+
+		USBC_SetBit_Mask_l(dest, usbc_bit);
+
+		USBC_ClrBit_Mask_l(dest, usbc_bit);
+
+		data >>= 1;
+	}
+}
+
+static void delay_ms(uint32_t ms)
+{
+#if CFG_TUSB_OS == OPT_OS_NONE
+  int now = board_millis();
+  while (board_millis() - now <= ms) asm("nop");
+#else
+  osal_task_delay(ms);
+#endif
+}
+
+static void USBC_HardwareReset(void)
+{
+  // Reset phy and controller
+  USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
+	USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
+  delay_ms(2);
+
+	USBC_REG_set_bit_l(USBPHY_CLK_GAT_BIT, USBPHY_CLK_REG);
+  USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
+
+	USBC_REG_set_bit_l(BUS_CLK_USB_BIT, BUS_CLK_GATE0_REG);
+	USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
+}
+
+static void USBC_PhyConfig(void)
+{
+	/* Regulation 45 ohms */
+	usb_phy_write(0x0c, 0x01, 1);
+
+	/* adjust PHY's magnitude and rate */
+	usb_phy_write(0x20, 0x14, 5);
+
+	/* threshold adjustment disconnect */
+	usb_phy_write(0x2a, 3, 2);
+
+	return;
+}
+
+static void USBC_ConfigFIFO_Base(void)
+{
+	u32 reg_value;
+
+	/* config usb fifo, 8kb mode */
+	reg_value = USBC_Readl(SUNXI_SRAMC_BASE + 0x04);
+	reg_value &= ~(0x03 << 0);
+	reg_value |= (1 << 0);
+	USBC_Writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
+}
+
+static unsigned int USBC_WakeUp_ClearChangeDetect(unsigned int reg_val)
+{
+	unsigned int temp = reg_val;
+    /* vbus, id, dpdm, these bit is set 1 to clear, so we clear these bit when operate other bits */
+	temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT);
+	temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT);
+	temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT);
+
+	return temp;
+}
+
+static void USBC_EnableDpDmPullUp(void)
+{
+	u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+	reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
+	reg_val |= 3<<USBC_BP_ISCR_VBUS_VALID_SRC;
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+static void USBC_ForceIdToHigh(void)
+{
+	/* first write 00, then write 10 */
+	u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+static void USBC_ForceVbusValidToHigh(void)
+{
+	/* first write 00, then write 11 */
+	u32 reg_val = USBC_Readl(USBC_REG_ISCR(USBC0_BASE));
+	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	USBC_Writel(reg_val, USBC_REG_ISCR(USBC0_BASE));
+}
+
+void USBC_SelectBus(u32 io_type, u32 ep_type, u32 ep_index)
+{
+	u32 reg_val = 0;
+
+	reg_val = USBC_Readb(USBC_REG_VEND0(USBC0_BASE));
+	if (io_type == USBC_IO_TYPE_DMA) {
+		if (ep_type == USBC_EP_TYPE_TX) {
+			reg_val |= ((ep_index - 0x01) << 1) << USBC_BP_VEND0_DRQ_SEL;  //drq_sel
+			reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL;   //io_dma
+		} else {
+			reg_val |= ((ep_index << 1) - 0x01) << USBC_BP_VEND0_DRQ_SEL;
+			reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL;
+		}
+	} else {
+		//reg_val &= ~(0x1 << USBC_BP_VEND0_DRQ_SEL);  //clear drq_sel, select pio
+		reg_val &= 0x00;  // clear drq_sel, select pio
+	}
+
+	/* in 1667 1673 and later ic, FIFO_BUS_SEL bit(bit24 of reg0x40 for host/device)
+	 * is fixed to 1, the hw guarantee that it's ok for cpu/inner_dma/outer_dma transfer */
+
+//	reg_val |= 0x1<<USBC_BP_VEND0_BUS_SEL;  //for 1663 set 1: enable dma, set 0: enable fifo
+
+	USBC_Writeb(reg_val, USBC_REG_VEND0(USBC0_BASE));
+}
+
+static void USBC_SelectActiveEp(u8 ep_index)
+{
+	USBC_Writeb(ep_index, USBC_REG_EPIND(USBC0_BASE));
+}
+
+static u8 USBC_GetActiveEp(void)
+{
+	return USBC_Readb(USBC_REG_EPIND(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_SendStall(void)
+{
+	USBC_REG_set_bit_w(USBC_BP_CSR0_D_SEND_STALL, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_ClearStall(void)
+{
+	USBC_REG_clear_bit_w(USBC_BP_CSR0_D_SEND_STALL, USBC_REG_CSR0(USBC0_BASE));
+	USBC_REG_clear_bit_w(USBC_BP_CSR0_D_SENT_STALL, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void USBC_Dev_Ctrl_ClearSetupEnd(void)
+{
+	USBC_REG_set_bit_w(USBC_BP_CSR0_D_SERVICED_SETUP_END, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void USBC_Dev_SetAddress(u8 address)
+{
+	USBC_Writeb(address, USBC_REG_FADDR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Tx_SendStall(void)
+{
+	//send stall, and fifo is flushed automaticly
+	USBC_REG_set_bit_w(USBC_BP_TXCSR_D_SEND_STALL, USBC_REG_TXCSR(USBC0_BASE));
+}
+static u32 __USBC_Dev_Tx_IsEpStall(void)
+{
+	return USBC_REG_test_bit_w(USBC_BP_TXCSR_D_SENT_STALL, USBC_REG_TXCSR(USBC0_BASE));
+}
+static void __USBC_Dev_Tx_ClearStall(void)
+{
+	u32 reg_val = USBC_Readw(USBC_REG_TXCSR(USBC0_BASE));
+	reg_val &= ~((1 << USBC_BP_TXCSR_D_SENT_STALL)|(1 << USBC_BP_TXCSR_D_SEND_STALL)|(1<<USBC_BP_TXCSR_D_UNDER_RUN));
+  reg_val |= (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE);
+	USBC_Writew(reg_val, USBC_REG_TXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_SendStall(void)
+{
+	USBC_REG_set_bit_w(USBC_BP_RXCSR_D_SEND_STALL, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static u32 __USBC_Dev_Rx_IsEpStall(void)
+{
+	return USBC_REG_test_bit_w(USBC_BP_RXCSR_D_SENT_STALL, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_ClearStall(void)
+{
+	u32 reg_val = USBC_Readw(USBC_REG_RXCSR(USBC0_BASE));
+	reg_val &= ~((1 << USBC_BP_RXCSR_D_SENT_STALL)|(1 << USBC_BP_RXCSR_D_SEND_STALL)|(1<<USBC_BP_RXCSR_D_OVERRUN));
+  reg_val |= (1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE);
+	USBC_Writew(reg_val, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static tusb_speed_t USBC_Dev_QueryTransferMode(void)
+{
+	if (USBC_REG_test_bit_b(USBC_BP_POWER_D_HIGH_SPEED_FLAG, USBC_REG_PCTL(USBC0_BASE)))
+		return TUSB_SPEED_HIGH;
+  else
+		return TUSB_SPEED_FULL;
+}
+
+static void __USBC_Dev_ep0_ReadDataHalf(void)
+{
+	USBC_Writew(1<<USBC_BP_CSR0_D_SERVICED_RX_PKT_READY, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_ReadDataComplete(void)
+{
+	USBC_Writew((1<<USBC_BP_CSR0_D_SERVICED_RX_PKT_READY) | (1<<USBC_BP_CSR0_D_DATA_END),
+	USBC_REG_CSR0(USBC0_BASE));
+}
+
+
+static void __USBC_Dev_ep0_WriteDataHalf(void)
+{
+	USBC_Writew(1<<USBC_BP_CSR0_D_TX_PKT_READY, USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_ep0_WriteDataComplete(void)
+{
+	USBC_Writew((1<<USBC_BP_CSR0_D_TX_PKT_READY) | (1<<USBC_BP_CSR0_D_DATA_END),
+	USBC_REG_CSR0(USBC0_BASE));
+}
+
+static void __USBC_Dev_Tx_WriteDataComplete(void)
+{
+	USBC_Writeb((1 << USBC_BP_TXCSR_D_TX_READY), USBC_REG_TXCSR(USBC0_BASE));
+}
+
+static void __USBC_Dev_Rx_ReadDataComplete(void)
+{
+	USBC_Writeb(0, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+static u32 __USBC_Dev_Rx_IsReadDataReady(void)
+{
+	return USBC_REG_test_bit_w(USBC_BP_RXCSR_D_RX_PKT_READY, USBC_REG_RXCSR(USBC0_BASE));
+}
+
+/* open a tx ep's interrupt */
+static void USBC_INT_EnableTxEp(u8 ep_index)
+{
+	USBC_REG_set_bit_w(ep_index, USBC_REG_INTTxE(USBC0_BASE));
+}
+
+/* open a rx ep's interrupt */
+static void USBC_INT_EnableRxEp(u8 ep_index)
+{
+	USBC_REG_set_bit_w(ep_index, USBC_REG_INTRxE(USBC0_BASE));
+}
+
+/* close a tx ep's interrupt */
+static void USBC_INT_DisableTxEp(u8 ep_index)
+{
+	USBC_REG_clear_bit_w(ep_index, USBC_REG_INTTxE(USBC0_BASE));
+}
+
+/* close a rx ep's interrupt */
+static void USBC_INT_DisableRxEp(u8 ep_index)
+{
+	USBC_REG_clear_bit_w(ep_index, USBC_REG_INTRxE(USBC0_BASE));
+}
+
+/*------------------------------------------------------------------
+ * INTERNAL FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+
+static dcd_data_t _dcd;
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+  free_block_t *cur = beg;
+  for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+  return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+  free_block_t *p = find_containing_block(blks, blks + num, addr);
+  TU_ASSERT(p != blks + num, -2);
+  if (p->beg == addr) {
+    /* Shrink block */
+    p->beg = addr + size;
+    if (p->beg != p->end) return 0;
+    /* remove block */
+    free_block_t *end = blks + num;
+    while (p + 1 < end) {
+      *p = *(p + 1);
+      ++p;
+    }
+    return -1;
+  } else {
+    /* Split into 2 blocks */
+    free_block_t tmp = {
+      .beg = addr + size,
+      .end = p->end
+    };
+    p->end = addr;
+    if (p->beg == p->end) {
+      if (tmp.beg != tmp.end) {
+        *p = tmp;
+        return 0;
+      }
+      /* remove block */
+      free_block_t *end = blks + num;
+      while (p + 1 < end) {
+        *p = *(p + 1);
+        ++p;
+      }
+      return -1;
+    }
+    if (tmp.beg == tmp.end) return 0;
+    blks[num] = tmp;
+    return 1;
+  }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+  return blk->end - blk->beg;
+}
+
+#if 0
+static inline void print_block_list(free_block_t const *blk, unsigned num)
+{
+  TU_LOG1("*************\n");
+  for (unsigned i = 0; i < num; ++i) {
+    TU_LOG1(" Blk%u %u %u\n", i, blk->beg, blk->end);
+    ++blk;
+  }
+}
+#else
+#define print_block_list(a,b)
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_F1C100S
+#define USB_FIFO_SIZE_KB 4
+#else
+#error "Unsupported MCU"
+#endif
+
+static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
+{
+  free_block_t free_blocks[2 * (DCD_ATTR_ENDPOINT_MAX - 1)];
+  unsigned num_blocks = 1;
+  /* Backup current EP to restore later */
+  u8 backup_ep = USBC_GetActiveEp();
+
+  /* Initialize free memory block list */
+  free_blocks[0].beg = 64 / 8;
+  free_blocks[0].end = (USB_FIFO_SIZE_KB << 10) / 8; /* 2KiB / 8 bytes */
+  for (int i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+    uint_fast16_t addr;
+    int num;
+    USBC_SelectActiveEp(i);
+    addr = USBC_Readw(USBC_REG_TXFIFOAD(USBC0_BASE));
+    if (addr) {
+      unsigned sz  = USBC_Readb(USBC_REG_TXFIFOSZ(USBC0_BASE));
+      unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+      num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+      TU_ASSERT(-2 < num, 0);
+      num_blocks += num;
+      print_block_list(free_blocks, num_blocks);
+    }
+    addr = USBC_Readw(USBC_REG_RXFIFOAD(USBC0_BASE));
+    if (addr) {
+      unsigned sz  = USBC_Readb(USBC_REG_RXFIFOSZ(USBC0_BASE));
+      unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+      num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+      TU_ASSERT(-2 < num, 0);
+      num_blocks += num;
+      print_block_list(free_blocks, num_blocks);
+    }
+  }
+  print_block_list(free_blocks, num_blocks);
+
+  USBC_SelectActiveEp(backup_ep);
+
+  /* Find the best fit memory block */
+  uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+  free_block_t const *min = NULL;
+  uint_fast16_t    min_sz = 0xFFFFu;
+  free_block_t const *end = &free_blocks[num_blocks];
+  for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+    uint_fast16_t sz = free_block_size(cur);
+    if (sz < size_in_8byte_unit) continue;
+    if (size_in_8byte_unit == sz) return cur->beg;
+    if (sz < min_sz) min = cur;
+  }
+  TU_ASSERT(min, 0);
+  return min->beg;
+}
+
+static void pipe_write_packet(void *buff, volatile void *fifo, unsigned cnt)
+{
+ 	u32 len = 0;
+	u32 i32 = 0;
+	u32 i8  = 0;
+	u8  *buf8  = 0;
+	u32 *buf32 = 0;
+
+	//--<1>-- adjust data
+	buf32 = buff;
+	len   = cnt;
+
+	i32 = len >> 2;
+	i8  = len & 0x03;
+
+	//--<2>-- deal with 4byte part
+	while (i32--) {
+		USBC_Writel(*buf32++, fifo);
+	}
+
+	//--<3>-- deal with no 4byte part
+	buf8 = (u8 *)buf32;
+	while (i8--) {
+		USBC_Writeb(*buf8++, fifo);
+	}
+}
+
+static void pipe_read_packet(void *buff, volatile void *fifo, unsigned cnt)
+{
+	u32 len = 0;
+	u32 i32 = 0;
+	u32 i8  = 0;
+	u8  *buf8  = 0;
+	u32 *buf32 = 0;
+
+	//--<1>-- adjust data
+	buf32 = buff;
+	len   = cnt;
+
+	i32 = len >> 2;
+	i8  = len & 0x03;
+
+	//--<2>-- deal with 4byte part
+	while (i32--) {
+		*buf32++ = USBC_Readl(fifo);
+	}
+
+	//--<3>-- deal with no 4byte part
+	buf8 = (u8 *)buf32;
+	while (i8--) {
+		*buf8++ = USBC_Readb(fifo);
+	}
+}
+
+static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir)
+{
+  static const struct {
+    void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
+    void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n);
+    void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len);
+  } ops[] = {
+    /* OUT */ {tu_fifo_get_write_info,tu_fifo_advance_write_pointer,pipe_read_packet},
+    /* IN  */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet},
+  };
+  tu_fifo_buffer_info_t info;
+  ops[dir].tu_fifo_get_info(f, &info);
+  unsigned total_len = len;
+  len = TU_MIN(total_len, info.len_lin);
+  ops[dir].pipe_read_write(info.ptr_lin, fifo, len);
+  unsigned rem = total_len - len;
+  if (rem) {
+    len = TU_MIN(rem, info.len_wrap);
+    ops[dir].pipe_read_write(info.ptr_wrap, fifo, len);
+    rem -= len;
+  }
+  ops[dir].tu_fifo_advance(f, total_len - rem);
+}
+
+/*------------------------------------------------------------------
+ * TRANSFER FUNCTION DECLARATION
+ *------------------------------------------------------------------*/
+
+static void process_setup_packet(uint8_t rhport)
+{
+  uint32_t *p = (uint32_t*)&_dcd.setup_packet;
+  p[0]        = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
+  p[1]        = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
+
+  _dcd.pipe0.buf       = NULL;
+  _dcd.pipe0.length    = 0;
+  _dcd.pipe0.remaining = 0;
+  dcd_event_setup_received(rhport, (const uint8_t*)(uintptr_t)&_dcd.setup_packet, true);
+
+  const unsigned len    = _dcd.setup_packet.wLength;
+  _dcd.remaining_ctrl   = len;
+  const unsigned dir_in = tu_edpt_dir(_dcd.setup_packet.bmRequestType);
+  /* Clear RX FIFO and reverse the transaction direction */
+  if (len && dir_in) __USBC_Dev_ep0_ReadDataHalf();
+}
+
+static bool handle_xfer_in(uint_fast8_t ep_addr)
+{
+  unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+  pipe_state_t  *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+  const unsigned rem  = pipe->remaining;
+
+  if (!rem) {
+    pipe->buf = NULL;
+    return true;
+  }
+
+  const unsigned mps = USBC_Readw(USBC_REG_TXMAXP(USBC0_BASE));
+  const unsigned len = TU_MIN(mps, rem);
+  uint8_t          *buf = pipe->buf;
+  // TU_LOG1("   %p mps %d len %d rem %d\n", buf, mps, len, rem);
+  if (len) {
+    volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
+    if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
+      pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_IN);
+    } else {
+      pipe_write_packet(buf, addr, len);
+      pipe->buf       = buf + len;
+    }
+    pipe->remaining = rem - len;
+  }
+  __USBC_Dev_Tx_WriteDataComplete();
+  // TU_LOG1(" TXCSRL%d = %x %d\n", epnum_minus1 + 1, regs->TXCSRL, rem - len);
+  return false;
+}
+
+static bool handle_xfer_out(uint_fast8_t ep_addr)
+{
+  unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+  pipe_state_t  *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
+  // TU_LOG1(" RXCSRL%d = %x\n", epnum_minus1 + 1, regs->RXCSRL);
+
+  TU_ASSERT(__USBC_Dev_Rx_IsReadDataReady());
+
+  const unsigned mps = USBC_Readw(USBC_REG_RXMAXP(USBC0_BASE));
+  const unsigned rem = pipe->remaining;
+  const unsigned vld = USBC_Readw(USBC_REG_RXCOUNT(USBC0_BASE));
+  const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
+  uint8_t          *buf = pipe->buf;
+  if (len) {
+    volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
+    if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
+      pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_OUT);
+    } else {
+      pipe_read_packet(buf, addr, len);
+      pipe->buf       = buf + len;
+    }
+    pipe->remaining = rem - len;
+  }
+  if ((len < mps) || (rem == len)) {
+    pipe->buf = NULL;
+    return NULL != buf;
+  }
+  __USBC_Dev_Rx_ReadDataComplete();
+  return false;
+}
+
+static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+  (void)rhport;
+
+  unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+  unsigned dir_in       = tu_edpt_dir(ep_addr);
+
+  pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1];
+  pipe->buf          = buffer;
+  pipe->length       = total_bytes;
+  pipe->remaining    = total_bytes;
+
+  USBC_SelectActiveEp(tu_edpt_number(ep_addr));
+
+  if (dir_in) {
+    handle_xfer_in(ep_addr);
+  } else {
+    if (__USBC_Dev_Rx_IsReadDataReady())
+      __USBC_Dev_Rx_ReadDataComplete();
+  }
+  return true;
+}
+
+static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
+{
+  (void)rhport;
+  TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */
+
+  const unsigned req = _dcd.setup_packet.bmRequestType;
+  TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0);
+
+  USBC_SelectActiveEp(0);
+
+  if (req == REQUEST_TYPE_INVALID || _dcd.status_out) {
+    /* STATUS OUT stage.
+     * MUSB controller automatically handles STATUS OUT packets without
+     * software helps. We do not have to do anything. And STATUS stage
+     * may have already finished and received the next setup packet
+     * without calling this function, so we have no choice but to
+     * invoke the callback function of status packet here. */
+    // TU_LOG1(" STATUS OUT CSRL0 = %x\n", CSRL0);
+    _dcd.status_out = 0;
+    if (req == REQUEST_TYPE_INVALID) {
+      dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
+    } else {
+      /* The next setup packet has already been received, it aborts
+       * invoking callback function to avoid confusing TUSB stack. */
+      TU_LOG1("Drop CONTROL_STAGE_ACK\n");
+    }
+    return true;
+  }
+  const unsigned dir_in = tu_edpt_dir(ep_addr);
+  if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
+    TU_ASSERT(total_bytes <= _dcd.remaining_ctrl);
+    const unsigned rem = _dcd.remaining_ctrl;
+    const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
+    if (dir_in) {
+      pipe_write_packet(buffer, (volatile void*) USBC_REG_EPFIFO0(USBC0_BASE), len);
+
+      _dcd.pipe0.buf       = buffer + len;
+      _dcd.pipe0.length    = len;
+      _dcd.pipe0.remaining = 0;
+
+      _dcd.remaining_ctrl  = rem - len;
+      if ((len < 64) || (rem == len)) {
+        _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; /* Change to STATUS/SETUP stage */
+        _dcd.status_out = 1;
+        /* Flush TX FIFO and reverse the transaction direction. */
+        __USBC_Dev_ep0_WriteDataComplete();
+      } else {
+        __USBC_Dev_ep0_WriteDataHalf();
+      }
+      // TU_LOG1(" IN CSRL0 = %x\n", CSRL0);
+    } else {
+      // TU_LOG1(" OUT CSRL0 = %x\n", CSRL0);
+      _dcd.pipe0.buf       = buffer;
+      _dcd.pipe0.length    = len;
+      _dcd.pipe0.remaining = len;
+      __USBC_Dev_ep0_ReadDataHalf();
+    }
+  } else if (dir_in) {
+    // TU_LOG1(" STATUS IN CSRL0 = %x\n", CSRL0);
+    _dcd.pipe0.buf = NULL;
+    _dcd.pipe0.length    = 0;
+    _dcd.pipe0.remaining = 0;
+    /* Clear RX FIFO and reverse the transaction direction */
+    __USBC_Dev_ep0_ReadDataComplete();
+  }
+  return true;
+}
+
+static void process_ep0(uint8_t rhport)
+{
+  USBC_SelectActiveEp(0);
+  uint_fast8_t csrl = USBC_Readw(USBC_REG_CSR0(USBC0_BASE));
+
+  // TU_LOG1(" EP0 CSRL0 = %x\n", csrl);
+
+  if (csrl & USB_CSRL0_STALLED) {
+    /* Returned STALL packet to HOST. */
+    __USBC_Dev_ep0_ClearStall();
+    return;
+  }
+
+  unsigned req = _dcd.setup_packet.bmRequestType;
+  if (csrl & USB_CSRL0_SETEND) {
+    // TU_LOG1("   ABORT by the next packets\n");
+    USBC_Dev_Ctrl_ClearSetupEnd();
+    if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) {
+      /* DATA stage was aborted by receiving STATUS or SETUP packet. */
+      _dcd.pipe0.buf = NULL;
+      _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+      dcd_event_xfer_complete(rhport,
+                              req & TUSB_DIR_IN_MASK,
+                              _dcd.pipe0.length - _dcd.pipe0.remaining,
+                              XFER_RESULT_SUCCESS, true);
+    }
+    req = REQUEST_TYPE_INVALID;
+    if (!(csrl & USB_CSRL0_RXRDY)) return; /* Received SETUP packet */
+  }
+
+  if (csrl & USB_CSRL0_RXRDY) {
+    /* Received SETUP or DATA OUT packet */
+    if (req == REQUEST_TYPE_INVALID) {
+      /* SETUP */
+      TU_ASSERT(sizeof(tusb_control_request_t) == USBC_Readw(USBC_REG_COUNT0(USBC0_BASE)),);
+      process_setup_packet(rhport);
+      return;
+    }
+    if (_dcd.pipe0.buf) {
+      /* DATA OUT */
+      const unsigned vld = USBC_Readw(USBC_REG_COUNT0(USBC0_BASE));
+      const unsigned rem = _dcd.pipe0.remaining;
+      const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
+      pipe_read_packet(_dcd.pipe0.buf, (volatile void*)USBC_REG_EPFIFO0(USBC0_BASE), len);
+
+      _dcd.pipe0.remaining = rem - len;
+      _dcd.remaining_ctrl -= len;
+
+      _dcd.pipe0.buf = NULL;
+      dcd_event_xfer_complete(rhport,
+                              tu_edpt_addr(0, TUSB_DIR_OUT),
+                              _dcd.pipe0.length - _dcd.pipe0.remaining,
+                              XFER_RESULT_SUCCESS, true);
+    }
+    return;
+  }
+
+  /* When CSRL0 is zero, it means that completion of sending a any length packet
+   * or receiving a zero length packet. */
+  if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir(req)) {
+    /* STATUS IN */
+    if (*(const uint16_t*)(uintptr_t)&_dcd.setup_packet == 0x0500) {
+      /* The address must be changed on completion of the control transfer. */
+	  USBC_Dev_SetAddress((uint8_t)_dcd.setup_packet.wValue);
+    }
+    _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+    dcd_event_xfer_complete(rhport,
+                            tu_edpt_addr(0, TUSB_DIR_IN),
+                            _dcd.pipe0.length - _dcd.pipe0.remaining,
+                            XFER_RESULT_SUCCESS, true);
+    return;
+  }
+  if (_dcd.pipe0.buf) {
+    /* DATA IN */
+    _dcd.pipe0.buf = NULL;
+    dcd_event_xfer_complete(rhport,
+                            tu_edpt_addr(0, TUSB_DIR_IN),
+                            _dcd.pipe0.length - _dcd.pipe0.remaining,
+                            XFER_RESULT_SUCCESS, true);
+  }
+}
+
+static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr)
+{
+  bool completed;
+  const unsigned dir_in     = tu_edpt_dir(ep_addr);
+  const unsigned epn        = tu_edpt_number(ep_addr);
+
+  USBC_SelectActiveEp(epn);
+
+  if (dir_in) {
+    // TU_LOG1(" TXCSRL%d = %x\n", epn_minus1 + 1, regs->TXCSRL);
+    if (__USBC_Dev_Tx_IsEpStall()) {
+	  __USBC_Dev_Tx_ClearStall();
+      return;
+    }
+    completed = handle_xfer_in(ep_addr);
+  } else {
+    // TU_LOG1(" RXCSRL%d = %x\n", epn_minus1 + 1, regs->RXCSRL);
+    if (__USBC_Dev_Rx_IsEpStall()) {
+	    __USBC_Dev_Rx_ClearStall();
+      return;
+    }
+    completed = handle_xfer_out(ep_addr);
+  }
+
+  if (completed) {
+    pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1];
+    dcd_event_xfer_complete(rhport, ep_addr,
+                            pipe->length - pipe->remaining,
+                            XFER_RESULT_SUCCESS, true);
+  }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+  /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF),
+   * a control transfer state is SETUP or STATUS stage. */
+  _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+  _dcd.status_out = 0;
+  /* When pipe0.buf has not NULL, DATA stage works in progress. */
+  _dcd.pipe0.buf = NULL;
+
+  USBC_Writew(1, USBC_REG_INTTxE(USBC0_BASE)); /* Enable only EP0 */
+  USBC_Writew(0, USBC_REG_INTRxE(USBC0_BASE));
+
+  dcd_event_bus_reset(rhport, USBC_Dev_QueryTransferMode(), true);
+}
+
+/*------------------------------------------------------------------
+ * Device API
+ *------------------------------------------------------------------*/
+
+static void usb_isr_handler(void) {
+	dcd_int_handler(0);
+}
+
+void dcd_init(uint8_t rhport)
+{
+  dcd_disconnect(rhport);
+  USBC_HardwareReset();
+  USBC_PhyConfig();
+  USBC_ConfigFIFO_Base();
+  USBC_EnableDpDmPullUp();
+  USBC_ForceIdToHigh(); // Force device mode
+  USBC_ForceVbusValidToHigh();
+  USBC_SelectBus(USBC_IO_TYPE_PIO, 0, 0);
+  dcd_edpt_close_all(rhport);
+
+  #if TUD_OPT_HIGH_SPEED
+    USBC_REG_set_bit_b(USBC_BP_POWER_D_HIGH_SPEED_EN, USBC_REG_PCTL(USBC0_BASE));
+  #else
+    USBC_REG_clear_bit_b(USBC_BP_POWER_D_HIGH_SPEED_EN, USBC_REG_PCTL(USBC0_BASE));
+  #endif
+
+  USBC_Writeb((1 << USBC_BP_INTUSBE_EN_SUSPEND)
+    | (1 << USBC_BP_INTUSBE_EN_RESUME)
+    | (1 << USBC_BP_INTUSBE_EN_RESET)
+    | (1 << USBC_BP_INTUSBE_EN_SOF)
+    | (1 << USBC_BP_INTUSBE_EN_DISCONNECT)
+    , USBC_REG_INTUSBE(USBC0_BASE));
+  f1c100s_intc_clear_pend(F1C100S_IRQ_USBOTG);
+  f1c100s_intc_set_isr(F1C100S_IRQ_USBOTG, usb_isr_handler);
+
+  dcd_connect(rhport);
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+  (void)rhport;
+  USBC_REG_set_bit_b(USBC_BP_POWER_D_SOFT_CONNECT, USBC_REG_PCTL(USBC0_BASE));
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+  (void)rhport;
+  USBC_REG_clear_bit_b(USBC_BP_POWER_D_SOFT_CONNECT, USBC_REG_PCTL(USBC0_BASE));
+}
+
+void dcd_int_enable(uint8_t rhport)
+{
+  (void)rhport;
+  f1c100s_intc_enable_irq(F1C100S_IRQ_USBOTG);
+}
+
+static void musb_int_mask(void)
+{
+  f1c100s_intc_mask_irq(F1C100S_IRQ_USBOTG);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void)rhport;
+  f1c100s_intc_disable_irq(F1C100S_IRQ_USBOTG);
+}
+
+static void musb_int_unmask(void)
+{
+  f1c100s_intc_unmask_irq(F1C100S_IRQ_USBOTG);
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  (void)rhport;
+  (void)dev_addr;
+  _dcd.pipe0.buf       = NULL;
+  _dcd.pipe0.length    = 0;
+  _dcd.pipe0.remaining = 0;
+  /* Clear RX FIFO to return ACK. */
+  USBC_SelectActiveEp(0);
+  __USBC_Dev_ep0_ReadDataComplete();
+}
+
+// Wake up host
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void)rhport;
+  USBC_REG_set_bit_b(USBC_BP_POWER_D_RESUME, USBC_REG_PCTL(USBC0_BASE));
+  delay_ms(10);
+  USBC_REG_clear_bit_b(USBC_BP_POWER_D_RESUME, USBC_REG_PCTL(USBC0_BASE));
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+#ifndef __ARMCC_VERSION
+#define __clz __builtin_clz
+#endif
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+  (void) rhport;
+
+  uint16_t reg_val;
+
+  const unsigned ep_addr = ep_desc->bEndpointAddress;
+  const unsigned epn     = tu_edpt_number(ep_addr);
+  const unsigned dir_in  = tu_edpt_dir(ep_addr);
+  const unsigned xfer    = ep_desc->bmAttributes.xfer;
+  const unsigned mps     = tu_edpt_packet_size(ep_desc);
+
+  TU_ASSERT(epn < DCD_ATTR_ENDPOINT_MAX);
+
+  pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
+  pipe->buf       = NULL;
+  pipe->length    = 0;
+  pipe->remaining = 0;
+
+  musb_int_mask();
+
+  // volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+  USBC_SelectActiveEp(epn);
+  if (dir_in) {
+    USBC_Writew(mps, USBC_REG_TXMAXP(USBC0_BASE));
+
+    reg_val = (1 << USBC_BP_TXCSR_D_MODE) 
+      | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO)
+      | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE);
+    if  (xfer == TUSB_XFER_ISOCHRONOUS)
+      reg_val |= (1 << USBC_BP_TXCSR_D_ISO);
+	  USBC_Writew(reg_val, USBC_REG_TXCSR(USBC0_BASE));
+
+    USBC_INT_EnableTxEp(epn);
+  } else {
+    USBC_Writew(mps, USBC_REG_RXMAXP(USBC0_BASE));
+
+    reg_val = (1 << USBC_BP_RXCSR_D_FLUSH_FIFO)
+      | (1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE);
+    if  (xfer == TUSB_XFER_ISOCHRONOUS)
+      reg_val |= (1 << USBC_BP_RXCSR_D_ISO);
+    USBC_Writew(reg_val, USBC_REG_RXCSR(USBC0_BASE));
+
+    USBC_INT_EnableRxEp(epn);
+  }
+
+  /* Setup FIFO */
+  int size_in_log2_minus3 = 28 - TU_MIN(28, __clz((uint32_t)mps));
+  if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+  unsigned addr = find_free_memory(size_in_log2_minus3);
+  TU_ASSERT(addr);
+
+  if (dir_in) {
+    USBC_Writew(addr, USBC_REG_TXFIFOAD(USBC0_BASE));
+    USBC_Writeb(size_in_log2_minus3, USBC_REG_TXFIFOSZ(USBC0_BASE));
+  } else {
+    USBC_Writew(addr, USBC_REG_RXFIFOAD(USBC0_BASE));
+    USBC_Writeb(size_in_log2_minus3, USBC_REG_RXFIFOSZ(USBC0_BASE));
+  }
+
+  musb_int_unmask();
+
+  return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+  (void) rhport;
+  musb_int_mask();
+  USBC_Writew(1, USBC_REG_INTTxE(USBC0_BASE)); /* Enable only EP0 */
+  USBC_Writew(0, USBC_REG_INTRxE(USBC0_BASE));
+  for (unsigned i = 1; i < DCD_ATTR_ENDPOINT_MAX; ++i) {
+    USBC_SelectActiveEp(i);
+    USBC_Writew(0, USBC_REG_TXMAXP(USBC0_BASE));
+		USBC_Writew((1 << USBC_BP_TXCSR_D_MODE) | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO),
+      USBC_REG_TXCSR(USBC0_BASE));
+
+    USBC_Writew(0, USBC_REG_RXMAXP(USBC0_BASE));
+	  USBC_Writew((1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_D_FLUSH_FIFO), 
+      USBC_REG_RXCSR(USBC0_BASE));
+
+    USBC_Writew(0, USBC_REG_TXFIFOAD(USBC0_BASE));
+    USBC_Writeb(0, USBC_REG_TXFIFOSZ(USBC0_BASE));
+    USBC_Writew(0, USBC_REG_RXFIFOAD(USBC0_BASE));
+    USBC_Writeb(0, USBC_REG_RXFIFOSZ(USBC0_BASE));
+  }
+  musb_int_unmask();
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+  (void)rhport;
+  unsigned const epn    = tu_edpt_number(ep_addr);
+  unsigned const dir_in = tu_edpt_dir(ep_addr);
+
+  musb_int_mask();
+  USBC_SelectActiveEp(epn);
+  if (dir_in) {
+    USBC_INT_DisableTxEp(epn);
+    USBC_Writew(0, USBC_REG_TXMAXP(USBC0_BASE));
+		USBC_Writew((1 << USBC_BP_TXCSR_D_MODE) | (1 << USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_TXCSR_D_FLUSH_FIFO),
+      USBC_REG_TXCSR(USBC0_BASE));
+
+    USBC_Writew(0, USBC_REG_TXFIFOAD(USBC0_BASE));
+    USBC_Writeb(0, USBC_REG_TXFIFOSZ(USBC0_BASE));
+  } else {
+    USBC_INT_DisableRxEp(epn);
+    USBC_Writew(0, USBC_REG_RXMAXP(USBC0_BASE));
+	  USBC_Writew((1 << USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE) | (1 << USBC_BP_RXCSR_D_FLUSH_FIFO), 
+      USBC_REG_RXCSR(USBC0_BASE));
+
+    USBC_Writew(0, USBC_REG_RXFIFOAD(USBC0_BASE));
+    USBC_Writeb(0, USBC_REG_RXFIFOSZ(USBC0_BASE));
+  }
+  musb_int_unmask();
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+  (void)rhport;
+  bool ret;
+  // TU_LOG1("X %x %d\n", ep_addr, total_bytes);
+  unsigned const epnum = tu_edpt_number(ep_addr);
+  musb_int_mask();
+
+  if (epnum) {
+    _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1);
+    ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes);
+  } else {
+    ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
+  }
+  musb_int_unmask();
+  return ret;
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+  (void)rhport;
+  bool ret;
+  // TU_LOG1("X %x %d\n", ep_addr, total_bytes);
+  unsigned const epnum = tu_edpt_number(ep_addr);
+  TU_ASSERT(epnum);
+
+  musb_int_mask();
+  _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1);
+  ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes);
+  musb_int_unmask();
+
+  return ret;
+}
+
+// Stall endpoint
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void)rhport;
+  unsigned const epn = tu_edpt_number(ep_addr);
+  musb_int_mask();
+  USBC_SelectActiveEp(epn);
+  if (0 == epn) {
+    if (!ep_addr) { /* Ignore EP80 */
+      _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
+      _dcd.pipe0.buf = NULL;
+      __USBC_Dev_ep0_SendStall();
+    }
+  } else {
+    if (tu_edpt_dir(ep_addr)) { /* IN */
+      __USBC_Dev_Tx_SendStall();
+    } else { /* OUT */
+      TU_ASSERT(!__USBC_Dev_Rx_IsReadDataReady(),);
+      __USBC_Dev_Rx_SendStall();
+    }
+  }
+  musb_int_unmask();
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void)rhport;
+  unsigned const epn = tu_edpt_number(ep_addr);
+  musb_int_mask();
+  USBC_SelectActiveEp(epn);
+  if (0 != epn) {
+    if (tu_edpt_dir(ep_addr)) { /* IN */
+      __USBC_Dev_Tx_ClearStall();
+    } else { /* OUT */
+      __USBC_Dev_Rx_ClearStall();
+    }
+  }
+  musb_int_unmask();
+}
+
+
+void dcd_int_handler(uint8_t rhport)
+{
+  uint8_t is;
+  uint16_t txis, rxis;
+
+  is   = USBC_Readb(USBC_REG_INTUSB(USBC0_BASE));   /* read interrupt status */
+  txis = USBC_Readw(USBC_REG_INTTx(USBC0_BASE)); /* read interrupt status */
+  rxis = USBC_Readw(USBC_REG_INTRx(USBC0_BASE)); /* read interrupt status */
+
+  is &= USBC_Readb(USBC_REG_INTUSBE(USBC0_BASE)); /* ignore disabled interrupts */
+  USBC_Writeb(is, USBC_REG_INTUSB(USBC0_BASE)); /* sunxi musb requires a write to interrupt register to clear */
+  if (is & USBC_INTUSB_DISCONNECT) {
+	dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+  }
+  if (is & USBC_INTUSB_SOF) {
+    dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+  }
+  if (is & USBC_INTUSB_RESET) {
+    /* ep0 FADDR must be 0 when (re)entering peripheral mode */
+    USBC_SelectActiveEp(0);
+    USBC_Dev_SetAddress(0);
+    process_bus_reset(rhport);
+  }
+  if (is & USBC_INTUSB_RESUME) {
+    dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+  }
+  if (is & USBC_INTUSB_SUSPEND) {
+    dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+  }
+
+  txis &= USBC_Readw(USBC_REG_INTTxE(USBC0_BASE));
+  USBC_Writew(txis, USBC_REG_INTTx(USBC0_BASE));
+  if (txis & USBC_INTTx_FLAG_EP0) {
+    process_ep0(rhport);
+    txis &= ~TU_BIT(0);
+  }
+  while (txis) {
+    unsigned const num = __builtin_ctz(txis);
+    process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN));
+    txis &= ~TU_BIT(num);
+  }
+
+  rxis &= USBC_Readw(USBC_REG_INTRxE(USBC0_BASE));
+  USBC_Writew(rxis, USBC_REG_INTRx(USBC0_BASE));
+  while (rxis) {
+    unsigned const num = __builtin_ctz(rxis);
+    process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT));
+    rxis &= ~TU_BIT(num);
+  }
+}
+
+#endif

+ 643 - 0
src/portable/sunxi/musb_def.h

@@ -0,0 +1,643 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2021 Tian Yunhao (t123yh)
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_MUSB_DEF
+#define _TUSB_MUSB_DEF
+
+
+#define  USBC_Readb(reg)	                    (*(volatile unsigned char *)(reg))
+#define  USBC_Readw(reg)	                    (*(volatile unsigned short *)(reg))
+#define  USBC_Readl(reg)	                    (*(volatile unsigned long *)(reg))
+
+#define  USBC_Writeb(value, reg)                (*(volatile unsigned char *)(reg) = (value))
+#define  USBC_Writew(value, reg)	            (*(volatile unsigned short *)(reg) = (value))
+#define  USBC_Writel(value, reg)	            (*(volatile unsigned long *)(reg) = (value))
+
+
+#define USBC_SetBit_Mask_b(reg,mask)	do {																		\
+																				unsigned char _r = USBC_Readb(reg);	\
+																			   _r  |=  (unsigned char)(mask);				\
+																				USBC_Writeb(_r,reg); 								\
+																		}while(0)
+#define USBC_SetBit_Mask_w(reg,mask)	do {																		\
+																				unsigned short _r = USBC_Readw(reg);	\
+																			   _r  |=  (unsigned short)(mask);				\
+																				USBC_Writew(_r,reg); 								\
+																		}while(0)
+#define USBC_SetBit_Mask_l(reg,mask)	do {																		\
+																				unsigned int _r = USBC_Readl(reg);	\
+																			   _r  |=  (unsigned int)(mask);				\
+																				USBC_Writel(_r,reg); 								\
+																		}while(0)
+
+
+#define USBC_ClrBit_Mask_b(reg,mask)	do {																		\
+																				unsigned char _r = USBC_Readb(reg);	\
+																			   _r  &=  (~(unsigned char)(mask));			\
+																				USBC_Writeb(_r,reg); 								\
+																		}while(0);
+#define USBC_ClrBit_Mask_w(reg,mask)	do {																		\
+																				unsigned short _r = USBC_Readw(reg);	\
+																			   _r  &=  (~(unsigned short)(mask));				\
+																				USBC_Writew(_r,reg); 								\
+																		}while(0)
+#define USBC_ClrBit_Mask_l(reg,mask)	do {																		\
+																				unsigned int _r = USBC_Readl(reg);	\
+																			   _r  &=  (~(unsigned int)(mask));				\
+																				USBC_Writel(_r,reg); 								\
+																		}while(0)
+#define  USBC_REG_test_bit_b(bp, reg)         	(USBC_Readb(reg) & (1 << (bp)))
+#define  USBC_REG_test_bit_w(bp, reg)   	    (USBC_Readw(reg) & (1 << (bp)))
+#define  USBC_REG_test_bit_l(bp, reg)   	    (USBC_Readl(reg) & (1 << (bp)))
+
+#define  USBC_REG_set_bit_b(bp, reg) 			(USBC_Writeb((USBC_Readb(reg) | (1 << (bp))) , (reg)))
+#define  USBC_REG_set_bit_w(bp, reg) 	 		(USBC_Writew((USBC_Readw(reg) | (1 << (bp))) , (reg)))
+#define  USBC_REG_set_bit_l(bp, reg) 	 		(USBC_Writel((USBC_Readl(reg) | (1 << (bp))) , (reg)))
+
+#define  USBC_REG_clear_bit_b(bp, reg)	 	 	(USBC_Writeb((USBC_Readb(reg) & (~ (1 << (bp)))) , (reg)))
+#define  USBC_REG_clear_bit_w(bp, reg)	 	 	(USBC_Writew((USBC_Readw(reg) & (~ (1 << (bp)))) , (reg)))
+#define  USBC_REG_clear_bit_l(bp, reg)	 	 	(USBC_Writel((USBC_Readl(reg) & (~ (1 << (bp)))) , (reg)))
+
+#define SW_UDC_EPNUMS 3
+
+#define SUNXI_SRAMC_BASE 0x01c00000
+//---------------------------------------------------------------
+//   reg base
+//---------------------------------------------------------------
+#define  USBC0_BASE                 0x01c13000
+#define  USBC1_BASE                 0x01c14000
+#define  USBC2_BASE                 0x01c1E000
+
+//Some reg whithin musb
+#define USBPHY_CLK_REG 		0x01c200CC
+#define USBPHY_CLK_RST_BIT 0
+#define USBPHY_CLK_GAT_BIT 1
+
+#define BUS_CLK_RST_REG	0x01c202c0 //Bus Clock Reset Register Bit24 : USB CLK RST
+#define BUS_RST_USB_BIT	24
+
+#define BUS_CLK_GATE0_REG	0x01c20060 //Bus Clock Gating Register Bit24 : USB CLK GATE 0: Mask 1 : Pass
+#define BUS_CLK_USB_BIT	24
+
+//#define USB_INTR
+
+#define NDMA_CFG_REG
+//-----------------------------------------------------------------------
+//   musb reg offset
+//-----------------------------------------------------------------------
+
+#define  USBC_REG_o_FADDR		    0x0098
+#define  USBC_REG_o_PCTL		    0x0040
+#define  USBC_REG_o_INTTx		    0x0044
+#define  USBC_REG_o_INTRx		    0x0046
+#define  USBC_REG_o_INTTxE		    0x0048
+#define  USBC_REG_o_INTRxE		    0x004A
+#define  USBC_REG_o_INTUSB		    0x004C
+#define  USBC_REG_o_INTUSBE         0x0050
+#define  USBC_REG_o_FRNUM		    0x0054
+#define  USBC_REG_o_EPIND		    0x0042
+#define  USBC_REG_o_TMCTL		    0x007C
+
+#define  USBC_REG_o_TXMAXP		    0x0080
+#define  USBC_REG_o_CSR0		    0x0082
+#define  USBC_REG_o_TXCSR		    0x0082
+#define  USBC_REG_o_RXMAXP		    0x0084
+#define  USBC_REG_o_RXCSR		    0x0086
+#define  USBC_REG_o_COUNT0		    0x0088
+#define  USBC_REG_o_RXCOUNT		    0x0088
+#define  USBC_REG_o_EP0TYPE		    0x008C
+#define  USBC_REG_o_TXTYPE		    0x008C
+#define  USBC_REG_o_NAKLIMIT0	    0x008D
+#define  USBC_REG_o_TXINTERVAL      0x008D
+#define  USBC_REG_o_RXTYPE		    0x008E
+#define  USBC_REG_o_RXINTERVAL	    0x008F
+
+//#define  USBC_REG_o_CONFIGDATA	0x001F   //
+
+#define  USBC_REG_o_EPFIFO0		    0x0000
+#define  USBC_REG_o_EPFIFO1		    0x0004
+#define  USBC_REG_o_EPFIFO2		    0x0008
+#define  USBC_REG_o_EPFIFO3		    0x000C
+#define  USBC_REG_o_EPFIFO4		    0x0010
+#define  USBC_REG_o_EPFIFO5		    0x0014
+#define  USBC_REG_o_EPFIFOx(n)	    (0x0000 + (n<<2))
+
+#define  USBC_REG_o_DEVCTL		    0x0041
+
+#define  USBC_REG_o_TXFIFOSZ	    0x0090
+#define  USBC_REG_o_RXFIFOSZ	    0x0094
+#define  USBC_REG_o_TXFIFOAD	    0x0092
+#define  USBC_REG_o_RXFIFOAD	    0x0096
+
+#define  USBC_REG_o_VEND0		    0x0043
+#define  USBC_REG_o_VEND1		    0x007D
+#define  USBC_REG_o_VEND3		    0x007E
+
+//#define  USBC_REG_o_PHYCTL		0x006C
+#define  USBC_REG_o_EPINFO		    0x0078
+#define  USBC_REG_o_RAMINFO		    0x0079
+#define  USBC_REG_o_LINKINFO	    0x007A
+#define  USBC_REG_o_VPLEN		    0x007B
+#define  USBC_REG_o_HSEOF		    0x007C
+#define  USBC_REG_o_FSEOF		    0x007D
+#define  USBC_REG_o_LSEOF		    0x007E
+
+//new
+#define  USBC_REG_o_FADDR0          0x0098
+#define  USBC_REG_o_HADDR0          0x009A
+#define  USBC_REG_o_HPORT0          0x009B
+#define  USBC_REG_o_TXFADDRx 		0x0098
+#define  USBC_REG_o_TXHADDRx		0x009A
+#define  USBC_REG_o_TXHPORTx		0x009B
+#define  USBC_REG_o_RXFADDRx		0x009C
+#define  USBC_REG_o_RXHADDRx		0x009E
+#define  USBC_REG_o_RXHPORTx		0x009F
+
+
+#define  USBC_REG_o_RPCOUNT			0x008A
+
+//new
+#define  USBC_REG_o_ISCR            0x0400
+#define  USBC_REG_o_PHYCTL          0x0404
+#define  USBC_REG_o_PHYBIST         0x0408
+#define  USBC_REG_o_PHYTUNE         0x040c
+
+#define  USBC_REG_o_CSR			0x0410
+
+#define USBC_REG_o_PMU_IRQ	 0x0800
+
+//-----------------------------------------------------------------------
+//   registers
+//-----------------------------------------------------------------------
+
+#define  USBC_REG_FADDR(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_FADDR		)
+#define  USBC_REG_PCTL(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_PCTL			)
+#define  USBC_REG_INTTx(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_INTTx		)
+#define  USBC_REG_INTRx(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_INTRx		)
+#define  USBC_REG_INTTxE(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_INTTxE     	)
+#define  USBC_REG_INTRxE(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_INTRxE     	)
+#define  USBC_REG_INTUSB(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_INTUSB     	)
+#define  USBC_REG_INTUSBE(usbc_base_addr)           ((usbc_base_addr) + USBC_REG_o_INTUSBE    	)
+#define  USBC_REG_FRNUM(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_FRNUM      	)
+#define  USBC_REG_EPIND(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_EPIND      	)
+#define  USBC_REG_TMCTL(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_TMCTL      	)
+#define  USBC_REG_TXMAXP(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_TXMAXP     	)
+
+#define  USBC_REG_CSR0(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_CSR0       	)
+#define  USBC_REG_TXCSR(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_TXCSR      	)
+
+#define  USBC_REG_RXMAXP(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_RXMAXP     	)
+#define  USBC_REG_RXCSR(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_RXCSR      	)
+
+#define  USBC_REG_COUNT0(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_COUNT0     	)
+#define  USBC_REG_RXCOUNT(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_RXCOUNT    	)
+
+#define  USBC_REG_EP0TYPE(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_EP0TYPE		)
+#define  USBC_REG_TXTYPE(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_TXTYPE     	)
+
+#define  USBC_REG_NAKLIMIT0(usbc_base_addr)	        ((usbc_base_addr) + USBC_REG_o_NAKLIMIT0  	)
+#define  USBC_REG_TXINTERVAL(usbc_base_addr)        ((usbc_base_addr) + USBC_REG_o_TXINTERVAL	)
+
+#define  USBC_REG_RXTYPE(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_RXTYPE		)
+#define  USBC_REG_RXINTERVAL(usbc_base_addr)	    ((usbc_base_addr) + USBC_REG_o_RXINTERVAL	)
+//#define  USBC_REG_CONFIGDATA(usbc_base_addr)	    ((usbc_base_addr) + USBC_REG_o_CONFIGDATA	)
+#define  USBC_REG_EPFIFO0(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_EPFIFO0		)
+#define  USBC_REG_EPFIFO1(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_EPFIFO1		)
+#define  USBC_REG_EPFIFO2(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_EPFIFO2		)
+#define  USBC_REG_EPFIFO3(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_EPFIFO3		)
+#define  USBC_REG_EPFIFO4(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_EPFIFO4		)
+#define  USBC_REG_EPFIFO5(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_EPFIFO5		)
+#define  USBC_REG_EPFIFOx(usbc_base_addr, n)	    ((usbc_base_addr) + USBC_REG_o_EPFIFOx(n)	)
+#define  USBC_REG_DEVCTL(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_DEVCTL		)
+#define  USBC_REG_TXFIFOSZ(usbc_base_addr)	        ((usbc_base_addr) + USBC_REG_o_TXFIFOSZ		)
+#define  USBC_REG_RXFIFOSZ(usbc_base_addr)	        ((usbc_base_addr) + USBC_REG_o_RXFIFOSZ		)
+#define  USBC_REG_TXFIFOAD(usbc_base_addr)	        ((usbc_base_addr) + USBC_REG_o_TXFIFOAD		)
+#define  USBC_REG_RXFIFOAD(usbc_base_addr)	        ((usbc_base_addr) + USBC_REG_o_RXFIFOAD		)
+#define  USBC_REG_VEND0(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_VEND0		)
+#define  USBC_REG_VEND1(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_VEND1		)
+#define  USBC_REG_EPINFO(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_EPINFO		)
+#define  USBC_REG_RAMINFO(usbc_base_addr)		    ((usbc_base_addr) + USBC_REG_o_RAMINFO		)
+#define  USBC_REG_LINKINFO(usbc_base_addr)	        ((usbc_base_addr) + USBC_REG_o_LINKINFO		)
+#define  USBC_REG_VPLEN(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_VPLEN		)
+#define  USBC_REG_HSEOF(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_HSEOF		)
+#define  USBC_REG_FSEOF(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_FSEOF		)
+#define  USBC_REG_LSEOF(usbc_base_addr)		        ((usbc_base_addr) + USBC_REG_o_LSEOF		)
+
+#define  USBC_REG_FADDR0(usbc_base_addr)            ((usbc_base_addr) + USBC_REG_o_FADDR0		)
+#define  USBC_REG_HADDR0(usbc_base_addr)            ((usbc_base_addr) + USBC_REG_o_HADDR0		)
+#define  USBC_REG_HPORT0(usbc_base_addr)            ((usbc_base_addr) + USBC_REG_o_HPORT0		)
+
+#define  USBC_REG_TXFADDRx(usbc_base_addr, n)		((usbc_base_addr) + USBC_REG_o_TXFADDRx		)
+#define  USBC_REG_TXHADDRx(usbc_base_addr, n)		((usbc_base_addr) + USBC_REG_o_TXHADDRx		)
+#define  USBC_REG_TXHPORTx(usbc_base_addr, n)		((usbc_base_addr) + USBC_REG_o_TXHPORTx		)
+#define  USBC_REG_RXFADDRx(usbc_base_addr, n)		((usbc_base_addr) + USBC_REG_o_RXFADDRx		)
+#define  USBC_REG_RXHADDRx(usbc_base_addr, n)		((usbc_base_addr) + USBC_REG_o_RXHADDRx		)
+#define  USBC_REG_RXHPORTx(usbc_base_addr, n)		((usbc_base_addr) + USBC_REG_o_RXHPORTx		)
+
+#define  USBC_REG_RPCOUNTx(usbc_base_addr, n)	    ((usbc_base_addr) + USBC_REG_o_RPCOUNT		)
+
+#define  USBC_REG_ISCR(usbc_base_addr)	    	    ((usbc_base_addr) + USBC_REG_o_ISCR			)
+#define  USBC_REG_PHYCTL(usbc_base_addr)	        ((usbc_base_addr) + USBC_REG_o_PHYCTL		)
+#define  USBC_REG_PHYBIST(usbc_base_addr)	        ((usbc_base_addr) + USBC_REG_o_PHYBIST		)
+#define  USBC_REG_PHYTUNE(usbc_base_addr)           ((usbc_base_addr) + USBC_REG_o_PHYTUNE		)
+#define  USBC_REG_PMU_IRQ(usbc_base_addr)           ((usbc_base_addr) + USBC_REG_o_PMU_IRQ		)
+#define  USBC_REG_CSR(usbc_base_addr)           ((usbc_base_addr) + USBC_REG_o_CSR)
+//-----------------------------------------------------------------------
+//   bit position
+//-----------------------------------------------------------------------
+
+/* USB Power Control for Host only  */
+#define  USBC_BP_POWER_H_HIGH_SPEED_EN			5
+#define  USBC_BP_POWER_H_HIGH_SPEED_FLAG		4
+#define  USBC_BP_POWER_H_RESET					3
+#define  USBC_BP_POWER_H_RESUME					2
+#define  USBC_BP_POWER_H_SUSPEND				1
+#define  USBC_BP_POWER_H_SUEPEND_EN				0
+
+/* USB Power Control for device only  */
+#define  USBC_BP_POWER_D_ISO_UPDATE_EN			7
+#define  USBC_BP_POWER_D_SOFT_CONNECT			6
+#define  USBC_BP_POWER_D_HIGH_SPEED_EN			5
+#define  USBC_BP_POWER_D_HIGH_SPEED_FLAG		4
+#define  USBC_BP_POWER_D_RESET_FLAG				3
+#define  USBC_BP_POWER_D_RESUME					2
+#define  USBC_BP_POWER_D_SUSPEND				1
+#define  USBC_BP_POWER_D_ENABLE_SUSPENDM		0
+
+/* interrupt flags for ep0 and the Tx ep1~4 */
+#define  USBC_BP_INTTx_FLAG_EP5				    5
+#define  USBC_BP_INTTx_FLAG_EP4				    4
+#define  USBC_BP_INTTx_FLAG_EP3				    3
+#define  USBC_BP_INTTx_FLAG_EP2		    		2
+#define  USBC_BP_INTTx_FLAG_EP1  				1
+#define  USBC_BP_INTTx_FLAG_EP0					0
+
+/* interrupt flags for Rx ep1~4 */
+#define  USBC_BP_INTRx_FLAG_EP5				    5
+#define  USBC_BP_INTRx_FLAG_EP4				    4
+#define  USBC_BP_INTRx_FLAG_EP3				    3
+#define  USBC_BP_INTRx_FLAG_EP2				    2
+#define  USBC_BP_INTRx_FLAG_EP1				    1
+
+/* interrupt enable for Tx ep0~4 */
+#define  USBC_BP_INTTxE_EN_EP5				    5
+#define  USBC_BP_INTTxE_EN_EP4				    4
+#define  USBC_BP_INTTxE_EN_EP3				    3
+#define  USBC_BP_INTTxE_EN_EP2				    2
+#define  USBC_BP_INTTxE_EN_EP1				    1
+#define  USBC_BP_INTTxE_EN_EP0					0
+
+/* interrupt enable for Rx ep1~4 */
+#define  USBC_BP_INTRxE_EN_EP5				    5
+#define  USBC_BP_INTRxE_EN_EP4				    4
+#define  USBC_BP_INTRxE_EN_EP3				    3
+#define  USBC_BP_INTRxE_EN_EP2			    	2
+#define  USBC_BP_INTRxE_EN_EP1  		    	1
+
+/* USB interrupt */
+#define  USBC_BP_INTUSB_VBUS_ERROR				7
+#define  USBC_BP_INTUSB_SESSION_REQ				6
+#define  USBC_BP_INTUSB_DISCONNECT				5
+#define  USBC_BP_INTUSB_CONNECT					4
+#define  USBC_BP_INTUSB_SOF						3
+#define  USBC_BP_INTUSB_RESET					2
+#define  USBC_BP_INTUSB_RESUME					1
+#define  USBC_BP_INTUSB_SUSPEND					0
+
+/* USB interrupt enable */
+#define  USBC_BP_INTUSBE_EN_VBUS_ERROR			7
+#define  USBC_BP_INTUSBE_EN_SESSION_REQ			6
+#define  USBC_BP_INTUSBE_EN_DISCONNECT			5
+#define  USBC_BP_INTUSBE_EN_CONNECT				4
+#define  USBC_BP_INTUSBE_EN_SOF					3
+#define  USBC_BP_INTUSBE_EN_RESET				2
+#define  USBC_BP_INTUSBE_EN_RESUME				1
+#define  USBC_BP_INTUSBE_EN_SUSPEND				0
+
+/* Test Mode Control */
+#define  USBC_BP_TMCTL_FORCE_HOST               7
+#define  USBC_BP_TMCTL_FIFO_ACCESS              6
+#define  USBC_BP_TMCTL_FORCE_FS                 5
+#define  USBC_BP_TMCTL_FORCE_HS                 4
+#define  USBC_BP_TMCTL_TEST_PACKET              3
+#define  USBC_BP_TMCTL_TEST_K                   2
+#define  USBC_BP_TMCTL_TEST_J                   1
+#define  USBC_BP_TMCTL_TEST_SE0_NAK             0
+
+/* Tx Max packet */
+#define  USBC_BP_TXMAXP_PACKET_COUNT            11
+#define  USBC_BP_TXMAXP_MAXIMUM_PAYLOAD         0
+
+/* Control and Status Register for ep0 for Host only */
+#define  USBC_BP_CSR0_H_DisPing 				11
+#define  USBC_BP_CSR0_H_FlushFIFO				8
+#define  USBC_BP_CSR0_H_NAK_Timeout				7
+#define  USBC_BP_CSR0_H_StatusPkt				6
+#define  USBC_BP_CSR0_H_ReqPkt					5
+#define  USBC_BP_CSR0_H_Error					4
+#define  USBC_BP_CSR0_H_SetupPkt				3
+#define  USBC_BP_CSR0_H_RxStall					2
+#define  USBC_BP_CSR0_H_TxPkRdy					1
+#define  USBC_BP_CSR0_H_RxPkRdy					0
+
+/* Control and Status Register for ep0 for device only */
+#define  USBC_BP_CSR0_D_FLUSH_FIFO				8
+#define  USBC_BP_CSR0_D_SERVICED_SETUP_END		7
+#define  USBC_BP_CSR0_D_SERVICED_RX_PKT_READY   6
+#define  USBC_BP_CSR0_D_SEND_STALL				5
+#define  USBC_BP_CSR0_D_SETUP_END				4
+#define  USBC_BP_CSR0_D_DATA_END				3
+#define  USBC_BP_CSR0_D_SENT_STALL				2
+#define  USBC_BP_CSR0_D_TX_PKT_READY			1
+#define  USBC_BP_CSR0_D_RX_PKT_READY			0
+
+/* Tx ep Control and Status Register for Host only */
+#define  USBC_BP_TXCSR_H_AUTOSET				15
+#define  USBC_BP_TXCSR_H_RESERVED				14
+#define  USBC_BP_TXCSR_H_MODE				    13
+#define  USBC_BP_TXCSR_H_DMA_REQ_EN			 	12
+#define  USBC_BP_TXCSR_H_FORCE_DATA_TOGGLE		11
+#define  USBC_BP_TXCSR_H_DMA_REQ_MODE			10
+#define  USBC_BP_TXCSR_H_NAK_TIMEOUT			7
+#define  USBC_BP_TXCSR_H_CLEAR_DATA_TOGGLE		6
+#define  USBC_BP_TXCSR_H_TX_STALL				5
+#define  USBC_BP_TXCSR_H_FLUSH_FIFO				3
+#define  USBC_BP_TXCSR_H_ERROR					2
+#define  USBC_BP_TXCSR_H_FIFO_NOT_EMPTY 		1
+#define  USBC_BP_TXCSR_H_TX_READY				0
+
+/* Tx ep Control and Status Register for Device only */
+#define  USBC_BP_TXCSR_D_AUTOSET				15
+#define  USBC_BP_TXCSR_D_ISO					14
+#define  USBC_BP_TXCSR_D_MODE					13
+#define  USBC_BP_TXCSR_D_DMA_REQ_EN				12
+#define  USBC_BP_TXCSR_D_FORCE_DATA_TOGGLE		11
+#define  USBC_BP_TXCSR_D_DMA_REQ_MODE			10
+#define  USBC_BP_TXCSR_D_INCOMPLETE				7
+#define  USBC_BP_TXCSR_D_CLEAR_DATA_TOGGLE		6
+#define  USBC_BP_TXCSR_D_SENT_STALL				5
+#define  USBC_BP_TXCSR_D_SEND_STALL				4
+#define  USBC_BP_TXCSR_D_FLUSH_FIFO				3
+#define  USBC_BP_TXCSR_D_UNDER_RUN				2
+#define  USBC_BP_TXCSR_D_FIFO_NOT_EMPTY 		1
+#define  USBC_BP_TXCSR_D_TX_READY				0
+
+/* Rx Max Packet */
+#define  USBC_BP_RXMAXP_PACKET_COUNT            11
+#define  USBC_BP_RXMAXP_MAXIMUM_PAYLOAD         0
+
+/* Rx ep Control and Status Register for Host only */
+#define  USBC_BP_RXCSR_H_AUTO_CLEAR			    15
+#define  USBC_BP_RXCSR_H_AUTO_REQ			    14
+#define  USBC_BP_RXCSR_H_DMA_REQ_EN			    13
+#define  USBC_BP_RXCSR_H_PID_ERROR			    12
+#define  USBC_BP_RXCSR_H_DMA_REQ_MODE		    11
+
+#define  USBC_BP_RXCSR_H_INCOMPLETE			    8
+#define  USBC_BP_RXCSR_H_CLEAR_DATA_TOGGLE	    7
+#define  USBC_BP_RXCSR_H_RX_STALL			    6
+#define  USBC_BP_RXCSR_H_REQ_PACKET			    5
+#define  USBC_BP_RXCSR_H_FLUSH_FIFO			    4
+#define  USBC_BP_RXCSR_H_NAK_TIMEOUT		    3
+#define  USBC_BP_RXCSR_H_ERROR				    2
+#define  USBC_BP_RXCSR_H_FIFO_FULL			    1
+#define  USBC_BP_RXCSR_H_RX_PKT_READY		    0
+
+/* Rx ep Control and Status Register for Device only */
+#define  USBC_BP_RXCSR_D_AUTO_CLEAR			    15
+#define  USBC_BP_RXCSR_D_ISO				    14
+#define  USBC_BP_RXCSR_D_DMA_REQ_EN			    13
+#define  USBC_BP_RXCSR_D_DISABLE_NYET		    12
+#define  USBC_BP_RXCSR_D_DMA_REQ_MODE		    11
+
+#define  USBC_BP_RXCSR_D_INCOMPLETE			    8
+#define  USBC_BP_RXCSR_D_CLEAR_DATA_TOGGLE	    7
+#define  USBC_BP_RXCSR_D_SENT_STALL			    6
+#define  USBC_BP_RXCSR_D_SEND_STALL			    5
+#define  USBC_BP_RXCSR_D_FLUSH_FIFO			    4
+#define  USBC_BP_RXCSR_D_DATA_ERROR			    3
+#define  USBC_BP_RXCSR_D_OVERRUN			    2
+#define  USBC_BP_RXCSR_D_FIFO_FULL			    1
+#define  USBC_BP_RXCSR_D_RX_PKT_READY		    0
+
+/* Tx Type Register for host only */
+#define  USBC_BP_TXTYPE_SPEED	                6              //new
+#define  USBC_BP_TXTYPE_PROROCOL	            4
+#define  USBC_BP_TXTYPE_TARGET_EP_NUM           0
+
+/* Rx Type Register for host only */
+#define  USBC_BP_RXTYPE_SPEED		            6              //new
+#define  USBC_BP_RXTYPE_PROROCOL	            4
+#define  USBC_BP_RXTYPE_TARGET_EP_NUM           0
+
+/* Core Configueation */
+#define  USBC_BP_CONFIGDATA_MPRXE               7
+#define  USBC_BP_CONFIGDATA_MPTXE               6
+#define  USBC_BP_CONFIGDATA_BIGENDIAN		    5
+#define  USBC_BP_CONFIGDATA_HBRXE			    4
+#define  USBC_BP_CONFIGDATA_HBTXE			    3
+#define  USBC_BP_CONFIGDATA_DYNFIFO_SIZING	    2
+#define  USBC_BP_CONFIGDATA_SOFTCONE		    1
+#define  USBC_BP_CONFIGDATA_UTMI_DATAWIDTH	    0
+
+/* OTG Device Control */
+#define  USBC_BP_DEVCTL_B_DEVICE			    7
+#define  USBC_BP_DEVCTL_FS_DEV				    6
+#define  USBC_BP_DEVCTL_LS_DEV				    5
+
+#define  USBC_BP_DEVCTL_VBUS				    3
+#define  USBC_BP_DEVCTL_HOST_MODE			    2
+#define  USBC_BP_DEVCTL_HOST_REQ			    1
+#define  USBC_BP_DEVCTL_SESSION				    0
+
+/* Tx EP FIFO size control */
+#define  USBC_BP_TXFIFOSZ_DPB				    4
+#define  USBC_BP_TXFIFOSZ_SZ				    0
+
+/* Rx EP FIFO size control */
+#define  USBC_BP_RXFIFOSZ_DPB				    4
+#define  USBC_BP_RXFIFOSZ_SZ				    0
+
+/* vendor0 */
+#define  USBC_BP_VEND0_DRQ_SEL				    1
+#define  USBC_BP_VEND0_BUS_SEL				    0
+
+/* hub address */
+#define  USBC_BP_HADDR_MULTI_TT					7
+
+/* Interface Status and Control */
+#define  USBC_BP_ISCR_VBUS_VALID_FROM_DATA		30
+#define  USBC_BP_ISCR_VBUS_VALID_FROM_VBUS		29
+#define  USBC_BP_ISCR_EXT_ID_STATUS				28
+#define  USBC_BP_ISCR_EXT_DM_STATUS				27
+#define  USBC_BP_ISCR_EXT_DP_STATUS				26
+#define  USBC_BP_ISCR_MERGED_VBUS_STATUS		25
+#define  USBC_BP_ISCR_MERGED_ID_STATUS			24
+
+#define  USBC_BP_ISCR_ID_PULLUP_EN				17
+#define  USBC_BP_ISCR_DPDM_PULLUP_EN			16
+#define  USBC_BP_ISCR_FORCE_ID					14
+#define  USBC_BP_ISCR_FORCE_VBUS_VALID			12
+#define  USBC_BP_ISCR_VBUS_VALID_SRC			10
+
+#define  USBC_BP_ISCR_HOSC_EN                 	7
+#define  USBC_BP_ISCR_VBUS_CHANGE_DETECT      	6
+#define  USBC_BP_ISCR_ID_CHANGE_DETECT        	5
+#define  USBC_BP_ISCR_DPDM_CHANGE_DETECT      	4
+#define  USBC_BP_ISCR_IRQ_ENABLE              	3
+#define  USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN   	2
+#define  USBC_BP_ISCR_ID_CHANGE_DETECT_EN     	1
+#define  USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN   	0
+
+
+#define SUNXI_EHCI_AHB_ICHR8_EN		(1 << 10)
+#define SUNXI_EHCI_AHB_INCR4_BURST_EN	(1 << 9)
+#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN	(1 << 8)
+#define SUNXI_EHCI_ULPI_BYPASS_EN	(1 << 0)
+//-----------------------------------------------------------------------
+//   �Զ���
+//-----------------------------------------------------------------------
+
+/* usb��Դ���� */
+#define  USBC_MAX_CTL_NUM                   1
+#define  USBC_MAX_EP_NUM                    3   //ep0~2, ep�ĸ���
+#define  USBC_MAX_FIFO_SIZE                 (2 * 1024)
+
+/* usb OTG mode */
+#define  USBC_OTG_HOST                      0
+#define  USBC_OTG_DEVICE                    1
+
+/* usb device type */
+#define  USBC_DEVICE_HSDEV                  0
+#define  USBC_DEVICE_FSDEV                  1
+#define  USBC_DEVICE_LSDEV                  2
+
+/*  usb transfer type  */
+#define  USBC_TS_TYPE_IDLE                  0
+#define  USBC_TS_TYPE_CTRL                  1
+#define  USBC_TS_TYPE_ISO                   2
+#define  USBC_TS_TYPE_INT                   3
+#define  USBC_TS_TYPE_BULK                  4
+
+/*  usb transfer mode  */
+#define  USBC_TS_MODE_UNKOWN                0
+#define  USBC_TS_MODE_LS                    1
+#define  USBC_TS_MODE_FS                    2
+#define  USBC_TS_MODE_HS                    3
+
+/* usb Vbus status */
+#define  USBC_VBUS_STATUS_BELOW_SESSIONEND                 0
+#define  USBC_VBUS_STATUS_ABOVE_SESSIONEND_BELOW_AVALID    1
+#define  USBC_VBUS_STATUS_ABOVE_AVALID_BELOW_VBUSVALID     2
+#define  USBC_VBUS_STATUS_ABOVE_VBUSVALID                  3
+
+/* usb io type */
+#define  USBC_IO_TYPE_PIO    		        0
+#define  USBC_IO_TYPE_DMA    		        1
+
+/* usb ep type */
+#define  USBC_EP_TYPE_IDLE    		        0
+#define  USBC_EP_TYPE_EP0    		        1
+#define  USBC_EP_TYPE_TX     		        2
+#define  USBC_EP_TYPE_RX     		        3
+
+/* usb id type */
+#define  USBC_ID_TYPE_DISABLE      	        0
+#define  USBC_ID_TYPE_HOST         	        1
+#define  USBC_ID_TYPE_DEVICE       	        2
+
+/* usb vbus valid type */
+#define  USBC_VBUS_TYPE_DISABLE    	        0
+#define  USBC_VBUS_TYPE_LOW       	        1
+#define  USBC_VBUS_TYPE_HIGH       	        2
+
+/* usb a valid source */
+#define  USBC_A_VALID_SOURCE_UTMI_AVALID	0
+#define  USBC_A_VALID_SOURCE_UTMI_VBUS    	1
+
+/* usb device switch */
+#define  USBC_DEVICE_SWITCH_OFF             0
+#define  USBC_DEVICE_SWITCH_ON              1
+
+/* usb fifo config mode */
+#define  USBC_FIFO_MODE_4K                  0
+#define  USBC_FIFO_MODE_8K                  1
+
+/*
+ **************************************************
+ *  usb interrupt mask
+ *
+ **************************************************
+ */
+
+/* interrupt flags for ep0 and the Tx ep1~4 */
+#define  USBC_INTTx_FLAG_EP5				    (1 << USBC_BP_INTTx_FLAG_EP5)
+#define  USBC_INTTx_FLAG_EP4				    (1 << USBC_BP_INTTx_FLAG_EP4)
+#define  USBC_INTTx_FLAG_EP3				    (1 << USBC_BP_INTTx_FLAG_EP3)
+#define  USBC_INTTx_FLAG_EP2		    		(1 << USBC_BP_INTTx_FLAG_EP2)
+#define  USBC_INTTx_FLAG_EP1  				    (1 << USBC_BP_INTTx_FLAG_EP1)
+#define  USBC_INTTx_FLAG_EP0					(1 << USBC_BP_INTTx_FLAG_EP0)
+
+/* interrupt flags for Rx ep1~4 */
+#define  USBC_INTRx_FLAG_EP5				    (1 << USBC_BP_INTRx_FLAG_EP5)
+#define  USBC_INTRx_FLAG_EP4				    (1 << USBC_BP_INTRx_FLAG_EP4)
+#define  USBC_INTRx_FLAG_EP3				    (1 << USBC_BP_INTRx_FLAG_EP3)
+#define  USBC_INTRx_FLAG_EP2				    (1 << USBC_BP_INTRx_FLAG_EP2)
+#define  USBC_INTRx_FLAG_EP1				    (1 << USBC_BP_INTRx_FLAG_EP1)
+
+/* USB interrupt */
+#define  USBC_INTUSB_VBUS_ERROR				    (1 << USBC_BP_INTUSB_VBUS_ERROR)
+#define  USBC_INTUSB_SESSION_REQ				(1 << USBC_BP_INTUSB_SESSION_REQ)
+#define  USBC_INTUSB_DISCONNECT				    (1 << USBC_BP_INTUSB_DISCONNECT)
+#define  USBC_INTUSB_CONNECT					(1 << USBC_BP_INTUSB_CONNECT)
+#define  USBC_INTUSB_SOF						(1 << USBC_BP_INTUSB_SOF)
+#define  USBC_INTUSB_RESET					    (1 << USBC_BP_INTUSB_RESET)
+#define  USBC_INTUSB_RESUME					    (1 << USBC_BP_INTUSB_RESUME)
+#define  USBC_INTUSB_SUSPEND					(1 << USBC_BP_INTUSB_SUSPEND)
+
+#define USB_CSRL0_NAKTO         0x00000080  // NAK Timeout
+#define USB_CSRL0_SETENDC       0x00000080  // Setup End Clear
+#define USB_CSRL0_STATUS        0x00000040  // STATUS Packet
+#define USB_CSRL0_RXRDYC        0x00000040  // RXRDY Clear
+#define USB_CSRL0_REQPKT        0x00000020  // Request Packet
+#define USB_CSRL0_STALL         0x00000020  // Send Stall
+#define USB_CSRL0_SETEND        0x00000010  // Setup End
+#define USB_CSRL0_ERROR         0x00000010  // Error
+#define USB_CSRL0_DATAEND       0x00000008  // Data End
+#define USB_CSRL0_SETUP         0x00000008  // Setup Packet
+#define USB_CSRL0_STALLED       0x00000004  // Endpoint Stalled
+#define USB_CSRL0_TXRDY         0x00000002  // Transmit Packet Ready
+#define USB_CSRL0_RXRDY         0x00000001  // Receive Packet Ready
+
+#define USB_RXFIFOSZ_DPB        0x00000010  // Double Packet Buffer Support
+#define USB_RXFIFOSZ_SIZE_M     0x0000000F  // Max Packet Size
+
+#define USB_TXFIFOSZ_DPB        0x00000010  // Double Packet Buffer Support
+#define USB_TXFIFOSZ_SIZE_M     0x0000000F  // Max Packet Size
+
+#endif

+ 4 - 0
src/tusb_option.h

@@ -145,6 +145,9 @@
 #define OPT_MCU_FT90X            2000 ///< BridgeTek FT90x
 #define OPT_MCU_FT93X            2001 ///< BridgeTek FT93x
 
+// Allwinner
+#define OPT_MCU_F1C100S          2100 ///< Allwinner F1C100s family
+
 // Helper to check if configured MCU is one of listed
 // Apply _TU_CHECK_MCU with || as separator to list of input
 #define _TU_CHECK_MCU(_m)   (CFG_TUSB_MCU == _m)
@@ -160,6 +163,7 @@
 #define OPT_OS_CUSTOM     4  ///< Custom OS is implemented by application
 #define OPT_OS_PICO       5  ///< Raspberry Pi Pico SDK
 #define OPT_OS_RTTHREAD   6  ///< RT-Thread
+#define OPT_OS_RTX4       7  ///< Keil RTX 4
 
 // Allow to use command line to change the config name/location
 #ifdef CFG_TUSB_CONFIG_FILE

+ 48 - 0
tools/mksunxi.py

@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+import sys
+import struct
+
+def align(num, alignment):
+    if num % alignment != 0:
+        num += (alignment - num % alignment)
+    return num
+
+
+def process_file(input, output):
+    with open(input, 'rb') as fin:
+        content = bytearray(fin.read())
+
+    align_value = 512
+    padded_length = align(len(content), align_value)
+    # pad file to actual length
+    content += b'\x00' * (padded_length - len(content))
+
+    struct_format = '<L8sLL'
+    (instruction, magic, checksum, length) = struct.unpack_from(struct_format, content)
+
+    if magic != b'eGON.BT0':
+        print("Magic is invalid:", magic)
+        return 2
+
+    checksum = 0x5F0A6C39
+    length = align(length, align_value)
+
+    struct.pack_into(struct_format, content, 0, instruction, magic, checksum, length)
+
+    checksum = 0
+    for i in range(0, length, 4):
+        (n, ) = struct.unpack_from('<L', content, i)
+        checksum += n
+        checksum %= 4294967296
+
+    struct.pack_into(struct_format, content, 0, instruction, magic, checksum, length)
+
+    with open(output, 'wb') as fout:
+        fout.write(content)
+    return 0
+
+if __name__ == "__main__":
+    if len(sys.argv) != 3:
+        print("Usage: mksunxi.py input.bin output.bin")
+        exit(1)
+    exit(process_file(sys.argv[1], sys.argv[2]))